I use this code for dragging a DIV, which is a small information box.
Within, I have some simple HTML including a input text or similar. When enabling the drag (see code) all inputs are frozen.
var selected = null, // Object of the element to be moved
x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
x_elem = x_pos - selected.offsetLeft;
y_elem = y_pos - selected.offsetTop;
}
// Will be called when user dragging an element
function _move_elem(e) {
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = (x_pos - x_elem) + 'px';
selected.style.top = (y_pos - y_elem) + 'px';
}
}
// Destroy the object when we are done
function _destroy() {
selected = null;
}
document.onmousemove = _move_elem;
document.onmouseup = _destroy;
There is a bigger code here, so I will simplify:
div = document.getElementById("mydiv");
div.onmousedown = function () {
_drag_init(this);
return false;
};
Now when I display the DIV, the drag works smoothly (FF 53) but any input elements within are frozen :)
The content of my infobox (the DIV) is simple
<input id="input_text" type="text" name="product" list="productName"/>
<datalist id="productName">
<option value="Pen">Pen</option>
<option value="Pencil">Pencil</option>
<option value="Paper">Paper</option>
</datalist><br> <button id="myNiceButton" action="input_text">OK</button>
I already tried bunch of solutions from StackOverflow without success, including eg. this one
Prevent drag event to interfere with input elements in Firefox using HTML5 drag/drop
<div draggable="true" id="draggableDiv">
<textarea onfocus="onFocus();" onblur="onBlur();">Inside draggable (FIXED)</textarea>
</div>
But seems that those events are not triggered at all. Also tried draggable="false" but the same story, not working.
What will be the problem?
Actually the drag code is fine.
div.onmousedown = function () {
_drag_init(this);
return false; // <-- remove this
};
Or play with preventdefault() which one suits best.
event.preventDefault() vs. return false
return false here will prevent any mouse "down" so I guess it's impossible to click in input text with the mouse, acting like "disabled".
Related
I'm working on a javascript draggable interaction that has to work with both mouse and touch input and does not have any dependencies. So far it works fine on desktops and mobiles.
Except Firefox for Android shows the following behaviour:
page is not scrolled: fine
page is scrolled vertically: element can only be dragged horizontally
page is scrolled horizontally: element can only be dragged vertically
page is scrolled both vertically and horizontally: element can't be
dragged at all
scroll page back to the very top and left: element can be dragged as
expected again
The code:
var evtStart, evtMove, evtEnd;
if ('ontouchend' in window) {
evtStart = 'touchstart';
evtMove = 'touchmove';
evtEnd = 'touchend';
} else {
evtStart = 'mousedown';
evtMove = 'mousemove';
evtEnd = 'mouseup';
}
// BASIC DRAGGABLE INTERACTION
// No further configuration, just drags ....
var panel = document.querySelector('.testpanel');
panel.addEventListener(evtStart, function(e) {
e.preventDefault();
var styles = window.getComputedStyle(panel),
left = parseFloat(styles.left), // css left on mousedown
top = parseFloat(styles.top), // css top on mousedown
psx = e.pageX || e.touches[0].pageX, // pointer x on mousedown
psy = e.pageY || e.touches[0].pageY; // pointer y on mousedown
// function actually draging the elmt
var drag = function (e) {
e.preventDefault();
var pmx = e.pageX || e.touches[0].pageX, // current pointer x while pointer moves
pmy = e.pageY || e.touches[0].pageY; // current pointer y while pointer moves
panel.style.left = left + (pmx - psx) + 'px'; // set new css left of elmt
panel.style.top = top + (pmy - psy) + 'px'; // set new css top of elmt
};
panel.addEventListener(evtMove, drag);
panel.addEventListener(evtEnd, function () {
panel.removeEventListener(evtMove, drag);
});
});
Demo page
Again, it works fine on desktop and mobiles except FF for Android.
Why does it not work on FF for Android? Is it something in my code or is it a bug in FF? So far I could not find anything helpful.
I would greatly appreciate any help.
Finally I found it myself:
Just swap pageX/pageY with clientX/clientY and it works in FF for Android as well.
I guess the implementation in FF for Android is somewhat different, pageX/pageY are not finalized standards yet according to MDN.
I'm working on a small thing where I want the user to be able to create any number of small window objects and then move them around independently on the screen like you would with normal windows. Later I will try to make it so that you can only grab the uppermost part of the windows.
The window objects will all be of the same type, WindowObject, or at least that's been the idea up until now.
The first thing I tried was putting the functionality inside of the objects themselves.
Html
<div id="container">
<div style="width:100px; height:100px; background-color:red">example</div>
<div style="width:100px; height:100px;background-color:red">example</div>
</div>
JavaScript
var WindowObject = function() {
this.xPos = 0;
this.yPos = 0;
};
WindowObject.prototype.addListeners = function() {
this.test1 = this.mouseDown.bind(this);
this.test2 = this.mouseUp.bind(this);
this.container = document.querySelector("#container");
this.container.addEventListener("mousedown", this.test1, false);
window.addEventListener("mouseup", this.test2, false);
};
WindowObject.prototype.move = function(event) {
event.target.style.position = "absolute";
event.target.style.top = (event.clientY - this.yPos) + "px";
event.target.style.left = (event.clientX - this.xPos) + "px";
};
WindowObject.prototype.mouseUp = function() {
window.removeEventListener("mousemove", this.test3, true);
};
WindowObject.prototype.mouseDown = function(event) {
this.xPos = event.clientX - event.target.offsetLeft;
this.yPos = event.clientY - event.target.offsetTop;
this.test3 = this.move.bind(this);
window.addEventListener("mousemove", this.test3, true);
};
This kind of works if you drag the divs very slowly (so that the mouse never leaves them) and also make sure not to overlap other elements. Otherwise the position of the div gets messed up and if there are more than one you may find yourself dragging several divs at the same time.
I also tried putting the functionality in a different kind of object, with some smaller adjustments, but the result was the same.
If you think I should try a different approach all together, please let me know. If not, what am I doing wrong?
I need to trigger mousedown event in dynamically changed element. I am making a image galary where if I click on small image then large image should be displayed with high quality image and user can view image by dragging large image in small div. For this is just changing the src of large image container image from jquery. Below is my code:
$(document).on("click", "#thumb_img", function () {
$("#loading").show();
var smallimg = $(this).attr("src");
var img = new Image();
img.src = smallimg.replace('thumbnail/', 'images/');
img.onload = function () {
$(".large-img").prop("src", this.src);
$("#loading").hide();
};
$("img.large-img").css({
width: "500px",
height: "100%",
position: "unset"
});
});
Above code changes the src of large image when small image is clicked and below code is for enabling drag on the large image generated.
var selected = null, // Object of the element to be moved
x_pos = 0, y_pos = 0, // Stores x & y coordinates of the mouse pointer
x_elem = 0, y_elem = 0; // Stores top, left values (edge) of the element
// Will be called when user starts dragging an element
function _drag_init(elem) {
// Store the object of the element which needs to be moved
selected = elem;
x_elem = x_pos - selected.offsetLeft;
y_elem = y_pos - selected.offsetTop;
}
// Will be called when user dragging an element
function _move_elem(e) {
// alert("ASdf");
x_pos = document.all ? window.event.clientX : e.pageX;
y_pos = document.all ? window.event.clientY : e.pageY;
if (selected !== null) {
selected.style.left = (x_pos - x_elem) + 'px';
selected.style.top = (y_pos - y_elem) + 'px';
}
}
// Destroy the object when we are done
function _destroy() {
selected = null;
}
// Bind the functions...
document.getElementById('large-img').onmousedown = function () {
_drag_init(this);
return false;
};
document.onmousemove = _move_elem;
document.onmouseup = _destroy;
This code works fine when page loads first time. Then When I clicked in another small image and It doesn't works.
EDITED
I had mentioned my code in JSFIDDLE. You can see the image is draggable when page loads in large image container but when you click on other thumbnail and try to drag the image in large image container then drag event is not triggering.
position: "unset" is the problem. Removed it and the problem gone.
http://jsfiddle.net/3abLhrep/3/
From your description and code, it looks like you have more than one element with id thumb_img, but IDs must be unique.
I am currently working on an online presentation software. For the sake of this question imagine it as powerpoint or keynote.
I want to be able to add elements to the slide and then drag them around (live), getting the new position, updating the database.
However I want to do this without any use of external libraries or frameworks, including jQuery.
Can anyone point me in a direction for my research? My current ideas to implement this are pretty messy. Especially the live-dragging is what's giving me headaches.
Thanks!
UPDATE!
the elements look something like this:
<div class="textelement"
data-id="528fc9026803fa9d4b03e506"
data-role="Textelement"
style=" left: 50px;
top: 50px;
z-index: 0;
width: 72px;
height: 72px;">
<div class="textnode">slide: 0 textelement: 0</div>
</div>
While HTML5 does provide native drag and drop, this isn't what you asked for. Check out this simple tutorial to accomplish dragging in vanilla JS: http://luke.breuer.com/tutorial/javascript-drag-and-drop-tutorial.aspx
There is great vanilla JS snippet available, but with one problem - when element start dragged on clickable element, it "clicks" on mouseup: see it on http://codepen.io/ekurtovic/pen/LVpvmX
<div class="draggable">
Dont click me, just drag
</div>
<script>
// external js: draggabilly.pkgd.js
var draggie = new Draggabilly('.draggable');
</script>
here is the "plugin": draggabilly
And, here is my independent solution, working by :class: of the element:
(function (document) {
// Enable ECMAScript 5 strict mode within this function:
'use strict';
// Obtain a node list of all elements that have class="draggable":
var draggable = document.getElementsByClassName('draggable'),
draggableCount = draggable.length, // cache the length
i; // iterator placeholder
// This function initializes the drag of an element where an
// event ("mousedown") has occurred:
function startDrag(evt) {
that.preventDefault();
// The element's position is based on its top left corner,
// but the mouse coordinates are inside of it, so we need
// to calculate the positioning difference:
var diffX = evt.clientX - this.offsetLeft,
diffY = evt.clientY - this.offsetTop,
that = this; // "this" refers to the current element,
// let's keep it in cache for later use.
// moveAlong places the current element (referenced by "that")
// according to the current cursor position:
function moveAlong(evt) {
evt.preventDefault();
var left = parseInt(evt.clientX - diffX);
var top = parseInt(evt.clientY - diffY);
// check for screen boundaries
if (top < 0) { top = 0; }
if (left < 0) { left = 0; }
if (top > window.innerHeight-1)
{ top = window.innerHeight-1; }
if (left > window.innerWidth-1)
{ left = window.innerWidth-1; }
// set new position
that.style.left = left + 'px';
that.style.top = top + 'px';
}
// stopDrag removes event listeners from the element,
// thus stopping the drag:
function stopDrag() {
document.removeEventListener('mousemove', moveAlong);
document.removeEventListener('mouseup', stopDrag);
}
document.addEventListener('mouseup', stopDrag);
document.addEventListener('mousemove', moveAlong);
return false;
}
// Now that all the variables and functions are created,
// we can go on and make the elements draggable by assigning
// a "startDrag" function to a "mousedown" event that occurs
// on those elements:
if (draggableCount > 0) for (i = 0; i < draggableCount; i += 1) {
draggable[i].addEventListener('mousedown', startDrag);
}
}(document));
without jquery
basically what I am looking for is the ability to see if the mouse is over a div when a countdown finishes
if the user is over the div then perform action for that div
onmouseover only triggers when the mouse crosses the threshold of the div, if the mouse hasn't moved it wouldn't trigger, so that wouldn't work
I need to determine if the mouse is currently over a div at a specific point in time, if it has moved or not from the starting point
all of my hunting has only found onmousover, and nothing to see if the mouse just happens to be there to begin with
I don't have the javascript skills to determine overall coords of div, then map mouse coords and see if it fits there... which is what I believe I need to do
After reading the second answer (the one with millions of a elements) on this SO question, I've came up with this method works without moving the mouse on page load, without involving millions of elements.
HTML
<div id=t></div>
CSS
#t {
/* for illustrative purposes */
width: 10em;
height: 5em;
background-color: #0af;
}
#t:hover {
border-top-style: hidden;
}
JavaScript
document.addEventListener('click', function () {
var c = window.getComputedStyle(document.getElementById('t')).getPropertyValue('border-top-style');
if (c === 'hidden') {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
As stated earlier, bind to the finish event of your countdown instead of the click event on the document.
You may also use any CSS style that's changed on :hover, I chose border-top-style as it is conspicuous. If you're using a border, choose something else.
Here's a jsFiddle.
set a flag to true onmouseover and to false onmouseleave. when countdown finishes if flag is true then it is over element.
HTML
<div id="div-name">the section of the code i am working with has a countdown timer, when it reaches 0 i need to know if the mouse is over a specific box</div>
<button id="notification" onclick="javascript: letsCountIt(5);">click to start countdown</button>
JS
window.ev = false;
document.getElementById('div-name').onmouseover = function () {
window.ev = true;
console.log(window.ev);
}
document.getElementById('div-name').onmouseout = function () {
window.ev = false;
console.log(window.ev);
}
window.letsCountIt = function (cdtimer) {
cdtimer--;
document.getElementById('notification').innerHTML = cdtimer;
if (cdtimer == 0) {
if (window.ev === true) {
alert('over');
} else {
alert('not over');
}
} else {
setTimeout(function(){letsCountIt(cdtimer);}, 1000);
}
}
Look into document.elementFromPoint . When you pass an x,y to elementFromPoint, it will return whatever element (or <body>, if no other specific element) is at that point. You can easily check if this element is the element you want.
The problem then is finding out what point your mouse is at. How to get the mouse position without events (without moving the mouse)? seems to say - don't. At least use mouseMove to track the cursor. The linked question gives examples of how to do so. (Look to the lower scoring answers, as the higher ones only got points for being snarky.)
Just want to say that, I think jQuery's mouseenter and mouseleave events would make this a lot easier, but if you can't use them, maybe this will help you.
Depending on how your page is laid out, this may not be too difficult. You can get the position of your element using the following. Quoting from another answer
element.offsetLeft and element.offsetTop are the pure javascript
properties for finding an element's position with respect to its
offsetParent; being the nearest parent element with a position of
relative or absolute
So, if your element is positioned relatively to the body, so far so good (We don't need to adjust anything).
Now, if we attach an event to the document mousemove event, we can get the current coordinates of the mouse:
document.addEventListener('mousemove', function (e) {
var x = e.clientX;
var y = e.clientY;
}, false);
Now we just need to determine if the mouse falls within the element. To do that we need the height and width of the element. Quoting from another answer
You should use the .offsetWidth and .offsetHeight properties. Note
they belong to the element, not .style.
For example:
var element = document.getElementById('element');
var height = element.offsetHeight;
var width = element.offsetWidth;
Now we have all the information we need, and just need to determine if the mouse falls within the element. We might use something like this:
var onmove = function(e) {
var minX = element.offsetLeft;
var maxX = minX + element.offsetWidth;
var minY = element.offsetTop;
var maxY = minY + element.offsetHeight;
if(e.clientX >= minX && e.clientX <= maxX)
//good horizontally
if(e.clientY >= minY && e.clientY <= maxY)
//good vertically
}
This code works, but the mouse has to be moved once after page load.
var coords;
var getMouseCoordinates = function (e) {
'use strict';
return {
x: e.clientX,
y: e.clientY
};
};
document.addEventListener('mousemove', function (e) {
coords = getMouseCoordinates(e);
}, false);
document.addEventListener('click', function () {
var divCoords = document.getElementById('t').getBoundingClientRect();
if (coords.x >= divCoords.left && coords.x <= divCoords.right && coords.y >= divCoords.top && coords.y <= divCoords.bottom) {
alert('Mouse in box');
} else {
alert('Mouse not in box');
}
}, false);
You wouldn't bind to the click event of document, but rather the finish event of your countdown.
Here's an example. Try clicking in the output window.
You don't need any coordinates or mouse events, if you know a selector for that element:
if (document.querySelector('#elementSelector:hover')) {
alert('I like it when you touch me!');
}