Canvas element with offset - javascript

Draws nothing if the item is biased.
jsfiddle: http://jsfiddle.net/9UyxF/
JavaScript:
var ctx = document.getElementById("drawing").getContext("2d");
$("#drawing").mousemove(function(e) {
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
});
var ctx_without_offset = document.getElementById("without_offset").getContext("2d");
$("#without_offset").mousemove(function(e) {
ctx_without_offset.lineTo(e.clientX, e.clientY);
ctx_without_offset.stroke();
});
CSS:
#drawing {
border: 1px solid #000;
position: absolute;
top: 50px;
right: 0;
}
#without_offset {
border: 1px solid #000;
}
How to fix it? Thanks in advance.

The coordinates on the canvas, and cooridnates of clientX and clientY have different origins. This version realigns them:
function makeDrawFunction(elem) {
var context = elem.getContext('2d');
return function(e) {
var offset = $(elem).offset();
context.lineTo(e.clientX - offset.left, e.clientY - offset.top);
context.stroke();
}
}
$("#drawing").mousemove(makeDrawFunction(
document.getElementById("drawing")
));
$("#without_offset").mousemove(makeDrawFunction(
document.getElementById("without_offset")
));
live demo

Your problem comes from how you get the mouse position.
clientX and clientY returns the mouse position relative to the page.
I don't know if there is something with jQuery to get the right coordinates, but you can try this :
.lineTo(e.clientX - this.offsetLeft, e.clientY - this.offsetTop);

