【问题标题】:Random pattern while animating simulated gradient in canvas element在画布元素中为模拟渐变设置动画时的随机模式
【发布时间】:2015-11-13 16:53:42
【问题描述】:

这是一个关于我在通过 javascript 试验 canvas 元素时弹出的问题的查询。我想要一个点数组,形成一个随时间移动的渐变,与出现的奇怪模式(仅在第一波或更多波之后)完全不同,它也根据列数和行数而变化画布(改变点的大小只会使图案变大或变小,它总是在相同的像素上。

这里有一个小演示,我的意思是有点界面让你乱搞,变化模式的一个例子是,如果行数更改为原始列数的 0.75 倍(即 40列,30 行)。

http://codepen.io/zephyr/pen/GpwwWB

Javascript:

String.prototype.hexToRGBA = function(a) {
        function cutHex(h) {
                return (h.charAt(0) == "#") ? h.substring(1, 7) : h
        }
        var r = parseInt((cutHex(this)).substring(0, 2), 16);
        var g = parseInt((cutHex(this)).substring(2, 4), 16);
        var b = parseInt((cutHex(this)).substring(4, 6), 16);
        return 'rgba(' + r.toString() + ',' + g.toString() + ',' + b.toString() + ',' + a.toString() + ')';
}

CanvasRenderingContext2D.prototype.clearDrawRect = function(shape) {
        this.clearRect(shape.position.x, shape.position.y, shape.size, shape.size);
        this.fillStyle = shape.color.base;
        this.fillRect(shape.position.x, shape.position.y, shape.size, shape.size);
}

CanvasRenderingContext2D.prototype.render = function(render) {
        (function animate() {
                requestAnimationFrame(animate);
                render();
        })();
}

CanvasRenderingContext2D.prototype.renderAndThrottleFpsAt = function(fps, render) {
        var fpsInterval, startTime, now, then, elapsed;

        fpsInterval = 1000 / fps;
        then = Date.now();
        startTime = then;

        (function animate() {
                requestAnimationFrame(animate);
                now = Date.now();
                elapsed = now - then;
                if (elapsed > fpsInterval) {
                        then = now - (elapsed % fpsInterval);
                        render();
                }
        })();
}

CanvasRenderingContext2D.prototype.pool = {};

CanvasRenderingContext2D.prototype.parsePoint = function(x, y, s, c) {
        return {
                color: c,
                position: {
                        x: x,
                        y: y
                },
                size: s
        }
}

CanvasRenderingContext2D.prototype.fillPointsPool = function(size, cols, rows, color) {
        var i = cols;
        var j = rows;
        while(i--){
            while(j--){
                var x = i * size;
                var y = j * size;
                var a = (i * j) / (cols * rows);
                var c = {
                        hex: color,
                        alpha: a,
                        dir: 1
                };
                if (typeof this.pool.points == 'undefined') {
                        this.pool.points = [this.parsePoint(x, y, size, c)];
                } else {
                        this.pool.points.push(this.parsePoint(x, y, size, c));
                }
            }
            j = rows;
        }
}

CanvasRenderingContext2D.prototype.updatePointsPool = function(size, cols, rows, color) {
        this.pool.points = [];
        this.clearRect(0,0,this.canvas.width,this.canvas.height);
        this.fillPointsPool(size, cols, rows, color);
}

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

// Populate Points
var size = document.getElementById('size');
var cols = document.getElementById('cols');
var rows = document.getElementById('rows');
var color = document.getElementById('color');
ctx.fillPointsPool(size.value, cols.value, rows.value, color.value);

size.oninput = function(){
    ctx.updatePointsPool(this.value, cols.value, rows.value, color.value);
}
cols.oninput = function(){
    ctx.updatePointsPool(size.value, this.value, rows.value, color.value);
}
rows.oninput = function(){
    ctx.updatePointsPool(size.value, cols.value, this.value, color.value);
}
color.oninput = function(){
    ctx.updatePointsPool(size.value, cols.value, rows.value, this.value);
}

ctx.renderAndThrottleFpsAt(60, function(){
        var i = 0;
        var len = ctx.pool.points.length;
        while (i<len) {
                var point = ctx.pool.points[i];

                // Change alpha for wave
                var delta = 0.01;
                point.color.alpha = point.color.alpha + (delta * point.color.dir);
                if (point.color.alpha > 1) {
                        point.color.dir = -1;
                } else if (point.color.alpha <= 0) {
                        point.color.dir = 1;
                }

                // Calculate rgba value with new alpha
                point.color.base = point.color.hex.hexToRGBA(point.color.alpha);
                ctx.clearDrawRect(point);
                i++;
        }
});

你们中是否有人知道导致该模式出现的原因,以及解决此问题的任何建议?

注意:我将更改 updatePointsPool 函数

【问题讨论】:

    标签: javascript animation canvas html5-canvas


    【解决方案1】:

    当您改变方向时,您忘记了限制您的 alpha 值。 alpha 值中的小错误会慢慢累积,从而在动画进行时产生您看到的不需要的伪影。

    在您将增量方向添加到 alpha 之后,修复在代码中添加上限和下限到 alpha。

    if (point.color.alpha > 1) {
        point.color.alpha = 1;  // clamp alpha max
        point.color.dir = -1;
    } else if (point.color.alpha <= 0) {
        point.color.alpha = 0;  // clamp alpha min
        point.color.dir = 1;
    } 
    

    【讨论】:

    • 啊,我尝试过类似的方法,但只是设置值完全没有想到。但是,我仍然很好奇这实际上是如何出现的,模式会随着列数和行数的变化而变化,并且它们都具有完全相同的“颜色”,我原以为不钳制它将意味着它会比它更随机。我用here 的解决方案制作了一支分叉笔,因为我喜欢这种模式 xD 就像 Bob Ross 所说的那样,这是一个快乐的小意外
    • 它是创建模式的起始条件,它不是随机的,并且开始时的模式比你从浮点中得到的任何噪声都要大许多数量级。因为 alpha 的起始值取决于行数和列数,并且由于这些值是从整数计算的,所以许多共享相同的偏移误差,因此看起来是一样的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-23
    • 1970-01-01
    • 1970-01-01
    • 2012-02-15
    • 2017-07-25
    • 1970-01-01
    相关资源
    最近更新 更多