如何消除渐变中的间隙

时间:2014-10-24 04:07:37

标签: javascript algorithm interpolation linear-gradients

渐变6,7,8和10在其初始颜色之后具有可见的间隙。有没有办法填补这个空白?

我假设一旦范围被分区,如果它们不能被画布的宽度整除,则整数分区的总和小于原始分区的总和。

信息

  • render1() - 通过生成两种颜色之间的颜色范围来插值。

  • render2() - JavaScript createLinearGradient(),偶数停止n次。



$(document).ready(function () {
    function addCanvas(ol) {
        var canvas = $('<canvas>', {
            "width": 240,
                "height": 10
        }).addClass('grd')
        .appendTo($('<li>').appendTo(ol));
      return canvas[0];
    }
    var ol = $('<ol>').appendTo($('body'));
    var c1 = '#FF0000';
    var c2 = '#00FF00';
    var canvas;
    for (var i = 1; i <= 30; i+=3) {
        canvas = addCanvas(ol);
        var colors = generateColors(c1, c2, i);
        render(canvas, colors);
    }
    canvas = addCanvas(ol);
    render2(canvas, [c1, c2]);
});

function toHex(c) {
    return (function (hex) {
        return hex.length == 1 ? "0" + hex : hex;
    })(c.toString(16));
}

function hexToRgb(hex) {
    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : null;
}

function rgbToHex(rgb) {
    var r = 0,
        g = 0,
        b = 0;
    if (arguments.length === 1) {
        r = rgb.r || 0;
        g = rgb.g || 0;
        b = rgb.b || 0;
    } else if (arguments.length === 3) {
        r = arguments[0];
        g = arguments[1];
        b = arguments[2];
    }
    return "#" + toHex(r) + toHex(g) + toHex(b);
}


function render(canvas, colors) {
    var ctx = canvas.getContext("2d");
    var n = colors.length;
    var x = 0;
    var subWidth = canvas.width / n;
    for (var i = 0; i < n; i++) {
        var start = i * subWidth;
        var end = start + subWidth;
        ctx.fillStyle = colors[i];
        ctx.fillRect(x + start, 0, x + end, canvas.height);
    }
}

function render2(canvas, colors) {
    var ctx = canvas.getContext("2d");
    var x = canvas.x;
    var y = canvas.y;
    var width = canvas.width;
    var height = canvas.height;
    ctx.fillStyle = createGradient(ctx, colors, x, y, width, height)
    ctx.fillRect(0, 0, width, height);
}

function generateColors(color1, color2, n) {
    function partition(a, b, n) {
        function magnitude(a, b) {
            if (a === b) return 0;
            else if (a > b) return -1 * (a - b);
            else return b - a;
        }
        return magnitude(a, b) / n;
    }
    var c1 = hexToRgb(color1);
    var c2 = hexToRgb(color2);
    var rd = partition(c1.r, c2.r, n);
    var gd = partition(c1.g, c2.g, n);
    var bd = partition(c1.b, c2.b, n);
    var colors = [];
    var i, r, g, b, h = n/2;
    for (i = 0; i < h; i++) {
        r = Math.floor(c1.r + rd * i);
        g = Math.floor(c1.g + gd * i);
        b = Math.floor(c1.b + bd * i);
        colors.push(rgbToHex(r, g, b));
    }
    for (var j = 0; i < n; j++, i++) {
        var k = h-j-1;
        r = Math.floor(c2.r - rd * k);
        g = Math.floor(c2.g - gd * k);
        b = Math.floor(c2.b - bd * k);
        colors.push(rgbToHex(r, g, b));
    }  
    return colors;
}

function createGradient(ctx, colors, x, y, width, height) {
    var h = height / 2;
    var grd = ctx.createLinearGradient(0, h, width, h);
    var n = Math.max(colors.length - 1, 1);
    for (var i = 0; i < colors.length; i++) {
        grd.addColorStop(i / n, colors[i]);
    }
    return grd;
}
&#13;
canvas.grd {
  display: inline-block;
  margin: 1px 0;
}

ol {
  padding-left: 32px; 
  list-style-type:decimal;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
&#13;
&#13;

1 个答案:

答案 0 :(得分:2)

更新后的答案:渲染功能的新版本,可以分割额外的像素,并在每一侧放置一半:

function render(canvas, colors) {
    var ctx = canvas.getContext("2d");
    var n = colors.length;
    var r = canvas.width % n;
    var a = Math.floor(r/2), b = n - r + a;
    var subWidth = Math.floor(canvas.width / n) + 1;
    var start = 0;

    for (var i = 0; i < n; i++) {
        if (i == a) {
            subWidth -= 1;
        }
        if(i == b) {
            subWidth += 1;
        }
        ctx.fillStyle = colors[i];
        ctx.fillRect(start, 0, subWidth, canvas.height);

        start += subWidth;
    }
}

原始答案

一些事情:

我认为导致微弱间隙的原因是某些矩形被绘制为包含分数像素的宽度。您可以做的是将矩形绘制为精确的像素宽度,其中一些像素宽度比其他像素宽。这是重写你的渲染函数来做到这一点(我想。现在已经很晚了: - ))

function render(canvas, colors) {
    var ctx = canvas.getContext("2d");
    var n = colors.length;
    var r = canvas.width % n;
    var subWidth = Math.floor(canvas.width / n) + 1;
    var start = 0;

    for (var i = 0; i < n; i++) {
        if (i == r) {
            subWidth -= 1;
        }
        ctx.fillStyle = colors[i];
        ctx.fillRect(start, 0, subWidth, canvas.height);

        start += subWidth;
    }
}

这将计算适合画布宽度colors.length次的最大整体宽度。然后它计算出剩余的多少像素(r)然后循环通过给第一个r矩形1个额外的像素宽度。

(另外,请记住fillRect函数的第三个参数是宽度,而不是结束。您的调用正在工作,因为矩形被绘制在彼此的顶部并且每个矩形的起始位置是正确的。)

我确信这有一个更优雅的解决方案,但这个似乎有效!

另外,当我玩这个时,我注意到在javascript中,canvas.width是300,而不是240.这导致我四处搜索,我发现了这个如何在SO上运行的很好的解释:{{3 }}。我认为代码渲染成300 x 150的画布,然后缩小到240 x 10.最终,这并没有导致问题。

希望这有帮助!