1

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

我想我可以画出自己的圆圈并给它上色,然后用更大的半径循环这个过程来填充它。但事实证明,这不仅效率极低,而且非常有问题......

这是我的第一次尝试: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

“亮度”(白色到黑色渐变)不是问题,因为我知道它可以通过在绘制色谱后使用径向渐变来完成。但是,在弄清楚如何绘制频谱本身时,我将不胜感激。

我什至在想我可以画一个线性的然后弯曲(变换)它,但是没有任何本机函数可以做到这一点,并且处理诸如超出我技能水平的事情。:-/

4

2 回答 2

4

看看这个: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
于 2013-02-08T19:02:00.270 回答
1

我的第一个注意事项是,您链接到的图像具有不需要更改的所有 3 个组件,并且可能只是静态图像。

我从我正在处理的项目中改编了一些代码: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);

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

于 2013-02-08T19:47:57.137 回答