add border to the outer area of slice in pie - javascript

http://jsfiddle.net/wm7pwL2w/8/
How can I add border to the outer area of slice in pie? Please check my jsfiddle. I have implemented Polar Area Chart here. I need each border to be of different color which I can specify. For example refer to this image
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
console.log(ctx);
var center = {
x: 200,
y: 150
};
var myColor = ["#ccc", "#ccc", "#ccc", "#ccc", "#c01c3f"];
var myData = [20, 40, 50, 70, 100];
var myRadius = [150, 120, 80, 100, 70];
var myDistance = [5, 5, 2, 2, 2];
var myText = ['first', 'second', 'third', 'fourth', 'fifth'];
function getTotal(data) {
var myTotal = 0;
for (var j = 0; j < data.length; j++) {
myTotal += (typeof data[j] == 'number') ? data[j] : 0;
}
return myTotal;
}
function plotData() {
var lastend = 0;
var myTotal = getTotal(myData);
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
//ctx.strokeStyle = 'rgba(255,255,255,0.5)';
ctx.lineWidth = 1;
ctx.font="15px Arial";
for (var i = 0; i < myData.length; i++) {
ctx.save();
ctx.fillStyle = myColor[i];
ctx.beginPath();
ctx.translate(center.x, center.y);
var thisAngle = (Math.PI * 2 * (myData[i] / myTotal));
ctx.rotate(lastend + thisAngle / 2);
ctx.translate(myDistance[i], 0);
ctx.moveTo(0, 0);
ctx.arc(0, 0, myRadius[i], -(thisAngle / 2), thisAngle / 2, false);
ctx.closePath();
ctx.fill();
// ctx.stroke();
ctx.fillStyle = '#fff';
ctx.translate(0.6 * myRadius[i], 0);
ctx.rotate(-(lastend + thisAngle / 2));
ctx.fillText(myText[i], 0, 0);
ctx.restore();
lastend += thisAngle;
}
}
plotData();
Thanks for all the help.

You need to do it in two steps, first fill the shape then stroke just an arc. To do so you need to use a beginPath() for the outer border after filling it so to not stroke the complete shape.
...
ctx.closePath();
ctx.fill();
// original code stops
// insert this code
ctx.beginPath();
ctx.strokeStyle = '#079';
ctx.lineWidth = 9;
ctx.arc(0, 0, myRadius[i], -(thisAngle / 2), thisAngle / 2);
ctx.stroke();
// original code continues...
// ctx.stroke();
ctx.fillStyle = '#fff';
...
Updated fiddle

Use strokeStyle. JSFiddle
var lineColor = ["blue", "green", "purple", "pink", "aqua"];
for (var i = 0; i < myData.length; i++) {
............................
ctx.strokeStyle = lineColor[i];
ctx.fillStyle = myColor[i];
........
.............
ctx.fill();
ctx.stroke();
......................
}

Related

HTML/JS Canvas Donut Chart How to create round strokes with overlap?

