繁体   English   中英

HTML5画布-在圆上绘制线性渐变(色轮)

[英]HTML5 Canvas - Drawing Linear Gradients on a Circle (Color Wheel)

我正在尝试绘制一个圆,而不是径向渐变,而是绘制围绕该圆的线性渐变...基本上,我正在尝试创建一个色轮,它必须是动态的,因为颜色可以自定义。但是,我对如何处理此事完全感到困惑。

我以为我可以画一个自己的圆并给它上色,然后以较大的半径将其循环以填充它。 但是事实证明,这不仅效率极低,而且还很容易出错。

这是我的第一次尝试: http : //jsfiddle.net/gyFqX/1/我坚持使用该方法,但将其更改为在圆上的每个点填充2x2的正方形。 可以混合多达3种颜色,效果很好,但是随后您开始注意到它的变形。

无论如何,我一直在继续努力,这就是我现在所拥有的: http : //jsfiddle.net/f3SQ2/

var ctx = $('#canvas')[0].getContext('2d'),
    points = [],
    thickness = 80;

for( var n = 0; n < thickness; n++ )
    rasterCircle( 200, 200, (50 + n) );

function fillPixels() {
    var size = points.length,
        colors = [ 
            hexToRgb( '#ff0000' ), // Red
            hexToRgb( '#ff00ff' ), // Magenta
            hexToRgb( '#0000ff' ), // Blue
            hexToRgb( '#00ffff' ), // Teal
            hexToRgb( '#00ff00' ), // Green
            hexToRgb( '#ffff00' ), // Yellow            
            hexToRgb( '#ff0000' ), // Red
        ],
        colorSpan = colors.length - 1;

    if ( colors.length > 0 ) {
        var lastPadding = size % colorSpan,
            stepSize = size / colorSpan,
            steps = null, 
            cursor = 0;

        for ( var index = 0; index < colorSpan; index++ ) {
            steps = Math.floor( ( index == colorSpan - 1 ) ? stepSize + lastPadding : stepSize );
            createGradient( colors[ index ], colors[ index + 1 ], steps, cursor );
            cursor += steps;
        }
    }

    function createGradient( start, end, steps, cursor ) {
        for ( var i = 0; i < steps; i++ ) {
            var r = Math.floor( start.r + ( i * ( end.r - start.r ) / steps ) ),
                g = Math.floor( start.g + ( i * ( end.g - start.g ) / steps ) ),
                b = Math.floor( start.b + ( i * ( end.b - start.b ) / steps ) );

            ctx.fillStyle = "rgba("+r+","+g+","+b+",1)";
            ctx.fillRect( points[cursor][0], points[cursor][1], 2, 2 );
            cursor++;
        }
    }

    points = [];
}

function setPixel( x, y ) {
    points.push( [ x, y ] );
}

