I want my rectangle to rotate in place. But currently it is rotating as though there is one object at center and my object is revolving around it i.e much like what we see in solar system. I want my object to rotate in place not revolve around something. How can I do that?
This is my code so far:
<script type="text/javascript">
var context;
var radian = 0.01;
var w, h;
$(document).ready(function () {
w = document.width;
h = document.height;
var canvas = $('#canvas');
context = canvas[0].getContext('2d');
canvas[0].width = w;
canvas[0].height = h;
setInterval(startAnim, 10);
});
function startAnim() {
context.save();
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(0,0,0)';
context.fillRect(0, 0, w, h);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(255,255,0)';
context.strokeRect(0, 0, 200, 200);
context.fillRect(0, 0, 200, 200);
context.restore();
context.fillStyle = 'rgb(0,255,255)';
context.fillRect(500, 400, 200, 200);
radian += 0.01;
}
</script>
UPDATE: Sorry I was experimenting before I posted and I forgot to add rotate function while posting here. This is the actual code:
function startAnim() {
context.save();
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(0,0,0)';
context.fillRect(0, 0, w, h);
context.translate(350, 300);
context.rotate(radian);
context.translate(-350, -300);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(255,255,0)';
context.strokeRect(0, 0, 200, 200);
context.fillRect(0, 0, 200, 200);
context.restore();
context.fillStyle = 'rgb(0,255,255)';
context.fillRect(500, 400, 200, 200);
radian += 0.01;
}
Use translate(x, y), rotate(r), and then draw your rectangle.
function startAnim() {
context.save();
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(0,0,0)';
context.fillRect(0, 0, w, h);
//^Shouldn't clearRect() be better here?
//Draw translated, rotated rectangle at (250, 250)
var x = 250;
var y = 250;
context.save();
context.translate(x, y);
context.rotate(radian);
context.fillStyle = 'rgb(255,255,0)';
context.fillRect(0, 0, 200, 200);
context.restore();
//Restore context (to reverse translation and rotation)
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(255,255,0)';
context.strokeRect(0, 0, 200, 200);
context.fillRect(0, 0, 200, 200);
context.restore();
context.fillStyle = 'rgb(0,255,255)';
context.fillRect(500, 400, 200, 200);
radian += 0.01;
}
jsFiddle demo and Simple jsFiddle demo with one rotating rectangle
You have to translate your context to the center of the rectangle before you rotate it:
context.translate(RECT_CENTER_X, RECT_CENTER_Y);
context.rotate(radian);
context.fillRect(-RECT_CENTER_X, -RECT_CENTER_Y, w, h);
Related
This is my code:
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
function draw() {
context.fillStyle = "rgb(200, 0, 0)";
context.fillRect(50, 50, 0, 0);
};
draw();
When I run it, I get no errors but it doesn't add the squares to the canvas. Can someone tell me why this happens and how to fix it?
Your second Rectangle does not have a height and width.
the function has the parameters x, y, width, height -> fillRect(x, y, width, height).
Your line context.fillRect(50, 50, 0, 0); creates a box with width and height of 0 at 50px from x and y.
const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");
const settings = {x: 50, y: 50, height: 50, width: 50};
function draw() {
if (ctx) {
ctx.fillStyle = "rgb(0, 200, 0)";
ctx.fillRect(settings.x, settings.y, settings.width, settings.height);
ctx.fillStyle = "rgb(200, 0, 0)";
ctx.fillRect(0, 0, 50, 50);
};
};
draw();
<canvas id="myCanvas"></canvas>
I donĀ“t know why the text in canvas is blurry and the image drawed is also blurry, this is my example how I create the canvas with the image and text.
https://jsfiddle.net/jorge182/5ju5pLqb/2/
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
context.save();
context.beginPath();
context.arc(25, 25, 25, 0, Math.PI * 2, true);
context.closePath();
context.clip();
context.drawImage(imageObj, 0, 0, 50, 50);
context.beginPath();
context.arc(0, 0, 25, 0, Math.PI * 2, true);
context.clip();
context.closePath();
context.restore();
context.lineWidth = 2;
context.textAlign = 'left';
context.font = '8pt Signika Negative';
context.fillStyle = 'black';
context.fillText('Jorge', 60, 15);
context.fillText(' have been here!', 60, 30);
context.font = '6pt Signika Negative';
context.textAling = 'left';
context.fillStyle = '#555';
context.fillText('Caribe Photo Weading Photograpy', 60, 40);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'
The blurry image is probably because you resized the image too much from its original size. Take a look at the jsFiddle below and you can see if you only resize half of its size it's still looking good.
https://jsfiddle.net/gracegotlost/5ju5pLqb/3/
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageObj = new Image();
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
imageObj.onload = function() {
var width = imageObj.width;
var height = imageObj.height;
context.save();
context.beginPath();
context.arc(width/2, height/2, 150, 0, Math.PI * 2, true);
context.fill();
context.closePath();
context.clip();
context.drawImage(imageObj, 0, 0, imageObj.width, imageObj.height);
context.beginPath();
context.arc(0, 0, 25, 0, Math.PI * 2, true);
context.clip();
context.closePath();
context.restore();
context.textAlign = 'left';
context.font = '32pt Signika Negative';
context.fillStyle = 'black';
context.fillText('Jorge', 60, 350);
context.fillText(' have been here!', 150, 350);
context.font = '20pt Signika Negative';
context.textAling = 'left';
context.fillStyle = '#555';
context.fillText('Caribe Photo Weading Photograpy', 60, 400);
};
For the blurry text I found one post very helpful. If you can increase the text size it will look better, but to give it even more higher resolution you would probably do as follows:
https://stackoverflow.com/a/15666143/4809052
For the jagged edge the first answer is very helpful.
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..
I just wanted to clip image in a curve .. but not happening this..
Only image is showing and but not with clip.
var canvas = document.getElementById('leaf');
var context = canvas.getContext('2d');
/*
* save() allows us to save the canvas context before
* defining the clipping region so that we can return
* to the default state later on
*/
context.save();
context.beginPath();
context.moveTo(188, 150);
context.quadraticCurveTo(288, 0, 388, 150);
context.lineWidth = 10;
context.quadraticCurveTo(288, 288, 188, 150);
context.lineWidth = 10;
context.clip();
context.beginPath();
var imageObj = new Image();
imageObj.onload = function() {
context.drawImage(imageObj, 10, 50);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
/* context.beginPath();
context.arc(x - offset, y - offset, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'yello';
context.fill();
*/
/*
* restore() restores the canvas context to its original state
* before we defined the clipping region
*/
context.restore();
context.beginPath();
context.moveTo(188, 150);
context.quadraticCurveTo(288, 0, 388, 150);
context.lineWidth = 10;
context.quadraticCurveTo(288, 288, 188, 150);
context.lineWidth = 10;
context.strokeStyle = 'blue';
context.stroke();
<canvas id="leaf" width="500" height="500" style='left: 0;
position: absolute; top: 0;'></canvas>
You have to move everything from the line context.save(); to context.clip(); inside the function object of your imgObj's onload handler:
imageObj.onload = function()
{
context.save();
context.beginPath();
context.moveTo(188, 150);
context.quadraticCurveTo(288, 0, 388, 150);
context.lineWidth = 10;
context.quadraticCurveTo(288, 288, 188, 150);
context.lineWidth = 10;
context.clip();
context.drawImage(imageObj, 10, 50);
};
See http://jsfiddle.net/CSkP6/1/ for an example.
When, a few time after your script is launched, your image gets loaded, you have no more a clipped Canvas since you restore it afterwise.
You need to do a drawClipped function, and call it in your onload function for instance :
function drawClipped(context, myImage) = {
context.save();
context.beginPath();
context.moveTo(188, 150);
context.quadraticCurveTo(288, 0, 388, 150);
context.lineWidth = 10;
context.quadraticCurveTo(288, 288, 188, 150);
context.lineWidth = 10;
context.clip();
context.drawImage(myImage, 10, 50);
context.restore();
};
var imageObj = new Image();
imageObj.onload = function() {
drawClipped(context, imageObj);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
I am just trying my hands at HTML5's most talked feature i.e canvas. There are 2 rectangles and I only want to rotate 1st and keep the 2nd one as it is. Problem is when the below code runs my whole canvas is rotated and both rectangles are rotated. I can't even find any API where I can get reference to the object that I have drawn and rotate only that specific object instead of the whole context.
Code:
<script type="text/javascript">
var context;
var radian = 0.01;
var w, h;
$(document).ready(function () {
w = document.width;
h = document.height;
var canvas = $('#canvas');
context = canvas[0].getContext('2d');
canvas[0].width = w;
canvas[0].height = h;
setInterval(startAnim, 200);
});
function startAnim() {
context.clearRect(0, 0, w, h);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(0,0,0)';
context.fillRect(0, 0, w, h);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(255,255,0)';
context.rotate(radian);
context.strokeRect(400, 300, 200, 200);
context.fillRect(400, 300, 200, 200);
context.fillStyle = 'rgb(0,255,255)';
context.fillRect(500, 400, 200, 200);
radian += 0.01;
}
</script>
How can I prevent this from happening?
Finally, I have resolved the issue on my own by trial and error. This is the code:
<script type="text/javascript">
var context;
var radian = 0.01;
var w, h;
$(document).ready(function () {
w = document.width;
h = document.height;
var canvas = $('#canvas');
context = canvas[0].getContext('2d');
canvas[0].width = w;
canvas[0].height = h;
setInterval(startAnim, 100);
});
function startAnim() {
context.save();
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(0,0,0)';
context.fillRect(0, 0, w, h);
context.rotate(radian);
context.strokeStyle = 'rgb(0,0,0)';
context.fillStyle = 'rgb(255,255,0)';
context.strokeRect(400, 300, 200, 200);
context.fillRect(400, 300, 200, 200);
context.restore();
context.fillStyle = 'rgb(0,255,255)';
context.fillRect(500, 400, 200, 200);
radian += 0.1;
}
</script>
As I understand you have to clear the whole canvas and redraw everything, between each frame. Keep the data for the rectangles in memory. Do the context.clearRect(0, 0, w, h); between each frame, then draw the rectangles again with there new altered properties.