Rotating a part of the canvas - javascript

I created a gear like object using canvas, now I want it to rotate.With that said, I tried to implement this, but what is happening is that the entire canvas is being rotated, which is not what I want. Here is my code:
var ctx = document.getElementById("canvas").getContext("2d"),
i = 0;
function init(){
drawGear();
setInterval(drawGear,1000);
}
var i = 0;
function drawGear(){
ctx.clearRect(0,0,200,200);
ctx.beginPath();
ctx.fillStyle = "#000";
ctx.translate(100,100);
ctx.arc(0,0,20,0,Math.PI*2);
ctx.fill();
ctx.closePath();
ctx.beginPath();
ctx.fillStyle = "#FFF";
ctx.arc(0,0,10,0,Math.PI*2);
ctx.fill();
ctx.closePath();
for(var i=0; i<9; i++){
drawTooth(-8,-18);
ctx.rotate(45*Math.PI/180);
}
ctx.rotate(i*Math.PI/180);
i++;
}
function drawTooth(startX,startY){
ctx.fillStyle = "#000";
ctx.beginPath();
ctx.moveTo(startX,startY);
ctx.lineTo(startX+5,startY-10);
ctx.lineTo(startX+10,startY-10);
ctx.lineTo(startX+15,startY);
ctx.closePath();
ctx.fill();
}
init();
http://jsfiddle.net/MsjyN/

Rotation always occurs on the origin of the context.
You need to translate the context (to change the origin point to the center of what you want to rotate), rotate the object, and then translate back.
So you need to do something like:
function drawGear(){
...
ctx.translate(100,100);
...
for(var i=0; i<8; i++){
drawTooth(-8,-18);
ctx.rotate(45*Math.PI/180);
}
ctx.rotate(i*Math.PI/180);
ctx.translate(-100,-100);
i++;
}
See here: http://jsfiddle.net/MsjyN/1/
By the way you had one more gear tooth being drawn than necessary, which was apparent when I changed the gear teeth to semi-transparent (just for testing purposes)

Related

Why do two lines drawn the same way render differently [duplicate]

