I got this code to draw 10 normal and 10 splattered circles on canvas, but I need to draw a random number of circles between 1 and 20. How can I do it?
var randomColour;
var randomSize;
var randomNumber;
var xPos;
var yPos;
var i;
var j;
c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
function drawFilledCircle(size,xPos,yPos,colour){
ctx.beginPath();
ctx.arc(xPos,yPos,size,0,2*Math.PI);
ctx.fillStyle = colour;
ctx.fill();
}
function drawSplatter(size,xPos,yPos,colour){
for(j=0;j<10;j++){
var splatSize = size / Math.round(Math.random()*30);
drawFilledCircle(splatSize,xPos + Math.round(Math.random()*40),yPos + Math.round(Math.random()*50),colour);
}
}
for(i=0;i<10;i++){
randomColour = '#' + Math.random().toString(16).substring(2, 8);
randomSize = Math.round(Math.random()*50);
xPos = Math.round(Math.random()*640);
yPos = Math.round(Math.random()*480);
drawFilledCircle(randomSize, xPos, yPos, randomColour);
drawSplatter(randomSize, xPos, yPos, randomColour);
}
Try this
//Find random number between 1 and 20.
var rand = Math.floor(Math.random() * 20) + 1;
for( i = 0; i < rand; i++ ){
randomColour = '#' + Math.random().toString(16).substring(2, 8);
randomSize = Math.round(Math.random()*50);
xPos = Math.round(Math.random()*640);
yPos = Math.round(Math.random()*480);
drawFilledCircle(randomSize, xPos, yPos, randomColour);
drawSplatter(randomSize, xPos, yPos, randomColour);
}
Related
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineWidth = 2;
ctx.font = '14px verdana';
var PI2 = Math.PI * 2;
var myColor = ["Green", "Red", "Blue"];
var myData = [30, 15, 38, 22, 30, 20, 10];
var cx = 150;
var cy = 150;
var radius = 100;
ctx.globalAlpha = 0.50;
pieChart(myData, myColor);
ctx.globalAlpha = 1.00;
function pieChart(data, colors) {
// calc data total
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
// calc sweep angles for each piece of pie
var sweeps = []
for (var i = 0; i < data.length; i++) {
sweeps.push(data[i] / total * PI2);
}
// draw outer pie
var accumAngle = 0;
for (var i = 0; i < sweeps.length; i++) {
var f = randomColor();
drawWedge(radius, accumAngle, accumAngle + sweeps[i], f, data[i]);
accumAngle += sweeps[i];
}
}
function drawWedge(radius, startAngle, endAngle, fill, label) {
// draw the wedge
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle, false);
ctx.closePath();
ctx.fillStyle = fill;
ctx.strokeStyle = 'white';
ctx.fill();
ctx.stroke();
}
function randomColor() {
return ('#' + (Math.floor(Math.random() * 0x1000000) +
0x1000000).toString(16).substr(1));
}
<canvas id="canvas" width=512 height=512></canvas>
I have a simply question - is there any option to add a tooltip on mouseover event on canvas pie arc? Can anyone help me how could i do that.
I am able to draw a pie chart using canvas please fine the below snippet:
Canvas.title = "Tool tip text"
At the most basic level you can use the canvas.title property to set the tooltip. Just get the mouse move events and record the mouse position. Then when you detect that the mouse has changed position, check which slice the mouse is over, if any and set the tooltip to match.
Note that the browsers tooltip is a little slow to respond to changes.
For a better response.
You could also draw the chart every frame of the render loop and highlight the parts of the pie the mouse is over and create a more responsive tooltip than the browser default which can be a little slow to respond at times.
The example below is just your code with the modification needed to get the basic tooltip.
Note that I keep the mouse event listener and the function that changes the tooltip separate, this is because on some systems the mouse can have a very high sample rate (my current gaming mouse can fire 700+ times a second) and doing too much in the mousemove event can cause laggy response to user input.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineWidth = 2;
ctx.font = '14px verdana';
var PI2 = Math.PI * 2;
var myColor = ["Green", "Red", "Blue"];
var myData = [30, 15, 38, 22, 30, 20, 10];
var cx = 150;
var cy = 150;
var radius = 100;
var mouse = {x :0,y:0,oldx : 0,oldy:0};
ctx.globalAlpha = 0.50;
pieChart(myData, myColor);
ctx.globalAlpha = 1.00;
function pieChart(data, colors) {
// calc data total
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
// calc sweep angles for each piece of pie
var sweeps = []
for (var i = 0; i < data.length; i++) {
sweeps.push(data[i] / total * PI2);
data[i] = {
value : data[i],
angle : data[i] / total * PI2,
text : "Data is "+((data[i] / total) * 100).toFixed(0) + "%",
}
}
// draw outer pie
var accumAngle = 0;
for (var i = 0; i < sweeps.length; i++) {
var f = randomColor();
drawWedge(radius, accumAngle, accumAngle + sweeps[i], f, data[i].value);
accumAngle += sweeps[i];
}
}
function drawWedge(radius, startAngle, endAngle, fill, label) {
// draw the wedge
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle, false);
ctx.closePath();
ctx.fillStyle = fill;
ctx.strokeStyle = 'white';
ctx.fill();
ctx.stroke();
}
function randomColor() {
return ('#' + (Math.floor(Math.random() * 0x1000000) +
0x1000000).toString(16).substr(1));
}
canvas.addEventListener("mousemove",function(event){
mouse.x = event.clientX;
mouse.y = event.clientY;
})
function update(){
// only on change in mouse position
if(mouse.x !== mouse.oldx || mouse.y !== mouse.oldy){
var x = mouse.oldx = mouse.x;
var y = mouse.oldy = mouse.y;
x -= cx; // vector from pie center
y -= cy;
var newText = "My pie chart. Mouse over slices for more info.";
var dist = Math.sqrt(x * x + y * y); // get distance from center
if(dist < radius){
var ang = Math.atan2(y,x); // get angle note y is first
ang += Math.PI * 2; // rotate 360 as atan2 starts at -Pi
ang %= Math.PI * 2; // normalize to range 0 to 2Pi
var i = 0;
var tAng = 0
while(i < myData.length-1){
if(ang < tAng + myData[i].angle){
break;
}
tAng += myData[i].angle;
i += 1;
}
newText = myData[i].text;
}
canvas.title = newText;
}
requestAnimationFrame(update);
}
update();
<canvas id="canvas" width=512 height=512></canvas>
I have drawn a grid in html5 canvas using StrokeLineX and StrokeLineY. I want to highlight the particular square/rectangle when I click on it in the grid.
I have tried using math.floor to define an index for a space but as soon as the width or height increases it starts giving different answers. I have tried too many times before finally posting it here.
Here is the code.
var canvas = document.getElementById("myCanvas");
canvas.addEventListener('click', on_canvas_click, false);
var ctx = canvas.getContext("2d");
var tray_length = 800;
var tray_depth = 800;
var boxHeight = 50;
var boxWidth = 50;
var canvas_X = tray_length;
var canvas_Y = tray_depth;
var box_x_pixels = canvas_X/no_of_columns;
var box_y_pixels = canvas_Y/no_of_rows;
// Drawing the grid
for (var y = boxWidth; y < canvas_Y; y += boxWidth) {
strokeLineX(ctx, y);
}
for (var x = boxHeight; x < canvas_X; x += boxHeight) {
strokeLineY(ctx, x);
}
function strokeLineX(ctx, y) {
ctx.beginPath();
ctx.strokeStyle = 'green';
ctx.moveTo(0, y);
ctx.lineTo(canvas_X, y);
ctx.stroke();
ctx.closePath();
}
function strokeLineY(ctx, x) {
ctx.beginPath();
ctx.strokeStyle = 'red';
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas_Y);
ctx.stroke();
ctx.closePath();
}
function on_canvas_click(ev) {
var x = ev.pageX - canvas.offsetLeft;
var y = ev.pageY - canvas.offsetTop;
console.log(x+":"+y);
var coordinateDisplay = "x=" + x + ", y=" + y;
if (y>= 0 && y <= y+boxHeight ) {
var indexOfX = Math.floor(x/boxWidth); //divide on width and round off
var indexOfY = Math.floor(y/boxHeight);
// alert('You clicked bar index: ' + indexOfX+"-"+indexOfY);
ctx.fillRect="green";
ctx.rect(x,y,box_x_pixels,box_y_pixels);
ctx.stroke();
console.log(indexOfX + "-" + indexOfY);
}
}
In on_canvas_click change the following:
Instead of
ctx.fillRect="green";
do:
ctx.fillStyle="green";
And instead of:
ctx.rect(x,y,box_x_pixels,box_y_pixels);
do:
ctx.fillRect(boxWidth*indexOfX, boxHeight*indexOfY, boxWidth, boxHeight);
... and you don't need:
ctx.stroke();
Here is a working snippet with those changes applied, but also with some simplifications which are unrelated to your problem:
Removal of unused variables;
Use of one function to draw lines, instead of two;
Use of canvas.width and canvas.height properties;
Drawing grid lines also on the outer grid boundaries
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
var boxHeight = 50;
var boxWidth = 50;
var canvas_X = canvas.width;
var canvas_Y = canvas.height;
canvas.addEventListener('click', on_canvas_click, false);
// Drawing the grid
for (var y = 0; y <= canvas_Y; y += boxWidth) {
strokeLine(ctx, 0, y, canvas_X, y, 'green');
}
for (var x = 0; x <= canvas_X; x += boxHeight) {
strokeLine(ctx, x, 0, x, canvas_Y, 'red');
}
function strokeLine(ctx, x0, y0, x1, y1, color) {
ctx.beginPath();
ctx.strokeStyle = color;
ctx.moveTo(x0, y0);
ctx.lineTo(x1, y1);
ctx.stroke();
ctx.closePath();
}
function on_canvas_click(ev) {
var x = ev.pageX - canvas.offsetLeft;
var y = ev.pageY - canvas.offsetTop;
if (y>= 0 && y <= y+boxHeight ) {
var indexOfX = Math.floor(x/boxWidth); //divide on width and round off
var indexOfY = Math.floor(y/boxHeight);
ctx.fillStyle="green";
ctx.fillRect(boxWidth*indexOfX, boxHeight*indexOfY, boxWidth, boxHeight);
}
}
<canvas id="myCanvas" width="600" height="200"></canvas>
I am trying to use the following code to draw 9 circles horizontally and 9 circles vertically on a canvas.
I have inserted a nested for-loop for this operation, but unfortunately I am having only one horizontal line of 9 circles.
Can anyone help please?
<canvas id="sCanvas" width="550" height="1000"> </canvas>
<script>
var randomColour;
var size;
var xPos;
var yPos;
var ctx;
var i;
var j;
function drawCircle(size, x, y, randomColour) {
ctx.beginPath();
ctx.arc(x, y, size / 2, 0, 2 * Math.PI, randomColour);
ctx.fill();
ctx.fillStyle = randomColour;
ctx.stroke();
ctx.strokeStyle = randomColour;
}
var c = document.getElementById("sCanvas");
ctx = c.getContext("2d");
xPos = 20;
yPos = 20;
for (j = 0; j < 9; j++) {
randomColour = "hsl(" + 360 * Math.random() + ",50%,50%)";
drawCircle(30, xPos, yPos, randomColour);
xPos += 50;
for (i = 0; i < 9; i++) {
randomColour = "hsl(" + 360 * Math.random() + ",50%,50%)";
drawCircle(30, xPos, yPos, randomColour);
xPos += 50;
}
yPos += 30;
}
</script>
You have to reset your xPos after every iteration, otherwise you just keep advancing right. This will work:
for (j = 0; j < 9; j++) {
xPos = 20; //Moved this in here from outside
randomColour = "hsl(" + 360 * Math.random() + ",50%,50%)";
drawCircle(30, xPos, yPos, randomColour);
for (i = 0; i < 9; i++) {
randomColour = "hsl(" + 360 * Math.random() + ",50%,50%)";
drawCircle(30, xPos, yPos, randomColour);
xPos += 50;
}
yPos += 50;
}
Fiddle
I am making a program that graphs a line based on data inputted by the user. (It's based on the slope form/equation). I am using the Canvas to graph my equation. I've been having a problem graphing the equation in a way that lets it adapt to the scaling (which is based on how large the numbers inputted are.)
How can I make the graphed equation (line) fit the graph as the canvas scales?
Here's my code:
var c=document.getElementById("graph_");
var ctx=c.getContext("2d");
graph_.style.backgroundColor="white";
// This is used to define the parameters of the canvas. Variables a and b are the x and y intercepts of the linear function.
var z0=Math.max(Math.abs(a),Math.abs(b));
var z=Math.round(z0);
var z1=Math.round(z);
var z2=z*2
// alert(z1);
// alert(z2);`
//The code below is used to properly scale the canvas and lines so they can accomodate larger numbers
var scale = 2*z/360;
var offsetX = 150;
var offsetY = 75
ctx.translate((-c.width /2 * scale) + offsetX,(-c.height / 2 * scale) + offsetY);
ctx.scale(scale,scale);
var lw = scale/2
var xnew = 360/2+360/2*a
var ynew = 360/2-360/2*b
alert(xnew);
alert(ynew);
//The two lines drawn below are the axises of the graph
ctx.lineWidth = 2/lw;
ctx.beginPath()
ctx.moveTo(150, 40000*-1);
ctx.lineTo(150, 40000);
ctx.closePath();
ctx.lineWidth = 1/lw;
ctx.moveTo(400000*-1, 75);
ctx.lineTo(40000, 75);
ctx.strokeStyle = "#8B8682";
ctx.stroke();
ctx.closePath();
//var xmax = 400000 - b
//var xmax1 = xmax/s
//var ymax = 400000*s
//var ymax1 = ymax + b
// The code below graphs the equation.
ctx.beginPath();
ctx.lineWidth = 1/lw;
ctx.moveTo(xnew, 180);
ctx.lineTo(180, ynew);
// ctx.lineTo(xmax, ymax)
// ctx.lineTo(xmax*-1, ymax*-1)
ctx.strokeStyle = "red";
ctx.stroke();
Here is the coding for the whole page:
As you can see the line, if drawn at all, doesn't become long enough, like it should. (linear lines are always infinite, so the line should be going across the WHOLE graph, not a small portion.)
var canwith=360
var canheight=360
// alert(window.innerWidth)
function doSolve() {
var s=''
var x1 = document.getElementById('x1').value
var y1 = document.getElementById('y1').value
var x2 = document.getElementById('x2').value
var y2 = document.getElementById('y2').value
var m
var b
var a
try {
if ((x2 - x1)==0) {
m='Undefined'
b='Undefined'
a=x1
} else {
m = (y2 - y1)/(x2 - x1)
b = (y2-x2*m)
a = (-b/m)
}
s += 'Coordinates are: ('
s += x1
s += ','
s += y1
s += '),('
s += x2
s += ','
s += y2
s += ')'
s += '<br>Slope:'
s += m
s +='<br>y intercept:'
s += b
s += '<br>x intercept:'
s += a
if (m=='undefined') {
s += '<br>Equation: x = ' + x1
} else {
s += '<br>Equation: y = '
if (m!=0) {
if (m!=1) {
s += m + 'x'
} else {
s += 'x'
}
}
if (b!=0) {
if (b>0) {
s += ' + ' + b
} else {
s += ' - ' + b*-1
}
}
}
document.getElementById('outputx').innerHTML=s
} catch (e) {alert(e.message)}
try {
var c=document.getElementById("graph_");
var ctx=c.getContext("2d");
graph_.style.backgroundColor="white";
var z0=Math.max(Math.abs(a),Math.abs(b));
var z=Math.round(z0);
var z1=Math.round(z);
var z2=z*2
// alert(z1);
// alert(z2);
var scale = 2*z/360;
var offsetX = 150;
var offsetY = 75
ctx.translate((-c.width /2 * scale) + offsetX,(-c.height / 2 * scale) + offsetY);
ctx.scale(scale,scale);
var lw = scale/2
var xnew = 360/2+360/2*a
var ynew = 360/2-360/2*b
alert(xnew);
alert(ynew);
ctx.lineWidth = 2/lw;
ctx.beginPath()
ctx.moveTo(150, 40000*-1);
ctx.lineTo(150, 40000);
ctx.closePath();
ctx.lineWidth = 1/lw;
ctx.moveTo(400000*-1, 75);
ctx.lineTo(40000, 75);
ctx.strokeStyle = "#8B8682";
ctx.stroke();
ctx.closePath();
var xmax = 400000 - b
var xmax1 = xmax/s
var ymax = 400000*s
var ymax1 = ymax + b
ctx.beginPath();
ctx.lineWidth = 1/lw;
ctx.moveTo(xnew, 180);
ctx.lineTo(180, ynew);
ctx.lineTo(xmax, ymax)
ctx.lineTo(xmax*-1, ymax*-1)
ctx.strokeStyle = "red";
ctx.stroke();
} catch (e) {alert(e.message)}
}
I couln't cope with your code, so I made my own implementation adjusting to your visual requirements, hope this fix the problem:
try {
var c = document.getElementById("graph_");
var ctx = c.getContext("2d");
graph_.style.backgroundColor="white";
var w = c.width;
var h = c.height;
var xAxisSize = 40;
var yAxisSize = 40;
var scaleFactorX = w / xAxisSize;
var scaleFactorY = -(h / yAxisSize);
var offsetX = -10;
var offsetY = -10;
ctx.scale(scaleFactorX, scaleFactorY);
ctx.translate((xAxisSize / 2) + offsetX, -((yAxisSize / 2) + offsetY));
ctx.lineWidth = 3 / scaleFactorX;
ctx.beginPath();
ctx.moveTo(-xAxisSize, 0);
ctx.lineTo( xAxisSize, 0);
ctx.strokeStyle = "#8B8682";
ctx.stroke();
ctx.closePath();
ctx.lineWidth = 3 / scaleFactorY;
ctx.beginPath();
ctx.moveTo(0, -yAxisSize);
ctx.lineTo(0, yAxisSize);
ctx.strokeStyle = "#8B8682";
ctx.stroke();
ctx.closePath();
ctx.lineWidth = 3 / scaleFactorY;
ctx.beginPath();
var xx1 = -xAxisSize - offsetX;
var yy1 = m * xx1 + b;
var xx2 = xAxisSize + offsetX;
var yy2 = m * xx2 + b;
ctx.moveTo(xx1, yy1);
ctx.lineTo(xx2,yy2);
ctx.strokeStyle = "red";
ctx.stroke();
ctx.closePath();
} catch (e) {
alert(e.message)
}
Using canvas, I have to take some data that is used to create a pie graph, and turn that pie graph into a circle of arrows.
So far the pie graph is simple, and cutting out the middle is easy. But can't figure out how to
get the x, y points of each end point of the pie peices.
use that to somehow draw a triangle, and
continue onto the next pie piece.
What I do have is the x, y of the center point of the circle, and the radius.
I can draw 1 triangle -
var friends=alumni=hopefuls=athletes=0,
data = ['Ahtlete', 'Athlete', 'Friend', 'Friend', 'Athlete'];
test = data.length;
for (var i = 0; i < test; i++){
if ( data[i] == "Athelete" ) {
athletes++;
} else if ( data[i] == "Friend"){
friends++;
} else if (data[i] == "Hopeful" ){
hopefuls++;
} else if (data[i] == "Alumni"){
alumni++
}
}
var mychart = new AwesomeChart('segmented-circle');
//friends, alumni, hopefuls, athletes;
mychart.colors = ['#d20007','#02f2fb', '#d2ebf6', '#0554ff']
mychart.title = "";
mychart.data = [friends, alumni, hopefuls, athletes];
mychart.labels = [];
mychart.chartType = 'ring';
mychart.draw();
function AwesomeChart(canvasElementId){
var canvas = document.getElementById(canvasElementId);
this.ctx = canvas.getContext('2d');
this.width = this.ctx.canvas.width;
this.height = this.ctx.canvas.height;
this.numberOfDecimals = 0;
this.proportionalSizes = true;
this.widthSizeFactor = this.width/400;
this.heightSizeFactor = this.height/400;
this.chartType = 'bar';
this.randomColors = false;
this.marginTop = 10;
this.marginBottom = 10;
this.marginLeft = 20;
this.marginRight = 50;
this.labelMargin = 10;
this.dataValueMargin = 20;
this.titleMargin = 10;
this.yAxisLabelMargin = 5;
this.data = new Array();
this.labels = new Array();
this.colors = new Array();
this.title = null;
this.backgroundFillStyle = 'rgba(255,255,255,0)';
this.borderStrokeStyle = 'rgba(255,255,255,0)';
this.borderWidth = 0;
this.labelFillStyle = 'rgb(220, 36, 0)';
this.labelFont = 'sans-serif';
this.labelFontHeight = 12;
this.labelFontStyle = '';
this.dataValueFillStyle = '#333';
this.dataValueFont = 'sans-serif';
this.dataValueFontHeight = 15;
this.dataValueFontStyle = '';
this.titleFillStyle = '#333';
this.titleFont = 'sans-serif';
this.titleFontHeight = 16;
this.titleFontStyle = 'bold';
this.yAxisLabelFillStyle = '#333';
this.yAxisLabelFont = 'sans-serif';
this.yAxisLabelFontHeight = 10;
this.yAxisLabelFontStyle = '';
var lingrad = this.ctx.createLinearGradient(0,0,0,this.height);
lingrad.addColorStop(0.2, '#fdfdfd');
lingrad.addColorStop(0.8, '#ededed');
this.chartBackgroundFillStyle = lingrad;
this.chartBorderStrokeStyle = '#999';
this.chartBorderLineWidth = 1;
this.chartHorizontalLineStrokeStyle = '#999';
this.chartHorizontalLineWidth = 1;
this.chartVerticalLineStrokeStyle = '#999';
this.chartVerticalLineWidth = 1;
this.chartMarkerSize = 5;
this.chartPointRadius = 4;
this.chartPointFillStyle = 'rgb(150, 36, 0)';
this.chartLineStrokeStyle = 'rgba(150, 36, 0, 0.5)';
this.chartLineWidth = 2;
this.barFillStyle = 'rgb(220, 36, 0)';
this.barStrokeStyle = '#fff';
this.barBorderWidth = 2.0;
this.barShadowColor = 'rgba(0, 0, 0, 0.5)';
this.barShadowBlur = 5;
this.barShadowOffsetX = 3.0;
this.barShadowOffsetY = 0.0;
this.barHGap = 20;
this.barVGap = 20;
this.explosionOffset = 20;
this.pieFillStyle = 'rgb(220, 36, 0)';
this.pieStrokeStyle = '#fff';
this.pieBorderWidth = 2.0;
this.pieShadowColor = 'rgba(255, 255, 255, 0.8)';
this.pieShadowBlur = 15;
this.pieShadowOffsetX = 0.0;
this.pieShadowOffsetY = 0.0;
this.pieStart = 0;
this.pieTotal = null;
this.generateRandomColor = function(){
var rgb = new Array();
for(var i=0; i<3; i++){
rgb.push(Math.ceil(Math.random()*150 + 50));
}
return 'rgb('+rgb.join(",")+')';
}
this.draw = function(){
var context = this.ctx;
context.lineCap = 'round';
var minFactor = Math.min(this.widthSizeFactor, this.heightSizeFactor);
if(this.proportionalSizes){
this.labelMargin = this.labelMargin * this.heightSizeFactor;
this.dataValueMargin = this.dataValueMargin * this.heightSizeFactor;
this.titleMargin = this.titleMargin * this.heightSizeFactor;
this.yAxisLabelMargin = this.yAxisLabelMargin * this.heightSizeFactor;
this.labelFontHeight = this.labelFontHeight * minFactor;
this.dataValueFontHeight = this.dataValueFontHeight * minFactor;
this.titleFontHeight = this.titleFontHeight * minFactor;
this.yAxisLabelFontHeight = this.yAxisLabelFontHeight * minFactor;
this.barHGap = this.barHGap * this.widthSizeFactor;
this.barVGap = this.barHGap * this.heightSizeFactor;
this.explosionOffset = this.explosionOffset * minFactor;
}
if(this.randomColors){
for(var i=0; i<this.data.length; i++){
if(!this.colors[i]){
this.colors[i] = this.generateRandomColor();
}
}
}
this.drawPieChart(true);
//Draw the outer border:
context.lineWidth = this.borderWidth;
context.strokeStyle = this.borderStrokeStyle;
context.strokeRect(0, 0, this.width, this.height);
context.globalCompositeOperation = 'destination-over';
//Fill the background:
context.fillStyle = this.backgroundFillStyle;
context.fillRect(0, 0, this.width, this.height);
context.globalCompositeOperation = 'source-over';
}
this.drawPieChart = function(ring){
var context = this.ctx;
context.lineWidth = this.pieBorderWidth;
var dataSum = 0;
if(this.pieTotal == null){
var len = this.data.length;
for (var i = 0; i < len; i++){
dataSum += this.data[i];
if(this.data[i]<0){
return;
}
}
}else{
dataSum = this.pieTotal;
}
var pieAreaWidth = this.width - this.marginLeft - this.marginRight;
var pieAreaHeight = this.height - this.marginTop - this.marginBottom;
var centerX = this.width / 2;
var centerY = this.marginTop + (pieAreaHeight / 2);
var doublePI = 2 * Math.PI;
var radius = (Math.min( pieAreaWidth, pieAreaHeight) / 2);
var maxLabelWidth = 0;
var labelWidth = 0;
context.font = this.labelFontStyle + ' ' + this.labelFontHeight + 'px '+ this.labelFont;
for (var i = 0; i < this.labels.length; i++){
labelWidth = context.measureText(this.labels[i]).width;
if(labelWidth > maxLabelWidth){
maxLabelWidth = labelWidth;
}
}
radius = radius - maxLabelWidth - this.labelMargin;
var startAngle = this.pieStart * doublePI / dataSum;
var currentAngle = startAngle;
var endAngle = 0;
var incAngleBy = 0;
for (var i = 0; i < this.data.length; i++){
context.beginPath();
incAngleBy = this.data[i] * doublePI / dataSum;
endAngle = currentAngle + incAngleBy;
// Draw pie graph then using same calculations
// draw an isoceles triangle at end points before the center
// is cut out to make the arrows
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, radius, currentAngle, endAngle, false);
context.lineTo(centerX, centerY);
var twidth = 15; // Triangle Width
var theight = 20; // Triangle Height
context.moveTo(centerX+radius/2, centerY+radius/2);
context.lineTo(centerX+radius, centerY+radius);
context.lineTo(centerX+radius-10, centerY+radius/3);
context.lineTo(centerX, centerY);
/*
var width = 15; // Triangle Width
var height = 20; // Triangle Height
var padding = endAngle;
context.save();
context.moveTo(centerX, dataSum);
context.arc(centerX *2, dataSum, 5, 0, doublePI, false);
context.moveTo(padding + width / 2, padding); // Top Corner
context.lineTo(padding + width, height + padding); // Bottom Right
context.lineTo(centerX , height + padding); // Bottom Left
*/
currentAngle = endAngle;
if (this.colors[i]){
context.fillStyle = this.colors[i];
}else{
context.fillStyle = this.pieFillStyle;
}
context.fill();
context.strokeStyle = this.pieStrokeStyle;
context.stroke();
}
//Draw the outer shadow:
context.save();
context.shadowOffsetX = this.pieShadowOffsetX;
context.shadowOffsetY = this.pieShadowOffsetY;
context.translate(centerX, centerY);
//context.rotate(this.pieStart* doublePI / dataSum);
context.beginPath();
context.moveTo(0, 0);
context.arc(0, 0, radius, startAngle, endAngle, false);
context.shadowBlur = this.pieShadowBlur;
context.shadowColor = this.pieShadowColor;
context.globalCompositeOperation = 'destination-over';
context.fillStyle = 'rgba(0,0,0,1.0)';
context.fill();
context.restore();
//Ring-charts:
if(ring){
// "cut" the central part:
context.save();
var ringCenterRadius = radius / 1.15;
context.beginPath();
context.moveTo(centerX + ringCenterRadius, centerY);
context.arc(centerX, centerY, ringCenterRadius, 0, doublePI, false);
// context.globalCompositeOperation = 'destination-out';
context.fillStyle = '#000';
context.fill();
context.restore();
// draw the ring's inner shadow below the ring:
context.save();
context.shadowOffsetX = this.pieShadowOffsetX;
context.shadowOffsetY = this.pieShadowOffsetY;
context.translate(centerX, centerY);
context.beginPath();
// added -1 to make inner border same width as outer
context.arc(0, 0, ringCenterRadius -1, startAngle, endAngle, false);
context.shadowBlur = this.pieShadowBlur;
context.shadowColor = this.pieShadowColor;
context.globalCompositeOperation = 'destination-over';
context.strokeStyle = this.pieStrokeStyle;
context.stroke();
context.restore();
}
// draw the labels:
var currentAngle = this.pieStart* doublePI / dataSum;
var endAngle = 0;
var incAngleBy = 0;
context.beginPath();
for(var i=0; i<this.data.length; i++){
context.save();
incAngleBy = this.data[i] * doublePI / dataSum;
endAngle = currentAngle + incAngleBy;
var mAngle = currentAngle + incAngleBy/2;
context.translate(centerX, centerY);
context.rotate(mAngle);
context.font = this.labelFontStyle + ' ' + this.labelFontHeight + 'px '+ this.labelFont;
if(this.colors[i]){
context.fillStyle = this.colors[i];
}else{
context.fillStyle = this.labelFillStyle;
}
context.textAlign = 'start';
if(this.labels[i]){
if( (currentAngle>Math.PI/2) && (currentAngle<=3*(Math.PI/2)) ){
var translateXBy = radius + this.labelMargin + context.measureText(this.labels[i]).width / 2;
context.translate(translateXBy, 0);
context.rotate(Math.PI);
context.translate(-translateXBy, 0);
}
context.textBaseline = 'middle';
context.fillText(this.labels[i], radius+this.labelMargin, 0);
}
context.restore();
currentAngle = endAngle;
}
}
}
canvas {
background: #000033;
}
<canvas id='segmented-circle' width='200' height='200'></canvas>
I have tried several different things and feel like this would be a great thing to ask here.
The last one here is how it should look in the end.