Safari page zoom causes wrong event.clientX/Y - javascript

I've got a page that reads the cursor location in event.clientX/Y and compares it with element.getBoundingClientRect() to do hit testing. This works even when the page scrolls or when Cmd+ is used. I found that in Safari (not Chrome), when I zoom the page in with a pinch gesture and scroll, the .clientX/Y are wrong. I made this snippet that shows the fixed element not following the mouse when zoomed.
window.onmousemove = function(event)
{
// it seems like if document is not zoomed, correction is not needed. but if it is, correction IS needed.
var x = event.clientX /*+ window.pageXOffset*/;
var y = event.clientY /*+ window.pageYOffset*/;
document.getElementById('cursor').style.left = x+'px';
document.getElementById('cursor').style.top = y+'px';
document.getElementById('cursor').innerText = [x,y,document.getElementById('cursor').getBoundingClientRect().x,document.getElementById('cursor').getBoundingClientRect().y];
}
/* force a large page */
document.write('<pre>');
for (var i = 0; i <= 100; i++) { document.write("<mark>" + i + "</mark>"); }
for (var i = 1; i <= 100; i++) { document.write("<mark>" + i + "</mark><br>"); }
document.write('</pre>');
html, body { min-height: 100%; }
mark { display: inline-block; width: 30px; height: 30px; outline: thin solid black; }
<!DOCTYPE html5>
<div id=cursor style="position: fixed; left: 30px; top: 30px; background: red;"></div>
UPDATE: Run Snippet is behaving correctly, however the following code in a plain html file is not. S.O. might be doing something to the event before the snippet gets it.
<!DOCTYPE html5>
<style>
html, body { min-height: 100%; }
mark { display: inline-block; width: 30px; height: 30px; outline: thin solid black; }
</style>
<div id=cursor style="position: fixed; left: 30px; top: 30px; background: red;"></div>
<script>
window.onmousemove = function(event)
{
// it seems like if document is not zoomed, correction is not needed. but if it is, correction IS needed.
var x = event.clientX /*+ window.pageXOffset*/;
var y = event.clientY /*+ window.pageYOffset*/;
document.getElementById('cursor').style.left = x+'px';
document.getElementById('cursor').style.top = y+'px';
document.getElementById('cursor').innerText = [x,y,document.getElementById('cursor').getBoundingClientRect().x,document.getElementById('cursor').getBoundingClientRect().y];
}
/* force a large page */
document.write('<pre>');
for (var i = 0; i <= 100; i++) { document.write("<mark>" + i + "</mark>"); }
for (var i = 1; i <= 100; i++) { document.write("<mark>" + i + "</mark><br>"); }
document.write('</pre>');
</script>

Related

I am trying to make an object resize based on the distance between the cursor and said object. The Y value I get is always naN

This is my js code, I always get a naN as a result of my Y variable
var elm = document.getElementById("qrcode");
elm.addEventListener("mousemove",getcordd , false)
function getcordd(ev){
var bdns = ev.target.getBoundingClientRect();
var x = ev.clientx - bdns.left;
var y = ev.clienty - bdns.top;
console.log (`${y}`);
}
I got carried away here, but reading that you wanted to know about changing an element's size based on mouse movements, I threw this thing together. Take a look and if you have any questions about it, let me know in a comment. Cheers
var elm = document.getElementById("qrcode");
document.getElementById("mousecapture").addEventListener("mousemove", getcordd, false)
function getcordd(ev) {
var bdns = ev.target.getBoundingClientRect();
// console.log(bdns)
var x = ev.clientX - bdns.left;
var y = ev.clientY - bdns.top;
// console.log(`${y}`, `${x}`, bdns.left, bdns.top);
// resize the div
//console.log(ev.clientX, ev.clientX/bdns.width,ev.clientY, ev.clientY/bdns.height)
let min = 10,
max = 200; // min width/height;
elm.style.width = Math.max(min, Math.min(max, Math.round(max * Math.abs(x / bdns.width)))) + "px";
elm.style.height = Math.max(min, Math.min(max, Math.round(max * Math.abs(y / bdns.height)))) + "px";
}
html,
body,
#container {
width: 100%;
height: 100%;
background: #f0f0f0;
}
#qrcode {
width: 50px;
height: 50px;
background: #f00;
color: #fff;
text-align: center;
display: inline-block;
}
#mousecapture {
width: 100px;
height: 100px;
border: 1px solid #ccc;
background: #fff;
float: right;
}
<div id='container'>
Move the mouse in the white box
<hr>
<div id='mousecapture'></div>
<div id='qrcode'></div>
</div>