I am drawing five horizontal lines to an HMTL 5 2D canvas:
var canvas_ctx = my_canvas.getContext("2d");
canvas_ctx.lineWidth = 0.5;
canvas_ctx.strokeStyle = "black";
{
let line_x = 0;
let line_length = canvas_ctx.width;
let offset = 5;
let numLines = 5;
let numYincrement = 10;
for (let i=0;i<numLines * numYincrement;i+=numYincrement) {
//canvas_ctx.beginPath();
canvas_ctx.moveTo(line_x,i + offset);
canvas_ctx.lineTo(line_length,i + offset);
canvas_ctx.stroke();
//canvas_ctx.closePath();
}
}
This should, ideally result in 5 black lines. Instead, the color of the lines seems to fade with each new line (as if it's a gradient!), so that line 5 is gray. If I uncomment canvas_ctx.beginPath(); and canvas_ctx.closePath();, all lines become gray. Why is this happening??
Strokes do overlap from both sides of the coordinates.
var ctx = c.getContext('2d');
ctx.strokeStyle="red";
// draw big
ctx.scale(30, 30);
ctx.beginPath();
ctx.moveTo(5, 0);
ctx.lineTo(5, 10);
ctx.stroke();
drawPixelGrid();
function drawPixelGrid() {
// simply renders where the pixel bounds are
ctx.beginPath();
// remove the zoom
ctx.setTransform(1,0,0,1,0,0);
ctx.strokeStyle = 'gray';
ctx.lineWidth = 2; // avoid the problem we are demonstrating by using a perfect lineWidth ;-)
for(let y=0; y<=300; y+=30) {
ctx.moveTo(0, y);
ctx.lineTo(300, y);
for(let x=0; x<=300; x+=30) {
ctx.moveTo(x, 0);
ctx.lineTo(x, 300);
}
}
ctx.stroke();
}
<canvas id="c" height=300></canvas>
But obviously, a pixel can't be set to two colors at the same time. So browsers apply antialiasing, which will fade your pixel color to an other color, being the result of mixing the background and the foreground color.
So for a black stroke over a white or transparent background, this leads to actual gray pixels being rendered. Here I'll keep using red as an example:
var ctx = c.getContext('2d');
ctx.strokeStyle="red";
// first draw as on a 10*10 canvas
ctx.beginPath();
ctx.moveTo(5, 0);
ctx.lineTo(5, 10);
ctx.stroke();
// zoom it
ctx.imageSmoothingEnabled = 0;
ctx.globalCompositeOperation = 'copy';
ctx.drawImage(c, 0,0,9000,9000);
drawPixelGrid();
// this is not red...
function drawPixelGrid() {
ctx.globalCompositeOperation = 'source-over';
ctx.beginPath();
ctx.setTransform(1,0,0,1,0,0);
ctx.strokeStyle = 'gray';
ctx.lineWidth = 2;
for(let y=0; y<=300; y+=30) {
ctx.moveTo(0, y);
ctx.lineTo(300, y);
for(let x=0; x<=300; x+=30) {
ctx.moveTo(x, 0);
ctx.lineTo(x, 300);
}
}
ctx.stroke();
}
<canvas id="c" height=300></canvas>
One way to avoid it is generally to apply an offset on your coordinates so that the line extends correctly on pixels boundaries. E.g for a 1px lineWidth, you would apply a 0.5 offset:
var ctx = c.getContext('2d');
ctx.strokeStyle="red";
// first draw as on a 10*10 canvas
ctx.beginPath();
ctx.moveTo(5.5, 0); // offset +0.5px
ctx.lineTo(5.5, 10);
ctx.stroke();
// zoom it
ctx.imageSmoothingEnabled = 0;
ctx.globalCompositeOperation = 'copy';
ctx.drawImage(c, 0,0,9000,9000);
drawPixelGrid();
// now we've got a real red
function drawPixelGrid() {
ctx.globalCompositeOperation = 'source-over';
ctx.beginPath();
ctx.setTransform(1,0,0,1,0,0);
ctx.strokeStyle = 'gray';
ctx.lineWidth = 2;
for(let y=0; y<=300; y+=30) {
ctx.moveTo(0, y);
ctx.lineTo(300, y);
for(let x=0; x<=300; x+=30) {
ctx.moveTo(x, 0);
ctx.lineTo(x, 300);
}
}
ctx.stroke();
}
<canvas id="c" height=300></canvas>
But in your case, you are drawing at 0.5px lineWidth, so no offset will be able to get rid of this antialiasing.
So if you want perfect color, choose a correct lineWidth.

How do I rotate pictures inside their circles on an html 5 canvas?

I'm trying to make the logos rotating (at a random speed if possible) inside their circles but I can't achieve that.
I tried this:
ctx.save();
ctx.rotate(0.10);
ctx.drawImage(object.image, object.x-object.size/2, object.y-object.size/2, object.size, object.size);
ctx.restore();
But as you can see, the logos are rotating not on their own center.
Pen: https://codepen.io/Le-future/pen/gKNoEE
the key thing is to translate first, then rotate
in spawnRandomObject
// add the new object to the objects[] array
object.rot = 0;
objects.push(object);
in animate
for (var i = 0; i < objects.length; i++) {
var object = objects[i];
object.y += object.speed*0.1;
object.rot += 0.05; // rotation speed
ctx.globalAlpha = object.opacite;
ctx.beginPath();
ctx.arc(object.x, object.y, object.size/1.25, 0,2*Math.PI);
ctx.fillStyle = object.couleur;
ctx.fill();
ctx.restore();
ctx.save();
ctx.translate(object.x, object.y);
ctx.rotate(object.rot);
ctx.drawImage(object.image, -object.size/2, -object.size/2, object.size, object.size);
ctx.restore();
}
working fork https://codepen.io/anon/pen/bjbeoq
It is best practice to save() at the beginning of the function/iteration and restore() at the end of function/iteration.
I recommend to write a function to draw object:
function drawObject(object)
{
ctx.save()
object.y += object.speed;
ctx.translate(object.x - object.size / 2, object.y - object.size / 2);
object.angle += 0.01; // can be randomized
ctx.rotate(object.angle);
ctx.globalAlpha = object.opacite;
ctx.beginPath();
ctx.arc(0, 0, object.size/1.25, 0,2*Math.PI);
ctx.fillStyle = object.couleur;
ctx.fill();
ctx.drawImage(object.image, -object.size/2, -object.size/2, object.size, object.size);
ctx.restore();
}
You can call it in the loop as:
for (var i = 0; i < objects.length; i++) {
drawObject(objects[i])
or don't write a function, just save() at the beginning of the iteration and restore() at the end.
Another working example:
https://codepen.io/anon/pen/RBbRJr?editors=0010

White background breaking my canvas

I'm trying to draw several shapes to a canvas and I'm running into a strange issue. When I try to draw a white rectangle on the canvas before drawing my shape, the shape never shows up. What am I doing wrong?
Sample code:
// drawing a white background
// This breaks it. If I comment thiese two line out, it works.
ctx.fillStyle = "#FFFFFF";
ctx.fillRect(0, 0, Canvas.width, Canvas.height);
// Draw the rectangle
ctx.lineWidth = LineWidth;
ctx.strokeStyle = Color;
ctx.beginPath();
var startPos = Ordinates[0];
ctx.moveTo(startPos.start.x, startPos.start.y);
ctx.lineTo(startPos.stop.x, startPos.stop.y);
for(var i = 0; i < Ordinates.length; i++){
if(i === 0) continue;
ctx.lineTo(Ordinates[i].stop.x, Ordinates[i].stop.y);
}
ctx.closePath();
ctx.fill();
And here's a fiddle.
If you comment out the 2 lines that draws the white background rectangle, it works fine. What am I doing wrong?
ctx.fillStyle = "#FFFFFF"; // <-- set the fill color to white
ctx.fillRect(0, 0, Canvas.width, Canvas.height);
// Draw the rectangle
ctx.lineWidth = LineWidth;
ctx.strokeStyle = Color;
ctx.beginPath();
var startPos = Ordinates[0];
ctx.moveTo(startPos.start.x, startPos.start.y);
ctx.lineTo(startPos.stop.x, startPos.stop.y);
for(var i = 0; i < Ordinates.length; i++){
if(i === 0) continue;
ctx.lineTo(Ordinates[i].stop.x, Ordinates[i].stop.y);
}
ctx.closePath();
ctx.fill(); // <--- filling with white, while the background is still. you can remove this line btw
ctx.fillStyle = '#000000'; // <-- now we set it to black
ctx.fill(); // <--- filling with black now
also, if you want to see an outline of the path:
ctx.stroke();
this draws the outline of it in the right color.
But in a reply to v.rouge you just said you wanted it white with a black outline:
ctx.fillStyle = '#ffffff';
ctx.strokeStyle = '#000000';
ctx.fill();
ctx.stroke();
done :-)
Fillstyle is white. Drawing is white. Might explain.

How to draw a trigonometric pattern on HTML canvas?

I'm trying to draw a graphic pattern of lines from the black to the red depending on the Y value of a wave. To find out if I'm doing it right whit the approach, I started a test in JSFiddle:
Test
var j,k;
k=255;
var green=150;
var blue=150;
var canvas=document.getElementById('canvas');
var ctx=canvas.getContext('2d');
for(j=0;j<k;j++)
{
ctx.beginPath();
ctx.moveTo(j, 0);
ctx.lineTo(j, 150);
ctx.strokeStyle = "rgb("&j&", 0, 0)";
ctx.stroke();
}
But the result is just a grey tone in all the lines, although the drawing method is inside a loop and the 'red' value is changing.
Putting #Juhana's good suggestion into practice:
var j,k;
k=255;
var green=150;
var blue=150;
var canvas=document.getElementById('canvas');
var ctx=canvas.getContext('2d');
for(j=0;j<k;j++){
ctx.beginPath();
ctx.moveTo(j, 0);
ctx.lineTo(j, 150);
ctx.strokeStyle = "rgb("+j+",0,0)";
ctx.stroke();
}

Change color of canvas element

I am trying to change the color of line drawn on canvas dynamically...
ctx.moveTo(0, 0);
ctx.lineTo(0, 200);
ctx.strokeStyle = "Grey"
It could be mouseover event or press botton or mouse click event, I want to change the color of line or make it bold. Is it possible to change the color by adding event or is it possible to give style on an event on particular element?
Very close. In a sense, you can't really "change" the color of an element on the canvas because it has no scene graph, or, in other words, it has no history of what has been drawn on the canvas. To change the color of a line, you would have to redraw the line.
ctx.moveTo(0, 0);
ctx.lineTo(0, 200);
ctx.strokeStyle = "Grey";
ctx.stroke();
// To make the line bold and red
ctx.moveTo(0, 0);
ctx.lineTo(0, 200);
ctx.strokeStyle = "Red";
ctx.lineWidth = 5;
ctx.stroke();
If the canvas had a more complex scene going on, you would have to redraw the entire scene. There are numerous Javascript libraries that extend the base features of the canvas tag, and provide other drawing capabilities. You may want to take a look at Processing, it looks quite impressive.
I was having the same problem, I did it by moving another line with another color of different canvas element, so it gives appearance of line changing its color dynamically.
function drawGreyLine() {
ctx1.clearRect(0, 0, WIDTH, HEIGHT);
ctx1.strokeStyle = "Grey"; // line color
ctx1.moveTo(0, 0);
ctx1.moveTo(0, 200);
ctx1.lineTo(200, 200);
}
function drawColorLine() {
x += dx;
if (x <= 200) {
ctx2.beginPath();
ctx2.lineWidth = 5;
ctx2.lineCap = "round";
ctx2.strokeStyle = "sienna"; // line color
ctx2.moveTo(0, 200);
ctx2.lineTo(x, 200);
ctx2.moveTo(200, 200);
ctx2.stroke();
}
}
Hope this solves your problem.... :)
var canvas = document.getElementById('canvas');
var ctx=canvas.getContext('2d');
var line1={x:10,y:10, l:40, h:1}
var down=false;
var mouse={x:0,y:0}
canvas.onmousemove=function(e){ mouse={x:e.pageX-this.offsetLeft,y:e.pageY-this.offsetTop};
this.onmousedown=function(){down=true};
this.onmouseup=function(){down=false} ;
}
setInterval(function(){
ctx.clearRect(0,0,canvas.width,canvas.height)
ctx.beginPath()
ctx.moveTo(line1.x,line1.y)
ctx.lineTo(line1.x +line1.l,line1.y)
ctx.lineTo(line1.x +line1.l,line1.y+line1.h)
ctx.lineTo(line1.x,line1.y+line1.h)
ctx.isPointInPath(mouse.x,mouse.y)? (ctx.fillStyle ="red",line1.x=down?mouse.x:line1.x,line1.y=down?mouse.y:line1.y):(ctx.fillStyle ="blue")
ctx.fill()
},100)

Categories