javascript - 在 Canvas 元素中对模拟渐变进行动画处理时的随机图案

标签 javascript animation canvas html5-canvas

这是一个关于我通过 javascript 试验 canvas 元素时弹出的内容的查询。我想要一个点数组,形成一个随时间移动的梯度,它与出现的奇怪模式完美地分开(仅在第一波或更多波之后),它也会根据中的列数和行数而变化 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 函数

最佳答案

当您改变方向时,您忘记限制 alpha 值。随着动画的进展,Alpha 值中的小误差会慢慢累积,产生您看到的不需要的伪影。

要修复此问题,请在将 delta 方向添加到 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;
} 

关于javascript - 在 Canvas 元素中对模拟渐变进行动画处理时的随机图案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33697876/

相关文章:

html - 我们如何将 animations.css 应用到 GWT 小部件。?

javascript - Canvas 清除无法正常工作

javascript - 使用 Azure VM Javascript SDK 从 RunCommand 获取 StdOut

JavaScript - 更改下拉列表索引和文本

css - 如何在多个字符串上使用 CSS 应用类型编写器动画

jquery - 使用 jQuery、CSS、HTML5 在表格单元格中进行图片动画对齐

javascript - 如何使用 fabric.js 将滚动条添加到(可能是无限的) Canvas

javascript - 使用 jquery 添加和删除 Canvas 类

javascript - 从 NPM( Node 模块)解析 nunjucks 模板?

javascript - CSS:如何删除伪元素(之后,之前......)?