I have the problem that my Donut Chart isn't working as I want it to do. I want to create a Donut Chart like this one:
But my Donut Chart looks like this at the moment:
As you can see the strokes don't overlap in the right direction. I think this might be, because I start to draw the strokes from right to left. Instead it should draw them from left to right, so the left "rounded end" is visible not the right rounded end.
This is what I have tried so far:
//function to draw the donut chart, ctx = context, cx - cy = position, radius and arcwith
dmbChart(ctx, cx, cy, radius, arcwidth) {
var tot = 0;
var accum = 0;
var PI = Math.PI;
var PI2 = PI * 2;
var offset = -PI/2;
for(var i = 0; i < this.canvasValues.length; i++) {
tot += this.canvasValues[i];
}
//Donut Sectors Color: Draw each stroke based on the value (canvasValues) and Color (canvasColors)
for(var i = 0; i < this.canvasValues.length; i++) {
ctx.lineWidth = arcwidth;
ctx.beginPath();
ctx.lineCap = "round";
ctx.arc(cx, cy, radius, offset + PI2 * (accum/tot), offset + PI2 * ((accum + this.canvasValues[i]) / tot));
ctx.strokeStyle = this.canvasColors[i];
ctx.stroke();
accum += this.canvasValues[i];
}
}
As you can see I get the values which are the percentages how long the each stroke should be and the color. Starting on top I draw each one from top -> right -> bottom -> left and this is the result. But how can I modify it to get the result on top?
Edit:
With the help of #Helder Sepulveda I created it like this now. I changed a lot of the calculations fixed some bugs which came with the changes. The only problem now is that it doesn't start to draw at the top. As you can see the green stroke should start on the top:
function dmbChart(ctx, cx, cy, radius, arcwidth) {
var canvasValues = [30, 5, 15, 10, 10, 10, 10, 10];
var canvasColors = ["#10dc60", "#DDDDDD", "#0cd1e8", "#ffce00", "#7044ff", "#f04141", "#ffea00", "#ee82ee"];
ctx.lineWidth = arcwidth;
ctx.lineCap = "round";
var accum = canvasValues.reduce((a,b) => a + b, 0);
for (var i = canvasValues.length-1; i >= 0; i--) {
var radians = canvasValues[i] / 100 * 360 * Math.PI / 180
ctx.beginPath();
ctx.arc(cx, cy, radius, accum, accum - radians, true);
ctx.strokeStyle = canvasColors[i];
ctx.stroke();
accum -= radians;
}
ctx.beginPath();
ctx.arc(cx, cy, radius, accum, accum - (0.1 / 100 * 360 * Math.PI / 180), true);
ctx.strokeStyle = canvasColors[canvasColors.length - 1];
ctx.stroke();
}
const canvas = document.getElementById("c");
canvas.width = canvas.height = 140;
const ctx = canvas.getContext("2d");
dmbChart(ctx, 70, 70, 50, 30)
<canvas id="c"></canvas>
I'm making some assumptions on canvasValues and canvasColors to show something working:
function dmbChart(ctx, cx, cy, radius, arcwidth) {
var accum = 0;
var PI = Math.PI;
var PI2 = PI * 2;
var offset = -PI / 2;
var canvasValues = [10, 10, 10]
var canvasColors = ["red", "green", "blue"]
var tot = canvasValues.reduce((a, b) => a + b, 0)
ctx.lineWidth = arcwidth;
ctx.lineCap = "round";
for (var i = 0; i < canvasValues.length; i++) {
ctx.beginPath();
ctx.arc(cx, cy, radius, offset + PI2 * (accum / tot), offset + PI2 * ((accum + canvasValues[i]) / tot));
ctx.strokeStyle = canvasColors[i];
ctx.stroke();
accum += canvasValues[i];
}
ctx.beginPath();
ctx.arc(cx, cy, radius, offset, offset);
ctx.strokeStyle = canvasColors[0];
ctx.stroke();
}
const canvas = document.getElementById("c");
canvas.width = canvas.height = 140;
const ctx = canvas.getContext("2d");
dmbChart(ctx, 70, 70, 50, 30)
<canvas id="c"></canvas>
The idea is to draw one last "short" arc with the first value(and color) at the end of the loop
I also moved a couple of lines out of the loop:
ctx.lineWidth = arcwidth;
ctx.lineCap = "round";
that could be set just once before the loop
And here is what we talked about in the comments inverting the direction
function dmbChart(ctx, cx, cy, radius, arcwidth) {
var PI = Math.PI;
var PI2 = PI * 2;
var offset = -PI / 2;
var canvasValues = [10, 10, 10]
var canvasColors = ["red", "green", "blue"]
var tot = canvasValues.reduce((a,b) => a + b, 0)
var accum = tot;
ctx.lineWidth = arcwidth;
ctx.lineCap = "round";
for (var i = canvasValues.length-1; i >= 0; i--) {
ctx.beginPath();
ctx.arc(cx, cy, radius, offset + PI2 * (accum / tot), offset + PI2 * ((accum + canvasValues[i]) / tot));
ctx.strokeStyle = canvasColors[i];
ctx.stroke();
accum -= canvasValues[i];
}
ctx.beginPath();
p = offset + PI2 * ((tot + canvasValues[canvasValues.length-1]) / tot)
ctx.arc(cx, cy, radius, p, p);
ctx.strokeStyle = canvasColors[canvasColors.length-1];
ctx.stroke();
}
const canvas = document.getElementById("c");
canvas.width = canvas.height = 140;
const ctx = canvas.getContext("2d");
dmbChart(ctx, 70, 70, 50, 30)
<canvas id="c"></canvas>

how to add stroke and shadow only on mousemove in a canvas?

