in the snippet below
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(canvas.width / 2, canvas.height / 2, 143, (startAngle * Math.PI / 180) - Math.PI / 2, 1.5 * Math.PI);
ctx.strokeStyle = "white";
ctx.lineWidth = 14;
ctx.stroke();
where i is in multiples of 6,i am not able to update the canvas every second(using loops), the appearance should be like of a receding clock.
link to fiddle:https://jsfiddle.net/727q1u7r/3/
In your fiddle, the code within the loop does not refer to startAngle, so each iteration of the loop is drawing exactly the same thing. You probably want to refer to startAngle within the arc call.
However this is not enough by itself, a for loop is not suitable for animation, the whole loop will be completed in a flash and you won't see any changes.
You could use setInterval as shown in this fiddle.
If you are trying to reliably show the system time however, you should look into using Date and possibly using requestAnimationFrame.
Related
I am trying to create an overlay that can highlight certain portions of the page. The best way I've figured out to do this is to use a canvas fit to the page, draw the shapes I need, and draw a rectangle using this trick:
ctx.rect(canvas.width, 0, 0 - canvas.width, canvas.height);
I'm not sure I can explain this well, so it might be best to look at the jsFiddle example here to get an idea of what I am trying to do.
This works perfectly in every browser except Safari. Is there any way to achieve this effect in Safari?
You can try filling the whole canvas first, then use composite mode to knock out the shapes.
Example:
ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
ctx.fillRect(canvas.width, 0, 0 - canvas.width, canvas.height);
// next shape will punch hole in the draw rectangle above
ctx.globalCompositeOperation = 'destination-out';
ctx.fillStyle = "rgba(0, 0, 0, 1)"; // make sure alpha is 100%
ctx.beginPath();
ctx.moveTo(300, 60);
ctx.arc(300, 60, 50, 0, 2 * Math.PI);
ctx.moveTo(500, 160);
ctx.arc(500, 160, 50, 0, 2 * Math.PI);
drawEllipse(ctx, 103, 23, 100, 30)
drawEllipse(ctx, 503, 23, 100, 30)
ctx.fill();
ctx.globalCompositeOperation = 'source-over'; // reset comp. mode
Modifed fiddle here
Alpha (not the color) will determine how much visible the hole will be.
Hope this helps.
I have a Flash app where I am performing a scale and rotation operation about the center of _background:MovieClip (representing a page of a book). I have simple event listeners on the GESTURE_ROTATE and GESTURE_SCALE events of this MC which update some variables currentRotation and currentScaleX, currentScaleY. I then have the following code trigger on the ENTER_FRAME event of the app.
The problem I am encountering is upon rotating the MC beyond the limits of roughly 60 or -60 degrees, or scaling slightly and rotating, the MC begins to oscillate and finally spin wildly out of control and off the screen. I've tried several things to debug it, and even tried Math.flooring the currentRotationValue and rounding the values of currentScaleX/Y to the tenths place (Math.floor(currentScale * 10) / 10), but neither of these seems to remedy it. I'm a little stuck at this point and have tried researching as much as I can, but couldn't find anything. Any suggestions? Is there an issue with doing this operation on each frame perhaps?
private function renderPage(e:Event) {
var matrix:Matrix = new Matrix();
// Get dimension of current rectangle.
var rect:Rectangle = _background.getBounds(_background.parent);
// Calculate the center.
var centerX = rect.left + (rect.width/2);
var centerY = rect.top + (rect.height/2);
// Translating to the desired reference point.
matrix.translate(-centerX, -centerY);
matrix.rotate(currentRotation / 180) * Math.PI);
matrix.scale(currentScaleX, currentScaleY);
matrix.translate(centerX, centerY);
_background.transform.matrix = matrix;
}
I'm not certain what behaviour you're trying to produce, but I think the problem is that centerX and centerY define the middle of _background in _background.parent's coordinate space. You're then translating the matrix so that _background is rotated around the values centerX, centerY, but in _background's coordinate space.
Assuming you want _background to rotate around a point which remains static on screen, what you actually need to do is use two different Points:
matrix.translate(-_rotateAroundPoint.x, -_rotateAroundPoint.y);
matrix.rotate(currentRotation / 180) * Math.PI);
matrix.scale(currentScaleX, currentScaleY);
matrix.translate(_centerOnPoint.x, _centerOnPoint.y);
Where _rotateAroundPoint is the point around which _background should turn in it's own coordinate space, and _centerOnPoint is the point around which it should turn in its parent's coordinate space.
Both of those values only need to be recalculated when you want to pan _background, rather than every frame. For example:
private var _rotateAroundPoint:Point = new Point(_background.width * 0.5, _background.height * 0.5);
private var _centerOnPoint:Point = new Point(50, 50);
private function renderPage(e:Event) {
var matrix:Matrix = new Matrix();
matrix.translate(-_rotateAroundPoint.x, -_rotateAroundPoint.y);
matrix.rotate((currentRotation / 180) * Math.PI);
matrix.scale(currentScaleX, currentScaleY);
matrix.translate(_centerOnPoint.x, _centerOnPoint.y);
_background.transform.matrix = matrix;
}
I can't find out how to get actual drawing cursor position after moveTo(). Check out my code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(10, 20);
// here i want to get from "ctx" actual offset
ctx.lineTo(20,30);
ctx.closePath();
Is there any way or I have to store offset in my own variables offsetX, offsetY ?
I assume you mean you have a bunch of relative path commands and you want to move them.
For instance, to draw a triangle at the top-left you would write:
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100,0);
ctx.lineTo(50,100);
ctx.closePath(); // makes the last line for you
ctx.stroke();
So what if you want to use the same path but draw the triangle starting at (175, 175) instead? Instead of changing your moveTo and all subsequent drawing command, all you have to do is translate the context.
ctx.save();
ctx.translate(175, 175);
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(100,0);
ctx.lineTo(50,100);
ctx.closePath(); // makes the last line for you
ctx.stroke();
// save/restore lets you undo the translation so the next object starts at (0,0)
// you could just call ctx.translate(-175, -175); at the end instead though
ctx.restore();
Translating the context changes the origin of the drawing surface, and allows you to move all of your coordinates (temporarily or not) with it. This means you can define a bunch of paths and redraw them using the same commands all over the place using ctx.translate.
See both triangles here:
http://jsfiddle.net/qzYFC/
This question already has answers here:
What's the best way to set a single pixel in an HTML5 canvas?
(14 answers)
Closed 7 years ago.
Drawing a line on the HTML5 canvas is quite straightforward using the context.moveTo() and context.lineTo() functions.
I'm not quite sure if it's possible to draw a dot i.e. color a single pixel. The lineTo function wont draw a single pixel line (obviously).
Is there a method to do this?
For performance reasons, don't draw a circle if you can avoid it. Just draw a rectangle with a width and height of one:
ctx.fillRect(10,10,1,1); // fill in the pixel at (10,10)
If you are planning to draw a lot of pixel, it's a lot more efficient to use the image data of the canvas to do pixel drawing.
var canvas = document.getElementById("myCanvas");
var canvasWidth = canvas.width;
var canvasHeight = canvas.height;
var ctx = canvas.getContext("2d");
var canvasData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
// That's how you define the value of a pixel
function drawPixel (x, y, r, g, b, a) {
var index = (x + y * canvasWidth) * 4;
canvasData.data[index + 0] = r;
canvasData.data[index + 1] = g;
canvasData.data[index + 2] = b;
canvasData.data[index + 3] = a;
}
// That's how you update the canvas, so that your
// modification are taken in consideration
function updateCanvas() {
ctx.putImageData(canvasData, 0, 0);
}
Then, you can use it in this way :
drawPixel(1, 1, 255, 0, 0, 255);
drawPixel(1, 2, 255, 0, 0, 255);
drawPixel(1, 3, 255, 0, 0, 255);
updateCanvas();
For more information, you can take a look at this Mozilla blog post : http://hacks.mozilla.org/2009/06/pushing-pixels-with-canvas/
It seems strange, but nonetheless HTML5 supports drawing lines, circles, rectangles and many other basic shapes, it does not have anything suitable for drawing the basic point. The only way to do so is to simulate a point with whatever you have.
So basically there are 3 possible solutions:
draw point as a line
draw point as a polygon
draw point as a circle
Each of them has their drawbacks.
Line
function point(x, y, canvas){
canvas.beginPath();
canvas.moveTo(x, y);
canvas.lineTo(x+1, y+1);
canvas.stroke();
}
Keep in mind that we are drawing to South-East direction, and if this is the edge, there can be a problem. But you can also draw in any other direction.
Rectangle
function point(x, y, canvas){
canvas.strokeRect(x,y,1,1);
}
or in a faster way using fillRect because render engine will just fill one pixel.
function point(x, y, canvas){
canvas.fillRect(x,y,1,1);
}
Circle
One of the problems with circles is that it is harder for an engine to render them
function point(x, y, canvas){
canvas.beginPath();
canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
canvas.stroke();
}
the same idea as with rectangle you can achieve with fill.
function point(x, y, canvas){
canvas.beginPath();
canvas.arc(x, y, 1, 0, 2 * Math.PI, true);
canvas.fill();
}
Problems with all these solutions:
it is hard to keep track of all the points you are going to draw.
when you zoom in, it looks ugly
If you are wondering, what is the best way to draw a point, I would go with filled rectangle. You can see my jsperf here with comparison tests
In my Firefox this trick works:
function SetPixel(canvas, x, y)
{
canvas.beginPath();
canvas.moveTo(x, y);
canvas.lineTo(x+0.4, y+0.4);
canvas.stroke();
}
Small offset is not visible on screen, but forces rendering engine to actually draw a point.
The above claim that "If you are planning to draw a lot of pixel, it's a lot more efficient to use the image data of the canvas to do pixel drawing" seems to be quite wrong - at least with Chrome 31.0.1650.57 m or depending on your definition of "lot of pixel". I would have preferred to comment directly to the respective post - but unfortunately I don't have enough stackoverflow points yet:
I think that I am drawing "a lot of pixels" and therefore I first followed the respective advice for good measure I later changed my implementation to a simple ctx.fillRect(..) for each drawn point, see http://www.wothke.ch/webgl_orbittrap/Orbittrap.htm
Interestingly it turns out the silly ctx.fillRect() implementation in my example is actually at least twice as fast as the ImageData based double buffering approach.
At least for my scenario it seems that the built-in ctx.getImageData/ctx.putImageData is in fact unbelievably SLOW. (It would be interesting to know the percentage of pixels that need to be touched before an ImageData based approach might take the lead..)
Conclusion: If you need to optimize performance you have to profile YOUR code and act on YOUR findings..
This should do the job
//get a reference to the canvas
var ctx = $('#canvas')[0].getContext("2d");
//draw a dot
ctx.beginPath();
ctx.arc(20, 20, 10, 0, Math.PI*2, true);
ctx.closePath();
ctx.fill();
I'm new to HTML5 canvas drawing im trying to fill this shape:
This is the code that I used to draw it:
function load() {
draw();
}
function draw() {
var ctx = document.getElementById("canvas").getContext('2d');
ctx.beginPath();
ctx.moveTo(37, 205);
ctx.lineTo(79, 160);
ctx.lineTo(136, 221);
ctx.lineTo(167, 188);
ctx.lineTo(124, 141);
ctx.quadraticCurveTo(113, 129, 127, 113);
ctx.lineTo(204, 28);
ctx.moveTo(149, 22);
ctx.arc(174, 45, 34, (223 * Math.PI) / 180, (330 * Math.PI) / 180);
ctx.moveTo(149, 22);
ctx.lineTo(38, 138);
ctx.moveTo(37, 205);
ctx.arc(66, 171, 43, (129 * Math.PI) / 180, (230 * Math.PI) / 180);
ctx.stroke();
}
Now when I change from stroke to fill I get this:
I know it´s a problem with the order of the drawing, I used to fix this in a software like 3D Studio Max by flipping the empty parts but here I`m lost and I don't know what I should do to fix this.
I want the whole shape to be filled normally, I don't know how to explain it but I guess the images say it all, this is what i want to get:
You'll notice something funny about the path you made: You're picking up your pen with moveTo commands. This is bad if you want to fill. Without moveTo, your shape really looks like this:
The reason the fill looks odd is because of these moveTos. And the reason you're using moveTo is because you used arc in a funny way.
My suggestion would be not not use arc in such a way that the ending point is where you would expect, or else use bezier or quadractic instead altogether.
In my opinion arc is kind of a pain to use well, so I'd suggest just going with bezier/quadratic curves instead.
Here's an example of a similar shape done with quadratic curves instead. I didn't get the control points identical though, you'll have to do that bit on your own.
Drawn with quadratics: