Rotating a drawn circle ind Javascript HTML5 Canvas - javascript

i have a Canvas:
function drawWindRose(){
var canvas = document.getElementById('windrose');
var bild = canvas.getContext('2d');
var frame = canvas.getContext('2d');
frame.fillStyle = "rgb(200,0,0)";
frame.fillRect (0, 0, 200, 200);
bild.save();
bild.translate(100,100);
bild.rotate((360-Compass)*Math.PI/180);
bild.fillStyle = "rgb(0,0,0)";
bild.font = '8pt Arial';
bild.fillText('N', 102, 30);
bild.fillText('E', 170, 110);
bild.fillText('S', 92, 170);
bild.fillText('W', 30, 96);
bild.closePath()
bild.strokeStyle= "rgb(0,0,0)"; // schwarz
bild.beginPath();
bild.lineWidth = 2;
bild.arc(100,100,95,0,Math.PI*2,true);
bild.moveTo(105,100);
bild.lineTo(195,100);
bild.moveTo(100,105);
bild.lineTo(100,195);
bild.moveTo(95,100);
bild.lineTo(5,100);
bild.moveTo(100,95);
bild.lineTo(100,5);
bild.moveTo(105,100);
bild.arc(100,100,5,0,Math.PI*2,true);
bild.closePath()
bild.stroke();
bild.beginPath();
bild.lineWidth = 5;
if(Azimuth>=0&&Distance>=1)
{
bild.arc(100,100,85,0,Math.PI*2,true);
bild.arc(100,100,85,0,(Azimuth-90)*(Math.PI/180),true);
bild.lineTo(100,100);
}
if(Distance<=1)
{
bild.arc(100,100,2,0,Math.PI*2,true);
}
bild.strokeStyle= "#00FF00";//green
bild.stroke();
bild.translate(-100,-100);
bild.restore();
};
<canvas style="padding-left: 0; padding-right: 0; margin-left: auto; margin-right: auto; display: block;"id="windrose" width="200" height="200"> Ihr Browser kann kein Canvas! </canvas>
Like u can see, i want to rotate the canvas. Its a kind of Compass for a FXOS-App.
I know how to rotate an image, but i dont get it to work with this drawing.
The "Compass" Variable is the Deviceorientation un Degrees.
So if you point the device to east, the Compass must be rotated 90degrees to the left...
Maybe some of you has got an idea.
regards
goerdy

I would use offscreen canvas to draw to the compass and then rotate that as an image onto my main canvas like (Example hardcoded values(azimuth and distance) and get deg from html):
window.onload = setupRose;
var TO_RADIANS = Math.PI / 180;
function drawRotatedImage(context, image, x, y, angle) {
var canvas = document.getElementById('myCanvas');
context.save();
context.translate(x, y);
context.rotate(angle * TO_RADIANS);
context.drawImage(image, -(image.width / 2), -(image.height / 2), image.width, image.height);
context.restore();
}
var myCompass = {};
function setupRose() {
myCompass.g_canvas = document.createElement('canvas');
myCompass.g_canvas.width = 200;
myCompass.g_canvas.height = 200;
m_context = myCompass.g_canvas.getContext('2d');
m_context.fillStyle = "rgb(0,0,0)";
m_context.font = '8pt Arial';
m_context.fillText('N', 102, 30);
m_context.fillText('E', 170, 110);
m_context.fillText('S', 92, 170);
m_context.fillText('W', 30, 96);
m_context.strokeStyle = "rgb(0,0,0)"; // schwarz
m_context.beginPath();
m_context.lineWidth = 2;
m_context.arc(100, 100, 95, 0, Math.PI * 2, true);
m_context.moveTo(105, 100);
m_context.lineTo(195, 100);
m_context.moveTo(100, 105);
m_context.lineTo(100, 195);
m_context.moveTo(95, 100);
m_context.lineTo(5, 100);
m_context.moveTo(100, 95);
m_context.lineTo(100, 5);
m_context.moveTo(105, 100);
m_context.arc(100, 100, 5, 0, Math.PI * 2, true);
m_context.closePath()
m_context.stroke();
m_context.beginPath();
m_context.lineWidth = 5;
if (32 >= 0 && 13 >= 1) {
m_context.arc(100, 100, 85, 0, Math.PI * 2, true);
m_context.arc(100, 100, 85, 0, (32 - 90) * (Math.PI / 180), true);
m_context.lineTo(100, 100);
}
if (13 <= 1) {
m_context.arc(100, 100, 2, 0, Math.PI * 2, true);
}
m_context.strokeStyle = "#00FF00"; //green
m_context.stroke();
}
function drawWindRose() {
var canvas = document.getElementById('windrose');
var bild = canvas.getContext('2d');
var frame = canvas.getContext('2d');
frame.fillStyle = "rgb(200,0,0)";
frame.fillRect(0, 0, 200, 200);
var deg = parseFloat(document.getElementById("degrees").value);
if (!deg) deg = 0;
drawRotatedImage(bild, myCompass.g_canvas, 100, 100, deg);
};

