javascript - Continuous gradient along a HTML5 canvas path -
i trying draw continous gradient along path of points, each point has it's own color, using html5 canvas api.
see http://bl.ocks.org/rveciana/10743959 inspiration, effect achieved d3.
there doesn't seem way add multiple linear gradients single canvas path, resorted this: http://jsfiddle.net/51toapv2/
var canvas = document.getelementbyid('canvas'); var ctx = canvas.getcontext('2d'); var pts = [[100, 100, "red"], [150, 150, "green"], [200, 100, "yellow"]]; ctx.linewidth = 20; ctx.linejoin = "round"; ctx.linecap = "round"; (var = 0; < pts.length - 1; i++) { var begin = pts[i]; var end = pts[i + 1]; ctx.beginpath(); var grad = ctx.createlineargradient(begin[0], begin[1], end[0], end[1]); grad.addcolorstop(0, begin[2]); grad.addcolorstop(1, end[2]); ctx.strokestyle = grad; ctx.moveto(begin[0], begin[1]); ctx.lineto(end[0], end[1]); ctx.stroke(); } as can see produces subpar effect paths aren't merged , "line joins" visible.
is possible achieve effect i'm looking canvas api?
you can simple approach interpolating 2 colors along line. if need smooth/shared gradients 2 lines joins @ steeper angles, need calculate , implement line drawing algorithm (almost) scratch. out of scope so, here simpler approach.
that being said - example in link not line several plots of squares of different colors. issues have "hidden" subtle variations.
example

this approach requires 2 main functions:
line interpolate function draws each segment in line previous mouse position current position
color interpolate function takes array of colors , interpolate between 2 current colors depending on length, position , segment size.
tweak parameters such segment size, number of colors in array etc. optimal result.
line interpolate function
function plotline(ctx, x1, y1, x2, y2) { var diffx = math.abs(x2 - x1), // line length diffy = math.abs(y2 - y1), dist = math.sqrt(diffx * diffx + diffy * diffy), step = dist / 10, // define resolution = 0, t, b, x, y; while (i <= dist) { // render circles along line t = math.min(1, / dist); x = x1 + (x2 - x1) * t; y = y1 + (y2 - y1) * t; ctx.fillstyle = getcolor(); // current color ctx.beginpath(); ctx.arc(x, y, 10, 0, math.pi*2); ctx.fill(); += step; } color interpolate function
function getcolor() { var r, g, b, t, c1, c2; c1 = colors[cindex]; // current color array c2 = colors[(cindex + 1) % maxcolors]; // next color t = math.min(1, total / segment); // calculate t if (++total > segment) { // rotate segment total = 0; if (++cindex >= maxcolors) cindex = 0; // rotate color array } r = c1.r + (c2.r - c1.r) * t; // interpolate color g = c1.g + (c2.g - c1.g) * t; b = c1.b + (c2.b - c1.b) * t; return "rgb(" + (r|0) + "," + (g|0) + "," + (b|0) + ")"; } demo
putting allow draw gradient lines. if don't want draw them manually call plotline() function whenever needed.
// setup code var c = document.queryselector("canvas"), ctx = c.getcontext("2d"), colors = [ {r: 255, g: 0, b: 0}, {r: 255, g: 255, b: 0}, {r: 0, g: 255, b: 0}, {r: 0, g: 255, b: 255}, {r: 0, g: 0, b: 255}, {r: 255, g: 0, b: 255}, {r: 0, g: 255, b: 255}, {r: 0, g: 255, b: 0}, {r: 255, g: 255, b: 0}, ], cindex = 0, maxcolors = colors.length, total = 0, segment = 500, isdown = false, px, py; setsize(); c.onmousedown = c.ontouchstart = function(e) { isdown = true; var pos = getpos(e); px = pos.x; py = pos.y; }; window.onmousemove = window.ontouchmove = function(e) {if (isdown) plot(e)}; window.onmouseup = window.ontouchend = function(e) { e.preventdefault(); isdown = false }; function getpos(e) { e.preventdefault(); if (e.touches) e = e.touches[0]; var r = c.getboundingclientrect(); return { x: e.clientx - r.left, y: e.clienty - r.top } } function plot(e) { var pos = getpos(e); plotline(ctx, px, py, pos.x, pos.y); px = pos.x; py = pos.y; } function plotline(ctx, x1, y1, x2, y2) { var diffx = math.abs(x2 - x1), diffy = math.abs(y2 - y1), dist = math.sqrt(diffx * diffx + diffy * diffy), step = dist / 50, = 0, t, b, x, y; while (i <= dist) { t = math.min(1, / dist); x = x1 + (x2 - x1) * t; y = y1 + (y2 - y1) * t; ctx.fillstyle = getcolor(); ctx.beginpath(); ctx.arc(x, y, 10, 0, math.pi*2); ctx.fill(); += step; } function getcolor() { var r, g, b, t, c1, c2; c1 = colors[cindex]; c2 = colors[(cindex + 1) % maxcolors]; t = math.min(1, total / segment); if (++total > segment) { total = 0; if (++cindex >= maxcolors) cindex = 0; } r = c1.r + (c2.r - c1.r) * t; g = c1.g + (c2.g - c1.g) * t; b = c1.b + (c2.b - c1.b) * t; return "rgb(" + (r|0) + "," + (g|0) + "," + (b|0) + ")"; } } window.onresize = setsize; function setsize() { c.width = window.innerwidth; c.height = window.innerheight; } document.queryselector("button").onclick = function() { ctx.clearrect(0, 0, ctx.canvas.width, ctx.canvas.height) }; html, body {background:#777; margin:0; overflow:hidden} canvas {position:fixed;left:0;top:0;background: #333} button {position:fixed;left:10px;top:10px} <canvas></canvas> <button>clear</button> tips:
- the gradient values can pre-populated / cached beforehand
- the step position in gradient can bound length spread independent of draw speed
- you can replace brush other path/figures/shapes, combine image based brushes composited current color
Comments
Post a Comment