I'm using the following to capture Touch Events on an Iphone.
document.addEventListener('touchmove', function(event) {
event.preventDefault();
var touch = event.touches[0];
$('#touchPosition').text("Touch x:" + touch.pageX + ", y:" + touch.pageY);
}, false);
Strangely, I'm finding that the positions are wrong? the farther to the right I move on the iPhones screen (horizontally or vertically positioned, the more prominent the inaccuracies are.
Any ideas here?
This might be because of styling.
The canvas.width and canvas.height properties define the size of the drawing area.
If you stretch the canvas with css, for example, the coordinates in the canvas will be stretched as well.
Therefore, when drawing, the coordinate you pass will be multiplied by the same ratio your canvas has been stretched.
Related
I am playing around with a project to learn more about node.js & html canvases.
In my project I have a canvas that I want to keep a fixed bitmap size, but fill its containing div while maintaining its aspect ratio.
I have applied a size of 500x500 to my canvas element, and then applied the following style in CSS.
canvas {
display: block;
width:100%;
height:100%;
object-fit: contain;
background-color: lightgrey;
}
Inside the javascript initially fill the canvas white so I get something like the below, so far so good.
I hook into the mouse events and use them to draw lines. I use the below function to correctly scale events to the canvas.
function getMousePos(evt) {
var rect = canvas.getBoundingClientRect(); // abs. size of element
var raw_x = evt.clientX||evt.touches[0].clientX;
var raw_y = evt.clientY||evt.touches[0].clientY;
var min_dimension = Math.min(rect.width,rect.height);
var x_offset = 0.5*(rect.width-min_dimension);
var y_offset = 0.5*(rect.height-min_dimension);
return {
x: ((raw_x - rect.left - x_offset) / min_dimension) * canvas.width,
y: ((raw_y - rect.top - y_offset) / min_dimension) * canvas.height
}
}
This works, however when drawing on the canvas when the mouse moves over a band on the right side of the image it doesn't update until the mouse leaves the band. The band is the same size as the space on the left of the canvas so I think its related but I don't know how to investigate. I have no Issues if I resize the window till there is no space on either side of the canvas bitmap (and performance is considerably faster). The below gif should make things more clear.
Does anyone have a suggestion on what could be causing this, or a better way for me to achieve the same effect.
Note: I am running chrome version 80.0.3987.149
For anyone else that comes across this, I couldn't find a good solution, beyond using JavaScript to resize the element when the window resize event occurs.
I'm working on a sketchpad application using html canvas and javascript (trying to stay away from jQuery). The canvas needs to be responsive and I've found several methods to do so, but each one stretches out the canvas and makes the sketchpad unusable. It's hard to explain without seeing the problem. Here's the CodePen. Try drawing inside the canvas and you'll see what I'm talking about. The current method I'm using to resize the canvas incorporates offsetWidth and offsetHeight like so:
var sketchpadContainer = [
document.getElementById('container').offsetWidth,
document.getElementById('container').offsetHeight]
var canvas = document.getElementById('sketchpad');
canvas.style.height = sketchpadContainer[1] + "px";
canvas.style.width = sketchpadContainer[0] + "px";
Is there a way to make the canvas responsive while at the same time keeping the dimensions of the sketch intact?
The CSS width and height properties are NOT the same as the width and height attributes on a Canvas element.
If you absolutely need to use css to set width/height, keep a scale factor of your default canvas size, then multiple the target x and y positions of your mouse position by the inverse of the x/y scale factors (or just divide the target position by them).
Using css to resize your canvas is a bit too hacky imo (and will leave your lines blurry), I highly recommend you instead simlpy change with width/height attributes of your canvas and use CanvasRenderingContext2D.scale() to change the size of your lines (A scale factor will still need to be used to calculate your true mouse pos, however)
Simply change
canvas.style.height = sketchpadContainer[1] + "px";
canvas.style.width = sketchpadContainer[0] + "px";
to
canvas.height = sketchpadContainer[1];
canvas.width = sketchpadContainer[0];
Apply CanvasRenderingContext2D.scale() when you first get your context, and then do as I mentioned above. (ctx.lineTo(x,y); -> ctx.lineTo(x/scaleFactorX,y/scaleFactorY); & lastX=x; -> lastX=x/scaleFactorX;)
I.E See HERE
i am trying to use an example from the three.js page's, the voxel painter one. In this example the mouse coordinates's are used to move a roll-over helper that indicates the position where a box will be placed after the click.
mouse.set((event.clientX/window.innerWidth)*2-1, -(event.clientY/window.innerHeight)*2+1);
This piece of code calculates the position of the mouse all over the page.
I have added other div elements in the page such that the total amount of space for the webGL canvas is different from the total amount of space in the page, the new dimensions of the webGL canvas are 95% of the total height and 85% of the total width.
Now, the mouse position's over my webGL canavas is obviously different therefore the roll-over helper does not overlap anymore the position of the mouse. How have i to modify the above piece of code?
You could use jQuery to detect mouse position which works off any jQuery object passed to it.
$(function() {
var xCoord, yCoord;
$(document).on("mousemove", function(event) {
xCoord = event.pageX;
yCoord = event.pageY;
console.log("x: "+ xCoord+ ", y: "+ yCoord);
} );
} );
Just change the jQuery selector to your canvas and jQuery will handle the rest.
Hope this helps!
If you want the global position of the mouse cursor on your page, you should rather use the page coordinates like this:
event.pageX
event.pageY
I am making a whiteboard with angularjs, socketio an node.js.
As long as I use a fixed width/height for the canvas everywhere I can just broadcast the coordinates of the mouse/touch event and recreate the graphic in realtime. However, the problem I am facing is when trying to make the canvas have different sizes across different platforms (think desktop and a smartphone), the canvas has to be scaled and so does the graphic, but this makes things pretty slow.
The approach I am currently taking is to draw the graphic in a temporary hidden canvas of original size, then when there is a pause in the drawing stream (in other words the user has stopped doodling), I scale and copy it to the main canvas. The problem with this is, it doesn't feel very realtime at all, especially when a user keeps doodling without a pause for a while. Another approach I could try is to push all the coordinates in an array, apply 2d affine transformation on it, then redraw the entire thing. Though this too doesn't seem like a good solution for when the array size increases, repeatedly trying to apply transformations in realtime can easily eat up a lot of resources.
Is there any better way to achieve this?
do it with css scale transform. Scale the canvas to fit the size of the device be it a mobile, desktop, or tablet, or whatever.
Have your canvas be fixed width across all devices. Say it's 640px by 480px. Now we'll resize it to fit whatever window.
$(window).resize(function() {
var w = 640; // $('#mycanvas').width();
var h = 480; // $('#mycanvas').height();
var newWidth = $(window).width(); // this could be either smaller or bigger than the canvas
var newHeight = $(window).height(); // same here
var scaleX = newWidth / w;
var scaleY = newHeight / h;
$('#mycanvas').css('transform','scale(' + scaleX + ',' + scaleY +')');
$('#mycanvas').css('-webkit-transform','scale(' + scaleX + ',' + scaleY +')');
});
note: mycanvas could also be a container if any kind that holds the canvas and other divs or whatever. just make sure that w is the width of that container, etc.
note: if someone uses their fingers to draw across the screen, you may need to convert it from scaled coordinates to fixed width (640x480) coordinates.
Btw, I found a different way to do this that might be better. not sure:
Scaling canvas element with static resolution
I'm trying to implement an image zoom effect, a bit like how the zoom works with Google Maps, but with a grid of fix position images.
I've uploaded an example of what I have so far here:
http://www.dominicpettifer.co.uk/Files/MosaicZoom.html
(uses CSS3 transforms so only works with Firefox, Opera, Chrome or Safari)
Use your mouse wheel to zoom in/out. The HTML source is basically an outer div with an inner-div, and that inner-div contains 16 images arranged using absolute position. It's going to be a Photo Mosaic basically.
I've got the zoom bit working using CSS3 transforms:
$(this).find('div').css('-moz-transform', 'scale(' + scale + ')');
...however, I'm relying on the mouse X/Y position on the outer div to zoom in on where the mouse cursor is, similar to how Google Maps functions. The problem is that if you zoom right in on an image, move the cursor to the bottom/left corner and zoom again, instead of zooming to the bottom/left corner of the image, it zooms to the bottom/left of the entire mosaic. This has the effect of appearing to jump about the mosaic as you zoom in closer while moving the mouse around, even slightly.
That's basically the problem, I want the zoom to work exactly like Google Maps where it zooms exactly to where your mouse cursor position is, but I can't get my head around the Maths to calculate the transform-origin: X/Y values correctly. Please help, been stuck on this for 3 days now.
Here is the full code listing for the mouse wheel event:
var scale = 1;
$("#mosaicContainer").mousewheel(function(e, delta)
{
if (delta > 0)
{
scale += 1;
}
else
{
scale -= 1;
}
scale = scale < 1 ? 1 : (scale > 40 ? 40 : scale);
var x = e.pageX - $(this).offset().left;
var y = e.pageY - $(this).offset().top;
$(this).find('div').css('-moz-transform', 'scale(' + scale + ')')
.css('-moz-transform-origin', x + 'px ' + y + 'px');
return false;
});
Finally figured it out, check it out here:
http://www.dominicpettifer.co.uk/Files/Mosaic/MosaicTest.html
Use the mouse wheel to zoom, you can also drag the image about, only works properly on latest Safari, Opera and Firefox (images are blurry on Chrome for some reason). Also a bit buggy in certain areas. Got a lot of help someone at DocType http://doctype.com/javascript-image-zoom-css3-transforms-calculate-origin-example