On an HTML5 canvas I can't find a method to make colored circles. I've been consulting this as a reference.
Here is my current attempt
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillRect(20, 20, 100, 100);
ctx.lineJoin = "round";
ctx.lineWidth = "cornerRadius";
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
(Also on jsFiddle: http://jsfiddle.net/kvnm21r1/1/)
I've tried using the canvas arc method, which creates a circle, but doesn't color it.
I can't use the border-radius property, because ctx is not an element.
Is there any way, I can transform my squares into circles?
Thanks in advance.
You can use quadratic curves to "round-out" the straight lines of your square until they form a circle.
// change sideCount to the # of poly sides desired
//
var sideCount = 4;
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 2;
ctx.fillStyle = randomColor();
var PI2 = Math.PI * 2;
var cx = 150;
var cy = 150;
var radius = 100;
var xx = function (a) {
return (cx + radius * Math.cos(a));
}
var yy = function (a) {
return (cy + radius * Math.sin(a));
}
var lerp = function (a, b, x) {
return (a + x * (b - a));
}
var sides = [];
for (var i = 0; i < sideCount; i++) {
sides.push(makeSide(i, sideCount));
}
var percent = 0;
var percentDirection = 0.50;
$("#toShape").click(function () {
percentDirection = -0.50;
})
$("#toCircle").click(function () {
percentDirection = 0.50;
})
animate();
// functions
function animate() {
requestAnimationFrame(animate);
drawSides(percent);
percent += percentDirection;
if (percent > 100) {
percent = 100;
}
if (percent < 0) {
percent = 0;
}
}
function drawSides(pct, color) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (pct == 100) {
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, PI2);
ctx.closePath();
ctx.fill();
} else {
ctx.beginPath();
ctx.moveTo(sides[0].x0, sides[0].y0);
for (var i = 0; i < sideCount; i++) {
var side = sides[i];
var cpx = lerp(side.midX, side.cpX, pct / 100);
var cpy = lerp(side.midY, side.cpY, pct / 100);
ctx.quadraticCurveTo(cpx, cpy, side.x2, side.y2);
}
ctx.fill();
}
}
function makeSide(n, sideCount) {
var sweep = PI2 / sideCount;
var sAngle = sweep * (n - 1);
var eAngle = sweep * n;
var x0 = xx(sAngle);
var y0 = yy(sAngle);
var x1 = xx((eAngle + sAngle) / 2);
var y1 = yy((eAngle + sAngle) / 2);
var x2 = xx(eAngle);
var y2 = yy(eAngle);
var dx = x2 - x1;
var dy = y2 - y1;
var a = Math.atan2(dy, dx);
var midX = lerp(x0, x2, 0.50);
var midY = lerp(y0, y2, 0.50);
var cpX = 2 * x1 - x0 / 2 - x2 / 2;
var cpY = 2 * y1 - y0 / 2 - y2 / 2;
return ({
x0: x0,
y0: y0,
x2: x2,
y2: y2,
midX: midX,
midY: midY,
cpX: cpX,
cpY: cpY,
color: randomColor()
});
}
function randomColor() {
return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
body{ background-color: ivory; }
canvas{border:1px solid red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<button id="toShape">Animate to Shape</button>
<button id="toCircle">Animate to Circle</button><br>
<canvas id="canvas" width=300 height=300></canvas>
JSfiddle with a circle
To draw a circle you'll need to draw an arc and have a starting angle and an ending angle. So you'll have to use Pi and define a radius.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var radius = 70;
context.beginPath();
context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke();
Avoid w3schools.com whenever possible. Refer to sites like MDN instead.
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext("2d");
ctx.beginPath();
var radius = 50; // Arc radius
var startAngle = 0; // Starting point on circle
var endAngle = Math.PI*2; // End point on circle
ctx.arc(150, 75, radius, startAngle, endAngle, true);
ctx.fill();
<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
Related
I am trying to draw a group of shapes using canvas.
I have referenced below SO threads:
Draw a parallel line
How to draw parallel line using three.js?
but not able to figure out how to calculate points for the rectangles parallel in as we stretch the line.
Any reference for stretching shapes with canvas is appreciated.
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
last_mousex = parseInt(e.clientX-canvasx);
last_mousey = parseInt(e.clientY-canvasy);
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
mousex = parseInt(e.clientX-canvasx);
mousey = parseInt(e.clientY-canvasy);
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(last_mousex,last_mousey);
ctx.lineTo(mousex,mousey);
//ctx.lineTo(mousex,mousey);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
startx = last_mousex;
starty = last_mousey;
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey-10, mousey-10, mousey-60, last_mousey-60],true, 'gray', false, 'black', 2);
drawPolygon([last_mousex, mousex, mousex, last_mousex, last_mousex],
[last_mousey+10, mousey+10, mousey+60, last_mousey+60],true, 'gray', false, 'black', 2);
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>
I'm guessing this is what you wanted.
Instead of trying to manually draw your line rotated, instead, move the origin of the canvas to the start of the line,
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
then rotate the origin so it points toward the end of the line in the positive X direction
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
then compute the length of the line from the start to the end
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
and just draw an arrow in the positive x direction of that length
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
while we're at it your code for calculating the mouse position didn't work if the page is scrolled. This will get the mouse position relative to the pixels in the canvas.
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
//Canvas
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
//Variables
var last_mousex = last_mousey = 0;
var mousex = mousey = 0;
var mousedown = false;
// grid parameters
var gridSpacing = 20; // pixels
var gridWidth = 1;
//var gridColor = "#f1f1f1";
var gridColor = "lightgray";
/** */
var originX = 0;
/** */
var originY = 0;
drawGrid();
//Mousedown
$(canvas).on('mousedown', function(e) {
const rect = canvas.getBoundingClientRect();
last_mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
last_mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
mousedown = true;
});
//Mouseup
$(canvas).on('mouseup', function(e) {
mousedown = false;
});
//Mousemove
$(canvas).on('mousemove', function(e) {
const rect = canvas.getBoundingClientRect();
mousex = (e.clientX - rect.left) * canvas.width / canvas.clientWidth;
mousey = (e.clientY - rect.top ) * canvas.height / canvas.clientHeight;
if(mousedown) {
ctx.clearRect(0,0,canvas.width,canvas.height); //clear canvas
drawGrid();
// save the canvas state
ctx.save();
// move origin to start of line
ctx.translate(last_mousex, last_mousey);
// compute direction of line from start to end
const dx = mousex - last_mousex;
const dy = mousey - last_mousey;
const angle = Math.atan2(dy, dx);
// rotate to point to end of line
ctx.rotate(angle);
// compute length of line
const length = Math.sqrt(dx * dx + dy * dy);
ctx.setLineDash([5, 15]);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(length, 0);
ctx.strokeStyle = 'blue';
ctx.lineDashOffset = 2;
ctx.lineWidth = 5;
ctx.lineJoin = ctx.lineCap = 'round';
ctx.stroke();
drawPolygon([0, length, length, 0, 0],
[-10, -10, -60, -60],true, 'gray', false, 'black', 2);
drawPolygon([0, length, length, 0, 0],
[+10, +10, +60, +60],true, 'gray', false, 'black', 2);
// restore the canvas state
ctx.restore();
}
//Output
$('#output').html('current: '+mousex+', '+mousey+'<br/>last: '+last_mousex+', '+last_mousey+'<br/>mousedown: '+mousedown);
});
/** */
function drawLine(startX, startY, endX, endY, width, color) {
// width is an integer
// color is a hex string, i.e. #ff0000
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(endX, endY);
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.stroke();
}
function drawPolygon(xArr, yArr, fill, fillColor, stroke, strokeColor, strokeWidth) {
// fillColor is a hex string, i.e. #ff0000
fill = fill || false;
stroke = stroke || false;
ctx.beginPath();
ctx.moveTo(xArr[0], yArr[0]);
for (var i = 1; i < xArr.length; i++) {
ctx.lineTo(xArr[i], yArr[i]);
}
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
if (stroke) {
ctx.lineWidth = strokeWidth;
ctx.strokeStyle = strokeColor;
ctx.stroke();
}
//console.log(xArr);
//console.log(yArr);
}
/** returns n where -gridSize/2 < n <= gridSize/2 */
function calculateGridOffset(n) {
if (n >= 0) {
return (n + gridSpacing / 2.0) % gridSpacing - gridSpacing / 2.0;
} else {
return (n - gridSpacing / 2.0) % gridSpacing + gridSpacing / 2.0;
}
}
/** */
function drawGrid() {
var offsetX = calculateGridOffset(-originX);
var offsetY = calculateGridOffset(-originY);
var width = canvas.width;
var height = canvas.height;
for (var x = 0; x <= (width / gridSpacing); x++) {
drawLine(gridSpacing * x + offsetX, 0, gridSpacing * x + offsetX, height, gridWidth, gridColor);
}
for (var y = 0; y <= (height / gridSpacing); y++) {
drawLine(0, gridSpacing * y + offsetY, width, gridSpacing * y + offsetY, gridWidth, gridColor);
}
}
canvas {
cursor: crosshair;
border: 1px solid #000000;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas" width="800" height="500"></canvas>
<div id="output"></div>
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 have an HTML5 canvas where I draw an arc of the circle using the code below:
c = document.querySelector("#myCanvas");
ctx = c.getContext("2d");
var startAngle = 0;
var endAngle = 0.25;
var xPos = 300;
var yPos = 200;
var radius = 100;
ctx.beginPath();
ctx.arc(xPos, yPos, radius, startAngle*Math.PI, endAngle*Math.PI);
ctx.stroke();
ctx.closePath();
How do I compute for the x and y coordinates of the end angle generated by endAngle*Math.PI?
If I understood you correctly, you could achieve this in the following way ...
var c = document.querySelector("#canvas");
var ctx = c.getContext("2d");
var startAngle = 0; //degree
var endAngle = 229; //degree
var xPos = 100;
var yPos = 100;
var radius = 60;
// compute x and y coordinates of the end angle relative to canvas
var x = xPos + Math.cos(endAngle * Math.PI / 180) * radius;
var y = yPos + Math.sin(endAngle * Math.PI / 180) * radius;
ctx.beginPath();
ctx.arc(xPos, yPos, radius, startAngle * Math.PI / 180, endAngle * Math.PI / 180);
ctx.stroke();
console.log('angle ended in position x:', x|0, ', y:', y|0);
canvas {
border: 1px solid lightgrey;
}
<canvas id="canvas" width="200" height="200"></canvas>
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>
I am trying to add a few more circles in the circular loop using HTML5 canvas but it doesn't seem to work. I want the other circles to kind of trail the circle is already rotating there. I am also wondering how to make the circular motion non-linear (that is, it moves in varying speed like it has easing).
Can you guys help? :/ Thanks heaps. Below is my code.
<canvas id="canvas" width="450" height="450"></canvas>
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
var dd = 4;
var angle = 0;
/*var cx = 197;
var cy = 199;
var radius = 200;*/
var cx = w/2;
var cy = h/2;
var radius = 200;
function draw(x, y) {
ctx.fillStyle = "rgb(38,161,220)";
ctx.strokeStyle = "rgb(38,161,220)";
ctx.clearRect(0, 0, w, h);
ctx.save();
ctx.beginPath();
ctx.beginPath();
//ctx.rect(x - 30 / 2, y - 30 / 2, 50, 30);
// Circle 1
ctx.arc(x-1/2, y-1/2, 10, 0, 2 * Math.PI, false);
ctx.fill();
ctx.stroke();
ctx.restore();
};
/** context.beginPath();
context.fillStyle = 'green';
context.fill();
context.lineWidth = 5;
context.strokeStyle = '#003300';
context.stroke(); **/
var fps = 120;
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / fps);
};
})();
function animate() {
setTimeout(function () {
requestAnimFrame(animate);
// increase the angle of rotation
//angle += Math.acos(1-Math.pow(dd/radius,2)/2);
angle += Math.acos(1-Math.pow(dd/radius,2)/2);
// calculate the new ball.x / ball.y
var newX = cx + radius * Math.cos(angle);
var newY = cy + radius * Math.sin(angle);
// draw
draw(newX, newY);
// draw the centerpoint
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.stroke();
}, 1000 / fps );
}
animate();
</script>
Easing between where and where?
Heres some non-linear angular velocities:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<canvas id="canvas" width="450" height="450"></canvas>
<script type="text/javascript">
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var w = canvas.width;
var h = canvas.height;
var dd = 4;
var angle = 0;
var cx = w/2;
var t = 0;
var velocity = 0.01;
var cy = h/2;
var radius = 200;
function draw(x, y) {
ctx.fillStyle = "rgb(38,161,220)";
ctx.strokeStyle = "rgb(38,161,220)";
ctx.clearRect(0, 0, w, h);
ctx.save();
ctx.beginPath();
ctx.beginPath();
ctx.arc(x-1/2, y-1/2, 10, 0, 2 * Math.PI, false);
ctx.fill();
ctx.stroke();
ctx.restore();
};
var fps = 120;
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback) {
window.setTimeout(callback, 1000 / fps);
};
})();
function animate() {
setTimeout(function () {
// increase the angle of rotation
angle += velocity;
//sinusoidal velocity
velocity += 0.005 * (Math.sin(t));
t += 0.1;
// randomzed velocity:
//velocity += 0.001 * (Math.random() - 1);
// draw
// calculate the new ball.x / ball.y
var newX = cx + radius * Math.cos(angle);
var newY = cy + radius * Math.sin(angle);
draw(newX, newY);
// draw the centerpoint
ctx.beginPath();
ctx.arc(cx, cy, radius, 0, Math.PI * 2, false);
ctx.closePath();
ctx.stroke();
requestAnimFrame(animate);
}, 1000 / fps );
}
animate();
</script>
</body>
</html>
You can make a circle class like this:
var Circle = function(radius,velocity,etc){
this.radius = radius
this.velocity = velocity
this.etc = etc
// and whatever other properties you think you need
}
then
var circleArray = []
for(var i = 0; i < circleCount; i++){
circleArray.push(new Circle(2,0.1,"some_property"))
}
then inside animate():
circleArray.forEach(function(circle){
//drawing code
})
Until you ask a more specific question, thats all I can give you