I made a cylinder gauge, very similar to this one:
It is drawn using about 7 or so functions... mine is a little different. It is very fleixble in that I can set the colors, transparency, height, width, whether there is % text shown and a host of other options. But now I have a need for the same thing, but all rotated 90 deg so that I can set the height long and the width low to generate something more like this:
I found ctx.rotate, but no mater where it goes all the shapes fall apart.. ctx.save/restore appears to do nothing, I tried putting that in each shape drawing function. I tried modifying, for example, the drawOval function so that it would first rotate the canvas if horizontal was set to one; but it appeared to rotate it every single iteration, even with save/restore... so the top cylinder would rotate and the bottom would rotate twice or something. Very tough to tell what is really happening. What am I doing wrong? I don't want to duplicate all this code and spend hours customizing it, just to produce something I already have but turned horizontal. Erg! Help.
Option 1
To rotate everything just apply a transform to the element itself:
canvas.style.transform = "rotate(90deg)"; // or -90 depending on need
canvas.style.webkitTransform = "rotate(90deg)";
Option 2
Rotate context before drawing anything and before using any save(). Unlike the CSS version you will first need to translate to center, then rotate, and finally translate back.
You will need to make sure width and height of canvas is swapped before this is performed.
ctx.translate(ctx.canvas.width * 0.5, ctx.canvas.height * 0.5); // center
ctx.rotate(Math.PI * 0.5); // 90°
ctx.translate(-ctx.canvas.width * 0.5, -ctx.canvas.height * 0.5);
And of course, as an option 3, you can recalculate all your values to go along the other axis.
Look at the rotate function in this example. You want to do a translation to the point you want to rotate around.
example1();
example2();
function rotate(ctx, degrees, x, y, fn) {
ctx.save();
ctx.translate(x, y);
ctx.rotate(degrees * (Math.PI / 180));
fn();
ctx.restore();
}
function rad(deg) {
return deg * (Math.PI / 180);
}
function example2() {
var can = document.getElementById("can2");
var ctx = can.getContext('2d');
var w = can.width;
var h = can.height;
function drawBattery() {
var percent = 60;
ctx.beginPath();
ctx.arc(35,50, 25,0,rad(360));
ctx.moveTo(35+percent+25,50);
ctx.arc(35+percent,50,25,0,rad(360));
ctx.stroke();
ctx.beginPath();
ctx.fillStyle = "rgba(0,255,0,.5)";
ctx.arc(35,50,25,0,rad(360));
ctx.arc(35+percent,50,25,0,rad(360));
ctx.rect(35,25,percent,50);
ctx.fill();
ctx.beginPath();
ctx.lineWidth = 2;
ctx.strokeStyle = "#666666";
ctx.moveTo(135,25);
ctx.arc(135,50,25, rad(270), rad(269.9999));
//ctx.moveTo(35,75);
ctx.arc(35,50,25,rad(270),rad(90), true);
ctx.lineTo(135,75);
ctx.stroke();
}
drawBattery();
can = document.getElementById("can3");
ctx = can.getContext('2d');
w = can.width;
h = can.height;
rotate(ctx, -90, 0, h, drawBattery);
}
function example1() {
var can = document.getElementById('can');
var ctx = can.getContext('2d');
var color1 = "#FFFFFF";
var color2 = "#FFFF00";
var color3 = "rgba(0,155,255,.5)"
var text = 0;
function fillBox() {
ctx.save();
ctx.fillStyle = color3;
ctx.fillRect(0, 0, can.width / 2, can.height);
ctx.restore();
}
function drawBox() {
ctx.save();
ctx.beginPath();
ctx.strokeStyle = ctx.fillStyle = color1;
ctx.rect(10, 10, 50, 180);
ctx.font = "30px Arial";
ctx.fillText(text, 25, 45);
ctx.stroke();
ctx.beginPath();
ctx.strokeStyle = color2;
ctx.lineWidth = 10;
ctx.moveTo(10, 10);
ctx.lineTo(60, 10);
ctx.stroke();
ctx.restore();
}
fillBox();
rotate(ctx, 90, can.width, 0, fillBox);
text = "A";
drawBox();
color1 = "#00FFFF";
color2 = "#FF00FF";
text = "B";
rotate(ctx, 90, can.width, 0, drawBox);
centerRotatedBox()
function centerRotatedBox() {
ctx.translate(can.width / 2, can.height / 2);
for (var i = 0; i <= 90; i += 10) {
var radians = i * (Math.PI / 180);
ctx.save();
ctx.rotate(radians);
ctx.beginPath();
ctx.strokeStyle = "#333333";
ctx.rect(0, 0, 50, 50)
ctx.stroke();
ctx.restore();
}
}
}
#can,
#can2,
#can3 {
border: 1px solid #333333
}
<canvas id="can" width="200" height="200"></canvas>
<canvas id="can2" width="200" height="100"></canvas>
<canvas id="can3" width="100" height="200"></canvas>
Related
So I am totally new to canvas and trying a project in which I need to make small balls move around with their background as images. Following code is what I am trying right now.
ctx.beginPath();
ctx.arc(
this.pos[0], this.pos[1], this.radius, 0, 2 * Math.PI, true
);
let tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
let ballbackground = new Image();
if (this.color === "green") {
ballbackground.src = "https://s26.postimg.cc/fl2vwj1mh/greenball.png";
}
else if (this.color === "yellow") {
ballbackground.src = "https://s26.postimg.cc/if61a18yh/yellowball.png";
}
else if (this.color === "blue") {
ballbackground.src = "https://s26.postimg.cc/xb4khn7ih/blueball.jpg";
}
tempCanvas.width = 50;
tempCanvas.height = 50;
tCtx.drawImage(ballbackground,0,0,ballbackground.width, ballbackground.height,0,0,50,50);
ctx.fillStyle = ctx.createPattern(tempCanvas, "repeat");
And for moving those balls I do as follows:
const velocityScale = timeDelta / NORMAL_FRAME_TIME_DELTA,
offsetX = this.vel[0] * velocityScale * this.speed,
offsetY = this.vel[1] * velocityScale * this.speed;
this.pos = [this.pos[0] + offsetX, this.pos[1] + offsetY];
However, the problem is when objects move they seem like sliding over background image like so:
If I try "no-repeat" with createPattern, the balls won't display at all.
What I want is those balls with background images moving on the canvas?
move the balls by using the canvas transform?
const ctx = document.querySelector("canvas").getContext("2d");
const pattern = createPattern(ctx);
function drawCircleByPosition(ctx, x, y) {
ctx.beginPath();
ctx.arc(x, y, 50, 0, Math.PI * 2, true);
ctx.fill();
}
function drawCircleByTransform(ctx, x, y) {
ctx.save();
ctx.translate(x, y);
ctx.beginPath();
ctx.arc(0, 0, 50, 0, Math.PI * 2, true);
ctx.fill();
ctx.restore();
}
function render(time) {
time *= 0.001;
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = pattern;
drawCircleByPosition(ctx, 90, 75 + Math.sin(time) * 50);
drawCircleByTransform(ctx, 210, 75 + Math.sin(time) * 50);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
function createPattern(ctx) {
const tCtx = document.createElement("canvas").getContext("2d");
tCtx.canvas.width = 50;
tCtx.canvas.height = 50;
tCtx.fillStyle = "yellow";
tCtx.fillRect(0, 0, 50, 50);
for (let x = 0; x < 50; x += 20) {
tCtx.fillStyle = "red";
tCtx.fillRect(x, 0, 10, 50);
tCtx.fillStyle = "blue";
tCtx.fillRect(0, x, 50, 10);
}
return ctx.createPattern(tCtx.canvas, "repeat");
}
canvas { border: 1px solid black; }
<canvas></canvas>
note that rather than call save and restore you can also just set the transform with setTransform which is probably faster since save and restore saves all state (fillStyle, strokeStyle, font, globalCompositeOperation, lineWidth, etc...).
You can either pass in your own matrix. Example
ctx.setTransform(1, 0, 0, 1, x, y); // for translation
and/or you can reset it to the default whenever and then use the standard transform manipulation functions
ctx.setTransform(1, 0, 0, 1, 0, 0); // the default
ctx.translate(x, y);
or whatever combination of things you want to do.
I have a project to do and I cannot do it until I understand how moving object inside canvas work.
I need to move one of the objects below by 50pixels to right.
Anyone willing to help me is greatly appreciated.
Meanwhile thank you very much in advance for your help or suggestions.
function canvasOneShape() {
//refers to the html canvasone id
var canvas = document.getElementById("canvasOne");
this.canvasOne.width = 945;
this.canvasOne.height = 650;
// draws the canvas in 2d
var ctx = canvas.getContext("2d");
// Set the fill colour to blue.
ctx.fillStyle = "blue"; //used like this instead of rgb due personal preference:)
// Create a filled rectangle at co-ordinates (10,10)
// with height and width set to 100.
ctx.fillRect(10, 10, 250, 330); //
// Here I draw the square
// Set the canvas up for drawing in 2D.
// Set the fill colour to blue.
ctx.fillStyle = "rgba(244, 244, 189,.5)";
ctx.fillRect(10, 50, 330, 250);
//draw my first circle
var midXone = canvas.width / 2; //x location
var midXtwo = canvas.height / 2; //y location
var radius = 60; //circle radius
ctx.beginPath();
ctx.arc(midXone, midXtwo, radius, 0, 2 * Math.PI, false);
ctx.fillStyle ="rgba(89, 192, 227,.4)";
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle = '#003300';
ctx.stroke();
//draw the second circle
var midX = canvas.width / 2.35; //x location
var midY = canvas.height / 2.35; //y location
var radius = 50; //circle radius
ctx.beginPath();
ctx.arc(midX, midY, radius, 0, 2 * Math.PI, false);
ctx.fillStyle ="rgba(66, 244, 89,.4)";
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle ="rgba(255, 244, 9,.4)";
ctx.stroke();
//draw Square with circle inside
//square
ctx.fillStyle = "rgb(222, 33, 51)";
ctx.fillRect(550, 20, 300, 300);
//circle
ctx.beginPath();
ctx.arc(700, 170, 150, 0, 2 * Math.PI, false);
ctx.fillStyle ="rgba(66, 244, 89,.4)";
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = '#f44242';
ctx.stroke();
//The Pacman object
var radius = 100; //circle radius
var x = 100;
var y = 500;
ctx.beginPath();
ctx.arc(120, 500, radius, 1.85 * Math.PI, .15 * Math.PI, true);
//Draw mouth
ctx.lineTo(120, 500);
ctx.closePath();
ctx.fillStyle = "rgb(255, 255, 0)";
ctx.fill();
ctx.lineWidth = 5;
ctx.strokeStyle = 'rgb(0,0,0)';
ctx.stroke();
//draw eye
ctx.beginPath();
ctx.arc(x + 40, y - 40, 10, 0 * Math.PI, 2 * Math.PI, true);
ctx.fillStyle = "rgb(0,0,0)";
ctx.fill();
}
there are no layers or objects on a canvas(it's just a single layer of pixels), so, if you draw something, you overwrite what's underneath it. to move something to the right, you will need to have a function to draw everything behind it, and then variables to store the location (x and y) of the objects you want to move.
then, to move it, you clear the canvas with
ctx.clearRect(0, 0,width of canvas, height height of canvas);,
call the background function to draw everything behind it again, and the redraw your object in a different location.
I am drawing a canvas and rotating it based on a value, it works if i use the canvas one time on a page.
If i add it the second time to the page, only the last one gets drawn, i cant find the error in my code and i dont get a js error.
i think the problem is in the next function:
function animate(){
function drawnumbers()
{context.save();
context.fillStyle = "#000000";
context.translate(73,0);
context.font="10px Orbitron";
context.textAlign = "center";
context.rotate(((i*(180/min)))*Math.PI/180);
context.fillText(data.values[i].amount,0,3);
context.restore();
};
if (d < defer){
context.clearRect(0,0,400,400);
d++;
context.save();
var ang = ((((d-minn)*(180/angle)))*(Math.PI/180));
context.translate(38,39);
context.scale(.8,.8);
base_image = new Image();
base_image.src = 'http://oi44.tinypic.com/2hfkx8p.jpg';
context.translate(base_image.width/2, base_image.height/2);
context.rotate(ang );
context.drawImage(base_image, -base_image.width/2, -base_image.height/2);
context.restore();
context.save();
context.beginPath();
context.arc(100,100,64,1*Math.PI,2*Math.PI, false);
context.lineWidth = .4;
context.strokeStyle="#00A1DE";
context.globalAlpha = 0.7;
context.stroke();
context.restore();
context.save();
context.translate(100,100);
context.rotate(Math.PI/180);
context.strokeStyle = "#00A1DE";
context.lineWidth = .7;
for (var i=0;i < data.values.length; i++){
context.beginPath();
context.moveTo(62,0);
context.lineTo(67,0);
context.stroke();
context.globalAlpha = 0.7;
drawnumbers();
context.rotate((182/(min))*(-Math.PI/180));
}
context.restore();
context.fillStyle="white";
context.fillRect(38,101,123,75);
context.save();
context.fillStyle = "#00a1de";
context.font = "22px Orbitron";
context.textAlign = "center";
context.fillText(defer, 100, 90);
context.restore();
context.save();
context.fillStyle = "#000000";
context.font = "10px arial";
context.textAlign = "center";
context.fillText(eenheid, 100, 115);
context.restore();
}
else
{
clearTimeout(t);
};
t=setTimeout("animate()",30-d);
};
check example to better understand:
http://jsbin.com/ogEgURu/1/
I had it in a function but it remains the same problem so i think something is wrong with my code.
Can anyone see the problem i am not seeing ?
Your code is way too complex, especially since there is no good reason for this complexity.
Copying a big (>200) lines block of code to duplicate a functionality is error-prone.
You'll be able to see easily the issue once you refactored your code.
Just a few hints :
Very easy one : beautify the code.
No redundancy : If a code lies here twice or more, make a function and factorize.
Break down the code into smaller parts. For example : drawText(context, text, x,y, font ) (to print eenheid and defer), drawNumbers(context), drawRotatingImage(context, angle), ...
use closePath() each time you beginPath();
load once the image when page loads, and wait for it to be loaded before animating.
do not define a function in a loop (drawnumbers).
use a single object to store the several parameters (context, angle, ...), or
even switch to an object oriented style.
have only one animate() loop, that will call several draw(...) functions if need be.
after all this, your code will look much simpler, and the bug should vanish very quickly.
I did this work (partially), in this fiddle :
http://jsfiddle.net/gamealchemist/ztczK/1/ (edited)
The code looks like :
// parameters : settings for one gauge display
var parameters1 = {
data: data,
defer: '520',
context: context,
left: 38,
top: 30,
d: 0,
angle: 0,
scale: 0.8,
//... whatever parameter here
};
var parameters2 = ... ;
split the draw into many functions so it's much simpler to understand :
// draws a gauge
function drawGauge(param) {
preDraw(param);
drawBaseImage(param);
drawArc(param);
drawTheNumbers(param);
writeDefer(param);
writeEenheid(param);
postDraw(param);
}
// translate and scales context, and updates some values for the gauge
function preDraw(param) {
var minn = param.data.values[param.data.values.length - 1].amount;
var maxn = data.values[0].amount;
var angle = maxn - minn;
var d = param.d;
param.ang = ((((d - minn) * (180 / angle))) * (Math.PI / 180));
var ctx = param.context;
ctx.save();
ctx.translate(param.left, param.top);
ctx.scale(param.scale, param.scale);
context.fillStyle = "white";
context.fillRect(0, 60, 123, 75);
}
// restore context
function postDraw(param) {
var ctx = param.context;
ctx.restore();
param.d++;
}
function drawBaseImage(param) {
var ctx = param.context;
var ang = param.ang;
ctx.save();
ctx.translate(base_image.width / 2, base_image.height / 2);
ctx.rotate(ang);
ctx.drawImage(base_image, -base_image.width / 2, -base_image.height / 2);
ctx.restore();
}
function drawArc(param) {
var ctx = param.context;
ctx.save();
ctx.beginPath();
ctx.arc(base_image.width / 2, base_image.height / 2, 64, 1 * Math.PI, 2 * Math.PI, false);
ctx.lineWidth = .4;
ctx.strokeStyle = "#00A1DE";
ctx.globalAlpha = 10.7;
ctx.stroke();
ctx.restore();
}
function writeDefer(param) {
var ctx = param.context;
var defer = param.defer;
ctx.save();
ctx.fillStyle = "#00a1de";
ctx.font = "22px Orbitron";
ctx.textAlign = "center";
ctx.fillText(defer, base_image.width / 2, base_image.height / 2);
ctx.restore();
}
function writeEenheid(param) {
var ctx = param.context;
ctx.save();
ctx.fillStyle = "#000000";
ctx.font = "10px arial";
ctx.textAlign = "center";
ctx.fillText(eenheid, base_image.width / 2, base_image.height / 2 + 20);
ctx.restore();
}
function drawTheNumbers(param) {
var ctx = param.context;
var dataValues = param.data.values;
var count = dataValues.length;
ctx.save();
ctx.translate(base_image.width / 2, base_image.height / 2);
ctx.rotate(Math.PI / 180);
ctx.strokeStyle = "#00A1DE";
ctx.lineWidth = .7;
ctx.fillStyle = "#000000";
ctx.font = "10px Orbitron";
ctx.textAlign = "center";
ctx.globalAlpha = 0.7;
for (var i = 0; i < count; i++) {
ctx.beginPath();
ctx.moveTo(62, 0);
ctx.lineTo(67, 0);
ctx.stroke();
ctx.closePath();
ctx.fillText(dataValues[i].amount, 60, 3);
ctx.rotate(-Math.PI / count);
}
context.restore();
}
then animate becomes very simple, even with several gauges :
function animate() {
context.clearRect(0, 0, canvasWidth, canvasHeight);
drawGauge(parameters1);
drawGauge(parameters2);
setTimeout(animate, 15);
};
base_image.onload = animate();
I'm currently trying to make so that when you click on one of the happy face you get an alert box which says "thanks for the feed back", but I'm currently not sure to to incoperate that in tho my code! Thanks! Here is the fiddle http://jsfiddle.net/bsjs9/
<html lang="en">
<head>
<meta charset="utf-8" />
<title>SmileMore</title>
</head>
<body>
<h1>
Bring your Charts to life with HTML5 Canvas</h1>
</hgroup>
<p>
Rendering Dynamic charts in JS
</p>
<div class="smile">
<canvas id="myDrawing" width="200" height="200" style="border:1px solid #EEE"></canvas>
<canvas id="canvas" width="200" height="200" style="border:1px solid #EEE"></canvas>
</div>
<script>
var FacePainter = function(canvasName)
{
var canvas = document.getElementById(canvasName);
var ctx = canvas.getContext("2d");
var x = canvas.width / 2;
var y = canvas.height / 2;
var radius = 75;
var startAngle = 0;
var endAngle = 2 * Math.PI;
function drawFace() {
ctx.beginPath();
ctx.arc(x, y, radius, startAngle, endAngle);
ctx.stroke();
ctx.fillStyle = "yellow";
ctx.fill();
}
function drawSmile(startAngle, endAngle)
{
var x = canvas.width / 2;
var y = 150;
var radius = 40;
ctx.beginPath();
ctx.arc(x, y, radius, startAngle * Math.PI, endAngle * Math.PI);
ctx.lineWidth = 7;
// line color
ctx.strokeStyle = 'black';
ctx.stroke();
}
function drawEyes() {
var centerX = 40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
//left eye
var centerX = -40;
var centerY = 0;
var radius = 10;
// save state
ctx.save();
// translate context so height is 1/3'rd from top of enclosing circle
ctx.translate(canvas.width / 2, canvas.height / 3);
// scale context horizontally by 50%
ctx.scale(.5, 1);
// draw circle which will be stretched into an oval
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
// restore to original state
ctx.restore();
// apply styling
ctx.fillStyle = 'black';
ctx.fill();
ctx.lineWidth = 2;
ctx.strokeStyle = 'black';
ctx.stroke();
}
this.drawHappyFace = function() {
drawFace();
drawEyes();
drawSmile(1.1, 1.9);
}
this.drawSadFace = function() {
drawFace();
drawEyes();
drawSmile(1.9, 1.1);
;
}
}
new FacePainter('canvas').drawHappyFace();
new FacePainter('myDrawing').drawSadFace();
</script>
</body>
</html>
</body>
</html>
As an extra assignment I would like to know if anyone knows how to fix the "happy" smile, its kinda way off! Thanks all!
Since you draw the happy face on its own canvas, you can simple put an onclick handler on the canvas.
<canvas id="myDrawing" width="200" height="200" style="border:1px solid #EEE" onclick="alert('thanks');"></canvas>
Regarding the smiles, I added a new ofsy parameter to drawSmile, which offsets the arc origin vertically.
Here is the updated fiddle.
If you only want to show the alert, when the user clicks inside the face, you need to get the click coordinates and hittest it against the circle. You can see this in this fiddle.
I need to know how to draw polygons on a canvas. Without using jQuery or anything like that.
Create a path with moveTo and lineTo (live demo):
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100,50);
ctx.lineTo(50, 100);
ctx.lineTo(0, 90);
ctx.closePath();
ctx.fill();
from http://www.scienceprimer.com/drawing-regular-polygons-javascript-canvas:
The following code will draw a hexagon. Change the number of sides to create different regular polygons.
var ctx = document.getElementById('hexagon').getContext('2d');
// hexagon
var numberOfSides = 6,
size = 20,
Xcenter = 25,
Ycenter = 25;
ctx.beginPath();
ctx.moveTo (Xcenter + size * Math.cos(0), Ycenter + size * Math.sin(0));
for (var i = 1; i <= numberOfSides;i += 1) {
ctx.lineTo (Xcenter + size * Math.cos(i * 2 * Math.PI / numberOfSides), Ycenter + size * Math.sin(i * 2 * Math.PI / numberOfSides));
}
ctx.strokeStyle = "#000000";
ctx.lineWidth = 1;
ctx.stroke();
#hexagon { border: thin dashed red; }
<canvas id="hexagon"></canvas>
//poly [x,y, x,y, x,y.....];
var poly=[ 5,5, 100,50, 50,100, 10,90 ];
var canvas=document.getElementById("canvas")
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f00';
ctx.beginPath();
ctx.moveTo(poly[0], poly[1]);
for(let item=2 ; item < poly.length-1 ; item+=2 ){ctx.lineTo( poly[item] , poly[item+1] )}
ctx.closePath();
ctx.fill();
//create and fill polygon
CanvasRenderingContext2D.prototype.fillPolygon = function (pointsArray, fillColor, strokeColor) {
if (pointsArray.length <= 0) return;
this.moveTo(pointsArray[0][0], pointsArray[0][1]);
for (var i = 0; i < pointsArray.length; i++) {
this.lineTo(pointsArray[i][0], pointsArray[i][1]);
}
if (strokeColor != null && strokeColor != undefined)
this.strokeStyle = strokeColor;
if (fillColor != null && fillColor != undefined) {
this.fillStyle = fillColor;
this.fill();
}
}
//And you can use this method as
var polygonPoints = [[10,100],[20,75],[50,100],[100,100],[10,100]];
context.fillPolygon(polygonPoints, '#F00','#000');
Here is a function that even supports clockwise/anticlockwise drawing do that you control fills with the non-zero winding rule.
Here is a full article on how it works and more.
// Defines a path for any regular polygon with the specified number of sides and radius,
// centered on the provide x and y coordinates.
// optional parameters: startAngle and anticlockwise
function polygon(ctx, x, y, radius, sides, startAngle, anticlockwise) {
if (sides < 3) return;
var a = (Math.PI * 2)/sides;
a = anticlockwise?-a:a;
ctx.save();
ctx.translate(x,y);
ctx.rotate(startAngle);
ctx.moveTo(radius,0);
for (var i = 1; i < sides; i++) {
ctx.lineTo(radius*Math.cos(a*i),radius*Math.sin(a*i));
}
ctx.closePath();
ctx.restore();
}
// Example using the function.
// Define a path in the shape of a pentagon and then fill and stroke it.
context.beginPath();
polygon(context,125,125,100,5,-Math.PI/2);
context.fillStyle="rgba(227,11,93,0.75)";
context.fill();
context.stroke();
In addition to #canvastag, use a while loop with shift I think is more concise:
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var poly = [5, 5, 100, 50, 50, 100, 10, 90];
// copy array
var shape = poly.slice(0);
ctx.fillStyle = '#f00'
ctx.beginPath();
ctx.moveTo(shape.shift(), shape.shift());
while(shape.length) {
ctx.lineTo(shape.shift(), shape.shift());
}
ctx.closePath();
ctx.fill();
You can use the lineTo() method same as:
var objctx = canvas.getContext('2d');
objctx.beginPath();
objctx.moveTo(75, 50);
objctx.lineTo(175, 50);
objctx.lineTo(200, 75);
objctx.lineTo(175, 100);
objctx.lineTo(75, 100);
objctx.lineTo(50, 75);
objctx.closePath();
objctx.fillStyle = "rgb(200,0,0)";
objctx.fill();
if you not want to fill the polygon use the stroke() method in the place of fill()
You can also check the following: http://www.authorcode.com/draw-and-fill-a-polygon-and-triangle-in-html5/
thanks
For the people looking for regular polygons:
function regPolyPath(r,p,ctx){ //Radius, #points, context
//Azurethi was here!
ctx.moveTo(r,0);
for(i=0; i<p+1; i++){
ctx.rotate(2*Math.PI/p);
ctx.lineTo(r,0);
}
ctx.rotate(-2*Math.PI/p);
}
Use:
//Get canvas Context
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.translate(60,60); //Moves the origin to what is currently 60,60
//ctx.rotate(Rotation); //Use this if you want the whole polygon rotated
regPolyPath(40,6,ctx); //Hexagon with radius 40
//ctx.rotate(-Rotation); //remember to 'un-rotate' (or save and restore)
ctx.stroke();
To make a simple hexagon without the need for a loop, Just use the beginPath() function. Make sure your canvas.getContext('2d') is the equal to ctx if not it will not work.
I also like to add a variable called times that I can use to scale the object if I need to.This what I don't need to change each number.
// Times Variable
var times = 1;
// Create a shape
ctx.beginPath();
ctx.moveTo(99*times, 0*times);
ctx.lineTo(99*times, 0*times);
ctx.lineTo(198*times, 50*times);
ctx.lineTo(198*times, 148*times);
ctx.lineTo(99*times, 198*times);
ctx.lineTo(99*times, 198*times);
ctx.lineTo(1*times, 148*times);
ctx.lineTo(1*times,57*times);
ctx.closePath();
ctx.clip();
ctx.stroke();
Let's do that with HTML and get that down to this:
<!DOCTYPE html>
<html>
<head>
<title> SVG hexagon </title>
</head>
<body>
<svg width="300" height="110" >
<polygon point="50 3, 100 28, 100 75, 50 100, 3 75, 3 25" stroke="red" fill="lime" stroke-width="5"/>
</svg>
</body>
</html>
var ctx = document.getElementById('hexagon').getContext('2d');
// hexagon
var numberOfSides = 4,
size = 25,
Xcenter = 40,
Ycenter = 40;
ctx.beginPath();
ctx.moveTo (Xcenter + size * Math.cos(0), Ycenter + size * Math.sin(0));
for (var i = 1; i <= numberOfSides;i += 1) {
ctx.lineTo (Xcenter + size * Math.cos(i * 2 * Math.PI / numberOfSides), Ycenter + size * Math.sin(i * 2 * Math.PI / numberOfSides));
}
ctx.strokeStyle = "#000000";
ctx.lineWidth = 1;
ctx.stroke();
#hexagon { border: thin dashed red; }
<canvas id="hexagon"></canvas>