Canvas angle

I am looking for code that allows this effect to be used on a canvas stroke . I already have an animated circular kick, I only need to get the ANGLE gradient, not linear and not radial. I have only 3 colors. Existing is available here (review rating)

Thanks everyone :)

+8
javascript html5 gradient canvas angle
source share
3 answers

The strokeStyle context can be a gradient:

// create a gradient gradient = ctx.createLinearGradient(xStart, yStart, xEnd, yEnd); gradient.addColorStop(0.0,"blue"); gradient.addColorStop(1.0,"purple"); // stroke using that gradient ctx.strokeStyle = gradient; 

Sample code and demo using the strokeStyle gradient: http://jsfiddle.net/m1erickson/w46ps/

enter image description here

 <!doctype html> <html> <head> <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css --> <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> <style> body{ background-color: ivory; } #canvas{border:1px solid red;} </style> <script> $(function(){ var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); function drawMultiRadiantCircle(xc, yc, r, radientColors) { var partLength = (2 * Math.PI) / radientColors.length; var start = 0; var gradient = null; var startColor = null, endColor = null; for (var i = 0; i < radientColors.length; i++) { startColor = radientColors[i]; endColor = radientColors[(i + 1) % radientColors.length]; // x start / end of the next arc to draw var xStart = xc + Math.cos(start) * r; var xEnd = xc + Math.cos(start + partLength) * r; // y start / end of the next arc to draw var yStart = yc + Math.sin(start) * r; var yEnd = yc + Math.sin(start + partLength) * r; ctx.beginPath(); gradient = ctx.createLinearGradient(xStart, yStart, xEnd, yEnd); gradient.addColorStop(0, startColor); gradient.addColorStop(1.0, endColor); ctx.strokeStyle = gradient; ctx.arc(xc, yc, r, start, start + partLength); ctx.lineWidth = 30; ctx.stroke(); ctx.closePath(); start += partLength; } } var someColors = []; someColors.push('#0F0'); someColors.push('#0FF'); someColors.push('#F00'); someColors.push('#FF0'); someColors.push('#F0F'); drawMultiRadiantCircle(150, 150, 120, someColors); }); // end $(function(){}); </script> </head> <body> <canvas id="canvas" width=300 height=300></canvas> </body> </html> 
+15
source share

I also needed this effect a few days ago, and I managed to create a workaround to achieve it.

What I did was impose one gradient over another using something like this:

 var ic = [ /*0*/{ a:"#FEC331" ,b:"#FB1E24" ,r1:0 ,r2:1 ,x0:0 ,y0:rd*0.5 ,x1:0 ,y1:-rd}, /*1*/{ a:"#FEC331" ,b:"#FB1E24" ,r1:0.5 ,r2:0.5 ,x0:0 ,y0:rd*0.3 ,x1:0 ,y1:-rd}, /*2*/{ a:"#EA6F2B" ,b:"transparent" ,r1:0 ,r2:1 ,x0:-rd ,y0:0 ,x1:rd ,y1:0 } ]; 

Here's the full code and demo in JSFiddle:

https://jsfiddle.net/flamedenise/n9no9Lgw/33/

Hope this helps.

+1
source share