Use pageX and pageY that will handle scroll offset for you, then subtract the offset position of the canvas and that's it.
Try it:
http://jsfiddle.net/9UyxF/14/
var ctx = document.getElementById("drawing").getContext("2d");
$("#drawing").mousemove(function(e) {
var pos = $(this).offset();
ctx.lineTo(e.pageX - pos.left, e.pageY - pos.top);
ctx.stroke();
});
var ctx_without_offset = document.getElementById("without_offset").getContext("2d");
$("#without_offset").mousemove(function(e) {
var pos = $(this).offset();
ctx_without_offset.lineTo(e.pageX - pos.left, e.pageY - pos.top);
ctx_with

You have to "normalize" pointer coords like:
var ctx = document.getElementById("drawing").getContext("2d"),
ctx_rect= ctx.canvas.getBoundingClientRect();
$("#drawing").mousemove(function(e) {
ctx.lineTo(e.clientX - ctx_rect.left, e.clientY - ctx_rect.top);
ctx.stroke();
});
In that case you'll have pointer coords relative to the canvas. Demo: http://jsfiddle.net/BuDpz/.
Also note that calculating offsets on every mousemove may affect the performance. That's why it's better to calculate it once, save values and update them on demand later.

You have to look for the offset of the element, too. You can find an updated fiddle here. As I'm in a rush it's quick and dirty, but it works.
$("#without_offset").mousemove(function(e) {
var left = e.clientX - $("#without_offset").offset().left;
var top = e.clientY - $("#without_offset").offset().top;
ctx_without_offset.lineTo(left, top);
ctx_without_offset.stroke();
});

Related

When the drag event is fired in Firefox, the mouse coordinates are (0,0)

I want to make a mobile phone theme effect on the browser, and I need to make the icon get the current mouse position when it is dragged. In order to judge whether the user wants to insert the currently dragged icon at the mouse position, but I use the event object (#drag($event) ) of the drag method in the Firefox browser to get the mouse coordinates (event. pageX, event.screenX), it shows (0,0) or a fixed value, but when I use Google Chrome, the above situation does not occur, it immediately gives me the coordinates of the current mouse. Regarding the problem of the value of layerXY in the picture, this value will only be updated once at the beginning of dragging, and will not change at the rest of the time. Since I personally like to use the Firefox browser, I want to solve this problem, can anyone help me? Or give me some other suggestions to implement this function (my English is not very good, from google translate)
You could update the mouse coordinate on a global variable when the mouse moves so that it will be ready for you when mouse is down.
let drag = document.querySelector('.note');
var pageX, pageY
drag.onmousedown = function(e) {
let coord = getCoord(drag);
let shiftX = pageX - coord.left;
let shiftY = pageY - coord.top;
drag.style.position = 'absolute';
document.body.appendChild(drag);
moveNote(e);
drag.style.zIndex = 1000;
function moveNote(e) {
drag.style.left = pageX - shiftX + 'px';
drag.style.top = pageY - shiftY + 'px';
var position = {
x: drag.style.left,
y: drag.style.top
}
}
document.onmousemove = function(e) {
moveNote(e);
};
drag.onmouseup = function() {
document.onmousemove = null;
drag.onmouseup = null;
};
}
function getCoord(elem) {
let main = elem.getBoundingClientRect();
return {
top: main.top,
left: main.left
};
}
window.onload = function() {
document.addEventListener("mousemove", function(e) {
pageX = e.pageX
pageY = e.pageY
});
drag.style.position = 'absolute';
document.body.appendChild(drag);
drag.style.display = 'block'
}
.note {
width: 50px;
height: 50px;
background: red;
display: none;
}
<div class="note"></div>

Snap a custom cursor back to the center of the mouse after a size increase?

I've got a custom cursor using some CSS - changes size on hover. What's the best way to snap the cursor back to the center of the mouse after the size increase?
Here's the fiddle: https://jsfiddle.net/fojn8bq9/
Here's the JavaScript I use to center the cursor initially:
const w = myCircle.offsetWidth / 2;
const h = myCircle.offsetHeight / 2;
const myMouse = new (function() {
this.follow = function(event) {
myCircle.style.left = event.pageX - w + 'px';
myCircle.style.top = event.pageY - h + 'px';
};
})();
What's the best way to fit ^it into my hover function?
$(document).ready(function(){
$("button").hover(function(){
$(myCircle).css({"height":"50px", "width":"50px"});
}, function(){
$(myCircle).css({"height":"25px", "width":"25px"});
});
});
You can just move the circle by half the difference between the old and new heights/widths:
$("button").hover(function(){
$(myCircle).css({"height":"50px", "width":"50px", transform: "translate(-12.5px, -12.5px)"});
}, function(){
$(myCircle).css({"height":"25px", "width":"25px", transform: ""});
});
});

Image that follows mouse

I'm trying to create a zoomed visual box with the possibility to move the visual on the Y avis from top to bottom with the mouse following.
My problem is that I need to limit the navigation to the top and the bottom of the visual to avoid white spaces over and below the image while navigate with the mouse to the extremes.
Here is my code :
HTML
<div class="follower-container">
<img src="https://picsum.photos/400/600?image=1083" class="follower-image" alt="" />
</div>
CSS
.follower-container {
position: relative;
height: 100vh;
max-width: 600px;
overflow: hidden;
border: 1px solid blue;
}
.follower-image {
position: absolute;
top: 50%;
left: 0; right: 0;
width: 100%;
display: block;
width: 100%;
height: auto;
transform: translateY(-50%);
}
JS
var mouse = { x:0, y:0 };
var image_position = { x:0, y:0 };
// Get mouse position
function getMouse(e){
mouse.x = e.clientX || e.pageX;
mouse.y = e.clientY || e.pageY;
}
$('.follower-container').mousemove(function(e){
getMouse(e);
});
// Move visual regarding mouse position
function moveImage(){
var distY = mouse.y - image_position.y;
image_position.y += distY/5;
$('.follower-image').css({
'top': image_position.y + "px"
});
}
setInterval(moveImage, 20);
My jsfiddle : https://jsfiddle.net/balix/hc2atzun/22/
You can use a combination of Math.min() and Math.max() to restrict the position to a certain range.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min
Math.max() will return the larger of the two passed numbers:
Math.max(0, 100); // 100
Math.max(12, 5); // 12
Math.min() will return the smaller of the two passed numbers:
Math.min(0, 100); // 0
Math.min(12, 5); // 5
By combining them, you can restrict a given number to be within a range. If it is outside of the range, it will max out (or min out) at the ends of the range:
function keepInRange(n, minNum, maxNum) {
return Math.min(Math.max(minNum, n), maxNum);
}
keepInRange(-12, 0, 100); // 0
keepInRange(30, 0, 100); // 30
keepInRange(777, 0, 100); // 100
Now, you just need to figure out the math behind what number range to keep your top CSS value inside of. I highly, highly recommend that you give a go at that yourself.
If you really can't figure out the solution on your own, here it is for this case: https://jsfiddle.net/oeynjcpL/
Animation gets even better with requestAnimationFrame ;)
var mouse = { x:0, y:0 };
var image_position = { x:0, y:0 };
// Get mouse position
function getMouse(e){
mouse.x = e.clientX || e.pageX;
mouse.y = e.clientY || e.pageY;
}
$('.follower-container').mousemove(function(e){
getMouse(e);
});
// Returns number n if is inside of minNum and maxNum range
// Otherwise returns minNum or maxNum
function keepInRange(n, minNum, maxNum) {
return Math.min(Math.max(minNum, n), maxNum);
}
// Move visual regarding mouse position
function moveImage(){
var distY = mouse.y - image_position.y;
image_position.y += distY/5;
// minHeight is the containing element's height minus half the height of the image
var minHeight = $('.follower-container').height() - $('.follower-image').height() / 2;
// maxHeight is half the height of the image
var maxHeight = $('.follower-image').height() / 2;
$('.follower-image').css({
'top': keepInRange(image_position.y, minHeight, maxHeight) + "px"
});
requestAnimationFrame(moveImage);
}
requestAnimationFrame(moveImage);

