I have a working 2d pie chart created using canvas2d by HTML and JavaScript. Is it possible to have in 3d the below same thing by using HTML, CSS, js or jQuery too. If not, is there any advanced graphics options such as splitting the pie chart and displaying it but 3d is preferred. Thanks in advance.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
nvas.height;
ctx.lineWidth = 2;
ctx.font = '12px verdana';
ctx.textAlign='center';
ctx.textBaseline='middle';
var PI2 = Math.PI * 2;
var myColor = ['green','blue'];
var myData = [chv2,chs2];
var labels =["LA:" +chv2+"%","LB:" +chs2+"%"];
var cx = 150;
var cy = 150;
var radius = 100;
pieChart(myData, myColor);
function pieChart(data, colors) {
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
var sweeps = [];
for (var i = 0; i < data.length; i++) {
sweeps.push(data[i] / total * PI2);
}
var accumAngle = 0;
for (var i = 0; i < sweeps.length; i++) {
drawWedge(accumAngle, accumAngle + sweeps[i], colors[i], labels[i]);
accumAngle += sweeps[i];
}
}
function drawWedge(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 = 'black';
ctx.fill();
ctx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .75;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'white';
ctx.fillText(label, x, y);
}
<canvas id="canvas" width="300" height="300" style="display:none;" >
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
Use this example using html, css, javascript:
var chart;
var legend;
var chartData = [{
country: "Lithuania",
value: 260},
/* more values ... */];
AmCharts.ready(function() {
// PIE CHART
chart = new AmCharts.AmPieChart();
chart.dataProvider = chartData;
chart.titleField = "country";
chart.valueField = "value";
chart.outlineColor = "";
chart.outlineAlpha = 0.8;
chart.outlineThickness = 2;
// this makes the chart 3D
chart.depth3D = 20;
chart.angle = 30;
// WRITE
chart.write("chartdiv");
});
Related
Me and my group (school project) are trying to create a modular multiplication in a circle, we've had some success with lines inside the circle but I can't figure out what I am missing when it comes to drawing lines between the points that make up the circle.
How I am trying to draw circle:
function drawCircle() {
points = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
var step = 2 * Math.PI/points;
ctx.beginPath();
for(var theta=0; theta < 2*Math.PI; theta+=step)
{ var test1 = x + radius*Math.cos(theta);
var test2 = y - radius*Math.sin(theta);
ctx.lineTo(test1,test2);
}
ctx.closePath();
ctx.stroke();
The entire js code:
function draw() {
var canvas = document.getElementById('multiplier');
var ctx = canvas.getContext('2d');
var x = 300; // x coordinate
var y = 300; // y coordinate
var radius = 295; // Arc radius
var point_size = 2;
var number_of_points = 10;
var multiplier = 2;
var points = [];
function drawCircle() {
points = [];
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
var step = 2 * Math.PI/points;
ctx.beginPath();
for(var theta=0; theta < 2*Math.PI; theta+=step)
{ var test1 = x + radius*Math.cos(theta);
var test2 = y - radius*Math.sin(theta);
ctx.lineTo(test1,test2);
}
ctx.closePath();
ctx.stroke();
var i;
var angleBetweenPoints = 360 / number_of_points;
for (i = 0; i < number_of_points ; i++) {
drawPoint(i * angleBetweenPoints, 1)
}
for (i = 1; i < points.length; i++ ) {
ctx.beginPath();
ctx.moveTo(points[i].x, points[i].y);
if (i < points.length / multiplier ) {
ctx.lineTo(points[i*multiplier].x, points[i*multiplier].y);
} else {
ctx.lineTo(points[i*multiplier % points.length].x, points[i*multiplier % points.length].y);
}
ctx.stroke();
}
}
function drawPoint(angle,distance){
var pointx = x + radius * Math.cos(-angle*Math.PI/180) * distance;
var pointy = y + radius * Math.sin(-angle*Math.PI/180) * distance;
ctx.beginPath();
ctx.arc(pointx, pointy, point_size, 0, 2 * Math.PI);
ctx.fill();
points.push({x: pointx, y: pointy});
}
if (canvas.getContext) {
drawCircle();
}
// add event listener to point number selection
var pointNumElement = document.getElementById("pointNumber");
pointNumElement.addEventListener('input', function(e){
number_of_points = this.value;
drawCircle();
});
// add event listener to multiplier number selection
var pointNumElement = document.getElementById("multiplierInput");
pointNumElement.addEventListener('input', function(e){
multiplier = this.value;
drawCircle();
});
}
In my canvas pie chart, I'm trying to get my labels to display either an A, B, or a C primarily using the following snippets of code:
var PI2 = Math.PI * 2;
var myColor = ["white", "white", "white"];
var myData = [30, 60, 29];
var myLabels = ["A", "B","C"]
var cx = 150;
var cy = 150;
var radius = 80;
pieChart(myData, myColor, myLabels);
// draw the the label at end of sector
var midAngle = endAngle ;
var labelRadius = radius * 1.5;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'blue';
ctx.fillText(myLabels, x, y);
Full code here: http://jsfiddle.net/2mf8gt2c/8/
However, each label shows all three letters from MyLabels. I tried adding an [i] after myLabels, but then only one sector appears.
How can I get each of the labels to display its respective letter?
Thanks!
Add a fifth argument to the drawWedge function and when calling the function inside for loop, pass myLabels[i] as the fifth parameter.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineWidth = 2;
ctx.font = '12px verdana';
var PI2 = Math.PI * 2;
var myColor = ["white", "white", "white"];
var myData = [30, 60, 29];
var myLabels = ["A", "B", "C"];
var cx = 150;
var cy = 150;
var radius = 80;
pieChart(myData, myColor, myLabels);
function pieChart(data, colors, myLabels) {
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
var sweeps = []
for (var i = 0; i < data.length; i++) {
sweeps.push(data[i] / total * PI2);
}
var accumAngle = 0;
for (var i = 0; i < sweeps.length; i++) {
drawWedge(accumAngle, accumAngle + sweeps[i], colors[i], data[i], myLabels[i]);
accumAngle += sweeps[i];
}
}
function drawWedge(startAngle, endAngle, fill, label, letter) {
// draw the wedge
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.arc(cx, cy, radius, startAngle, endAngle, false);
ctx.closePath();
ctx.fillStyle = fill;
ctx.strokeStyle = 'black';
ctx.fill();
ctx.stroke();
// draw the label in middle of sector
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * 0.5;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'green';
ctx.fillText(label, x, y);
// draw the label in middle of arc on exterior
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * 1.25;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'black';
ctx.fillText(label, x, y);
// draw the the label at start of sector
var midAngle = startAngle;
var labelRadius = radius * 1.25;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'red';
ctx.fillText(label, x, y);
// draw the the label at end of sector
var midAngle = endAngle;
var labelRadius = radius * 1.5;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'blue';
ctx.fillText(letter, x, y);
}
<section>
<div>
<table width="80%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td width=50%>
<canvas id="canvas" align="center" width="400" height="300"> This text is displayed if your browser does not support HTML5 Canvas. </canvas>
</td>
</tr>
</table>
</div>
</section>
I'm just starting with js and need little help! I got these two functions, to draw circles and splattered circles, I need to create a for loop to draw 10 random coloured circles and 10 random splattered circles! how can i do it? thanks
<canvas id="myCanvas" width="550" height="400"></canvas>
<script>
var randomColour;
var randomSize;
var xPos;
var yPos;
var i;
var j;
randomColour = '#' + Math.random().toString(16).substring(4); // random colour
c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
function drawFilledCircle(size,xPos,Ypos,colour){ //draw circle
ctx.beginPath();
ctx.arc(xPos,yPos,size,0,2*Math.PI);
ctx.fillStyle = colour;
ctx.fill();
}
function drawSplatter(size,xPos,yPos,colour){ // draw splattered circle
for(j=0;j<10;j++){
var splatSize = size / Math.round(Math.random()*30);
drawFilledCircle(splatSize,xPos + Math.round(Math.random()*50),yPos + Math.round(Math.random()*50),colour);
}
}
</script>
var randomColour;
var randomSize;
var xPos;
var yPos;
var i;
var j;
c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
function drawFilledCircle(size, xPos, yPos, colour) { //draw circle
ctx.beginPath();
ctx.arc(xPos, yPos, size, 0, 2 * Math.PI);
ctx.fillStyle = colour;
ctx.fill();
}
function drawSplatter(size, xPos, yPos, colour) { // draw splattered circle
for (j = 0; j < 10; j++) {
var splatSize = size / Math.round(Math.random() * 30);
drawFilledCircle(splatSize, xPos + Math.round(Math.random() * 50), yPos + Math.round(Math.random() * 50), colour);
}
}
var maxSize = 30;
var minSize = 10;
var maxX = c.width;
var maxY = c.height;
function randoms() {
var size = Math.ceil(Math.random() * maxSize);
size = Math.max(size, minSize);
var x = Math.floor(Math.random() * maxX);
var y = Math.floor(Math.random() * maxY);
var colour = '#' + Math.random().toString(16).substr(2,6);
return {size:size, x:x, y:y, colour:colour};
}
for (var i = 0; i < 10; i++) {
var r = randoms();
drawFilledCircle(r.size, r.x, r.y, r.colour);
r = randoms();
drawSplatter(r.size, r.x, r.y, r.colour);
}
body {
background-color:#222222;
}
<canvas id="myCanvas" width="550" height="400"></canvas>
I am making a pie chart with canvas but I am unable to put labels into the canvas. I tried so many things... Can you help me?
HTML
<canvas id="can" width="200" height="200" />
JS
var D1 = 15;
var D2 = 15;
var D3 = 45;
var D4 = 25;
var canvas = document.getElementById("can");
var ctx = canvas.getContext("2d");
var lastend = 0;
var data = [D1,D2,D3,D4]; // If you add more data values make sure you add more colors
var myTotal = 0; // Automatically calculated so don't touch
var myColor = ["#ECD078","#D95B43","#C02942","#542437"];
var labels = ["25%","25%","25%","25%"];
for (var e = 0; e < data.length; e++) {
myTotal += data[e];
ctx.font = 'bold 15pt Calibri';
ctx.fillText(labels[e],15,15);
}
for (var i = 0; i < data.length; i++) {
ctx.fillStyle = myColor[i];
ctx.beginPath();
ctx.moveTo(canvas.width / 2, canvas.height / 2);
// Arc Parameters: x, y, radius, startingAngle (radians), endingAngle (radians), antiClockwise (boolean)
ctx.arc(canvas.width / 2, canvas.height / 2, canvas.height / 2, lastend, lastend + (Math.PI * 2 * (data[i] / myTotal)), false);
ctx.lineTo(canvas.width / 2, canvas.height / 2);
ctx.fill();
lastend += Math.PI * 2 * (data[i] / myTotal);
}
My intention is to put the labels[] number in order, inside the pie chart.
If its not too late, you may try this:
https://jsfiddle.net/rradik/kuqdwuyd/
<canvas id="canvas" width="200" height="200" />
var canvas;
var ctx;
var lastend = 0;
var pieColor = ["#ECD078","#D95B43","#C02942","#542437","#53777A"];
var pieData = [10,30,20,60,40];
var pieTotal = 10 + 30 + 20 + 60 + 40; // done manually for demo
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, canvas.width, canvas.height);
var hwidth = ctx.canvas.width/2;
var hheight = ctx.canvas.height/2;
for (var i = 0; i < pieData.length; i++) {
ctx.fillStyle = pieColor[i];
ctx.beginPath();
ctx.moveTo(hwidth,hheight);
ctx.arc(hwidth,hheight,hheight,lastend,lastend+
(Math.PI*2*(pieData[i]/pieTotal)),false);
ctx.lineTo(hwidth,hheight);
ctx.fill();
//Labels on pie slices (fully transparent circle within outer pie circle, to get middle of pie slice)
//ctx.fillStyle = "rgba(255, 255, 255, 0.5)"; //uncomment for debugging
// ctx.beginPath();
// ctx.moveTo(hwidth,hheight);
// ctx.arc(hwidth,hheight,hheight/1.25,lastend,lastend+
// (Math.PI*(pieData[i]/pieTotal)),false); //uncomment for debugging
var radius = hheight/1.5; //use suitable radius
var endAngle = lastend + (Math.PI*(pieData[i]/pieTotal));
var setX = hwidth + Math.cos(endAngle) * radius;
var setY = hheight + Math.sin(endAngle) * radius;
ctx.fillStyle = "#ffffff";
ctx.font = '14px Calibri';
ctx.fillText(pieData[i],setX,setY);
// ctx.lineTo(hwidth,hheight);
//ctx.fill(); //uncomment for debugging
lastend += Math.PI*2*(pieData[i]/pieTotal);
}
May not be perfect and very efficient one, but does the job nevertheless
The problem was that all your text was overlapping.
I simply changed the order of execution. The text is now drawn after the pie chart. One more thing, I added an offset to the text, each time the loop runs I offset by 50.
Working Example
var offset = 50;
for (var e = 0; e < data.length; e++) {
ctx.font = 'bold 15pt Calibri';
ctx.fillText(labels[e],offset*e,180);
}
I'm trying to plot a pie chart using HTML5 and Canvas.
Here below is my working example in jsfiddle.
http://jsfiddle.net/2mf8gt2c/
I need to show the values inside of the pie chart.
i.e
var myColor = ["Green","Red","Blue"];
var myData = [30,60,10];
The value should be displayed inside the pie chart. How can I achieve that?
The full code is available below.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>My Title</title>
</head>
<body>
<section>
<div>
<table width="80%" cellpadding=1 cellspacing=1 border=0>
<tr>
<td width=50%><canvas id="canvas" align="center" width="400" height="250"> This text is displayed if your browser does not support HTML5 Canvas. </canvas>
</td>
</tr>
</table>
</div>
<script type="text/javascript">
var myColor = ["Green","Red","Blue"];
var myData = [30,60,10];
function degreesToRadians(degrees) {
return (degrees * Math.PI)/180;
}
function sumTo(a, i) {
var sum = 0;
for (var j = 0; j < i; j++) {
sum += a[j];
}
return sum;
}
function getTotal(){
var myTotal = 0;
for (var j = 0; j < myData.length; j++) {
myTotal += (typeof myData[j] == 'number') ? myData[j] : 0;
}
return myTotal;
}
var drawSegmentLabel = function(canvas, context, i)
{
context.save();
var x = Math.floor(250 / 2);
var y = Math.floor(100 / 2);
var angle;
var angleD = sumTo(myData, i);
var flip = (angleD < 90 || angleD > 270) ? false : true;
context.translate(x, y);
if (flip) {
angleD = angleD-180;
context.textAlign = "left";
angle = degreesToRadians(angleD);
context.rotate(angle);
context.translate(-(x + (canvas.width * 0.5))+15, -(canvas.height * 0.05)-10);
}
else {
context.textAlign = "right";
angle = degreesToRadians(angleD);
context.rotate(angle);
}
var fontSize = Math.floor(canvas.height / 25);
context.font = fontSize + "pt Helvetica";
context.fillStyle = "black";
var dx = Math.floor(250 * 0.5) - 10;
var dy = Math.floor(100 * 0.05);
context.fillText(myData[i], dx, dy);
context.restore();
}
function plotData()
{
var canvas;
var ctx;
var lastend = 0;
var myTotal = getTotal();
var pRadius = 100;
var xPie=250;
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = true;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < myData.length; i++)
{
ctx.fillStyle = myColor[i];
ctx.beginPath();
ctx.moveTo(xPie,pRadius+10);
ctx.arc(xPie,pRadius+10,pRadius,lastend,lastend +
(Math.PI*2*(myData[i]/myTotal)),false);
ctx.lineTo(xPie,pRadius+10);
ctx.fill();
lastend += Math.PI*2*(myData[i]/myTotal);
ctx.lineWidth = 2;
ctx.strokeStyle = '#000000';
ctx.stroke();
}
}
plotData();
</script>
</section>
</body>
</html>
Can someone help me to get this done?
Thanks,
Kimz
Here's an alternate way to draw a wedge with a specified starting & ending angle:
ctx.beginPath();
ctx.moveTo(cx,cy);
ctx.arc(cx,cy,radius,startAngle,endAngle,false);
ctx.closePath();
ctx.fillStyle=fill;
ctx.strokeStyle='black';
ctx.fill();
ctx.stroke();
I suggest this alternate method because you can easily calculate the angle exactly between the starting & ending angle like this:
var midAngle=startAngle+(endAngle-startAngle)/2;
And given the midAngle, you can use some trigonometry to calculate where to draw your values inside the wedge:
// draw the value labels 75% of the way from centerpoint to
// the outside of the wedge
var labelRadius=radius*.75;
// calculate the x,y at midAngle
var x=cx+(labelRadius)*Math.cos(midAngle);
var y=cy+(labelRadius)*Math.sin(midAngle);
Here's example code and a Demo:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
ctx.lineWidth = 2;
ctx.font = '12px verdana';
var PI2 = Math.PI * 2;
var myColor = ["Green", "Red", "Blue"];
var myData = [30, 60, 10];
var cx = 150;
var cy = 150;
var radius = 100;
pieChart(myData, myColor);
function pieChart(data, colors) {
var total = 0;
for (var i = 0; i < data.length; i++) {
total += data[i];
}
var sweeps = []
for (var i = 0; i < data.length; i++) {
sweeps.push(data[i] / total * PI2);
}
var accumAngle = 0;
for (var i = 0; i < sweeps.length; i++) {
drawWedge(accumAngle, accumAngle + sweeps[i], colors[i], data[i]);
accumAngle += sweeps[i];
}
}
function drawWedge(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 = 'black';
ctx.fill();
ctx.stroke();
// draw the label
var midAngle = startAngle + (endAngle - startAngle) / 2;
var labelRadius = radius * .75;
var x = cx + (labelRadius) * Math.cos(midAngle);
var y = cy + (labelRadius) * Math.sin(midAngle);
ctx.fillStyle = 'white';
ctx.fillText(label, x, y);
}
body {
background-color: ivory;
padding: 10px;
}
#canvas {
border: 1px solid red;
}
<canvas id="canvas" width=400 height=300></canvas>