Related

Creating a line animation on canvas

I'm a newbie in canvas drawing. I want to draw the PV string model and the direction of flow of electrons into <canvas> tag.
This is what I want to achieve, redrawing the lines from the following direction:
How do I initially set the animation location, and do I need to update it via setTimeout?
Here is what I try so far:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
if (canvas.getContext) {
var ctx = canvas.getContext('2d');
// drawing code here
/* First Row */
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(50, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(110, 50, 50, 50);
ctx.fillStyle = "rgb(188,12,50, 1)";
ctx.fillRect(170, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(230, 50, 50, 50);
ctx.fillStyle = "rgb(2,150,224, 1)";
ctx.fillRect(290, 50, 50, 50);
/* Second Row */
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(50, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(110, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(170, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(230, 150, 50, 50);
ctx.fillStyle = "rgb(0,106,160, 1)";
ctx.fillRect(290, 150, 50, 50);
/* Paths */
ctx.beginPath();
ctx.lineWidth = "3";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(0, 75);
ctx.lineTo(400, 75);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = "10";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(400, 75);
ctx.lineTo(400, 175);
ctx.stroke();
ctx.beginPath();
ctx.lineWidth = "3";
ctx.strokeStyle = "rgb(34,177,76, 1)";
ctx.moveTo(0, 175);
ctx.lineTo(400, 175);
ctx.stroke();
} else {
// canvas-unsupported code here
}
/* canvas {
border: 1px solid #d3d3d3;
} */
<canvas id="myCanvas" width="400" height="400">
Your browser does not support the HTML5 canvas tag.</canvas>
Any help would be appreciated!
There are many ways to animate this; here's my approach (excerpt; see
JSFiddle for full code):
var lerp = (a, b, t) => a + t * (b - a);
var speed = 0.01;
var time = 0;
var visited = [];
var points = [
{
from: { x: 0, y: 75 },
to: { x: 395, y: 75 }
},
{
from: { x: 395, y: 75 },
to: { x: 395, y: 175 }
},
{
from: { x: 395, y: 175 },
to: { x: 0, y: 175 }
}
];
/* Paths */
ctx.lineWidth = 3;
ctx.strokeStyle = "rgb(34, 177, 76, 1)";
(function update() {
if (points.length) {
visited.push({
x: lerp(points[0].from.x, points[0].to.x, time),
y: lerp(points[0].from.y, points[0].to.y, time)
});
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBoxes(ctx);
ctx.beginPath();
ctx.moveTo(visited[0].x, visited[0].y)
visited.forEach(e => ctx.lineTo(e.x, e.y));
ctx.stroke();
time += speed;
if (time >= 1) {
time = 0;
points.shift();
}
requestAnimationFrame(update);
}
})();
The idea is to keep a data structure of all the turning points, then lerp along the path, drawing a line along the way. Use an easing function instead of lerp if you prefer a more "modern"-looking animation; easing is usually easier to implement and may result in removal of some code (for example, no need to keep track of starting points and time).
Last minor note--your original code was cutting off the line at the right edge of the canvas, so I took the liberty of using 395 instead of 400 for the drawing width.

Click on object to do certain function

I'm programming on JavaScript and basically what I'm supposed to do is to draw a face on a canvas and those faces have certain effects.
One of the effects I'm supposed to do is to click on the nose and it will change the face to an angry face. I have created objects for all the face parts (nose, eyes, etc.) and what I'm trying to do is that I want the function "angryFace" to be called when the nose is clicked. The nose is already an object.
Been stuck for a long time on this. Would appreciate it if someone could help! Uploaded the whole code down here. Thanks guys!
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>COM1008 Assignment 2</title>
<link rel="stylesheet" href="main1.css">
</head>
<main>
<h1>COM 1008 Assignment 2</h1>
<p>By Samuel Fung Chi Lun</p>
</main>
<body>
<canvas id="canvasFrame" width="600" height="600"></canvas>
<p>
<button name="sadbutton" id="sadFace">Sad</button>
<button name="angrybutton" id="angryFace">Angry</button>
<button name="surprisedbutton" id="surprisedFace">Surprised</button>
<button name="neutralbutton" id="neutralFace">Neutral</button>
</p>
<script>
var canvas = document.getElementById('canvasFrame');
var context = canvas.getContext('2d');
//Function to obtain x and y coordinates of mouse positions - Obtained from 20/11/2017 lecture slides
function getMouseXY(e) {
var boundingRect = canvas.getBoundingClientRect();
var offsetX = boundingRect.left;
var offsetY = boundingRect.top;
var w = (boundingRect.width - canvas.width);
var h = (boundingRect.height - canvas.height);
offsetX += w;
offsetY += h;
var mx = Math.round(e.clientX - offsetX);
var my = Math.round(e.clientY - offsetY);
return { x: mx, y: my };
}
const BROWS_UP = 190;
const BROWS_DOWN = 170;
//Creating an object for left eye brow
var leftEyeB = {
draw: function (x1,brows_direction1,x2,brows_direction2) {
context.beginPath();
context.lineWidth = 18;
context.moveTo(x1, brows_direction1);
context.lineTo(x2, brows_direction2)
context.stroke();
}
};
//Creating an object for right eye brow
var rightEyeB = {
draw: function (x1,brows_direction1,x2,brows_direction2) {
context.beginPath();
context.lineWidth = 18;
context.moveTo(x1, brows_direction1);
context.lineTo(x2, brows_direction2)
context.stroke();
}
};
//Creating an object for the head
var faceShape = {
draw: function() {
context.beginPath();
context.fillStyle = "rgb(255,255,0)"
context.lineWidth = 3;
context.arc(300, 300, 200, 0, Math.PI * 2, true);
context.fill();
context.stroke();
}
}
//Creating an object for the eyes
var eyes = {
draw: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.moveTo(255, 250); //LeftEye
context.arc(220, 250, 40, 0, Math.PI * 2, true);
context.moveTo(415, 250);//Right Eye
context.arc(380, 250, 40, 0, Math.PI * 2, true);
context.fill();
context.fill();
context.stroke();
context.beginPath();
context.fillStyle = "rgb(255,255,255)";
context.moveTo(240, 250); //LeftPupil
context.arc(220, 250, 15, 0, Math.PI * 2, true);
context.moveTo(400, 250); //Right Pupil
context.arc(380, 250, 15, 0, Math.PI * 2, true);
context.fill();
context.stroke();
}
}
//Creating an object for the nose
var nose = {
draw: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.moveTo(300, 275);
context.lineTo(275, 325);
context.lineTo(325, 325);
context.fill();
context.closePath();
context.stroke();
}
}
//Creating an object for the mouth
var mouth = {
frown: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.moveTo(305, 427);//Mouth
context.arc(305, 427, 80, 0, Math.PI, true);
context.fill();
context.closePath();
context.stroke();
},
circle: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.arc(300, 400, 50, 0, Math.PI * 2, true);
context.fill();
context.stroke();
},
straight: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.rect(225, 390, 150, 20);//Mouth
context.fill();
context.stroke();
}
}
//Drawing the sad face
function sadFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.frown();
leftEyeB.draw(175,BROWS_DOWN,265,BROWS_DOWN);
rightEyeB.draw(335,BROWS_DOWN,425,BROWS_DOWN);
}
//Drawing the angry face
function angryFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.frown();
leftEyeB.draw(175,BROWS_DOWN,265,BROWS_UP);
rightEyeB.draw(335,BROWS_UP,425,BROWS_DOWN);
}
//Drawing the surprised face
function surprisedFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.circle();
leftEyeB.draw(175,BROWS_UP,265,BROWS_DOWN);
rightEyeB.draw(335,BROWS_DOWN,425,BROWS_UP);
}
//Drawing the neutral face
function neutralFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.circle();
leftEyeB.draw(175,BROWS_DOWN,265,BROWS_DOWN);
rightEyeB.draw(335,BROWS_DOWN,425,BROWS_DOWN);
}
//Not sure how to properly do the bottom part. It does not work at all for the eyebrows one so please help!
function effects() {
//Click on the eyebrows to raise them
if (mousePosition.x > x1 && mousePosition.x < x2 && mousePosition.y < BROWS_UP && mousePosition.y > BROWS_DOWN) {
BROWS_UP += 20;
}
//Click on eye to show angry face
if (mousePosition = on coordinates of the eye) {
angryFace();
}
//Click on nose to show happy face
if (mousePosition = on coordinates of the nose) {
smileFace();
}
}
canvas.addEventListener('click', function(evt) {
effects(evt);
});
neutralFace();
//Linking the face functions to the buttons
var angryButton = document.getElementById("angryFace");
var sadButton = document.getElementById("sadFace");
var surprisedButton = document.getElementById("surprisedFace");
var neutralButton = document.getElementById("neutralFace");
sadButton.addEventListener("click", sadFace);
angryButton.addEventListener("click", angryFace);
surprisedButton.addEventListener("click", surprisedFace);
neutralButton.addEventListener("click", neutralFace);
</script>
</body>
</html>
When you make face, for you, there are different objects(say nose, eyes etc). For DOM, there is only 1 object i.e. Canvas. So when you click, you are clicking on canvas and not nose.
So to achieve this, you will have to play with coordinates. You have to assume the position of every container and on click of canvas, check the coordinates. If the coordinates are within range of some object, fire necessary function.
canvas.addEventListener('click', function(event){
var x = event.clientX, y = event.clientY;
if(x> 280 && x <335 && y > 280 && y <335) {
// nose is clicked.
angryFace();
}
else {
neutralFace();
}
})
Following is a partial sample:
var canvas = document.getElementById('canvasFrame');
var context = canvas.getContext('2d');
//Function to obtain x and y coordinates of mouse positions - Obtained from 20/11/2017 lecture slides
function getMouseXY(e) {
var boundingRect = canvas.getBoundingClientRect();
var offsetX = boundingRect.left;
var offsetY = boundingRect.top;
var w = (boundingRect.width - canvas.width);
var h = (boundingRect.height - canvas.height);
offsetX += w;
offsetY += h;
var mx = Math.round(e.clientX - offsetX);
var my = Math.round(e.clientY - offsetY);
return {
x: mx,
y: my
};
}
const BROWS_UP = 190;
const BROWS_DOWN = 170;
//Creating an object for left eye brow
var leftEyeB = {
draw: function(x1, brows_direction1, x2, brows_direction2) {
context.beginPath();
context.lineWidth = 18;
context.moveTo(x1, brows_direction1);
context.lineTo(x2, brows_direction2)
context.stroke();
}
};
//Creating an object for right eye brow
var rightEyeB = {
draw: function(x1, brows_direction1, x2, brows_direction2) {
context.beginPath();
context.lineWidth = 18;
context.moveTo(x1, brows_direction1);
context.lineTo(x2, brows_direction2)
context.stroke();
}
};
//Creating an object for the head
var faceShape = {
draw: function() {
context.beginPath();
context.fillStyle = "rgb(255,255,0)"
context.lineWidth = 3;
context.arc(300, 300, 200, 0, Math.PI * 2, true);
context.fill();
context.stroke();
}
}
//Creating an object for the eyes
var eyes = {
draw: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.moveTo(255, 250); //LeftEye
context.arc(220, 250, 40, 0, Math.PI * 2, true);
context.moveTo(415, 250); //Right Eye
context.arc(380, 250, 40, 0, Math.PI * 2, true);
context.fill();
context.fill();
context.stroke();
context.beginPath();
context.fillStyle = "rgb(255,255,255)";
context.moveTo(240, 250); //LeftPupil
context.arc(220, 250, 15, 0, Math.PI * 2, true);
context.moveTo(400, 250); //Right Pupil
context.arc(380, 250, 15, 0, Math.PI * 2, true);
context.fill();
context.stroke();
}
}
//Creating an object for the nose
var nose = {
draw: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.moveTo(300, 275);
context.lineTo(275, 325);
context.lineTo(325, 325);
context.fill();
context.closePath();
context.stroke();
}
}
//Creating an object for the mouth
var mouth = {
frown: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.moveTo(305, 427); //Mouth
context.arc(305, 427, 80, 0, Math.PI, true);
context.fill();
context.closePath();
context.stroke();
},
circle: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.arc(300, 400, 50, 0, Math.PI * 2, true);
context.fill();
context.stroke();
},
straight: function() {
context.beginPath();
context.fillStyle = "rgb(0,0,0)";
context.rect(225, 390, 150, 20); //Mouth
context.fill();
context.stroke();
}
}
//Drawing the sad face
function sadFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.frown();
leftEyeB.draw(175, BROWS_DOWN, 265, BROWS_DOWN);
rightEyeB.draw(335, BROWS_DOWN, 425, BROWS_DOWN);
}
//Drawing the angry face
function angryFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.frown();
leftEyeB.draw(175, BROWS_DOWN, 265, BROWS_UP);
rightEyeB.draw(335, BROWS_UP, 425, BROWS_DOWN);
}
//Drawing the surprised face
function surprisedFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.circle();
leftEyeB.draw(175, BROWS_UP, 265, BROWS_DOWN);
rightEyeB.draw(335, BROWS_DOWN, 425, BROWS_UP);
}
//Drawing the neutral face
function neutralFace() {
faceShape.draw();
eyes.draw();
nose.draw();
mouth.circle();
leftEyeB.draw(175, BROWS_DOWN, 265, BROWS_DOWN);
rightEyeB.draw(335, BROWS_DOWN, 425, BROWS_DOWN);
}
function effects() {
mousePosition = getMouseXY(e);
console.log(mousePosition);
}
neutralFace();
canvas.addEventListener('click', function(event){
var x = event.clientX, y = event.clientY;
if(x> 280 && x <335 && y > 280 && y <335) {
// nose is clicked.
angryFace();
}
else {
neutralFace();
}
})
//Linking the face functions to the buttons
var angryButton = document.getElementById("angryFace");
var sadButton = document.getElementById("sadFace");
var surprisedButton = document.getElementById("surprisedFace");
var neutralButton = document.getElementById("neutralFace");
sadButton.addEventListener("click", sadFace);
angryButton.addEventListener("click", angryFace);
surprisedButton.addEventListener("click", surprisedFace);
neutralButton.addEventListener("click", neutralFace);
<!-- This is not the original markup. This is a part of an edit to make the code executable. -->
<canvas id='canvasFrame' width=600 height=600></canvas>
<div>
<button id="angryFace">Angry Face</button>
<button id="sadFace">Sad Face</button>
<button id="surprisedFace">Surprised Face</button>
<button id="neutralFace">Neutral Face</button>
</div>

