How to get dragged position using vanilla javascript - javascript

Basically I just want to get the position of a dragged element. I have read the previous questions like this one: How to get the position of a draggable object. But that is based on jQuery. Is there a way to achieve this with pure javascript?
I have tried something like below but doesn't work:
itemDrag() {
let card = document.querySelector("div.draggable");
let rect = card.getBoundingClientRect();
console.log(rect.top, rect.right, rect.bottom, rect.left);
}
I triggered this with ondrag event. It turns out that although the event is fired multiple times, the rect remains in the original position. Is there a way to handle that?

Related

Unable to set element style top or left during mousemove event

TLDR: Here is a JS Fiddle https://jsfiddle.net/qn8jhsaf/10/
I am attempting to create a simple drag and drop UI using mouse events as I didn't like any of the libraries available for the framework I am using. While I have all the events wired up and am getting the application side behavior I want, animating the div moving around isn't working how I would expect.
I am trying to use vanilla JS to insert a cloned div into the dom, absolutlely position it, and then move it around with tranform: translate as the mouse moves around.
So in onMouseDown, I'm doing just that:
const onMouseDown = (e) => {
isDragging = true
const rect = element.getBoundingClientRect()
let node = element.cloneNode(true)
node.style.position = 'absolute'
node.style.zIndex = 1000
node.style.left = rect.x
node.style.top = rect.y
console.log(rect.x)
console.log(node.style.left)
draggableNode = node
document.body.append(node)
}
The curious part happens when I call node.style.left =. It does not throw an error or anything but the value remains stubbornly empty ("") and it does not get translated to the style attribute of the cloned div. As far as I can tell from documentation this is a supported thing. I'm not sure what else to try.
The left and top styles need to be strings.
node.style.left = `${rect.x}px`
node.style.top = `4{rect.y}px`
FWIW, I swear I tried this at some point but ¯\_(ツ)_/¯

Javascript abstract figures following mouse

I just found a very cool effect that I would love to implement on website. The effect can be seen here: http://whois.domaintools.com/
As you can see, some kind of gif is following the mouse around. I think this look extremely cool, and I would love to know how its made.
So here's the question: How can this in fact be made (javascript is MUCH preffered) Keep in mind that this effect only occurs inside the header of the site.
It is made by javascript. You create a canvas element and javascript draws some randomly positioned dots and lines between them.
Because javascript is client language, you can view the source. The file you are looking for is there.
If you want to get an image to move with your mouse, you'll need to bind to the mousemove event. That's what's happening on that site, too, though I think it's more complex than just moving a gif along with your mouse.
But if you want to make a gif appear under your cursor as it moves, you can use this:
// when mouse enters whatever element you want
// (in this case the header), create the image
window.addEventListener('mouseenter', function(e) {
img = document.createElement('img');
img.src = 'http://path.to.image';
document.body.appendChild(img);
});
// move image according to mouse position
window.addEventListener('mousemove', function(e) {
img.style.position = 'absolute';
img.style.top = e.clientY + 'px';
img.style.left = e.clientX + 'px';
});
// remove image when mouse leaves element
window.addEventListener('mouseleave', function(e) {
document.body.removeChild(img);
img = null;
});

How can I stop an image from moving and cause an action based on a keystroke?

I am teaching myself web programming. I'm also working on C++. I am having a problem with Javascript.
I need to know how to create an "if statement" based on the location of an image.
I am making a simple game that has a cannon that is moving back and forth. I want the user to press a button that will cause the cannon to stop and fire launching another image toward the target.
I have already created the images and a gif of the image that will travel from the cannon in an arc toward the target.
If the user fires when the cannon is in the correct position the image will hit the target.
Can someone tell me how to create an if statement based on position? Or can someone tell me how to make the cannon stop and make the gif appear?
To move the cannon, read up on the onkeyup() event - it will wait for when a key is released, and do something.
What will it do? Probably change the left position of the cannon somehow. I'd recommend setting the CSS style position:absolute on your cannon, then changing the .left property with Javascript.
For example, here's some Javascript to get you started (untested):
var cannon = document.getElementById("cannonPic");
var leftlim = 200;
document.body.onkeyup = function() {
// Remove 'px' from left position style
leftPosition = cannon.style.left.substring(0, cannon.style.left - 2);
// Stop the cannon?
if (leftPosition >= leftLim) {
return;
}
// Move cannon to new position
cannon.style.left = cannon.style.left.substr(0, cannon + 10);
}
And its companion HTML would look like...
...
<img id='cannonPic' src='cannon.jpg' />
...
<script type='text/javascript' src='cannon.js' />
The HTML could be styled like this:
#cannonPic {
left:0;
position:absolute;
}
To answer your "appear/reappear" sub-question, you can use the .display property, accessed via Javascript:
var cannon = document.getElementById("cannonPic");
function appear() {
cannon.style.display = '';
}
function hide() {
cannon.style.display = 'none';
}
A small word of warning, things traveling in arcs will require some math to translate them in two dimensions, depending on how accurate you want it. A fun exercise though if you like math :)
To get the very first image on your page's x and y position on the screen, for instance, try:
var xpos = document.getElementsByTagName('img')[0].x;
var ypos = document.getElementsByTagName('img')[0].y;
Just to add a little background, the way this is typically done:
You have a main loop that will "run" the game.
Each iteration of the loop, you a) update the positions of in-game objects (cannon, projectiles, and targets in your case) and b) render the resulting objects to the screen.
When you detect a "fire" keypress, you simply set the "speed" of your moving cannon to 0, causing it to "stop".
You can retrieve the object's position using Steve's or sajawikio's approach but your game logic determines (and should know) the position of all objects at all times. It is your game logic that says "draw the projectile at position (x,y)". Your game logic should NOT say "I have a projectile, not sure exactly where it is, HMM, so let's query it's position using Javascript". At least not in this case where you have simple, predictable movement.

javascript bind an event handler to horizontal scroll

Is there a way in javascript to bind an event handler to a horizontal scroll as opposed to the generic scroll event which is fired when the user scrolls horizontally and vertically? I want to trigger an event only when the user scrolls horizontally.
I searched around for an answer to this question, but couldn't seem to find anything.
Thanks!
P.S. My apologies if I'm using some terminology incorrectly. I'm fairly new to javascript.
UPDATE
Thanks so much for all your answers! In summary, it looks like you are all saying that this isn't supported in javascript, but I that I can accomplish the functionality with something like this (using jQuery) (jsFiddle):
var oldScrollTop = $(window).scrollTop();
$(window).bind('scroll', function () {
if (oldScrollTop == $(window).scrollTop())
//scrolled horizontally
else {
//scrolled vertically
oldScrollTop = $(window).scrollTop();
}
});​
That's all I needed to know. Thanks again!
Answering from my phone, so unable to provide code at the moment.
What you'll need to do is subscribe to the scroll event. There isn't a specific one for vertical/horizontal.
Next, you'll need to get some measurements about the current display area. You'll need to measure the window.clientHeight and window.clientWidth.
Next, get window.top and window.left. This will tell you where position of the viewport is, ie if it's greater than 0 then scroll bars have been used.
It's pretty simple math from here to get what you need. If no one else has provided a code example in the next few hours I'll try to do so.
Edit:
A bit further information.
You must capture the scroll event. You also need to store the initial window.top and window.left properties somewhere. Whenever the scroll event happens, do a simple check to see if the current top/left values differ from the stores value.
At this point, if either are different you can trigger your own custom events to indicate vertical or horizontal scrolling. If you are using jQuery, this is very easy. If you are writing js without library assistance, it's easy too but a little more involved.
Do some searches for event dispatching in js.
You can then write any other code you want to subscribe to your custom events without needing to tie them together with method calls.
I wrote a jQuery plugin for you that lets you attach functions to the scrollh event.
See it in action at jsfiddle.net.
/* Enable "scrollh" event jQuery plugin */
(function ($) {
$.fn.enableHScroll = function() {
function handler(el) {
var lastPos = el
.on('scroll', function() {
var newPos = $(this).scrollLeft();
if (newPos !== lastPos) {
$(this).trigger('scrollh', newPos - lastPos);
lastPos = newPos;
}
})
.scrollLeft();
}
return this.each(function() {
var el = $(this);
if (!el.data('hScrollEnabled')) {
el.data('hScrollEnabled', true);
handler(el);
}
});
}
}(jQuery));
It's this easy to use:
$('#container')
.enableHScroll()
.on('scrollh', function(obj, offset) {
$('#info').val(offset);
});
Please note that scroll events come very fast. Even if you click in the scrollbar to jump to a new position, many scroll events are generated. You may want to adjust this code to wait a short time and accumulate all the changes in position during that time before firing the hscroll event.
You can use the same scroll event, but within your handler use the scrollLeft function to see if the scrollbar moved horizontally from the last time the event was fired. If the scrollbar did not move then just return from your handler. Otherwise update your variable to the new position and take action.
You can check if the the x value of the page changes and ignore your y value.
If the x value changes: There is your horizontal scroll.
With page-load, store the initial scrollbar positions for both in two variables (presumably both will be 0). Next, whenever a scroll event occurs, find the scrollleft and scrolltop properties. If the scrollleft property's value is different and scrolltop's value is same as compared to their earlier values, that's a horizontal scroll. Then set the values of the variables to the new scroll values.
No, there is no special event for scroll horizontal (it is for global scroll), but you can try to check the position of content by property .scrollLeft and if it's different from the previous value it means that the user scrolled content horizontally.

How can I make page scrolling trigger mouseover events?

When the mouse starts hovering over an element because of scrolling (either by wheel, or by keyboard scrolling), it does not trigger a mouseover event on the elements it is hovering (Chrome 6 on OSX). What would be an elegant way to trigger the mouseover event for the correct elements when scrolling?
Honestly, this is gonna be a pain. You'll have to
determine the size and position of every element that should get a mouseover handler.
add a scroll listener to the window.
In the handler, get the mouse cursor position and pageOffset.
Find out which element(s) the cursor is in.
manually call the actual mouseover handler
(Find out which elements the cursor has left, if you want some mouseout behaviour too)
You may need to re-calculate the elements' positions and sizes if they are dynamic. (move 1. beneath 3.)
While this should work fine with block-level elements, I have absolutely no idea on a solution for inline elements.
This is much more simple in the modern day web using document.elementsFromPoint:
Add a scroll listener to the window.
In the handler, call document.elementsFromPoint.
Manually call the actual pointerover handler for those elements. Keep track of these elements.
(optionally) Manually call the actual pointermove handler for those elements.
Check the list of elements from the previous time around. Manually call the actual pointerleave handler for elements no longer being hovered.
Here's some psuedo-code:
let prevHoveredEls = [];
document.addEventListener("scroll", (e) => {
let hoveredEls = document.elementsFromPoint(e.pageX, e.pageY);
hoveredEls = hoveredEls.filter(
(el) => el.classList.contains("elements-cared-about")
);
const notHoveredEls = prevHoveredEls.filter(
(el) => !prevHoveredEls.includes(el)
);
hoveredEls.forEach((el) => {
const bcr = el.getBoundingClientRect();
el.handlePointerEnter({
layerX: e.pageX - bcr.left,
layerY: e.pageY - bcr.top,
});
});
notHoveredEls.forEach((el) => {
const bcr = el.getBoundingClientRect();
el.handlePointerLeave({
layerX: e.pageX - bcr.left,
layerY: e.pageY - bcr.top,
});
});
prevHoveredEls = hoveredEls;
});
Try some hack like myDiv.style.opacity = 1+Math.random(); on scroll ;)

Categories

Resources