How to console log when offsetLeft reach a number of pixels - javascript

I'm creating a simple game: drag en element far enough (200px) The console logs fine, when I drag the element 200px the console reads 200px, but I still get the wrong message.(not there yet)..
function far_enough() {
console.log('You have moved the box ' + el.offsetLeft + 'pixels');
if(el.offsetleft == 200){
console.log('200px great!');
} else {
console.log('not there yet!');
}
}
}

To answer your question, element.offsetLeft can return a decimal value. This means that it may return 200.01px instead of 200px exactly. This is what's causing your code to not work. A simple work-around is simply to use Math.round(element.offsetLeft) to return an integer value. However, even when using this, there's a chance that the offsetLeft does not return 200px exactly, especially when you drag the element too fast (the browser does not repaint for each pixel moved). Another solution is to use a range like from 200px to 250px.
I suppose that you're using position: absolute and manipulating left CSS property to cause the element to be draggable. However, moving elements with transform is better than using position. I highly suggest reading this article on why.
As you're moving your element using transform now, the offsetLeft value of the element never changes. Therefore, you can alternatively get the rendered box position using getBoundingClientRect(). Here's an example using a getBoundingClientRect(), which returns a left value relative to the viewport.
const draggable = document.querySelector('#draggable')
function farEnough() {
const box = draggable.getBoundingClientRect()
// Get center of box; move center of box by 200px to return true
let center = box.left + (box.right - box.left) / 2
if (center >= 200 && center <= 300) return true
else return false
}
let dragging = false
let dragStartX = null
let dragStartY = null
let draggableMovedX = null
let draggableMovedY = null
function dragHandler(e) {
dragging = true
dragStartX = e.clientX
dragStartY = e.clientY
}
function moveHandler(e) {
if (dragging) {
let moveX = e.clientX - dragStartX + draggableMovedX
let moveY = e.clientY - dragStartY + draggableMovedY
draggable.style.transform = `translate(${moveX}px, ${moveY}px)`
if (farEnough()) {
draggable.removeEventListener('mousedown', dragHandler)
window.removeEventListener('mousemove', moveHandler)
window.removeEventListener('mouseup', leaveHandler)
dragging = false
dragStartX = null
dragStartY = null
// 175px so that the center of the box is exactly at 200px from the left
draggable.style.transform = `translate(175px, ${moveY}px)`
console.log('You did it! You moved it 200px to the right!')
}
}
}
function leaveHandler(e) {
dragging = false
dragStartX = null
dragStartY = null
const box = draggable.getBoundingClientRect()
draggableMovedX = box.left
draggableMovedY = box.top
}
draggable.addEventListener('mousedown', dragHandler)
window.addEventListener('mousemove', moveHandler)
window.addEventListener('mouseup', leaveHandler)
body,
html {
width: 100%;
height: 100%;
position: relative;
margin: 0;
}
#draggable {
width: 50px;
height: 50px;
border-radius: 5px;
background: #121212;
cursor: grab;
}
#draggable:active {
cursor: grabbing;
}
#line {
position: absolute;
top: 0;
left: 200px;
width: 2px;
height: 100%;
background: red;
transform: translateX(-50%);
}
<div id="draggable"></div>
<div id="line"></div>

try
function far_enough()
{
let leftOffset = el.offsetLeft;
console.log('You have moved the box ' + leftOffset + 'pixels');
if (leftOffset == 200)
{
console.log('200px great!');
}
else
{
console.log('not there yet!');
}
}

Related

How to fix this javascript onmousemove that is not working only on wordpress site