how can we give shadow and stroke for circle drawn using html canvas only during a mouse hover .
i have two cirles and want to have a shadow and stroke during mouse hover, but when i hover over the circles the code adds shadow and stroke, but once the mouse focuses out of the circles the shadow gets darker but doesnot go away.
<html>
<body>
<canvas id="myCanvas" width="1000" height="500" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</body>
<script>
var canvas = document.getElementById("myCanvas"),
ctx = canvas.getContext("2d"),
circle = [
{x: 60, y: 50, r: 40, },
{x: 100, y: 150, r: 50,}// etc.
];
// render initial rects.
for (var i = 0; i < circle.length; i++) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r,0,2*Math.PI);
ctx.fillStyle= "grey";
ctx.fill();
}
canvas.onmousemove = function (e){
// console.log("mouseover");
var cir = this.getBoundingClientRect(),
x= e.clientX - cir.left,
y = e.clientX - cir.top,
i = 0 , r;
console.log(r);
// ctx.clearRect(0, 0, c.width, c.height);
while (r = circle[i++])
{
ctx.beginPath();
ctx.arc(r.x,r.y,r.r,0,2*Math.PI)
if (ctx.isPointInPath(x, y))
{
ctx.shadowBlur= 10;
ctx.shadowColor = "grey";
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgb(255,255,255)'
ctx.stroke();
}
else
{
ctx.arc(r.x,r.y,r.r,0,2*Math.PI)
}
}
};
</script>
</html>
canvas.onmousemove = function (e){
var cir = this.getBoundingClientRect(),
x= e.clientX - cir.left,
y = e.clientX - cir.top,
i = 0 , r;
/* add this */
ctx.clearRect(0, 0, canvas.width, canvas.height);
while (r = circle[i++])
{
ctx.beginPath();
ctx.arc(r.x,r.y,r.r,0,2*Math.PI)
if (ctx.isPointInPath(x, y))
{
ctx.shadowBlur= 10;
ctx.shadowColor = "grey";
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgb(255,255,255)'
ctx.stroke();
}
else
{
ctx.arc(r.x,r.y,r.r,0,2*Math.PI)
}
}
/* add this */
for (var i = 0; i < circle.length; i++) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r,0,2*Math.PI);
ctx.fillStyle= "grey";
ctx.fill();
}
};
I have modified your code to add stroke onmouse hover.
<html>
<body>
<canvas id="myCanvas" width="1000" height="500" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
</body>
<script>
var canvas = document.getElementById("myCanvas"),
ctx = canvas.getContext("2d"),
circle = [{
x: 60,
y: 50,
r: 40,
},
{
x: 100,
y: 150,
r: 50,
} // etc.
];
// render initial rects.
for (var i = 0; i < circle.length; i++) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
}
canvas.onmousemove = function(e) {
var x = e.clientX,
y = e.clientY,
i = 0,
r;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < circle.length; i++) {
if ((x > circle[i].x - circle[i].r) && (y > circle[i].y - circle[i].r) && (x < circle[i].x + circle[i].r) && (y < circle[i].y + circle[i].r)) {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.shadowBlur = 10;
ctx.lineWidth = 3;
ctx.strokeStyle = 'rgb(255,255,255)';
ctx.shadowColor = 'grey';
ctx.stroke();
ctx.shadowColor = 'white';
ctx.shadowBlur = 0;
} else {
ctx.beginPath();
ctx.arc(circle[i].x, circle[i].y, circle[i].r, 0, 2 * Math.PI);
ctx.fillStyle = "blue";
ctx.fill();
ctx.shadowColor = 'white';
ctx.shadowBlur = 0;
}
}
};
</script>
</html>

canvas - cant see color of my stars