Cannot see script result

Hi I have following script, but when I run it in Chrome I dont see the result.
What did I miss? What do I have to add to html to see my results.
<script>
noStroke();
var leftX = 145;
var rightX = 274;
var sunRadius = 100;
var draw = function() {
background(184, 236, 255);
fill(255, 170, 0);
ellipse(200, 100, sunRadius, sunRadius);
// clouds
fill(255, 255, 255);
// left cloud
ellipse(leftX, 150, 126, 97);
ellipse(leftX+62, 150, 70, 60);
ellipse(leftX-62, 150, 70, 60);
// right cloud
ellipse(rightX, 100, 126, 97);
ellipse(rightX+62, 100, 70, 60);
ellipse(rightX-62, 100, 70, 60);
leftX--;
rightX++;
sunRadius+=2;
};
</script>
Whatever noStroke (and other functions like fill and `background) are, make sure they're defined in your code, or else the rest of the function won't execute.
The reason that your function isn't being callled... Is because you're not calling it.
Add a call to draw after the function is declared. The end of the code should look like:
leftX--;
rightX++;
sunRadius+=2;
};
draw(); //Actually run the function
I think ellipse is new for canvas. I found a function for backwards compatibility on github.
var can = document.getElementById('can');
var ctx = can.getContext('2d');
var leftX = 145;
var rightX = 274;
var sunRadius = 100;
draw();
function draw() {
ctx.fillStyle = "rgb(184, 236, 255)";
ctx.fillRect(0, 0, can.width, can.height);
ctx.beginPath();
ellipse(200, 100, sunRadius, sunRadius);
ctx.fillStyle = "rgb(255, 170, 0)";
ctx.fill();
// clouds
ctx.fillStyle = "rgb(255, 255, 255)";
// left cloud
ctx.beginPath();
ellipse(leftX, 150, 126, 97);
ellipse(leftX + 62, 150, 70, 60);
ellipse(leftX - 62, 150, 70, 60);
ctx.fill();
// right cloud
ctx.beginPath();
ellipse(rightX, 100, 126, 97);
ellipse(rightX + 62, 100, 70, 60);
ellipse(rightX - 62, 100, 70, 60);
ctx.fill();
leftX--;
rightX++;
sunRadius += 2;
};
function ellipse(cx, cy, w, h) {
var rx = w / 2;
var ry = h / 2;
var rot = 0;
var aStart = 0;
var aEnd = Math.PI * 2;
florianEllipse(ctx, cx, cy, rx, ry, rot, aStart, aEnd);
}
function florianEllipse(context, cx, cy, rx, ry, rot, aStart, aEnd){
context.save();
context.translate(cx, cy);
context.rotate(rot);
context.translate(-rx, -ry);
context.scale(rx, ry);
context.arc(1, 1, 1, aStart, aEnd, false);
context.restore();
}
<canvas id="can" width="400" height="300"></canvas>

Center a bezierCurve html5 canvas drawing?

So I have made basic drawings with html5 canvas and the basic shapes you can create have parameters to position the whole shape, below I center a circle centerX and centerY by taking the window size and dividing by 2.
context.beginPath();
context.globalCompositeOperation = 'destination-out';
context.arc(centerX, centerY, radius, Math.PI*2, false);
context.fill();
context.closePath();
The above drawing is nice and centered but now that I am playing with the bezier curve I can't find anything on the web that suggests how to center it.
// some arbitrary example
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.globalCompositeOperation = 'destination-out';
context.closePath();
I wrote up a fiddle so there is something to work with JSFIDDLE. Below is the code pasted directly from my fiddle.
var canvas = document.getElementById("c");
var context = canvas.getContext("2d");
canvas.width = $(window).width();
canvas.height = $(window).height();
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.fillStyle = '#333';
context.fillRect(0, 0, canvas.width, canvas.height);
context.closePath();
// custom shape (weird shape lol)
context.beginPath();
context.globalCompositeOperation = 'destination-out';
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.closePath();
context.globalCompositeOperation = 'source-over';
}
draw();
Here's one method to accurately center your group of cubic Bezier curves
A Demo: http://jsfiddle.net/m1erickson/6GZmp/
Step#1. Use De Casteljau's algorithm to plot points along each curve in your group of curves.
// De Casteljau's algorithm which calculates points along a cubic Bezier curve
// plot a point at interval T along a bezier curve
// T==0.00 at beginning of curve. T==1.00 at ending of curve
// Calculating 100 T's between 0-1 will usually define the curve sufficiently
function getCubicBezierXYatT(startPt,controlPt1,controlPt2,endPt,T){
var x=CubicN(T,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(T,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
return({x:x,y:y});
}
// cubic helper formula at T distance
function CubicN(T, a,b,c,d) {
var t2 = T * T;
var t3 = t2 * T;
return a + (-a * 3 + T * (3 * a - a * T)) * T
+ (3 * b + T * (-6 * b + b * 3 * T)) * T
+ (c * 3 - c * 3 * T) * t2
+ d * t3;
}
Step#2. Determine the bounding box of the curve-group by getting the minX,maxX,minY,maxY of the points you plotted in #1. And use max-min to determine the width and height of the curves group.
var curvesWidth = maxX - minX;
var curvesHeight = maxY - minY;
Step#3. Calculate the offset needed in order to center your curves-group.
var offsetX=(canvas.width/2-curvesWidth/2)-curvesLeft;
var offsetY=(canvas.height/2-curvesHeight/2)-curvesTop;
Step#4. Knowing the offsets, you can use context.translate to draw your centered curves.
context.save();
context.translate(offsetX,offsetY);
context.beginPath();
context.moveTo(170, 80);
context.bezierCurveTo(130, 100, 130, 150, 230, 150);
context.bezierCurveTo(250, 180, 320, 180, 340, 150);
context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.restore();
I don't know if there's a quick way of doing it. My attempt works like this:
you check each point on the x axis and compare it to the other points, if it is the most left or the most right store their position in a variable, otherwise do nothing. Once you have those points you know the width of the whole path and you can calculate an offset value to place it inside the center (because you know the canvas width). Then just add that offset value to the points coordinates and you're good:
http://jsfiddle.net/jonigiuro/8jsw9/4/
var canvas = document.getElementById("c"); var context = canvas.getContext("2d");
canvas.width = $(window).width(); canvas.height = $(window).height();
var centerX = canvas.width / 2; var centerY = canvas.height / 2;
var bezierSteps = [
[130, 100, 130, 150, 230, 150],
[250, 180, 320, 180, 340, 150],
[420, 150, 420, 120, 390, 100]
];
var mostLeft = 2000; var mostRight = 0;
findCenter();
function findCenter() {
for (var i = 0; i < bezierSteps.length; i++) {
for (var p = 0; p < bezierSteps.length; p+=2) {
mostLeft = bezierSteps[i][p] < mostLeft ? bezierSteps[i][p] : mostLeft;
mostRight = bezierSteps[i][p] > mostRight ? bezierSteps[i][p] : mostRight;
}
}
console.log(mostLeft, mostRight) } var offset = (canvas.width - mostLeft - mostRight) / 2;
console.log(offset)
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
context.beginPath();
context.fillStyle = '#333';
context.fillRect(0, 0, canvas.width, canvas.height);
context.closePath();
// custom shape (weird shape lol)
context.beginPath();
context.globalCompositeOperation = 'destination-out';
context.moveTo(170 + offset, 80);
for (var i = 0, l = bezierSteps.length ; i < l ; i++) {
context.bezierCurveTo(bezierSteps[i][0] + offset,bezierSteps[i][1],bezierSteps[i][2] + offset,bezierSteps[i][3],bezierSteps[i][4] + offset,bezierSteps[i][5])
}
//context.bezierCurveTo(130, 100, 130, 150, 230, 150);
//context.bezierCurveTo(250, 180, 320, 180, 340, 150);
//context.bezierCurveTo(420, 150, 420, 120, 390, 100);
context.fill();
context.closePath();
context.globalCompositeOperation = 'source-over';
}
draw();
sorry for the dirty code..

html5 canvas switch draw functions

For a project I'm working on I need to draw a solar system on the canvas using the arc function and the lineTo function,and with one button press switch between them. I think I'm close I can switch once but I can't switch back to the original. Sorry for the massive block of code but I've been working on this for hours and I can no longer remember what is important.
if (window.addEventListener)
{
window.addEventListener( 'load', initialise, false);
window.addEventListener('keydown',onKeyDown, false);
}
var canvas;
var context;
var angle = 0;
var time = 20;
var paused = false;
var timer;
var drawStyle = drawArc();
function onKeyDown(event)
{
var keyCode = event.keyCode;
switch(keyCode)
{
case 80: //p
togglePause();
break;
}
switch(keyCode)
{
case 75: //k
toggleDrawStyle();
break;
}
switch(keyCode)
{
case 70: //f
speedUp();
break;
}
switch(keyCode)
{
case 82: //r
speedDown();
break;
}
}
function toggleDrawStyle()
{
if(drawStyle == drawArc())
{
drawStyle = drawLine();
}
else if(drawStyle == drawLine())
{
drawStyle = drawArc();
}
}
function speedUp()
{
time = time / 2;
}
function speedDown()
{
time = time * 2;
}
function togglePause()
{
if (!paused)
{
clearInterval(timer);
paused = true;
}
else
{
timer = setInterval(drawArc, time);
timer = setInterval(drawLine, time);
paused = false;
}
}
function initialise()
{
canvas = document.getElementById('canvas');
if (!canvas.getContext)
{
alert('Error: no canvas.getContext!');
return;
}
context = canvas.getContext('2d');
if (!context)
{
alert('Error: failed to getContext!');
return;
}
timer = setInterval(drawArc, time);
}
function drawArc()
{
clearCanvas();
context.fillStyle = "#000000";
context.fillRect(0, 0, canvas.width, canvas.height);
incrementAngle();
context.save();
//draw the sun
context.translate(canvas.width/2, canvas.height/2);
context.rotate(convertToRadians(angle));
circle(0, 0, 30, "#ffaa00");
//draw mercury
context.save();
context.rotate(convertToRadians(angle)*1.5);
moveCirlce(1/6, 1/6 , 30 , 30, "#555555");
context.restore();
//draw venus
context.save();
context.rotate(convertToRadians(angle)*1.25);
moveCirlce(1/5, 1/5, 40, 40, "#aa0011");
context.restore();
// draw earth
context.save();
context.rotate(convertToRadians(angle));
moveCirlce(0.3, 0.3, 55, 55, "#0077ff");
context.restore();
//draw the moon
context.save();
context.rotate(convertToRadians(angle));
context.translate(55, 55);
context.rotate(convertToRadians(angle) * 2);
moveCirlce(1/15, 1/15, 10, 10, "#555555");
context.restore();
//draw mars
context.save();
context.rotate(convertToRadians(angle) *0.9);
moveCirlce(1/3, 1/3, 80, 80, "#ff0000");
context.restore();
//draw jupiter
context.save();
context.rotate(convertToRadians(angle)* 0.75);
moveCirlce(2/3, 2/3, 110, 110, "#cc8811");
context.restore();
//draw sautrn
context.save();
context.rotate(convertToRadians(angle)*0.55);
moveCirlce(17/30, 17/30, 140, 140, "#dd7722");
context.restore();
//draw uranus
context.save();
context.rotate(convertToRadians(angle)*0.3);
moveCirlce(14/30, 14/30, 170, 170, "#4444ff");
context.restore();
//draw neptune
context.save();
context.rotate(convertToRadians(angle)*0.2);
moveCirlce(11/30, 11/30, 190, 190, "#9999ff");
context.restore();
context.restore();
}
function drawLine()
{
clearCanvas();
context.fillStyle = "#000000";
context.fillRect(0, 0, canvas.width, canvas.height);
incrementAngle();
context.save();
//draw sun
context.translate(canvas.width/2, canvas.height/2);
context.rotate(convertToRadians(angle));
lineCircle(0, 0, 30, "#ffaa00");
//draw mercury
context.save();
context.rotate(convertToRadians(angle)*1.5);
moveLineCirlce(1/6, 1/6 , 30 , 30, "#555555");
context.restore();
//draw venus
context.save();
context.rotate(convertToRadians(angle)*1.25);
moveLineCirlce(1/5, 1/5, 40, 40, "#aa0011");
context.restore();
// draw earth
context.save();
context.rotate(convertToRadians(angle));
moveLineCirlce(0.3, 0.3, 55, 55, "#0077ff");
context.restore();
//draw the moon
context.save();
context.rotate(convertToRadians(angle));
context.translate(55, 55);
context.rotate(convertToRadians(angle) * 2);
moveLineCirlce(1/15, 1/15, 10, 10, "#555555");
context.restore();
//draw mars
context.save();
context.rotate(convertToRadians(angle) *0.9);
moveLineCirlce(1/3, 1/3, 80, 80, "#ff0000");
context.restore();
//draw jupiter
context.save();
context.rotate(convertToRadians(angle)* 0.75);
moveLineCirlce(2/3, 2/3, 110, 110, "#cc8811");
context.restore();
//draw sautrn
context.save();
context.rotate(convertToRadians(angle)*0.55);
moveLineCirlce(17/30, 17/30, 140, 140, "#dd7722");
context.restore();
//draw uranus
context.save();
context.rotate(convertToRadians(angle)*0.3);
moveLineCirlce(14/30, 14/30, 170, 170, "#4444ff");
context.restore();
//draw neptune
context.save();
context.rotate(convertToRadians(angle)*0.2);
moveLineCirlce(11/30, 11/30, 190, 190, "#9999ff");
context.restore();
context.restore();
}
function convertToRadians(degree)
{
return degree*(Math.PI/180);
}
function incrementAngle()
{
angle++;
}
function clearCanvas()
{
canvas.width = canvas.width;
}
function circle(x, y, r , col)
{
context.beginPath();
context.arc(x, y, r, 0, 2*Math.PI);
context.fillStyle = col;
context.fill();
}
function moveCirlce(a, b, x, y, col)
{
context.save();
context.translate(x, y);
context.scale(a, b);
circle(0, 0, 30, col);
context.restore();
}
function lineCircle(a, b, r, col)
{
var theta = Math.PI * 2 / 9;
for (var i = 0; i <= 9; i = i + 1)
{
var angle = theta * i;
var x = a + r * Math.cos(angle);
var y = b + r * Math.sin(angle);
if (i == 0)
{
context.moveTo(x,y);
}
else
{
context.lineTo(x,y);
}
}
context.fillStyle = col;
context.fill();
}
function moveLineCirlce(a, b, x, y, col)
{
context.save();
context.translate(x, y);
context.scale(a, b);
lineCircle(0, 0, 30, col);
context.restore();
}
initialise();
drawArc();
Your switch statements, as written, are nothing more than a bizarre way to write a bunch of if (condition) do_statements; so that's not the problem (although it does mean you aren't using a switch statement as intended; if this is homework for a grade, this might mean some deductions).
A clear indication that something is a muck is that your togglePause fires setInterval with drawArc and then overwrites the timer id by also firing setInterval with drawLine. This means whenever you attempt to clearInterval, you're only clearing the interval for drawLine.
You also have a drawStyle variable, but you aren't really using it for anything, as drawArc and drawLine don't return any values.
So, some hints...
Assign something proper to your drawStyle variable... whether or not you use some flag or the actual functions themselves, I don't care.
handle your setInterval logic better. Hint: with a few tweaks, you could use just use timer = setInterval(function(){drawStyle();}, time); everywhere.
your speed up/slow down functionality is broken. your solar system should work by varying time increments--that is, instead of just incrementing angle by 1, increment it by some variable amount that you can vary.
Finally, after you get the logic worked out, Fix your switch statement

Categories