Im trying to create a ball that follow the cursor inside my site: www.effevisual.altervista.org using wordpress and divi theme.
I tried this code lot of times without any problem but actually it looks like the objects block the ball.
I also want if possible to change the ball to less opacity when the cursor is hover a link.
<body onload = "followMouse();">
<div class="wrap">
<div id="ball"></div>
</div></body>
.wrap {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
}
#ball {
width: 20px;
height: 20px;
background: #0034fc;
border-radius: 50%;
position: absolute;
left: 50%;
top: 50%;
margin: -10px 0 0 -10px;
pointer-events: none;
}
var $ = document.querySelector.bind(document);
var $on = document.addEventListener.bind(document);
var xmouse, ymouse;
$on('mousemove', function (e) {
xmouse = e.clientX || e.pageX;
ymouse = e.clientY || e.pageY;
});
var ball = $('#ball');
var x = void 0,
y = void 0,
dx = void 0,
dy = void 0,
tx = 0,
ty = 0,
key = -1;
var followMouse = function followMouse() {
key = requestAnimationFrame(followMouse);
if(!x || !y) {
x = xmouse;
y = ymouse;
} else {
dx = (xmouse - x) * 0.125;
dy = (ymouse - y) * 0.125;
if(Math.abs(dx) + Math.abs(dy) < 0.1) {
x = xmouse;
y = ymouse;
} else {
x += dx;
y += dy;
}
}
ball.style.left = x + 'px';
ball.style.top = y + 'px';
};
</script>
Any message error, just the ball doesnt follow properly.
So what I found is that you are applying a transform to the class .et_pb_code_0. transform: translateX(-89px) translateY(-81px) rotateX(0deg) rotateY(0deg) rotateZ(90deg); That alone has sent your ball to a different direction making left and right up and down and up and down now left and right.
Aside from that your wrapper and ball class are contained in many other divs which position it away from the top left of the page.
I can fix it in inspecter by dragging the wrap class to the top under the main-content1 class.
You will also have to apply position:fixed to the wrap class to keep it on the screen at all times. And a z-index for the lower parks of the page. And pointer-events:none so you can click links.
And something like this to get you started:
jQuery( "li" ).mouseenter(function() {
jQuery( "#ball" ).fadeTo( "slow" , 0, function() {
// Animation complete.
});
});
jQuery( "li" ).mouseleave(function() {
jQuery( "#ball" ).fadeTo( "slow" , 1, function() {
// Animation complete.
});
});

Show element when in viewport on scroll

