I am using phrogz's solution for zooming and panning. Basically for a drawing pad.
The issue is, after zooming and panning, the mouse movement and the drawing movement have a bit of distance, i.e. I mouse the mouse somewhere, it draws elsewhere.
The blue represents my actual mouse movement
Example
From his example, it may seem like he has handled it here, however, I am still facing the issue
canvas.addEventListener('mousedown',function(evt){
document.body.style.mozUserSelect = document.body.style.webkitUserSelect = document.body.style.userSelect = 'none';
lastX = evt.offsetX || (evt.pageX - canvas.offsetLeft);
lastY = evt.offsetY || (evt.pageY - canvas.offsetTop);
dragStart = ctx.transformedPoint(lastX,lastY);
dragged = false;
},false);
Related
I want to know how to track the position of the mouse on X-axis on the screen. Based on limited knowledge of Java/Processing, it is something similar to mouseX in Java. In addition, I want to rotate an image element based on the position of the mouse on X-axis. It would be nice to receive some pieces of advice.
Track the mouse position in the X axis is done with an eventListener (the mousemove event)
This listener uses a callback function which should change the transform (rotate) css property of your element.
// DOM accessor to your HTML element
const rotatingE = document.getElementById('my-rotating-el')
// Event Listener
document.addEventListener('mousemove', e => {
// Callback function
const mX = e.clientX / window.innerWidth * 360
rotatingE.style.transform = 'rotate('+ mX +'deg)'
})
I've made a quick example here
a popular library/framework that is similar to Processing is P5.js (developed by the same people but for javascript) which can handle this for you
but in vanilla javascript, you would need an event listener
var mouse = {
x: undefined,
y:undefined
};
window.addEventListener("mousemove", function(event) {
mouse.x = event.x;
mouse.y = event.y;
});
what this does is listens for a mouse movement, and then records it to an object
then to take the mouseX position you can write
var mouseX = mouse.x;
or you can directly take it from
mouse.x;
//still the same
I am creating a web-based annotation application for annotating images via the HTML canvas element and Javascript. I would like the user to mouse down to indicate the start of the rectangle, drag to the desired end coordinate and let go to indicate the opposite end of the rectangle.
Currently, I am able to take the starting coordinates and end coordinates to create a rectangle on the image with the context.rects() function, however as I am uncertain on how to resize a specific rectangle on the canvas, that leaves me with the rectangle only being drawn after the user has released the mouse click.
How would I be able to resize a specific rectangle created onmousedown while dragging?
The following is the code snippet that performs the function:
var isMouseDown = false;
var startX;
var startY;
canvas.onmousedown = function(e) {
if(annMode){
isMouseDown = true;
var offset = $(this).offset();
startX = parseInt(e.pageX - offset.left);
startY = parseInt(e.pageY - offset.top);
}
};
canvas.onmousemove = function(e) {
if(isMouseDown) {
var offset = $(this).offset();
var intermediateX = parseInt(e.pageX - offset.left);
var intermediateY = parseInt(e.pageY - offset.top);
console.log(intermediateX);
}
};
canvas.onmouseup = function(e) {
if(annMode&&isMouseDown){
isMouseDown = true;
var offset = $(this).offset();
var endX = parseInt(e.pageX - offset.left);
var endY = parseInt(e.pageY - offset.top);
var width = endX - startX;
var height = endY - startY;
context.strokeStyle = "#FF0000";
context.rect(startX, startY, width, height);
context.stroke();
}
isMouseDown = false
};
Here my handy-front-end scripts come in handy!
As I understood the question, you wanted to be able to move your mouse to any point on the canvas, hold the left mouse button, and drag in any direction to make a rectangle between the starting point and any new mouse position. And when you release the mouse button it will stay.
Scripts that will help you accomplish what you are trying to do:
https://github.com/GustavGenberg/handy-front-end/blob/master/README.md#canvasjs
https://github.com/GustavGenberg/handy-front-end/blob/master/README.md#pointerjs
Both scripts just makes the code a lot cleaner and easier to understand, so I used those.
Here is a fiddle as simple as you can make it really using
const canvas = new Canvas([]);
and
const mouse = new Pointer();
https://jsfiddle.net/0y8cbao3/
Did I understand your question correctly?
Do you want a version with comments describing every line and what is does?
There are still some bugs at the moment but im going to fix those soon!
EDIT
After reading your questions again, I reacted to: "...however as I am uncertain on how to resize a specific rectangle on the canvas...".
Canvas is like an image. Once you have drawn to it, you can NOT "resize" different shapes. You can only clear the whole canvas and start over (ofcourse you can clear small portions too).
That's why the Canvas helper is so helpful. To be able to "animate" the canvas, you have to create a loop that redraws the canvas with a new frame each 16ms (60 fps).
The canvas API does not preserve references to specific shapes drawn with it (unlike SVG). The canvas API simply provides convenient functions to apply operations to the individual pixels of the canvas element.
You have a couple options to achieve a draggable rectangle:
You can position a styled div over your canvas while the user is dragging. Create a container for your canvas and the div, and update the position and size the div. When the user releases, draw your rectangle. Your container needs to have position: relative and the div needs to be absolutely positioned. Ensure the div has a higher z-index than the canvas.
In your mouse down method, set div.style.display to block. Then update the position (style.left, style.top, style.width, and style.height) as the mouse is dragged. When the mouse is released, hide it again (style.display = 'none').
You can manually store references to each item you want to draw, clear the canvas (context.clearRect), and redraw each item on the canvas each frame. This kind of setup is usually achieved through recursive usage of the window.requestAnimationFrame method. This method takes a callback and executes on the next draw cycle of the browser.
The first option is probably easier to achieve in your case. If you plan to expand the capabilities of your app further, the 2nd will provide more versatility. A basic loop would be implemented as so:
// setup code, create canvas & context
function mainLoop() {
context.clearRect(0, 0, canvas.width, canvas.height);
/** do your logic here and re-draw **/
requestAnimationFrame(mainLoop);
}
function startApp() {
requestAnimationFrame(mainLoop)
}
This tutorial has detailed explanation of event loops for HTML canvas: http://www.isaacsukin.com/news/2015/01/detailed-explanation-javascript-game-loops-and-timing
I also have a fully featured implementation on my GitHub that's part of rendering engine I wrote: https://github.com/thunder033/mallet/blob/master/src/mallet/webgl/webgl-app.ts#L115
I'm making this mini-game in HTML5 canvas using javascript's requestAnimationFrame.
function animate() {
frame = requestAnimationFrame( animate );
render();
}
It's destined to be a Cordova application, so I have to record touch input.
The game starts when the screen is pressed
document.addEventListener('touchstart',run);
It stops when the finger is removed.
I'm now looking for a way to record the touch's x and y coordinates, in order to display the finger's position smoothly on the screen.
So I was thinking about getting the x and y coordinates, and making an arc on this place in the
render()
function
But how could I permanently get these coordinates, or is there another way of doing this?
Thanks!!
You can refer this..
Is there an equivalent to e.PageX position for 'touchstart' event as there is for click event?
$(document).on('touchstart', 'body', function(e) {
var xPos = e.originalEvent.touches[0].pageX;
var yPos = e.originalEvent.touches[0].pageY;
});
http://www.asifslab.com/reveal.js-master/Why%20does%20wind%20feel%20cold.html#/4
Why doesn't the drawing canvas work properly? The line drawn is away from the point clicked. However, if I use the canvas out of reveal.js it works perfectly. http://codepen.io/anon/pen/eEaKh
Also when the erase function is run, it leaves a white border outside. How do I fix these problems?
just change e.pageX to e.clientX and e.pageY to e.clientY because in your codepen account
canvas origin and page origin is almost at same place but in other it is not.
To calculate the mouse position you need to subtract the position of the canvas:
Here is one way of doing this (inside the event handler):
var rect = canvas.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top;
Now your x and y will be relative to canvas.
Here's a copy/pasta of a small part of my paint app. Notice I'm using offsets of the canvas in my calculations. I also have a zoom function that scales the canvas, so taking into account that I added it to the calculation of the mouse cursor.
$('canvas').mousemove(function(e) {
// x and y are globals, x inits to null, mousedown sets x, mouseup returns x to null
if (x==null) return;
x = (100/$('#zoom').val())*(e.pageX - $(this).offset().left);
y = (100/$('#zoom').val())*(e.pageY - $(this).offset().top);
$('#debug').html(x+', '+y); // constantly update (x,y) position in a fixed div during debugging
});
I'm capturing mouse position like this
mouse_move: function(e)
{
mousePos.x = e.pageX - vr.o.context.canvas.offsetLeft;
mousePos.y = e.pageY - vr.o.context.canvas.offsetTop;
},
and it has worked like a dream in all modern browsers while in development, Even tested Wrapping the <canvas/> in a basic dom structure to make sure mouse position adjusted...
obviously now I'm putting it in the actual site it's not working...
You can see here http://jondavidjohn.com/projects/
the mouse position ends up quite a ways south of the actual cursor, anything specifically that could be causing this?
SOLUTION
mouse_move: function(e)
{
mousePos.x = e.offsetX;
mousePos.y = e.offsetY;
},
COPIED FROM: http://simonsarris.com/blog/510-making-html5-canvas-useful
Getting mouse coordinates on Canvas
Getting good mouse coordinates is a little tricky on Canvas. You could use offsetX/Y and LayerX/Y, but LayerX/Y is deprecated in webkit (Chrome and Safari) and Firefox does not have offsetX/Y.
The most bulletproof way to get the correct mouse position is shown below. You have to walk up the tree adding the offsets together. Then you must add any padding or border to the offset. Finally, to fix coordinate problems when you have fixed-position elements on the page (like the wordpress admin bar or a stumbleupon bar) you must add the ’s offsetTop and offsetLeft.
Then you simply subtract that offset from the e.pageX/Y values and you’ll get perfect coordinates in almost every possible situation.
// Creates an object with x and y defined,
// set to the mouse position relative to the state's canvas
// If you wanna be super-correct this can be tricky,
// we have to worry about padding and borders
CanvasState.prototype.getMouse = function(e) {
var element = this.canvas, offsetX = 0, offsetY = 0, mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar
offsetX += this.stylePaddingLeft + this.styleBorderLeft + this.htmlLeft;
offsetY += this.stylePaddingTop + this.styleBorderTop + this.htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object (a hash) with x and y defined
return {x: mx, y: my};
}
Use e.offsetX and e.offsetY for now instead.
It actually gets more complicated when you introduce some other things, like margins and padding, but offsetX and offsetY will be much more accurate than what you've got to say the least.
I don't have my new "bulletproof-works-in-every-situation" mouse code on me right now, I can get that later for you if you think you'll need it.
edit: Derp! Thanks chopperdave for finally providing the code I forgot to add!