In my case, I needed to fill the whole circle, and not just around the perimeter. Using the answer above and setting the line width to double, the radius gave undesirable results, so I wrote my own.

 /** * @description Options used when calling CanvasRenderingContext2D.strokeArcGradient() and * CanvasRenderingContext2D.fillArcGradient(). * @property {Boolean} useDegrees Whether the specified angles should be interpreted as degrees rather than radians. * (default: false) * @property {Number} resolutionFactor The number of lines to render per pixel along the arc. A higher number produces * a cleaner gradient, but has worse performance for large radii. Must be greater * than 0. (default: 8) */ class ArcGradientOptions { constructor(options) { function validateParam(test, errorMessage, fatal = false) { if (!test) { if (fatal) { throw new Error(errorMessage); } else { console.assert(false, errorMessage); } } } options = Object.assign({ useDegrees: false, resolutionFactor: 8, }, options); validateParam( (options.resolutionFactor instanceof Number | typeof options.resolutionFactor === 'number') && options.resolutionFactor > 0, `ArcGradientOptions.resolutionFactor must be a Number greater than 0. Given: ${options.resolutionFactor}`, true); Object.assign(this, options); } }; (function () { /** * @description Strokes an arc using a linear gradient. * @param {number} x The x-component of origin of the arc. * @param {number} y The y-component of the origin of the arc. * @param {number} radius The radius of the arc. * @param {number} startAngle Where in the circle to begin the stroke. * @param {number} endAngle Where in the circle to end the stroke. * @param {ArcGradientOptions} options Additional options. */ CanvasRenderingContext2D.prototype.strokeArcGradient = function (x, y, radius, startAngle, endAngle, colorStops, options) { options = new ArcGradientOptions(options); let lineWidth = this.lineWidth; this.fillArcGradient(x, y, startAngle, endAngle, colorStops, radius + lineWidth / 2, radius - lineWidth / 2, options); } /** * @description Fills a sector or a portion of a ring with a linear gradient. * @param {number} x The x-component of origin of the arc * @param {number} y The y-component of the origin of the arc * @param {number} startAngle Where in the circle to begin the fill. * @param {number} endAngle Where in the circle to end the fill. * @param {number} outerRadius The radius of the arc. * @param {number} innerRadius The radius of the arc that won't be filled. An innerRadius = 0 will fill the whole * arc. (default: 0) * @param {ArcGradientOptions} options Additional options. */ CanvasRenderingContext2D.prototype.fillArcGradient = function (x, y, startAngle, endAngle, colorStops, outerRadius, innerRadius = 0, options) { options = new ArcGradientOptions(options); let oldLineWidth = this.lineWidth, oldStrokeStyle = this.strokeStyle; if (options.useDegrees) { startAngle = startAngle * Math.PI / 180; endAngle = endAngle * Math.PI / 180; } let deltaArcAngle = endAngle - startAngle; gradientWidth = Math.floor(outerRadius * Math.abs(deltaArcAngle) * options.resolutionFactor), gData = generateGradientImgData(gradientWidth, colorStops).data; this.lineWidth = Math.min(4 / options.resolutionFactor, 1); for (let i = 0; i < gradientWidth; i++) { let gradi = i * 4, theta = startAngle + deltaArcAngle * i / gradientWidth; this.strokeStyle = `rgba(${gData[gradi]}, ${gData[gradi + 1]}, ${gData[gradi + 2]}, ${gData[gradi + 3]})`; this.beginPath(); this.moveTo(x + Math.cos(theta) * innerRadius, y + Math.sin(theta) * innerRadius); this.lineTo(x + Math.cos(theta) * outerRadius, y + Math.sin(theta) * outerRadius); this.stroke(); this.closePath(); } this.lineWidth = oldLineWidth; this.strokeStyle = oldStrokeStyle; } function generateGradientImgData(width, colorStops) { let canvas = document.createElement('canvas'); canvas.setAttribute('width', width); canvas.setAttribute('height', 1); let ctx = canvas.getContext('2d'), gradient = ctx.createLinearGradient(0, 0, width, 0); for (let i = 0; i < colorStops.length; i++) { gradient.addColorStop(colorStops[i].offset, colorStops[i].color); } ctx.fillStyle = gradient; ctx.fillRect(0, 0, width, 1); return ctx.getImageData(0, 0, width, 1); } })(); 

This method draws lines from the center of the circle to each pixel along its edge. This way you get a cleaner gradient.

Circles side by side

For large line thicknesses it is even cleaner.

Rings side by side

One of its main drawbacks is performance. If your radius is very large, the number of lines needed to create a good circle is about 50 times the radius.

jsFiddle

0
source share

All Articles