1

Я пытаюсь нарисовать круг с не радиальными градиентами, а линейными градиентами, которые идут по кругу ... В основном, я пытаюсь создать цветовое колесо, и оно должно быть динамичным, поскольку цвета будут настраиваться ... Однако я полностью озадачен тем, как подойти к этому вопросу ...HTML5 Холст - рисование линейных градиентов на круге (колесо цвета)

Я думал, что смогу нарисовать собственный круг и покрасить его, затем переместите процесс с большим радиусом, чтобы заполнить его. Но это оказалось не только крайне неудобным, но и очень багги ...

Была здесь моя первая попытка: 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

' яркость "(от белого до черного) не является проблемой, поскольку я знаю, что это может быть достигнуто с помощью радиального градиента после того, как был отображен цветовой спектр. Тем не менее, я был бы признателен за помощь в выяснении того, как рисовать спектр.

Я даже думал, что могу нарисовать линейный, а затем изгибать (преобразовывать) его, но нет никаких нативных функций для этого и решения чего-то такого, что выше моего уровня мастерства. : -/

+2

Создание чего-то вроде изображения, с которым вы связались, лучше всего сделать, перейдя с HSB на RGB, я разместил пример на http://jsfiddle.net/f3SQ2/1/, но, как вы сказали, вам нужны цвета, которые можно настроить вам нужно что-то другое? – Kris

+0

@ Kris вы должны опубликовать это как ответ, это намного лучше, чем мое. – Shmiddty

+0

@ Kris Wow!Это какая-то приятная кодировка ... К сожалению, у меня есть трудности, связанные с этим из-за моих недостаточных математических навыков. Однажды я надеюсь, что смогу создать такие вещи. Спасибо, что поделились! – user1960364

ответ

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(); 
} 

Edit: фиксированный цветовой спектр. По-видимому, мы можем просто дать ему 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 
+0

О, интересный подход! Мне это нравится! Определенно собираюсь поиграть с этим немного! – user1960364

+0

Ahh, я не знал о hsl() и переписал ваш первый, чтобы вычислить hsv, а затем конвертировать в rgb ... Но спасибо за обновление, это намного проще! – user1960364

+0

Нашел только одну проблему, позиция на 'arc' под' // Knockout' должна быть '0, 0', потому что' ctx.translate' все еще применяется. Это или, вы могли бы сделать 'ctx.save()' перед переводом, а затем еще один 'ctx.restore()' before' // Knockout' – user1960364

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); 

Это делает его на пиксель, который является точной, но вы можете нарисовать схему для сражаться с псевдонимом. Он может быть адаптирован для использования пользовательских цветов вместо интерполирования оттенка.

+0

Еще один прекрасный подход к моей проблеме! Математика выше моего уровня мастерства, но простота решения на пиксель велика! Еще раз спасибо за обмен. : D – user1960364

+0

Удивительно, но, похоже, что @ Shmiddty's немного быстрее – user1960364

Смежные вопросы