I've run into a problem with running a loop to trigger a mousemove event on my HTML/CSS.
I know I can go through and get every individual ID on the HTML tags to execute the code the way I want. But I know there is a better way to do it with a loop of some sort and use far less code.
The images should follow the mouse while moving over the div with class mycard. Any suggestions or ideas on how to get it working properly would be very much appreciated.
I've tried running a loop to add the classes to divs but had no luck.
var mouseHover = document.getElementById('moveHover');
window.onmousemove = function(e) {
var x = e.clientX;
var y = e.clientY;
mouseHover.style.top = (y + 20) + 'px';
mouseHover.style.left = (x + 20) + 'px';
};
.mycard span {
position: absolute;
display: none;
z-index: 99;
}
.mycard:hover span {
display: block;
position: fixed;
overflow: hidden;
}
.imgHover a {
position: relative;
}
.imgHover span {
position: absolute;
display: none;
z-index: 99;
}
.imgHover a:hover span {
display: block;
position: fixed;
overflow: hidden;
}
<div class="imgHover mycard">
<div class="cardcost">
<p class="cardcosttext">2</p>
</div>
<div class="hscardepic">
<a style="margin-left: 1000%;vertical-align: middle;">
Doomsayer
<span id="moveHover">
<img src="Classic_Set/doomsayer.png" height="300" width="300" />
</span>
</a>
</div>
<div class="cardamount">
<p class="cardamounttext">×2</p>
</div>
</div>
If I understand what you're asking, you could use querySelectorAll to get the elements and forEach to move them:
// get the div that responds to mouse movement
const mycard = document.querySelector('.mycard');
// add a mousemove listener
mycard.addEventListener('mousemove', function(e) {
// get the DOM element with the mousemove listener from the event
const {target} = e;
// get img child elements of the target.
// (use whatever css selector you need here. doesn't have to img)
const images = target.querySelectorAll('img');
// iterate over each item...
images.forEach(image => {
// ...and do whatever you need to do with it
const x = e.clientX;
const y = e.clientY;
image.style.top = (y + 20) + 'px';
image.style.left = (x + 20) + 'px';
})
});
I'm also not entirely sure what your end-goal is, but I'll take a stab at it.
I would recommend changing moveHover to being the class instead of the ID. Then you could do something like this:
var mouseHover = null;
window.onmousemove = function (e) {
if(mouseHover != null){
var x = e.clientX;
var y = e.clientY;
mouseHover.style.top = (y+20) + 'px';
mouseHover.style.left = (x+20) + 'px';
}
};
function onHover(e){
mouseHover = e.target.querySelector('.moveHover');
}
var elements = document.getElementsByClassName('imgHover');
for(var i = 0; i < elements.length; i++){
elements[i].onmouseenter = onHover;
}
The loop runs one time to set the onmouseenter event. Sure beats moving all .moveHover elements all the time.
I am looking for way to make page scroll on menu click.
My found place where to go. When I use translateY it work(but ofcouse I can't use it).
I need a scroll I tried to use scrollTop and scrollBy but it doesn't work for me.
What I do wrong?
function scroll(id: number) {
for (let k = 0; k < sectionsForScroll.length; k++) {
if (sectionsForScroll[k].dataset.navId == id) {
const bigginer = sectionsForScroll[0].getBoundingClientRect().top;
console.log( bigginer + 'px how far we from the start ');
const distanceToGo= sectionsForScroll[k].getBoundingClientRect().top;
console.log(sectionsForScroll[k].offsetTop);
const distanceToScroll = bigginer - distanceToGo;
console.log(distanceToGo + ' where we have to go ');
console.log(distanceToScroll + ' what the distanse we need to scroll ');
main.style.transform = 'translateY(' + distanceToScroll + 'px)';
// main.scrollTop=distanceToGo;
// window.scrollBy(0, distanceToGo);
}
}
}
window.scroll will work for you. Here is an example of scrolling 300px after clicking the scroll button.
Before using it you should checkout the compatibility table for the smooth option.
document.getElementById("myButton").addEventListener("click", scrollMe);
function scrollMe() {
window.scroll({
top: 300,
left: 0,
behavior: 'smooth'
});
}
.myDiv {
background-color: green;
height: 1000px;
}
<div class="myDiv">
<button id="myButton">Scroll</button>
</div>
I am using jquery function element.scrollTop() to get the current scroll position of the page using following line:
var currentScrollPosition= $('html').scrollTop() || $('body').scrollTop();
But it always return a value of previous scroll position. Please check the code below (which is same as is in here).
As you can try yourself and see in the code, after each tiny scroll, we get following series of values:
(1: when code is first run and no move is made yet)
delta:0
cumulativeDelta:0
functionCallCount:0
currentScrollPosition:0
(delta gives how much is scrolled, cumulativeDelta gives total amount of scroll, functionCallCount is how many times you scrolled and currentScrollPosition is value returned by scrolltop() )
(2: when scrolled a little)
delta:-120
cumulativeDelta:-120
functionCallCount:1
currentScrollPosition:0
(note here, currentScrollPosition is still not updated)
(3: when scrolled a little further)
delta:-120
cumulativeDelta:-240
functionCallCount:2
currentScrollPosition:90.90908893868948
(here, cumulativeDelta, which is addition of total scroll made so far, is doubled and currentScrollPosition is updated for the first time)
(4: when scrolled a little more)
delta:-120
cumulativeDelta:-360
functionCallCount:3
currentScrollPosition:181.81817787737896
(now, cumulativeDelta is tripled while currentScrollPosition is doubled. Hence, this is value after two scrolls but is updated adter 3 scrolls)
I apologize for long question, but would have been difficult to ask otherwise. I would like to know why is this happening and if I should use this function some other way there are any alternative to this function.
document.addEventListener("mousewheel", MouseWheelHandler);
var cumulativeDelta = 0,
functionCallCount = 0;
function MouseWheelHandler(e) {
e = window.event || e; // 'event' with old IE support
var delta = e.wheelDelta || -e.detail; // get delta value
cumulativeDelta += delta;
functionCallCount += 1;
currentScrollPosition = $('html').scrollTop() || $('body').scrollTop();
document.getElementById("info1").innerHTML = "delta:" + delta;
document.getElementById("info2").innerHTML = "cumulativeDelta:" + cumulativeDelta;
document.getElementById("info3").innerHTML = "functionCallCount:" + functionCallCount;
document.getElementById("info4").innerHTML = "currentScrollPosition:" + currentScrollPosition;
}
body {
height: 2000px;
border: solid red 3px;
}
.normalPart {
border: solid green 2px;
height: 900px;
}
.stationary {
position: fixed;
top: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<div class="stationary">
<div id="info1"></div>
<div id="info2"></div>
<div id="info3"></div>
<div id="info4"></div>
</div>
The issue is because the mousewheel event fires when the mousewheel movement starts. You are reading the scrollTop at the point before the update has happened. You need to use a timer to get the scrollTop after the mouse wheel scroll has finished. Try this:
document.addEventListener("mousewheel", MouseWheelHandler);
var cumulativeDelta = 0,
functionCallCount = 0,
currentScrollPosition = 0;
function MouseWheelHandler(e) {
e = window.event || e; // 'event' with old IE support
var delta = e.wheelDelta || -e.detail; // get delta value
cumulativeDelta += delta;
functionCallCount += 1;
setTimeout(function() {
currentScrollPosition = $(window).scrollTop();
document.getElementById("info4").innerHTML = "currentScrollPosition:" + currentScrollPosition;
}, 200); // update currentScrollPos 200ms after event fires
document.getElementById("info1").innerHTML = "delta:" + delta;
document.getElementById("info2").innerHTML = "cumulativeDelta:" + cumulativeDelta;
document.getElementById("info3").innerHTML = "functionCallCount:" + functionCallCount;
}
body {
height: 2000px;
border: solid red 3px;
}
.normalPart {
border: solid green 2px;
height: 900px;
}
.stationary {
position: fixed;
top: 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<div class="stationary">
<div id="info1"></div>
<div id="info2"></div>
<div id="info3"></div>
<div id="info4"></div>
</div>
Alternatively you could read the currentScrollTop position directly on the scroll event of the window as that will always be in sync with its current position.
I would listen for the scroll event instead of wheel. Scroll activates after the scrollTop value has been updated.
target.onscroll = functionRef
Great example here
I am creating a weird WYSIWYG from scratch using pure JS as an exercise. Here is my code thus far:
<style>
body {
height: 200px;
background: white;
}
.title1 {
height: 12px;
width: 100px;
background: white;
position: relative;
}
</style>
<script>
newTitle1 = function() {
var title1 = document.createElement("div")
title1.setAttribute("contentEditable", "true")
title1.innerHTML = "whatever";
title1.className = "title1";
title1.addEventListener("click", function() {
removeEventListener("click", newTitle1);
})
title1.style.left = (event.pageX -4) + "px";
title1.style.top = (event.pageY -4 ) + "px";
document.body.appendChild(title1)
}
addEventListener("click", newTitle1)
</script>
My question is specifically about
title1.addEventListener("click", function() {
removeEventListener("click", newTitle1);
})
I want removeEventListener to work while I click into the div that it just created. BUT, when I click outside of the div, I want newTitle1 to work.
Bottomline: I want newTitle1 listener to work outside of the div it just created, and not to work inside the div it creates. Any ideas how to make this happen? Here is a fiddle of my code to test if needed: https://jsfiddle.net/nirchernia/v3cLwb82/
You want to stop the event propagating. Solution shamelessly stolen from over here.
newTitle1 = function() {
var title1 = document.createElement("div")
title1.setAttribute("contentEditable", "true")
title1.innerHTML = "whatever";
title1.className = "title1";
title1.addEventListener("click", function(event) {
event.stopPropagation()
window.event.cancelBubble = true
})
title1.style.left = (event.pageX -4) + "px";
title1.style.top = (event.pageY -4 ) + "px";
document.body.appendChild(title1)
}
addEventListener("click", newTitle1)
/edit: And I think you want your .title1 CSS to have position:absolute; too :)
I'm making a drag and drop engine in JavaScript, and I don't know how to set the correct position of the dragObj because it changes depending on the parent element's positioning type (Does the dragObj also change depending on its parent's "parent element" ect.?).
So, my dragObj looks like this:
function makeObj(event) {
var obj = new Object();
var e = event.target;
obj.element = e;
obj.boundElement = null;
while(e = e.parentNode) {
if(~e.className.search(/bound/)) { //if(/bound/.test(e.className)) {
obj.boundElement = e;
break;
}
}
if(obj.boundElement == null)
obj.boundElement = document.body;
// I would like to find the correct minimum bounds with findPos(); however, I need
// findPos() to work with every type of positioning (absolute, relatice, ect.)
//var elemPos = findPos(obj.boundElement);
//obj.minBoundX = elemPos.x;
//obj.minBoundY = elemPos.y;
obj.minBoundX = obj.boundElement.offsetLeft + obj.boundElement.offsetWidth - obj.element.offsetWidth;
obj.minBoundY = obj.boundElement.offsetTop + obj.boundElement.offsetHeight - obj.element.offsetHeight;
obj.maxBoundX = obj.boundElement.offsetLeft;
obj.maxBoundY = obj.boundElement.offsetTop;
setHelperBoxPos(obj);
obj.posX = event.clientX - obj.element.offsetLeft;
obj.posY = event.clientY - obj.element.offsetTop;
return obj;
}
So, when I make a dragObj, I also set its "position" and its bounding element. In a comment portion right before I set the .minBoundX and .minBoundY attributes I explain how I would like to set them; however, it doesn't work because the findPos() function doesn't work.
Here is the findPos() function:
function findPos(obj) { // Donated by `lwburk` on StackOverflow
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return { x: curleft, y: curtop };
}
}
I believe this function works if the bounding element has position: absolute; set, but I want the user to be able to set its positioning type. Also, the bounding element is set by the .bound class, and the dragObj is set by the .drag class.
Here's the HTML:
<div id="min" class="helper-box" style="border: 1px solid blue;"></div>
<div id="max" class="helper-box" style="border: 1px solid red;"></div>
<div id="center">
<h1>Hello World! <hr /></h1>
<div id="box" class="bound">
<p class="drag square"> One </p>
<p class="drag square"> Two </p>
</div>
</div>
And here is the CSS:
#charset "utf-8";
/* CSS Document */
* {
padding: 0px;
margin: 0px;
}
body {
background-color:#DFDFDF;
}
.drag {
position: absolute;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
.bound {
;
}
.square {
width: 100px;
height: 100px;
background: #1047A9;
cursor:move;
border-radius: 25px;
-moz-border-radius: 25px;
}
#center {
width: 500px;
margin: auto;
margin-top: 50px;
background-color: #29477F;
color: #E8E8E8;
text-align: center;
border-radius: 25px;
-moz-border-radius: 25px;
}
#box {
background-color: #009EBE;
height: 275px;
border-radius: 0 0 25px 25px;
-moz-border-radius: 0 0 25px 25px;
opacity: 1.0;
}
.helper-box {
position: absolute;
width: 5px;
height: 5px;
}
And here is the entire engine:
// JavaScript Document
var dragObj;
document.addEventListener("mousedown", down, false);
function down(event) {
if(~event.target.className.search(/drag/)) {
dragObj = makeObj(event);
dragObj.element.style.zIndex="100";
document.addEventListener("mousemove", freeMovement, false);
}
}
function freeMovement(event) {
if (typeof(dragObj.element.mouseup) == "undefined")
document.addEventListener("mouseup", drop, false);
//Prevents redundantly adding the same event handler repeatedly
dragObj.element.style.left = Math.max(dragObj.maxBoundX, Math.min(dragObj.minBoundX, event.clientX - dragObj.posX)) + "px";
dragObj.element.style.top = Math.max(dragObj.maxBoundY, Math.min(dragObj.minBoundY, event.clientY - dragObj.posY)) + "px";
}
function drop() {
dragObj.element.style.zIndex="1";
document.removeEventListener("mousemove", freeMovement, false);
document.removeEventListener("mouseup", drop, false);
//alert("DEBUG_DROP");
}
function makeObj(event) {
var obj = new Object();
var e = event.target;
obj.element = e;
obj.boundElement = null;
while(e = e.parentNode) {
if(~e.className.search(/bound/)) { //if(/bound/.test(e.className)) {
obj.boundElement = e;
break;
}
}
if(obj.boundElement == null)
obj.boundElement = document.body;
// I would like to find the correct minimum bounds with findPos(); however, I need
// findPos() to work with every type of positioning (absolute, relatice, ect.)
//var elemPos = findPos(obj.boundElement);
//obj.minBoundX = elemPos.x;
//obj.minBoundY = elemPos.y;
obj.minBoundX = obj.boundElement.offsetLeft + obj.boundElement.offsetWidth - obj.element.offsetWidth;
obj.minBoundY = obj.boundElement.offsetTop + obj.boundElement.offsetHeight - obj.element.offsetHeight;
obj.maxBoundX = obj.boundElement.offsetLeft;
obj.maxBoundY = obj.boundElement.offsetTop;
setHelperBoxPos(obj);
obj.posX = event.clientX - obj.element.offsetLeft;
obj.posY = event.clientY - obj.element.offsetTop;
return obj;
}
function findPos(obj) { // Donated by `lwburk` on StackOverflow
var curleft = curtop = 0;
if (obj.offsetParent) {
do {
curleft += obj.offsetLeft;
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return { x: curleft, y: curtop };
}
}
function setHelperBoxPos(obj) {
var minBox = document.getElementById('min');
minBox.style.left = obj.minBoundX + 'px';
minBox.style.top = obj.minBoundY + 'px';
var maxBox = document.getElementById('max');
maxBox.style.left = obj.maxBoundX + 'px';
maxBox.style.top = obj.maxBoundY + 'px';
}
I have also made a jsfiddle for your convenience: http://jsfiddle.net/2XGhK/
So, how do I make a findPos() function which allows for different kinds of positioning. Will I need to make another findPos() function to allow the dragObj to be any kind of positioning as well?
Important Please do not recommend using a library (unless you suggest looking at it for tips on how they deal with positioning).The reason is that I am just learning the language and building things helps me do just that. What's the point in learning a library before I even understand the language?
Most importantly, I greatly appreciate all of your help. Thank you.
In developing Javascript, jQuery really is your best friend, as it simplifies many of these (potentially annoying) tasks. I totally dig the desire to learn without them though; it's a great way to become proficient.
Take a look at jQuery's docs and implementation for position and offset, and hopefully that will give you a good idea for a starting place.
Docs:
http://api.jquery.com/position/
http://api.jquery.com/offset/
Source:
https://github.com/jquery/jquery/blob/master/src/offset.js
I don't know if this is exactly what you need but implementing drag&drop with javascript requires a lot of efforts and testing, especially when you are dealing with parent-children dragging.
Try this one:
http://interface.eyecon.ro/demos/drag.html
Maybe you can read its source code and use it to fit your needs.
Simply make drag object's position absolute -
obj.element = e;
obj.element.style.position = "absolute";
obj.boundElement = null;
btw, thanks for using jsfiddle, it helps.
How useful is this code fragment?
var position = {};
var dragObj = "";
function initDrag(e){
e = e || window.event;
position.objLeft = parseInt(dragObj.style.left);
position.objTop = parseInt(dragObj.style.top);
if( isNaN(position.objLeft) )
position.objLeft = 0;
if( isNaN(position.objTop) )
position.objTop = 0;
position.startX = e.clientX;
position.startY = e.clientY;
if( document.addEventListener )
{
e.preventDefault();
dragObj.addEventListener('mousemove',startDrag,false);
dragObj.addEventListener('mouseup',stopDrag,false);
dragObj.addEventListener('mouseout',stopDrag,false);
}
else
{
dragObj.attachEvent('onmousemove',startDrag);
dragObj.attachEvent('onmouseup',stopDrag);
dragObj.attachEvent('onmouseout',stopDrag);
}
}
function startDrag(e){
e = e || window.event;
dragObj.style.left = position.objLeft+e.clientX-position.startX;
dragObj.style.top = position.objTop+e.clientY-position.startY;
return false;
}
Actually when working with finding the elements position, you use its offsetLeft(/Top). And each element have an offsetParent from where that position origins. When you drag an element, it is good to know it's position according to the whole document (read ), so you get a more precise point. So to find an elementes position you must create the following function:
function findPos(elm) {
var testElm = elm, pos = {x:0, y:0};
while( !!testElm && testElm.tagName.toLowerCase() !== "body" ) {
pos.x += testElm.offsetLeft;
pos.y += testElm.offsetTop;
// important to use offsetParent instead of just parentNode,
// as offsetParent will be where the element gets its offset from.
// And that is not necesarily it parentNode!
testElm = testElm.offsetParent;
}
return pos;
}
But i agree with some of the others, that jQuery DO simplify alot of these tedious calculations. But I really think it is best to get to know JS before you use the API's as it give you an understading of what JS really is.
PS. Dont call this method for every mousemove event, as it will compromise performance. Intead save the value on the element (<your node>["startoffset"] = findPos(<your node>)), and then use it in the mousemove script to find its new position. Actually it is good practice, to save as many values you can upon mousedown, as mousemove will be called ALOT, and therefore should perform as little calculations/traversing as possible.
See it in action: http://jsfiddle.net/fnwxu/22/
Simplest solution:
Set the element to visibility:hidden. Clone the element, set the clone to position:absolute, perform dragging. Once dragging stops (i.e. the user has released the left mouse button), replace the clone with the original element.
This allows you to keep the element in flow for the duration of the draggable operation. That way if the element cannot be dropped in location y (for example), you can have the helper snap back to the original location.
I am a beginner in JavaScript. I found your question very interesting and thought of Googling it. I found these two links which may be of use to you:
http://www.codingforums.com/archive/index.php/t-84055.html
http://www.codeproject.com/KB/scripting/DragDrop_Part-2.aspx