I'm drawing to the canvas using the x/y coords of the mouse, but the line that I'm drawing always draws off a little bit, try drawing on here: http://zachrip.net/widgets/onlineedit/index.html (top left) for an example of what I mean. There is no offset so I do not account for it, so I don't know what the issue is?
The problem here is that you are setting the Canvas Element Size through your CSS, but you do not set the Drawing Surface Size.
The default size of the Drawing Surface is 300px by 150px. Since you do not set it, but set the Element Size, the browser scales the drawing surface size to fit the element. The x and y co-ordinates you get through the mouse event correspond to the Element Size, and not the actual Drawing Surface Size. Which is why you get the offset.
Now, the fiddle that I posted earlier merely had you set the size of Drawing Surface, instead of the Element. And that works, but if you'd rather have different Element and Drawing Surface sizes, then you can also do
function scaleCoords(x, y) {
x = x * DrawingSurfaceSize.width/ElementSize.width;
y = y * DrawingSurfaceSize.height/ElementSize.height;
return {x: x, y: y};
}
Example for second method.
Related
I use getImageData and putImageData to draw on canvas from a buffer canvas. I use these methods because I have a large number of particles and these proved to provide the best performance.
Now I'd like to add rotation of particles but I'm having problems with that.
Here is a jsfiddle which uses transformation matrix for rotation. As you can see in the picture (or fiddle) there are holes in the resulting image which I kinda expected from using this matrix.
nx = ~~ (xx * Math.cos(angle) + yy * Math.sin(angle) + cx);
ny = ~~ (xx * Math.sin(angle) - yy * Math.cos(angle) + cy);
But I don't know how to make this better, especially when I'm looking performance effecient solution?
jsfiddle demo
Image - square after rotation (square is used as a simple body):
Currently my backup is procedurally generated sprite animation which is prepared in advance with standard canvas states: save -> translate -> rotate -> restore.
Thank you very much for any directions you can give me.
The problem is that you are trying to map a single pixel to a single pixel. When you rotate an image, each pixel in the original can influence any of the surrounding pixels in the new image. You are effectively mapping the top left corner of each pixel to it's location in the new image, but you need map the center of each pixel to it's location in the new image and then check the overlap of this rotated pixel with that location, and the 8 surrounding pixels in the new image.
Here you can see the effect. The yellow dots are the centers of the pixel which find the "home" location for the pixel (i.e. where the majority of the influence will be placed). You then need to figure out the percentage of that pixel (the underlying blue/white grid) cell is covered by the original pixel (black box surrounding the yellow dot). Once you figure out the home location influence, you need to repeat that process for the 8 surrounding pixel with respect to current pixel in the original image. In your current code, you are using the top left corner of each pixel to find the home pixel for the new image. You should use the center of the pixel.
Since multiple iterations might affect the same pixel, you'll need to calculate the transformation in a buffer before drawing it to the final image. For pixels in the transformation that are not fully covered by pixels in the original image, figure out the percentage of the pixel that is covered and use that to influence the alpha channel. You'll have to take care when applying the pixels to the final image that you account for the alpha portion and blend with what's already there.
I have a bit of code (involving "canvas"), which generates a graph on a four-quadrant cartesian plane. (Please see the JsFiddle link in the comment below.)
I want to create a bit of code that adds a point to a specific position on the plane. However, I want the point to get plotted based on the intervals on the x- & y-axes rather than pixels. In other words, I don't want to have to guess and check where each coordinate is on the graph and then adjust accordingly. If I move the graph 200 pixels down on the page, I want the point to likewise move 200 pixels down.
Coding novice, here (if you couldn't tell already). It took me forever to get to this point, so I would greatly appreciate any help anyone is willing to offer.
Thanks!
The 2D canvas context provides a transformation to all rendering.
You can set the matrix with ctx.setTransform and you can multiply the existing transformation with ctx.transform, ctx.scale, ctx.rotate, ctx.translate
Personally I am a big fan of ctx.setTransform(a,b,c,d,e,f); where
a,b is the unit length and direction of the X axis in pixels
c,d is the unit length and direction of the Y axis in pixels
e,f is the location of the origin relative to the top left and is in
pixels.
Basicly 2 vectors defining the size (scale) and direction of a pixel x and y axis, and a coordinate defining where on the canvas the origin is. The coordinate is not effected by the scale or rotation.
So if you want the X axis to point down and the scale to be two then
a = 0, b = 2 the Y axis is then b = -2, c = 0 to be 90deg clockwise from the X axis.
If you want the axis to remain the same but the scale scale = 2 changed then
a = scale,b = 0, c= 0, d = scale. And to have the origin at the center of the canvas e = canvas.width/2, f = canvas.height/2
Now if you draw an arc ctx.arc(0,0,100,0,Math.PI*2) you will see a circle in the center of the canvas with a radius = 100*scale
Hope that makes sense....
I've been struggling to get this code working. Basically, I want the user to be able to click anywhere inside of the canvas, and the coordinates at the clicked point will be where the rectangle gets drawn. However, the code I have places the rectangles at totally unexpected points along the canvas. I checked the values in Firebug and they seemed to be accurate based on where I clicked inside the canvas, so I'm not sure why the rectangles are not getting drawn at the correct points. Maybe there is some other mistake going on that I am not seeing though, so any help or input would be appreciated. I've posted the relevant code below.
I should also note that the canvas element is inside the div with id='container'.
$('#container').click(function (e) {
var offset=$(this).offset();
var x=(e.pageX - offset.left);
var y=(e.pageY - offset.top);
ctx.fillStyle='#FF0000'; //color red
ctx.fillRect(x,y,10,10); //draw 10 x 10 rectangle starting at x,y
});
pageX/Y gets the x/y coordinate of the page (think 100, 200). Let's say your canvas is positioned at (100,100) on the page. When you're graphing the point, you're saying "Graph a point at 100,200 IN RELATION TO THE CANVAS. That would mean you are trying to graph a point at (200,300) instead of (100,200) linke you want. You need to get your x/y in relation to the canvas, like so:
var x = event.offsetX !== undefined ? event.offsetX : event.layerX;
var y = event.offsetY !== undefined ? event.offsetY : event.layerY;
If you only want to add a click event on the canvas then it's better to use
$("#myCanvas").click(function(e){
});
If you use myCanvas instead of container then $(this) would refer to the canvas and you get the position of the mouse relative to the canvas.
It is because you use the container div that the variable offset is wrong.
Here is the graphics:
http://snag.gy/aVFGA.jpg
the big rectangle is canvas element, the small rectangle is the image object in the canvas. I want to find what is the real distance from the left.
values are such from what I see in console:
regX: 564.256
regY: 41.4
scaleX: 0.4491319444444445
scaleY: 0.4491319444444445
x: 363.3333333333333
y: 409.77777777777777
So as I see x is not real. It somehow relates with regX and scaleX. But I am not finding how it relates. From the image I think the x should be about 100 - 150 px.
THe bigger the x - the more it is to the right.
But the bigger regX - the more it makes rectangle go to the left.
So if I would just take the difference 564.256 - 363.333 = ~200 - left corner of the rectangle should be in them middle of canvas because canvas is 400px widh. But it is not, so substraction does not help. So how do I get how many pixels are in real from the left?
You can do this by using the localToGlobal method (see here).
It depends to which object the given attributes belong.
If they belong to the shape and your rectangle inside the image / shape starts at (0,0):
var point = shape.localToGlobal(0, 0);
// this will calculate the global point of the shape's local point (0,0)
If they belong to the stage:
var point = stage.localToGlobal(yourRectObject.x, yourRectObject.y);
// point.x should contain the position on the canvas
You should use these methods in general because your method might work for the current situation but will probably break as soon as you scale the stage itself or put the shape in a scaled / positioned container.
I guess I found what by experimenting with values:
distanceFromLeft = x - scaleX * regX;
so getting 109.90793888888885 px
If someone has worked more with this library, they could confirm that its not accidental.
I have an <img> within a <div> which can be moved around using four directional buttons, for example:
The image is obviously larger than its container, hence the directional buttons to move it in different directions.
There is also a zoom control where you can zoom in and out. I set up the scaling method with ease, by just applying a zoom factor as a percentage to the base width and height:
scale: function(zoom)
{
image.width = baseWidth * zoom;
image.height = baseHeight * zoom;
}
// Zoom in 50%.
Scene.scale(1.5);
This is fine however the image scales from top-left, meaning that the image looks like it's getting sucked out towards the top left during a zoom in and spat back out when zooming out.
I'm trying to have the zoom effect apply from the centre of the container, like this:
But I'm finding it hard to get my head around the mathematics required to move the image after scaling applies to give this effect.
The closest I've gotten is to move the image based on the difference between the current zoom and the new zoom level, but it's still slightly off and gives a 'curved' effect when zooming.
Is there a common formula used to reposition an image so that it scales around a different origin (i.e. not top-left (0,0)).
This is what it looks like currently.
You have to take your original coordinates and calculate the center of your original image, that is x_center = x_orig + width_orig / 2; Then you can calculate the new x coordinate of your scaled image: x_new = x_center - width_new / 2. The same applies for y. Then move your scaled image to these new coordinates. If you do it after each time you scale the image, it will look as though it is scaled around its center.