javascript - Canvas: draw lots of elements with a changing gradient (emulate angular gradient) -
for project http://biduleohm.free.fr/ledohm/ (sorry, user interface in french code in english) need angular gradient doesn't exists in native i've implemented using linear gradient on line , draw lines more , more longer form triangle. result graphically ok speed isn't (1850 ms 125 triangles). it's in tab [répartition], redraws if there keyup event on 1 of inputs, don't afraid of apparent slowness, i've limited maximum 1 redraw every 2000 ms.
before used simple linear gradient on whole triangle (but doesn't match reality) , speed ok, draws thousands of triangles in less second. function used :
drawfrontlightforcolor : function(x, y, w, h, color) { var x2 = x - w; var x3 = x + w; var gradient = distri.frontcanvas.createlineargradient(x2, y, x3, y); gradient.addcolorstop(0, 'rgba(' + color + ', ' + distri.lightedgealpha + ')'); gradient.addcolorstop(0.5, 'rgba(' + color + ', ' + (color == distri.lightcolors.cw ? distri.lightcenteralphacw : distri.lightcenteralphaother) + ')'); gradient.addcolorstop(1, 'rgba(' + color + ', ' + distri.lightedgealpha + ')'); distri.frontcanvas.fillstyle = gradient; distri.frontcanvas.beginpath(); distri.frontcanvas.moveto(x, y); distri.frontcanvas.lineto(x2, (y + h)); distri.frontcanvas.lineto(x3, (y + h)); distri.frontcanvas.lineto(x, y); distri.frontcanvas.fill(); distri.frontcanvas.closepath(); },
then switched function :
drawfrontlightforcolor : function(x, y, w, h, centercolor, edgecolor) { var ratio = w / h; var tmpy; var tmpw; var x2; var x3; var gradient; distri.frontcanvas.linewidth = 1; (var tmph = 0; tmph < h; tmph++) { tmpy = y + tmph; tmpw = math.round(tmph * ratio); x2 = x - tmpw; x3 = x + tmpw; gradient = distri.frontcanvas.createlineargradient(x2, tmpy, x3, tmpy); gradient.addcolorstop(0, edgecolor); gradient.addcolorstop(0.5, centercolor); gradient.addcolorstop(1, edgecolor); distri.frontcanvas.beginpath(); distri.frontcanvas.moveto(x2, tmpy); distri.frontcanvas.lineto(x, tmpy); distri.frontcanvas.lineto(x3, tmpy); distri.frontcanvas.strokestyle = gradient; distri.frontcanvas.stroke(); distri.frontcanvas.closepath(); } },
you can find whole source here
i can't put beginpath, stroke, closepath out of loop because of gradient changing every iteration (i've tried used last gradient every line (which, ironically, identical first function...) understandable not want).
i accept advice (including redo whole function , modify caller outsource code) improve speed let's 5x (ideally more).
i think took wrong way start : when doing changes of color, have better operate @ pixel level.
yes webgl pixel shader, you'll have fight boilerplate running ok on platform (or lib you).
, anyway there's solution perfect need, , fast enough (a few ms) : use raw pixel data, update them 1 one relevant function, draw result.
the steps :
- create buffer same size canvas.
- iterate through it's pixel, keeping track of x,y of point.
- normalize coordinates match 'space'.
- compute value normalized (x,y) out of data have.
- write color (in example choose greyscale) out of value.
- draw whole buffer canvas.
i did jsfiddle, , here's result 4 data points :
fiddle here : http://jsfiddle.net/gamealchemist/ksm9c/3/
var canvas = document.getelementbyid("canvas"); var ctx = canvas.getcontext('2d'); var width = canvas.width, height = canvas.height; // builds image target canvas function buildimage(targetcanvas, valueforxy, somedata) { var width = targetcanvas.width; var height = targetcanvas.height; var tempimg = ctx.createimagedata(width, height); var buffer = tempimg.data; var offset = 0; var xy = [0, 0]; function normalizexy(xy) { xy[0] = xy[0] / width ; xy[1] = xy[1] / height; } (var y = 0; y < height; y++) (var x = 0; x < width; x++, offset += 4) { xy[0] = x; xy[1]=y; normalizexy(xy); var val = math.floor(valueforxy(xy, somedata) * 255); buffer[offset] = val; buffer[offset + 1] = val; buffer[offset + 2] = val; buffer[offset + 3] = 255; } ctx.putimagedata(tempimg, 0, 0); } // return normalized (0->1) value x,y , // provided data. // xy 2 elements array function somevalueforxy(xy, somedata) { var res = 0; (var = 0; < somedata.length; i++) { var thisdata = somedata[i]; var dist = math.pow(sq(thisdata[0] - xy[0]) + sq(thisdata[1] - xy[1]), -0.55); localres = 0.04 * dist; res += localres; } if (res > 1) res = 1; return res; } var somedata = [ [0.6, 0.2], [0.35, 0.8], [0.2, 0.5], [0.6, 0.75] ]; buildimage(canvas, somevalueforxy, somedata); // ------------------------ function sq(x) { return x * x }
Comments
Post a Comment