i create canvas animated background... but... i cant see my stars...
Stars should be white.
code:
window.onload = sky();
function sky(){
var canvas = document.getElementById("sky");
var ctx = canvas.getContext("2d");
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;
var ms = 100;
var stars =[];
for (var i=0; i<ms; i++){
stars.push({
x: Math.random()*W,
y: Math.random()*H,
r: Math.random()*5+2,
d: Math.random()+1
})
}
function drawStars(){
ctx.clearRect(0,0,W,H);
ctx.fillStyle = "white";
ctx.beginPath();
for(var i=0; i<ms; i++){
var s = stars[i];
ctx.moveTo(s.x, s.y);
ctx.arc(s.x, s.y, 0, Math.Pi*2, true);
}
ctx.fill();
moveStars();
}
var angle = 0;
function moveStars(){
angle +=0.01;
for( var i=0; i<ms; i++){
var s = stars[i];
s.y += Math.pow(s.d, 2)+1;
s.x += Math.sin(angle)*2;
if(s.y>H){
stars[i] = {x: Math.random()+W, y:0, r: s.r, d: s.d};
}
}
}
setInterval(drawStars,25);
}
my background color is black, so i should see white stars...
fiddle: https://jsfiddle.net/w39fs7at/
You are missing the radius argument to the arc function. Also Math.Pi is undefined, it should be Math.PI.
So, change ctx.arc(s.x, s.y, 0, Math.Pi*2, true); to
ctx.arc(s.x, s.y, 5, 0, Math.PI*2, true);
Where 5 is the radius of the star.
Things to look at:
window.onload=sky();
should be
window.onload=sky;
to set the load event handler to the sky function, not the return value of calling it.
ctx.clearRect(0,0,W,H);
sets canvas pixels to transparent black which lets the background show through. If the background is white....
ctx.fillStyle= "black";
ctx.fillRect(0,0,W,H);
sets the canvas pixels to solid black which obscures the background color.
In the call to the context's arc method, the radius parameter is missing and Math.Pi is a typo for Math.PI.
For a fix try
ctx.arc(s.x, s.y, s.r, 0, Math.PI*2, true);
That leaves moveStars. I didn't work out what it is supposed to do. As coded it moves the stars off screen, but they come back after a while (you have to wait) as a wave of falling stars:.
"use strict";
window.onload = sky;
function sky(){
var canvas = document.getElementById("sky");
var ctx = canvas.getContext("2d");
var W = window.innerWidth;
var H = window.innerHeight;
canvas.width = W;
canvas.height = H;
var ms = 100;
var stars =[];
for (var i=0; i<ms; i++){
stars.push({
x: Math.random()*W,
y: Math.random()*H,
r: Math.random()*2+5,
d: Math.random()+1
})
}
function drawStars(){
ctx.fillStyle="black";
ctx.fillRect(0,0,W,H);
ctx.fillStyle = "white";
ctx.beginPath();
for(var i=0; i<ms; i++){
var s = stars[i];
ctx.moveTo(s.x, s.y);
ctx.arc(s.x, s.y, s.r, 0, Math.PI*2, true);
}
ctx.fill();
moveStars();
}
var angle = 0;
function moveStars(){
angle +=0.01;
for( var i=0; i<ms; i++){
var s = stars[i];
s.y += Math.pow(s.d, 2)+1;
s.x += Math.sin(angle)*2;
if(s.y>H){
stars[i] = {x: Math.random()+W, y:0, r: s.r, d: s.d};
}
}
}
setInterval(drawStars,25);
}
<canvas id="sky"></canvas>
Hope it helps!

Create a new object on button click