function rasterCircle(x0, y0, radius) {
    var f = 1 - radius,
        ddF_x = 1,
        ddF_y = -2 * radius,
        x = 0,
        y = radius;

    setPixel(x0, y0 + radius);
    while(x < y) {
        if(f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;    
        setPixel(x0 - x, y0 - y);
    }

    var temp = [];
    f = 1 - radius,
    ddF_x = 1,
    ddF_y = -2 * radius,
    x = 0,
    y = radius;
    while(x < y) {
        if(f >= 0) {
            y--;
            ddF_y += 2;
            f += ddF_y;
        }
        x++;
        ddF_x += 2;
        f += ddF_x;    
        temp.push( [x0 - y, y0 - x] );
    }
    temp.push( [x0 - radius, y0] );

    for(var i = temp.length - 1; i > 0; i--)
        setPixel( temp[i][0], temp[i][1] );

    fillPixels();
}

我要完成的工作是这样的: http : //img252.imageshack.us/img252/3826/spectrum.jpg

“亮度”(从白色到黑色褪色)不是问题,因为我知道可以在绘制色谱后通过使用径向渐变来实现。 但是,我希望在弄清楚如何绘制频谱本身方面有所帮助。

我什至以为我可以画一个线性的线然后弯曲(变形)它,但是没有任何本机函数可以做到这一点并解决诸如超出我的技术水平之类的事情。 :-/

检查一下: http : //jsfiddle.net/f3SQ2/5/

var can = $('#canvas')[0],
    ctx = can.getContext('2d'),
    radius = 120,
    thickness = 80,
    p = {
        x: can.width,
        y: can.height
    },
    start = Math.PI,
    end = start + Math.PI / 2,
    step = Math.PI / 180,
    ang = 0,
    grad,
    r = 0,
    g = 0,
    b = 0,
    pct = 0;

ctx.translate(p.x, p.y);
for (ang = start; ang <= end; ang += step) {
    ctx.save();
    ctx.rotate(-ang);
    // linear gradient: black->current color->white
    grad = ctx.createLinearGradient(0, radius - thickness, 0, radius);
    grad.addColorStop(0, 'black');

    h = 360-(ang-start)/(end-start) * 360;
    s = '100%';
    l = '50%';

    grad.addColorStop(.5, 'hsl('+[h,s,l].join()+')');
    grad.addColorStop(1, 'white');
    ctx.fillStyle = grad;

    // the width of three for the rect prevents gaps in the arc
    ctx.fillRect(0, radius - thickness, 3, thickness);
    ctx.restore();
}

编辑:固定色谱。 显然,我们可以给它提供HSL值,而无需进行转换或混乱的计算!

修改了一些内容以更好地处理缩放: http : //jsfiddle.net/f3SQ2/6/

step = Math.PI / 360

ctx.fillRect(0, radius - thickness, radius/10, thickness);

例如,您可以这样设置渐变停止:

h = 360-(ang-start)/(end-start) * 360;
s = '100%';

grad.addColorStop(0, 'hsl('+[h,s,'0%'].join()+')');  //black 
grad.addColorStop(.5,'hsl('+[h,s,'50%'].join()+')'); //color
grad.addColorStop(1, 'hsl('+[h,s,'100%'].join()+')');//white

我的第一个注意事项是,链接到的图像具有所有三个组成部分,无需更改,而可以只是一个静态图像。

我从我正在研究的项目中改编了一些代码: http : //jsfiddle.net/f3SQ2/1/

function drawColourArc(image) {
    var data = image.data;
    var i = 0;
    var w = image.width, h = image.height;
    var result = [0, 0, 0, 1];
    var outer = 1, inner = 0.5;
    var mid = 0.75;

    for (var y = 0; y < h; y++) {
        for (var x = 0; x < w; x++) {

            var dx = (x / w) - 1, dy = (y / w) - 1;

            var angular = ((Math.atan2(dy, dx) + Math.PI) / (2 * Math.PI)) * 4;
            var radius = Math.sqrt((dx * dx) + (dy * dy));

            if (radius < inner || radius > outer) {
                data[i++] = 255;
                data[i++] = 255;
                data[i++] = 255;
                data[i++] = 0;
            }
            else {
                if (radius < mid) {
                    var saturation = 1;
                    var brightness = (radius - 0.5) * 4;
                }
                else {
                    var saturation = 1- ((radius - 0.75) * 4);
                    var brightness = 1;
                }

                result[0] = angular;
                result[1] = saturation;
                result[2] = brightness;

                result[3] = 1;

                //Inline HSBToRGB
                if (result[1] == 0) {
                    result[0] = result[1] = result[2] = result[2];
                }
                else {
                    var varH = result[0] * 6;
                    var varI = Math.floor(varH); //Or ... var_i = floor( var_h )
                    var var1 = result[2] * (1 - result[1]);
                    var var2 = result[2] * (1 - result[1] * (varH - varI));
                    var var3 = result[2] * (1 - result[1] * (1 - (varH - varI)));

                    if (varI == 0 || varI == 6) {
                        result[0] = result[2];
                        result[1] = var3;
                        result[2] = var1;
                    }
                    else if (varI == 1) {
                        result[0] = var2;
                        result[1] = result[2];
                        result[2] = var1;
                    }
                    else if (varI == 2) {
                        result[0] = var1;
                        result[1] = result[2];
                        result[2] = var3;
                    }
                    else if (varI == 3) {
                        result[0] = var1;
                        result[1] = var2;
                        result[2] = result[2];
                    }
                    else if (varI == 4) {
                        result[0] = var3;
                        result[1] = var1;
                        result[2] = result[2];
                    }
                    else {
                        result[0] = result[2];
                        result[1] = var1;
                        result[2] = var2;
                    }

                }
                //End of inline
                data[i++] = result[0] * 255;
                data[i++] = result[1] * 255;
                data[i++] = result[2] * 255;
                data[i++] = result[3] * 255;
            }
        }
    }
};

var canvas = document.getElementsByTagName("canvas")[0];
var ctx = canvas.getContext("2d");
var image = ctx.createImageData(canvas.width, canvas.height);

drawColourArc(image);
ctx.putImageData(image, 0, 0);

这是按像素进行的,这是准确的,但您可能需要绘制轮廓以消除锯齿。 它可以适合使用自定义颜色,而不是插值色调。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM