First, I apologize for asking yet another question re canvas offsets. I see there are many related questions on stackoverflow, but I still couldn't solve my problem.
When I draw to canvas (see code below), it does not draw under the mouse cursor. It offsets to the right and down. I am expecting it to begin drawing under the mouse cursor.
Do I need to use any of these properties: Canvas offset? Event offset? ClientX? LayerX? OffsetLeft? OffsetTop?
move: function(event) {
this.prevX = this.currX;
this.prevY = this.currY;
this.currX = event.clientX;
this.currY = event.clientY;
if (this.drawing) {
this.ctx.lineTo(this.currX, this.currY);
this.ctx.stroke();
}
}
Can someone please correct the bug in the jsfiddle below and explain why it works the way it does?
https://jsfiddle.net/f9trjzk5/4/
The JavaScript uses vue.js. It's what I'm learning now. If you are unfamiliar with it, just pretend it's not there. You'll see you have access to both the canvas and context variables -- this.canvas, this.ctx.
Thanks very much!
UPDATE The line is also clearly being drawn faster than the movement of the mouse....
SOLVED Needed to replace style height and width properties with height and width attributes
style="height: 500px" width: 500px" --> height="500" width="500
To quote the helpful answer I was given on the vuejs forum:
What that does, is that is scales the canvas from its original (default) size up to match the width/height you've specified (like resizing an image, it becomes distorted). This is the same problem. That's why when moving the mouse to the right, it gets further and further away cos its a compounding effect.
https://forum.vuejs.org/t/canvas-drawing-wonky-under-vue-js-offset-all-weird/9028
Related
I am working on a big project where exercises in Canvas are created through JSON-data and CreateJS. The purpose of having it in HTML 5 is to not have to use a separate app for your phone, you can always use the website.
Everything works fine, however in mobile the Canvas is rescaled to full screen. This is done through checking the screen size, and if it's small enough to be mobile the canvas is scaled through this code:
// browser viewport size
var w = window.innerWidth;
var h = window.innerHeight;
// stage dimensions
var ow = canvasWidth;
var oh = canvasHeight;
// keep aspect ratio
var scale = Math.min(w / ow, h / oh);
stage.scaleX = scale;
stage.scaleY = scale;
// adjust canvas size
stage.canvas.width = ow * scale;
stage.canvas.height = oh * scale;
This works great for most of the exercises, like quizzes and such, where all you have to do is click on a button. However we also have some drag and drop-exercises, and an exercise where you can color a drawing. These of course rely on the mouse coordinates to work properly. The problem is, when the canvas is scaled the mouse coordinates are not. So when you drag an item or try to draw, there is an offset happening. So your drawing appears way left of your click, and when picking up a draggable object it doesn't quite follow your click correctly.
Had I made the code from the beginning I'm fairly sure how I would have recalculated the coordinates, but since they are calculated by CreateJS I don't really know how I should go about this.
This was reported as a problem by someone about a year ago here, where this solution was suggested:
I was able to work around this by adding a top-level container and attaching my Bitmaps to that and scaling it.
The whole exercise is inside a container which I have tried to scale but to no avail. I have also tried sending the scale as a parameter to the parts of the exercise created (for example the menu, background images and such) and not scale it all together, and it seems to work okay since then I can exclude the drawing layer. But since it is a large project and many different exercises and parts to be scaled it would take quite some time to implement, and I'm not sure it's a viable solution.
Is there a good and easy way to rescale the mouse coordinates along with the canvas size in CreateJS? I have found pure Javascript examples here on SO, but nothing for CreateJS in particular.
Continued searching and finally stumbled upon this, which I hadn't seen before:
EaselJS - dragging children of scaled parent. It was exactly what I was looking for. I needed to change the coordinates I drew with this:
var coords = e.target.globalToLocal(e.stageX, e.stageY);
Then I could use the coords.x and coords.y instead of directly using e.stageX and e.stageY like before.
I have problem with canvas createPattern. I have two boxes, both will move after pressing a keyarrow:
Example:
http://jsfiddle.net/wA73R/1/
The problem is that the box background filled by createPattern also is moving. How to avoid that? Is there any solution? The big box is only an example (drawImage is not the good solution for me, I need something that will repeat background image).
Thank you for help
The problem is that the box background filled by createPattern also is moving.
Actually your problem is that the background is not moving - it is static, while you are drawing your rectangle to different positions.
How to avoid that?
The pattern will always be drawn at the coordinate origin, whose actual position is defined by the current transformation. In future you will be able to transform the pattern itself with the setTransform method, but since that currently is not implemented anywhere you instead will have to change the global transformation matrix.
In your case it means, that instead of drawing your rectangle at x/y, you translate the whole context to x/y and draw your rectangle at 0/0 then:
ctx.fillStyle=pattern;
ctx.save();
ctx.translate(boxes[i].x - left , boxes[i].y);
ctx.fillRect(0, 0, boxes[i].width, boxes[i].height);
ctx.restore();
(updated demo)
I am having trouble finding a good method to limit my mouse to be only able to click on a pre existing line in canvas (stroke width of 3)
What I need to know
how to limit mouse so can only click on pre- existing line, add a dot on click
line is drawn with this function
function createLine(startX:Float, startY:Float, endX:Float, endY:Float)
{
surface.beginPath();
surface.moveTo(startX, startY);
surface.lineTo(endX, endY);
surface.closePath();
surface.strokeStyle = '#ffffff';
surface.lineWidth = 2;
surface.stroke();
}
I am working in haxe, but solution in JS is fine
Thanks in advance.
The only way is for you to keep track of what you have drawn and do the collision/mouse over detection on your own.
If you need your canvas to be highly interactive, you should probably be looking at SVG. http://raphaeljs.com/ is a great library for drawing which will use canvas or SVG, whichever is available.
I'm trying to accomplish an effect similar to what you might see on the cartoon Chowder (example link) , where shapes serve as masking layers for a texture underneath that stays static. I've begun playing around with this idea by creating a render loop that clears the canvas, saves it's state, then draws a rectangular clipping region, followed by drawing the background texture that occupies the entire width and height of the canvas.
Here's the draw function:
function draw()
{
context.clearRect(0,0, 640, 480);
context.save();
x += velocityX;
y += velocityY;
context.rect(x, y, 40, 40);
context.clip();
context.drawImage(image, 0,0, 640, 480);
context.restore();
}
Basically it just runs at 60 frames per second, updating the position of the rectangle and clipping a background image inside the clipping region. (I know the code isn't structured perfectly, but I was just experimenting to see if this effect was even possible on the canvas).
http://jsfiddle.net/JERje/86/
The problem I seem to be having is that the clipping area from the previous iteration of the loop hangs around creating the weird effect that you see in the fiddle above. I've tried reordering everything in the draw() step of the loop, but the only thing that seems to work is the canvas.width = canvas.width trick for clearing the screen. I'd like to avoid this method of clearing the screen, since it doesn't seem to work in IE, and it also destroys the canvas state. clearRect() should work to clear the screen. What am I doing wrong?
You're using the same HTML5 Canvas paperback I am aren't you.
If you set up an adhoc canvas as I did on your jsfiddle like so:
var newCanvas = document.createElement('canvas');
newCanvas.getContext("2d").drawImage(image,0,0);
A function such as this would be able to hack a section out of that canvas:
context.putImageData(newCanvas.getContext("2d").getImageData(x,y,40,40),x,y);
Thus giving you the chowder effect. Good show man, good luck. Pst me if it doesn't work
EDIT: However this solution will ignore some context scaling transformations. Just be smart about how you handle scale on your own (and you really should be anyways if you want the true "chowder" effect)
So, feel pretty dumb about this, but apparently when you call rect() you also have to make sure to call closePath afterwards in order to close the clipping area. Glad I figured it out finally, now on to adding multiple layers!
Here's the working fiddle: http://jsfiddle.net/JERje/129/
I just started with fabric.js and I have a (probably beginner) error:
I am using fabric with jquery with the following code:
$(document).ready(function () {
canvas = new fabric.StaticCanvas('scroller');
canvas.add(
new fabric.Rect({ top: 0, left: 0, width: 140, height: 100, fill: '#f55' })
);
});
This code should draw a 140x100 Rectangle on the canvas.
Sadly, only a quarter of the Rectangle appears.
If I change the top and left values to higher numbers, more of the Rectangle appears on the canvas.
So it seems, that the canvas origin is not at 0/0, but at sth. higher.
Does someone know how to fix this or what I am doing wrong?
Thanks in advance,
McFarlane
Here is a jsfiddle link with some examples http://jsfiddle.net/pukster/sdQ7U/2/
My guess is that fabric.js calculates everything from the origin (middle point) since it is drawing exactly one quarter of a rectangle even with a canvas 10 times the size of the rectangle. My guess is that top and left actually refer to the origin and not the top and left sides of the imaginary bounding box. Trouble is there is very little documentation on fabricjs. Is there any reason you are using fabricjs and not easeljs
EDIT Here's the same fiddle but with squares instead of rectangles (it is more clear) http://jsfiddle.net/pukster/sdQ7U/3/
EDIT OK I am now almost absolutely certain that fabric.js uses the center as the top/left. I ripped their example off of their site and overlayed it with the transparent couterpart to those shapes had they been coded in pure canvas http://jsfiddle.net/pukster/uathZ/2/ (blue border is the limit of the canvas element).
What you see is that the boxes are exactly offset by half but the circle (I only drew a semi circle otherwise it would not have been discernable) is perfectly overlapped. This is b/c in HTML Canvas, the circle coordinates (x,y) refer to the origin and not the top left. I did not bother with the triangle b/c my trigonometry is a bit rusty. I personally think it's misleading to use the terms top and left, when x and y would have been more representative and shorter.
Yes, this is highly unexpected and even more undocumented.
Workaround:
Set
originX: "left"
originY: "top"
for each created object.
edit: or use kangax simpler solution in the comment below.
I want to comment but lack the reputation to do so. So anyway, here is what happens when I do the following:
fabric.Object.prototype.originX = "left";
fabric.Object.prototype.originY = "top";
The shape gets rendered fine but when I select it for resizing or moving, it gets offset to a different location. The best approach seems to be to set the coordinates for every object separately using the set() method.