I am making an animation with Javascript. It is a ball that has a set speed and travels around inside a box. The animation works, and I have a button that increases the speed of the animations. I want to make a new button that creates a new ball when I click on it.
My Javascript code is the following:
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var fart = document.getElementById("fart")
var ny = document.getElementById("ny")
var circle = {
x:40,
y:50,
r:40,
}
var dx=5;
var dy=5;
var color = ["green", "blue", "yellow", "red", "orange", "pink"]
fart.onclick = function circleto (x,y,r) {
circle.x += 0;
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.r, 0, 2*Math.PI);
ctx.closePath();
ctx.fillStyle = color[Math.floor(Math.random()*color.length)];
ctx.fill();
requestAnimationFrame(circleto);
if( circle.x<0+circle.r || circle.x>canvas.width-circle.r) dx=-dx;
if( circle.y<0 + circle.r || circle.y>canvas.height-circle.r) dy=-dy;
circle.x+=dx;
circle.y+=dy;
}
This is my HTML code:
<button id="fart">øk hastigheten</button>
<button id="ny">ny ball</button>
<canvas id="canvas" width="600px" height="400px"></canvas>
What you should do is storing circles inside an array.
And then loop through each item and change them seperatly.
I hope the following code can help as an example:
var
animationRunning = false,
circles = [{ x : 0, y : 0, r : 0 }]; // array
...
function step() {
if(animationRunning === true) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = O, length = circles.length; i < length; i++) {
var circle = circles[i];
ctx.beginPath();
ctx.arc(circle.x, circle.y, circle.r, 0, 2*Math.PI);
ctx.closePath();
ctx.fillStyle = color[Math.floor(Math.random()*color.length)];
ctx.fill();
if( circle.x<0+circle.r || circle.x>canvas.width-circle.r) dx=-dx;
if( circle.y<0 + circle.r || circle.y>canvas.height-circle.r) dy=-dy;
circle.x+=dx;
circle.y+=dy;
circles[i] = circle; // overide the previous version
}
requestAnimationFrame(circleto);
}
}
fart.onclick = function circleto (x,y,r) {
if(animationRunning === false) {
step();
}
}
ny.onclick = function circleto (x,y,r) {
circles.push({ x : 0, y : 0, r : 0 });
if(animationRunning === false) {
step();
}
}
<button id="fart">øk hastigheten</button>
<button id="ny">ny ball</button>
<canvas id="canvas" width="600px" height="400px"></canvas>
<script>
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var fart = document.getElementById("fart")
var ny = document.getElementById("ny")
var color = ["green", "blue", "yellow", "red", "orange", "pink"]
var circles = [
{
x:40,
y:50,
r:40,
dx:5,
dy:5,
},
];
fart.onclick = function circleto (x,y,r) {
ctx.clearRect(0, 0, canvas.width, canvas.height)
ctx.beginPath();
for (i in circles){
var circle = circles[i];
circle.x += 0;
ctx.arc(circle.x, circle.y, circle.r, 0, 2*Math.PI);
ctx.closePath();
ctx.fillStyle = color[Math.floor(Math.random()*color.length)];
ctx.fill();
if( circle.x<0+circle.r || circle.x>canvas.width-circle.r) circle.dx=-circle.dx;
if( circle.y<0 + circle.r || circle.y>canvas.height-circle.r) circle.dy=-circle.dy;
circle.x+=circle.dx;
circle.y+=circle.dy;
}
requestAnimationFrame(circleto);
}
ny.onclick = function newcircleto (x,y,r) {
var newcircle = {
x:40,
y:50,
r:40,
dx:5,
dy:5,
};
circles.push(newcircle);
}
</script>

Add another stroke to the existing canvas element

How to add another stroke with a different color and length into the same circle?
This script use Mootools lib. Can it be converted in pure JavaScript or jQuery?
fiddle: http://jsfiddle.net/xc4xnzcq/1/
Thanks :)
// SVG stuff
var ctx = document.id('counter').getContext('2d');
var circ = Math.PI * 2;
var quart = Math.PI / 2;
ctx.beginPath();
ctx.strokeStyle = '#ff00ab';
ctx.lineCap = 'square';
ctx.closePath();
ctx.fill();
ctx.lineWidth = 10;
var imd = ctx.getImageData(0, 0, 160, 160);
var draw = function(current) {
ctx.putImageData(imd, 0, 0);
ctx.beginPath();
ctx.arc(119, 70, 60, -(quart), ((circ) * current) - quart, false);
ctx.stroke();
}
var myFx = new Fx({
duration: 5500,
transition: 'bounce:out',
onStep: function(step){
draw(step / 100);
}
});
myFx.set = function(now){
var ret = Fx.prototype.set.call(this, now);
this.fireEvent('step', now);
return ret;
};
myFx.start(0, 80);
Drawing a second path seems to work fine for me.
// SVG stuff
var ctx = document.id('counter').getContext('2d');
var circ = Math.PI * 2;
var quart = Math.PI / 2;
var imd = ctx.getImageData(0, 0, 160, 160);
var draw = function(current) {
ctx.putImageData(imd, 0, 0);
ctx.beginPath();
ctx.strokeStyle = '#ff00ab';
ctx.lineCap = 'square';
ctx.lineWidth = 10;
ctx.arc(119, 70, 60, -(quart), ((circ) * current) - quart, false);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = '#bb00bc';
ctx.lineCap = 'square';
ctx.lineWidth = 5;
ctx.arc(119, 70, 60, -(quart), ((circ) * current) - quart, false);
ctx.stroke();
}
var myFx = new Fx({
duration: 5500,
transition: 'bounce:out',
onStep: function(step){
draw(step / 100);
}
});
myFx.set = function(now){
var ret = Fx.prototype.set.call(this, now);
this.fireEvent('step', now);
return ret;
};
myFx.start(0, 80);

Categories