how to make a box reach the edge of a bigger box

javascript beginner here! so i'm trying to do a box(that is inside a larger box) move from the top to the edge of the box. Here's the code:
var boxcont = document.getElementById("boxcont");
var boxbtn = document.getElementById("boxbtn");
boxbtn.addEventListener("click", function() {
var loc = 0;
var timebox = setInterval(boxmove, 5);
function boxmove() {
if (loc == 320) {
clearInterval(timebox);
} else {
loc++;
boxcont.style.top = loc + "px";
boxcont.style.left = loc + "px";
}
}
});
#movebox {
width: 300px;
height: 350px;
background-color: grey;
}
#boxcont {
width: 30px;
height: 30px;
background-color: indianred;
position: relative;
}
<div id="movebox">
<div id="boxcont"></div>
</div>
<button id="boxbtn">Move the box</button>
The problem is that the small box doesn't exactly ends up at the edge, it goes more to the right. I tried doing
boxcont.style.left = (loc - 0.5) + "px";
but doesn't work. pretty sure the solution is simple but as a newbie here it's confusing me :p. Oh and i also tried doing ++ to the 0.5 and Number(0.5) so it reads it as a decimal but still doesn't work!
the big gray box is not set to the correct height and width that corresponds with the small red box's movement. You have it going down 1 and to the right 1 every 5 however, your actually going across a rectangle, not a square. set your width and height the same for the gray box and slightly adjust the stopping point to a little bit less.
var boxcont = document.getElementById("boxcont");
var boxbtn = document.getElementById("boxbtn");
boxbtn.addEventListener("click", function() {
var loc = 0;
var timebox = setInterval(boxmove, 5); // every five milliseconds
function boxmove() {
if (loc == 290) {
clearInterval(timebox);
} else {
loc++;
boxcont.style.top = loc + "px";
boxcont.style.left = loc + "px";
}
}
});
#movebox {
width: 300px;
height: 350px;
background-color: grey;
}
#boxcont {
width: 30px;
height: 30px;
background-color: indianred;
position: relative;
}
<div id="movebox" style = "height: 320px; width: 320px">
<div id="boxcont" ></div>
</div>
<button id="boxbtn">Move the box</button>
if (loc == 270) {
instead of
if (loc == 320) {
Gets you there.
300px is the width of the containing div and the moving div is 30px wide so 300-30=270px
var boxcont = document.getElementById("boxcont");
var boxbtn = document.getElementById("boxbtn");
boxbtn.addEventListener("click", function() {
var loc = 0;
var timebox = setInterval(boxmove, 5);
function boxmove() {
if (loc == 270) {
clearInterval(timebox);
} else {
loc++;
boxcont.style.top = loc + "px";
boxcont.style.left = loc + "px";
}
}
});
#movebox {
width: 300px;
height: 350px;
background-color: grey;
}
#boxcont {
width: 30px;
height: 30px;
background-color: indianred;
position: relative;
}
<div id="movebox">
<div id="boxcont"></div>
</div>
<button id="boxbtn">Move the box</button>

Slider handle needs to restricted inside the container, should not go beyond the container

In the custom slider i have created, the handle is moving beyond the container. But i want it to stay within the container limits. We could just do it simple by setting margin-left as offset in CSS. But My requirement is when the handle right end detect the container's end the handle should not be allowed to move anymore. Any help is appreciated. Thanks.
Demo Link: https://jsfiddle.net/mohanravi/1pbzdyyd/30/
document.getElementsByClassName('contain')[0].addEventListener("mousedown", downHandle);
function downHandle() {
document.addEventListener("mousemove", moveHandle);
document.addEventListener("mouseup", upHandle);
}
function moveHandle(e) {
var left = e.clientX - document.getElementsByClassName('contain')[0].getBoundingClientRect().left;
var num = document.getElementsByClassName('contain')[0].offsetWidth / 100;
var val = (left / num);
if (val < 0) {
val = 0;
} else if (val > 100) {
val = 100;
}
var pos = document.getElementsByClassName('contain')[0].getBoundingClientRect().width * (val / 100);
document.getElementsByClassName('bar')[0].style.left = pos + 'px';
}
function upHandle() {
document.removeEventListener("mousemove", moveHandle);
document.removeEventListener("mouseup", upHandle);
}
.contain {
height: 4px;
width: 450px;
background: grey;
position: relative;
top: 50px;
left: 40px;
}
.bar {
width: 90px;
height: 12px;
background: transparent;
border: 1px solid red;
position: absolute;
top: calc(50% - 7px);
left: 0px;
cursor: ew-resize;
}
<div class='contain'>
<div class='bar'></div>
</div>
You need to change
this
document.getElementsByClassName('bar')[0].style.left = pos + 'px';
to this
if(pos > 90){
document.getElementsByClassName('bar')[0].style.left = pos - 90 + 'px';
}
else{
document.getElementsByClassName('bar')[0].style.left = 0 + 'px';
}
since width of your bar is 90px I am subtracting 90.
See this updated fiddle