Panning DIV element around using javascript

I am trying to have a div in a container which when the user clicks and drags somewhere in the document area, the .room element pans around inside the .viewport element by holding down the middle click button.
Here is the issue: (Hold right click for this one, middle click didn't work for some reason)
http://jsfiddle.net/JeZj5/2/
JS
var mouseX = 0;
var mouseY = 0;
var scale = 1.0;
$(document).mousemove(function (e) {
var offset = $('.room').offset();
//relative mouse x,y
mouseX = parseFloat((e.pageX - offset.left) / scale, 2);
mouseY = parseFloat((e.pageY - offset.top) / scale, 2);
//absolute mouse x,y
mouseXRaw = e.pageX;
mouseYRaw = e.pageY;
$(".room").html(mouseX + ', ' + mouseY + '<br />Right click document and pan');
switch (e.which) {
case 3:
$('.room').css({
left: mouseX,
top: mouseY
});
break;
}
return true;
});
$(document).on('contextmenu', function () {
return false;
});
This should be more along the lines of what you're looking for. Key change:
delta.x = e.pageX - drag.x;
delta.y = e.pageY - drag.y;
Using the delta to change the position. The .room's position should be moving with respect to it's current location, minus the mouse drag position (not the other way around).
http://jsfiddle.net/X2PZP/3/

clientX and clientY not giving correct mouse pointer location

I wrote this simple code to print a small dot on the location where I clicked with the mouse pointer:-
$(document).ready(function(){
$('#pane').click(function(e){
var pixel = $('<div />')
.addClass('pixel')
.css({
top: e.clientY,
left: e.clientX
});
$('#pane').append(pixel)
});
});
See this fiddle I created. When I click anywhere inside the rectangle, a small dot is printed in that location. But the problem is that dot is not printed where the mouse pointer's tip was. See the below image to see what I meant:-
I tried in both Firefox and Chrome.
Your code is working correctly,
Zoom your page and check,
i have changed pixel height and width for better understanding from 2px to 3px.
and drawing from e.clientX -1 and e.clientY -1 position so it looks exactly center.
You can find Fiddle
The most examples I've found don't work if there are a scrolled page... I used this algorythm in order to get the position:
var getOffsets = function($event){
var p = {};
var body = "search the document for the body element";
p.x = body.offsetLeft;
p.y = body.offsetTop;
while (body.offsetParent) {
p.x = p.x + body.offsetParent.offsetLeft;
p.y = p.y + body.offsetParent.offsetTop;
if (body == document.getElementsByTagName("body")[0]) {
break;
}
else {
body = body.offsetParent;
}
}
return p;
}
However, after that you have to consider also other elements, im my case:
var GetExactClickPosition = function($event){
var tr = $($event.target);
if ($event.target.localName != 'tr'){
tr = $($event.target).closest('tr');
}
var listDiv = $($event.target).closest('div');
var p = getOffsets($event);
var container = $('#mailingListExcludeMenuContainer');
container.css({
top: p.y - listDiv.scrollTop() - tr.height() - container.height() + $event.offsetY + "px",
left: p.x + $event.offsetX + "px"
});
container.show();
};
I have a list with scroller inside the main scroller of the page...
I used it in order to show a little menu at the position of the mouse click.

Categories