I'm new to canvas in html5 and would like to know how to animate a custom shape with lots of coordinates. I searched the web but with n o results. I'm only seeing results for circles or squares.
Here's an example of a random drawing. I would like it to move around the screen without setting coordinates for each point. http://jsfiddle.net/ZJdus/
var drawing = function(){
// rand drawing drawing
context.strokeStyle = "red";
context.beginPath();
context.moveTo(318, 200);
context.lineTo(183, 87);
context.lineTo(446, 125);
context.lineTo(446, 202);
context.lineTo(383, 236);
context.lineTo(318, 202);
context.lineTo(318, 125);
context.lineTo(446, 125);
context.lineTo(183, 236);
context.lineTo(318, 125);
context.lineTo(383, 187);
context.lineTo(383, 125);
context.lineTo(613, 180);
context.lineTo(446,400);
context.lineTo(413, 180);
context.lineTo(350, 180);
context.lineTo(318, 202);
context.lineTo(350, 180);
context.lineTo(183, 125);
context.stroke();
};
Is there a way to achieve this?
I'm also fairly new to Javascript so please explain as much as possible if you can.
Thanks
You can use translate() before you redraw the shape:
/// clear canvas before each redraw
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
/// translate canvas (move origin)
context.translate(deltaX, deltaY);
... draw points here...
/// reset translate (faster than save()/restore())
context.translate(-deltaX, -deltaY);
Modified fiddle here
Optionally, instead of resetting the translate just use it as delta values directly instead of the absolute delta as now.
You can also add the delta values directly on your coordinates but that is slower than using the translate approach.
Hope this helps.
If your shape doesn't change, you should absolutely not redraw it every frame. Instead draw the shape once to a buffer canvas and then use drawImage at the location to animate the shape.
var drawing = //same as your code above only context is a buffer canvas...
contextOfDisplayedCanvas.drawImage(canvasWithShape, shape.x, shape.y);
Let me know if that doesn't make sense and I can expand.
Related
Cannot get rectangle drawn on canvas with javascript in Adobe Animate with code below.
Successful only when using Createjs Ticker function with eventListener. Please note I'm NOT asking about animation -- but just about drawing something on the Canvas.
Am I incurring in a coding or in a conceptual error?
Thanks in advance for kind help to beginner.
this.stop();
//Line below not needed as far as I checked (when in in Adobe Animate)
//var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
// I get the rectangle and text on Canvas ONLY when I uncomment the three commented lines below
//createjs.Ticker.addEventListener("tick", handleTick);
//function handleTick() {
alert("ctx 25")
ctx.lineWidth = 5;
ctx.strokeRect(20, 20, 100, 100);
ctx.font = "bold 25px Verdana";
ctx.fillText("Index", 200, 70);
//}
You are accessing the context directly. EaselJS will clear the canvas each time it redraws.
There are a number of ways to add your own content:
1. Ensure it happens after the stage.update() or after a child's draw method
2. Draw to an external canvas, and use that as a source of a Bitmap
3. Draw to EaselJS's display list instead.
Here is how to draw to the stage using EaselJS
// You just need to do this once, not on every tick
var shape = new createjs.Shape();
shape.graphics.setLineStyle(5).drawRect(0,0,100,100);
shape.set({x: 20, y: 20}); // You can also set the x/y directly, or offset the shape in the drawRect call
stage.addChild(shape); // Wherever the stage is constructed.
var text = new createjs.Text("Index", "bold 25px Verdana", "#000");
text.set({x: 200, y:70});
stage.addChild(text);
Hope that helps!
Is there any way to draw a rectangle whose composing lines have width thinner than 1 pixel?
This code works perfectly, as expected:
// context is a HTML5 canvas 2D context
context.lineWidth = 1;
context.strokeStyle = "black";
context.rect(0, 0, 20, 20);
context.stroke();
It draws a nice rectangle.
But, if I try to draw a rectangle with thinner lines:
// See line width
context.lineWidth = 0.5;
context.strokeStyle = "black";
context.rect(0, 0, 20, 20);
context.stroke();
It still draws a rectangle whose borders have 1 pixel width.
I'm dealing with the canvas object here, and not CSS, where you have ways to "simulate" this.
Although it doesn't make much sense, you can acheive that with using a regular 1-pixel line with a 50% scaled canvas (but again it's a 1-pixel rendition, read below). See this snippet:
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
function scale() {
context.scale(0.5, 0.5);
draw();
}
function draw() {
context.beginPath();
context.moveTo(100, 150);
context.lineTo(450, 50);
context.stroke();
}
draw()
<canvas width="400" height="150"></canvas>
<button onclick="scale()">Scale down</button>
But again, I wonder how you expect the half-pixel line to look on your screen, antialiasing?
Right :) I suppose I was thinking on some way of drawing thinner lines, like, for example, when you use CSS styles. I've looked around and I don't think I can use alternate units.
There's no way to make something that's smaller than the smallest component unit, in our case a pixel. You can mimic the thinner look by transparency, or opacity, or even some sort of antialiasing (which again relies on transparency or the colouring of the neighbouring pixels), but not by trying to go below one pixel.
I agree, there is a sub-pixel rendering mode in browsers, for example, when you work with percentages, but in the end, the browser just renders full pixels with some of the modification I've described above.
And you know if you could render unit smaller than pixels, you'd technically have infinite resolutions on displays. I wish it was possible. :)
I have an HTML canvas. Inside it I've drawn a hexagon. The hexagon rotates in place.
Well now I want this rotating hexagon to move along a set path. I want to be able to track it's location.
Normally when you want to move an object you say: (object.x+howmuchtomove) and it will simply
move by that much, and you can track it's whereabouts by just adding object.x+howmuchtomove to get the x coord.
Well in this case I'm using translate and rotate to give it the rotating effect. So adding +2 to it's x location simply makes it rotate in a bigger circle.
Here is what I've got, thanks!
retObject.draw = function() {
// Wipe the canvas
ctx.fillStyle = "rgba(0, 0, 0, 1)";
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw rotating shape
ctx.save(); // Don't rotate everything
ctx.strokeStyle="red"; // Set Color
ctx.translate(356.5, 700); // Center pivot inside hexagon
ctx.rotate(rotValue*(Math.PI/180)); // Rotate
ctx.translate(-356.5, -700); // Un-Translate
for (i=0;i<3;i++) {
ctx.beginPath();
ctx.moveTo(300, 700);
ctx.lineTo(330, 650);
ctx.lineTo(383, 650);
ctx.lineTo(413, 700);
ctx.lineTo(383, 750);
ctx.lineTo(330, 750);
ctx.lineTo(300, 700);
ctx.stroke(); // Draw Hexagon
}
ctx.restore(); // Get back normal
}
Note that draw() is inside of a loop so that it gets called every frame.
So, for simplicity sake, say I just want this rotating hexagon to drop straight down.
Basically I'm wanting to add +1 to it's y coordinate every frame.
Well I figured it out and I feel stupid.
You simply add the desired move amount to the first translate ONLY.
So:
ctx.translate(356.5, 700);
Becomes:
ctx.translate(356.5, 700+moveAmount);
That will make it move straight down by "moveAmount" per frame.
Maybe this will help someone lol
So I'm creating a simple userscript for me - I want to draw a play button over shaded version of any GIF image on the site to have them only played when I want to.
I have inspired myself here. To make the whole thing nice, I'm drawing a green circle over the animation. This is my intended effect (I really wonder if once can make some shapes in GIMP):
And this is what I currently have:
The Cleese ironic face animation comes from this GIF portal
I made a fiddle of my current GIF pauser userscript.
The critical code for printing the circle:
//Assume these variables
var ctx = canvas context (2d)
var w = canvas width
var h = canvas height
//The code:
ctx.beginPath();
//I'm making sure the circle will always fit - therefore Math.min
ctx.arc(w/2, h/2, Math.min(60, w/2-20, h/2-20), 0, 2 * Math.PI, false);
ctx.fillStyle = 'rgba(0,180,0,0.5)';
ctx.fill();
ctx.lineWidth = 1;
ctx.strokeStyle = 'red';
ctx.stroke();
ctx.closePath();
I hope it's clear that the triangle must always fit into the circle (size of which may vary). It must have the vertical line a little bit shorter then the other two, which must be of equal length.
I'm totally not interested in any existing GIF pausing libraries. Keep in mind that the question is about the triangle, not the GIFs.
Like this? http://jsfiddle.net/32ECU/
//Draw a triangle in it
ctx.strokeStyle = 'white';
ctx.beginPath();
ctx.moveTo(w/3, h/3);
ctx.lineTo(w/3, h-h/3);
ctx.lineTo(w-w/4, h/2);
ctx.lineTo(w/3, h/3);
ctx.fillStyle = 'white';
ctx.fill();
Using canvas I am creating a collection of triangles on a page and then overlaying them all with a large gradient.
Once these triangles are created is there a way to reference them to change their color with javascript on a certain event? Or do I have to draw the triangle again?
The for loop that makes the triangles:
context.fillStyle = color[i-1];
context.beginPath();
context.moveTo(1,leftStart+(itemStartHeight*(i-1))); //Tl
context.lineTo(width,(itemHeight*(i-1))); //Tr
context.lineTo(width,(itemHeight*i)+1); //Br
context.lineTo(1,leftStart+(itemStartHeight*i)+(i!=items ? 1 : 0)); //Bl
context.closePath();
context.fill();
Theres no way to reference individual things drawn on the canvas element by default, to change the colors you have to redraw them