I've been trying to show an element on scroll when it's in viewport and when no, hide it again. But no matter what I try, I can't make it work.
This is what I have so far, but the function is running just once, when the page is loaded and not when it's scrolled, so it doesn't update the value.
$(window).scroll(function() {
var top_of_element = $("#cont_quote blockquote").offset().top;
var bottom_of_element = $("#cont_quote blockquote").offset().top + $("#cont_quote blockquote").outerHeight();
var bottom_of_screen = $(window).scrollTop() + window.innerHeight;
var top_of_screen = $(window).scrollTop();
if((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)){
$('#cont_quote blockquote').animate({'opacity':'1'},1000);
}
else {
$('#cont_quote blockquote').animate({'opacity':'0'},1000);
}
});
<section id="cont_quote">
<article class="cont_q">
<blockquote>Lorem ipsum</blockquote>
</article>
</section>
In pure javascript, you could do something like this, which uses a lot less resources than a full on jQuery approach:
function inViewport( element ){
// Get the elements position relative to the viewport
var bb = element.getBoundingClientRect();
// Check if the element is outside the viewport
// Then invert the returned value because you want to know the opposite
return !(bb.top > innerHeight || bb.bottom < 0);
}
var myElement = document.querySelector( 'div' );
// Listen for the scroll event
document.addEventListener( 'scroll', event => {
// Check the viewport status
if( inViewport( myElement ) ){
myElement.style.background = 'red';
} else {
myElement.style.background = '';
}
})
body {
height: 400vh;
}
div {
width: 50vw;
height: 50vh;
position: absolute;
top: 125vh;
left: 25vw;
transition: background 4s;
border: 1px solid red;
}
<p>Scroll Down</p>
<div></div>
Here is a snippet with the opacity change:
function inViewport( element ){
// Get the elements position relative to the viewport
var bb = element.getBoundingClientRect();
// Check if the element is outside the viewport
// Then invert the returned value because you want to know the opposite
return !(bb.top > innerHeight || bb.bottom < 0);
}
var myElement = document.querySelector( 'div' );
// Listen for the scroll event
document.addEventListener( 'scroll', event => {
// Check the viewport status
if( inViewport( myElement ) ){
myElement.style.opacity = 1;
} else {
myElement.style.opacity = '';
}
})
body {
height: 400vh;
}
div {
width: 50vw;
height: 50vh;
position: absolute;
top: 125vh;
left: 25vw;
transition: opacity 1s;
opacity: .2;
background: blue;
}
<p>Scroll Down</p>
<div></div>
And here is a snippet showing you how to define where in the viewport it triggers, I just changed the innerHeight and 0 values to an object where you define the amount of pixels from the top it should be and the amount of pixels from the bottom. Don't forget to also add an event listener for resize, as these pixel based values will change if your viewport changes, so your myViewport object would need to be updated accordingly:
function inViewport( element, viewport = { top: 0, bottom: innerHeight } ){
// Get the elements position relative to the viewport
var bb = element.getBoundingClientRect();
// Check if the element is outside the viewport
// Then invert the returned value because you want to know the opposite
return !(bb.top > viewport.bottom || bb.bottom < viewport.top);
}
var myViewport = { top: innerHeight * .4, bottom: innerHeight * .6 };
var myElement = document.querySelector( 'div' );
// Listen for the scroll event
document.addEventListener( 'scroll', event => {
// Check the viewport status
if( inViewport( myElement, myViewport ) ){
myElement.style.opacity = 1;
} else {
myElement.style.opacity = '';
}
})
window.addEventListener( 'resize', event => {
// Update your viewport values
myViewport.top = innerHeight * .4;
myViewport.bottom = innerHeight * .6;
})
body {
height: 400vh;
}
div {
width: 50vw;
height: 50vh;
position: absolute;
top: 125vh;
left: 25vw;
transition: opacity 1s;
opacity: .2;
background: blue;
}
<p>Scroll Down</p>
<div></div>
Try using:
$(window).on('scroll mousewheel', function() {
And surround your function with:
$(document).ready(function(){
});
i tried to solve your problem by your code only. its working fine for me now. plz try this and let me know. also open your browser console to see if there is any js error.
$(window).scroll(function() {
var top_of_element = $("#cont_quote blockquote").offset().top;
var bottom_of_element = $("#cont_quote blockquote").offset().top + $("#cont_quote blockquote").outerHeight();
var bottom_of_screen = $(window).scrollTop() + window.innerHeight;
var top_of_screen = $(window).scrollTop();
if((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)){
$('#cont_quote blockquote').fadeIn(1000);
console.log('if cond');
} else {
$('#cont_quote blockquote').fadeOut(1000);
console.log('else cond');
}
});

Detect hover/mouseover/mouseenter while dragging an element

How to detect hover/mouseover/mouseenter while dragging an element? I want to have green box after hovering it with the "drag" element. Is there any solution for that?
Note: I know that I could use jQuery UI for it but I want to do it by myself.
$("box").mouseover(function() {
$(this).addClass("green");
var box = $(this).attr("id");
$("#result").html(box);
});
$("box").mouseleave(function() {
$(this).removeClass("green");
});
$("drag").bind({
mousedown: function() {
$(this).addClass("absolute");
},
mouseup: function() {
$(this).removeClass("absolute");
},
mousemove: function(e) {
$(this).css({
left: e.pageX - (50 / 2),
top: e.pageY - (50 / 2)
});
}
});
$("body").mousemove(function(event) {
$("#log").text("pageX: " + event.pageX + ", pageY: " + event.pageY);
});
https://jsfiddle.net/38zecoL1/1/
Thank you for any help.
I would try to disable pointer events on the dragged object using: pointer-events: none;. That way you should get the events of the hovered objects instead of the dragged.
But you also need to adapt to the situation that the move and mouseup event will not work. You will have to bind them elsewhere (body for example)
This short example is not perfect but schuld give you a hint of how to do it better ;)
$("box").mouseover(function () {
$(this).addClass("green");
var box = $(this).attr("id");
$("#result").html(box);
});
$("box").mouseleave(function () {
$(this).removeClass("green");
});
$("#drag").bind({
mousedown : function (e) {
$(document.body).css({ 'user-select': 'none' })
var dragged = $(this);
dragged.css({
left : e.pageX - (50 / 2),
top : e.pageY - (50 / 2)
});
dragged.css({
'pointer-events' : 'none'
})
var upHandler = function () {
dragged.removeClass("absolute");
dragged.css({
'pointer-events' : 'all'
})
$(document.body).css({ 'user-select': 'initial' })
$("body").off('mouseup', upHandler);
$("body").off('mousemove', moveHandler);
}
var moveHandler = function (e) {
dragged.addClass("absolute");
dragged.css({
left : e.pageX - (50 / 2),
top : e.pageY - (50 / 2)
});
}
$("body").bind({
mouseup : upHandler,
mousemove : moveHandler
})
}
});
$("body").mousemove(function (event) {
$("#log").text("pageX: " + event.pageX + ", pageY: " + event.pageY);
});
box {
float: left;
width: 100px;
height: 100px;
background-color: red;
margin: 20px;
}
#log {
position: absolute;
top: 150px;
}
.green {
background-color: green;
}
#drag {
width: 50px;
height: 50px;
float: left;
background-color: blue;
}
#drag.absolute {
position: absolute;
}
html,
body {
width: 100%;
height: 100%;
}
* {
margin: 0;
padding: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<box id="box1">
<div id="drag"></div>
</box>
<box id="box2"></box>
<div id="result"></div>
<div id="log"></div>
The reason the container stays green and the other one doesn't change is that the element you're dragging is a child of the first container. So while your mouse is in the blue draggable box it's still considered inside the container on the left because the blue box is a child of the first container.
One way to fix this (and most likely isn't the best way) is to keep track of where the mouse is on the screen (which you're already doing to move the blue block). In there if you add a bit of code checking if the mouse is within the bounding box of either of the other containers and add/remove classes based on that. Then the classes will be added based on mouse position and not whether the mouse is over an element that is a child or is not a child.
Example: https://jsfiddle.net/38zecoL1/3/
var boxes = $("box")
for(var i = 0; i < boxes.length; i++){
var boundingBox = boxes[i].getBoundingClientRect();
if(e.pageX < boundingBox.right &&
e.pageX > boundingBox.left &&
e.pageY < boundingBox.bottom &&
e.pageY > boundingBox.top){
$(boxes[i]).addClass("green");
} else{
$(boxes[i]).removeClass("green");
}
}
This is likely pretty expensive to add in a page that deals with a more complex page than just a few divs and may not perform well in those more complex situations.
If you want to drag element I recommend you to use this JS library https://github.com/RubaXa/Sortable
There is an opt called
chosenClass: "sortable-chosen", // Class name for the chosen item
and in this class you can add different color and everything you want.
But if you wanto to do this by yourself i don't now

How to add a text box popup (Jquery tooltip or similar) to a Fabric JS image within a canvas?

I'm working on a Fabric JS project to map a floor with its rooms' locations.
At each room location I added an icon. I want to have a text box pop up (such as jquery tooltip) each time the mouse hover above the icon.
The text box should show room information (phone number \ person \ size \ etc.)
I found this google group post, but no one really described the solution beside sharing this link
Step 1: Set up your watchers
Step 2: Load the dialog
Step 3: Figure out where the bounding rect is on the page and move the dialog.
canvas.observe('mouse:over', function (e) {
console.log("Everyday I'm hovering");
showImageTools(e.target);
});
canvas.observe('mouse:out', function (e) {
$('#imageDialog').remove();
});
function showImageTools (e) {
var url = 'dialog/imageDialog.htm';
$.get(url, function(data) {
// Don't add it twice
if (!$('#imageDialog').length) {
$(body).append(data);
}
moveImageTools();
});
function moveImageTools () {
var w = $('#imageDialog').width();
var h = $('#imageDialog').height();
var e = canvas.getActiveObject();
var coords = getObjPosition(e);
// -1 because we want to be inside the selection body
var top = coords.bottom - h - 1;
var left = coords.right - w - 1;
$('#imageDialog').show();
$('#imageDialog').css({top: top, left: left});
}
function getObjPosition (e) {
// Get dimensions of object
var rect = e.getBoundingRect();
// We have the bounding box for rect... Now to get the canvas position
var offset = canvas.calcOffset();
// Do the math - offset is from $(body)
var bottom = offset._offset.top + rect.top + rect.height;
var right = offset._offset.left + rect.left + rect.width;
var left = offset._offset.left + rect.left;
var top = offset._offset.top + rect.top;
return {left: left, top: top, right: right, bottom: bottom};
}
That should be enough to get you started. Let me know if any of this doesn't make sense.
Add span element below the canvas
<span ref="toolTip" class="toolTip">ToolTip</span>
Add style for span element
NB: Visibility is hidden by default
.toolTip{
position: absolute;
z-index: 1;
background: rgb(119, 128, 0);
height: 30px;
width: 120px;
padding: 8px;
font-size: 13px;
color: #fff;
visibility: hidden;
}
Add mouse over and mouse out events
this.$data.canvas.on('mouse:over', function (e) {
// console.log(e.e.offsetX)
if (e.target && e.target.feature === 'Seat') {
self.$refs.toolTip.innerHTML =
'Seat: ' + e.target.label + ' Row: ' + e.target.rowLabel
self.$refs.toolTip.style.visibility = 'visible'
self.$refs.toolTip.style.top = e.e.offsetY + 'px'
self.$refs.toolTip.style.left = e.e.offsetX + 'px'
}
})
this.$data.canvas.on('mouse:out', function (e) {
self.$refs.toolTip.style.visibility = 'hidden'
})

WebKit: How to determine what elements are under a touch while dragging an animating div

I'm trying to implement drag and drop for Mobile Safari.
Basically I want to drag a div via touch while it plays a looping CSS animation. I also want to determine when it's above a drop target and do something special.
I'm using elementFromPoint to determine what elements my div is being dragged over on touchmove events. However, the dragged div is always the topmost element. So before querying, I set it to display: none. However, this has the effect of resetting my animation every frame in which the touch moves.
How do I determine what I'm dragging above without resetting my CSS animation every time I query?
JSFiddle using touch events in WebKit.
HTML On every touchmove I move the drag div.
<div id='drop'>Drop here</div>
<div id='drag'>Drag me</div>
JavaScript
var drag = document.getElementById('drag');
var drop = document.getElementById('drop');
drag.addEventListener('touchmove', move, true);
function move(e) {
var touch = e.changedTouches[0];
drag.style.left = touch.pageX - 25 + 'px';
drag.style.top = touch.pageY - 25 + 'px';
drag.style.display = 'none';
if (drop === document.elementFromPoint(touch.pageX, touch.pageY)) {
drag.classList.add('in-drop-zone');
} else {
drag.classList.remove('in-drop-zone');
}
drag.style.display = 'inline';
}
CSS
div {
position: absolute;
}
div#drag {
width: 50px;
height: 50px;
background-color: blue;
-webkit-transform-origin: 50% 50%;
-webkit-animation: sway 1s infinite alternate;
}
div#drop {
width: 100px;
height: 100px;
background-color: green;
left: 200px;
top: 200px;
}
div#drag.in-drop-zone {
background-color: yellow;
}
#-webkit-keyframes sway {
from {
-webkit-transform: rotate(-30deg);
}
to {
-webkit-transform: rotate(30deg);
}
}
You could probably set pointer-events: none and then pointer-events: auto, but that seems pretty hacky. A better option is to have an intersection function:
var drag = document.getElementById('drag');
var drop = document.getElementById('drop');
var drop_bbox = drop.getBoundingClientRect();
window.addEventListener('touchmove', move, true);
window.addEventListener('mousemove', move, true);
function move(e) {
drag.style.left = e.clientX - 25 + 'px';
drag.style.top = e.clientY - 25 + 'px';
var drag_bbox = e.target.getBoundingClientRect();
drag.className = rectsIntersect(drag_bbox, drop_bbox) ? "in-drop-zone" : null;
}
function rectsIntersect(r1, r2) {
if (!r1 || !r2) return false;
return r2.left < (r1.left+r1.width) &&
(r2.left+r2.width) > r1.left &&
r2.top < (r1.top+r1.height) &&
(r2.top+r2.height) > r1.top;
};
Here is a JSFiddle http://jsfiddle.net/duopixel/SvPpw/

Categories