animated loads in wrong spot

I have a div that animates up and down which works fine. The issue I'm getting is that every time the page loads the div starts at the very top of the page and then jumps down to where it needs to be after the animation starts.
<body id="body">
<div id="square"></div>
</body>
#body {
background: #000;
}
#square {
background-color: #fff;
margin: 0 auto;
position: relative;
width: 100px;
height: 100px;
}
var box = document.getElementById('square');
TOP = (window.innerHeight - box.offsetHeight)/2;
box.style.top = TOP;
var down = setInterval(animateDown, 15);
var up;
function animateDown()
{
TOP += 3;
box.style.top = TOP + 'px';
if(TOP > 900){
clearInterval(down);
up = setInterval(animateUp, 15);
}
}
function animateUp()
{
TOP -= 3;
box.style.top = TOP + 'px';
if(TOP <= (window.innerHeight - box.offsetHeight)/2){
clearInterval(up);
down = setInterval(animateDown, 15);
}
}
Here is a link to the jsfiddle as well >> https://jsfiddle.net/xgilmore/pLbgvc3L/
thanks in advance
This is sort of a work around, but you can start the box off as hidden, and then once you start animating, set it visible. https://jsfiddle.net/pLbgvc3L/1/
function animateDown()
{
box.style.visibility = 'visible';
#square {
background-color: #fff;
//margin: 0 auto;
position: relative;
width: 100px;
height: 100px;
top: 20%;
visibility: hidden;
}
Oh sorry, I actually know what is going on, it just took a second look to figure it out. top: 20% doesn't do anything because percentages only work if the parent element (body) has an explicit height. Like so https://jsfiddle.net/pLbgvc3L/2/

Unable to animate DOM element in codepen

I want to simply animate a shape every x milliseconds. I'm doing this in CODEPEN.
I tried moving it using:
JavaScript:
ball.getBoundingClientRect().left += 100 + 'px'
ball.style.left += 100 + 'px'
jQuery:
$('#ball').position().left += 100 + 'px'
But nothing seemed to work. The ball appears, but does not move. The timeout is being called as well. No errors in console are being thrown.
var ball = null;
var ball_x = null;
var ball_y = null;
function doMove() {
ball.style.left += 100 + 'px';
setTimeout(doMove,100);
}
function init() {
ball = document.getElementById('ball');
ball_x = ball.getBoundingClientRect().left; //displays correct location
ball_y = ball.getBoundingClientRect().top; //displays correct location
doMove();
}
window.onload = init;
CSS:
#ball {
width: 25px;
height: 25px;
background-color: red;
border-radius: 50%;
position: absolute;
left: 100px;
top: 200px;
}
HTML:
<div>
<div id='ball'></div>
</div>
The problem is left css returns a text like 100px value not a numerical one so that won't work. So using += with it does a string concatenation not a numeric one creating a invalid value
getBoundingClientRect() returns a read-only object, so changing its properties don't have an effect
The returned value is a DOMRect object, which contains read-only left,
top, right and bottom properties describing the border-box in pixels.
top and left are relative to the top-left of the viewport.
var ball = null;
function doMove() {
ball.style.left = ((parseInt(ball.style.left) || 0) + 100) + 'px'
setTimeout(doMove, 2000);
}
function init() {
ball = document.getElementById('ball');
doMove();
}
window.onload = init;
#ball {
width: 25px;
height: 25px;
background-color: red;
border-radius: 50%;
position: absolute;
left: 100px;
top: 200px;
transition: left 2s;
}
<div>
<div id='ball'></div>
</div>

Categories

Resources