How to drag & drop select -option element with Vanilla JS - javascript

I have recently tried to drag option box content in select element. It seems that ca not be done - drag doesn't fire at all.
I consider redesign this element totally that it will act & look as Select. Other option with jQuery is described here:
https://stackoverflow.com/questions/ask
In my case it must be done with Vanilla.JS.
I can of course back-engineer the above code, however maybe someone knows other working solution?

Make the element you wish to drag absolute and place it above the rest of the content using z-index. Then get the x and y coordinates of the element. Move the element directly into the body, center the element on pointer. Add an event listener for mousemove using a function to center the element at the page x/y coords. Function to drop element when you release the mouse button .onmouseup, this would remove all event listeners relevant to the moving of the element.
NOTE: This is very basic, more code would have to be used to determine page constraints in case user drags element out of the page bounding.
let drag = document.getElementById('draggableSpan');
drag.onmousedown = function(event) {
// make element absolute and place it on top with z-index
drag.style.position = 'absolute';
drag.style.zIndex = 1000;
let shiftX = event.clientX - drag.getBoundingClientRect().left;
let shiftY = event.clientY - drag.getBoundingClientRect().top;
// move it out of any current parents directly into body
// to make it positioned relative to the body
document.body.append(drag);
// function that centers the element at (pageX, pageY) coordinates
function moveTo(pageX, pageY) {
drag.style.left = pageX - shiftX + 'px';
drag.style.top = pageY - shiftY + 'px';
}
// move the absolutely positioned element under the pointer
moveTo(event.pageX, event.pageY);
function onMouseMove(event) {
moveTo(event.pageX, event.pageY);
}
// move the element on mousemove with event listener
document.addEventListener('mousemove', onMouseMove);
// drop the element on the page by removing eventlisteners that
// are relavent to the moving of the element
drag.onmouseup = function() {
document.removeEventListener('mousemove', onMouseMove);
drag.onmouseup = null;
};
};
<div class='parent'>
<span id='draggableSpan'>
draggable
</span>
</div>

Related

How to release object after drag-drop in Javascript

I found this interesting example for a javascript Drag/Drop on https://codepen.io/islempenywis/pen/VXqJVY.
However, there is an issue with it that if you click on the top of the "TODO Item" rectangle, after drag (MouseDown + Drag + MouseUp) it is not possible to drop this item; it sticks to the cursor and travels with it :/
MouseUp is a simple function, nothing fancy :
function onMouseUp(e, item) {
isMouseDown = false;
item.style.backgroundColor = "#F44336";
}
Since I can replicate it with Chrome, Edge and Firefox, I am guessing that this is a code problem but can't find out what that would be.
Please help.
Geo
There is a miscalculation in the onMouseMove event handler:
item.style.top = e.clientY + mouseOffset.y + "px";
When you move the mouse while holding the "TODO" item, the top of the whole element, including its margin, is being placed on the vertical coordinate of the viewport (e.clientY) where you clicked and adjusted to the point in the element where you clicked (+ mouseOffset.y), so the element moves along with the cursor. But it is ignoring its margin. If you pay attention, when you click and move the item, it will move down slightly. Those are 10 pixels of margin. When you click on the top, the element will be placed slightly down the cursor, the cursor will lose it, and it gets bugged. To fix, you have to substract the margin in the calculation.
item.style.top = e.clientY - 10 + mouseOffset.y + "px";

Mousemove Event: mouse position relative to parent element

I have a div that I want to listen to the mousemove event to see the offset between the mouse and the top of the div (so I use event.layerY). Inside this div I have another div.
The problem is when I move my mouse over this inner div, my mousemove event listens to the inner div and not the outer div where I set the listener to. Meaning event.layerY will give me the offset to the inner div and not the outer div.
This is my code:
this.draglistener = this.renderer.listen(this.container.nativeElement, 'mousemove', e => {
e.stopPropagation();
});
As you can see I tired stopPropagation()but that doesn't work.
I also tried this:
if (e.target !== this.container.nativeElement) {
return;
}
But this way it just stops listening to the event when moving over the inner div. So thats not working too.
Also I can't do pointer-events: none; for the inner div because I need to listen to some other events on this div.
Any Ideas?
To get the mouse position relative to the outer div, subtract the client position of the outer div from the client position of the mouse. A template reference variable outerDiv can be used to pass the outer element to the event handler.
<div #outerDiv (mousemove)="onMouseMove($event, outerDiv)">
<div class="innerDiv">
</div>
</div>
In the event handler, the client mouse position is obtained with event.clientX and event.clientY, and the outer div client position is obtained with outerDiv.getBoundingClientRect().
onMouseMove(event: MouseEvent, outerDiv: HTMLElement) {
const bounds = outerDiv.getBoundingClientRect();
const posX = event.clientX - bounds.left;
const posY = event.clientY - bounds.top;
console.log(posX, posY);
}
See this stackblitz for a demo.

CSS background position relative to cursor

I'm wondering how to do an effect like this:
http://www.gazprom.com/
(please note, the moving blue background, in top blue menu), and its relativity to cursor position)
Is there any script that follows cursor and changes background position style?
This effect can be achieved using small piece of JavaScript:
JavaScript
document.addEventListener('mousemove', function (event) {
if (window.event) { // IE fix
event = window.event;
}
// Grab the mouse's X-position.
var mousex = event.clientX;
var header = document.getElementById('header');
header.style.backgroundPosition = mousex/3 + 'px 0';
}, false);
Working Demo
How it works :
It binds a function on the mousemove event on document.
It grabs the current mouse position using event.clientX.
It changes the background-position of element #header with 1/3rd of the speed (mousex/3). Reference

Mouse event: Getting mouse coords from base level element

I have a layout similar to
<div id="outer">
<div id="inner"></div>
</div>
with a mouse event for the 'outer' element.
I am accessing the mouse coords of the event using jQuery's mouseup event with the layerX and layerY values.
When a click is received on the 'inner' element, it gives the coords of the click relative to the 'inner' element. Is it possible that when a click is given to the element, it can give the mouse coords relative to the outer element
Basic overview of what I have:
$('#outer').mouseup(function(e){
// do stuff with
//e.layerX
//e.layerY
}
jQuery doesn't have a built in way to do this, however you could calculate what you are looking for in the way you are describing. However a simpler way would be to always get the mouse position relative to the document, and then subtract the #outer elements position relative to the document:
var $outer = $('#outer');
$outer.mouseup(function(e) {
var offset = $outer.offset();
var x = e.pageX - offset.left;
var y = e.pageY - offset.top;
});

How to solve - DIV element flashes/disappears immediately after it is rendered

Here's what is happening:
After the page loads, JavaScript reads an XML from the underlying code
The XML contains a bunch of field-ids, and corresponding content to display in popups when the mouse hovers over a field id listed
My code generates a bunch of popups as div-elements with the styles:
.render{
background-color: #fffc80;
border: .1em solid rgb(200, 128, 0);
padding-left: 2px;
padding-right: 2px;
z-index: 1000;
}
.hide{
display:none;
}
All created popups are attached to the root element.
EDITED: Added script snippets
The event handlers are attached as below
// instantiate a div element
var myDiv = document.createElement('div');
// generate an ID
myDiv.id = generatePopupId(getFieldId());
// attach the content from the XML into the new div element
myDiv.innerHTML = getPopupContent();
// apply mouseover/out handlers to the main element
document.getElementById(getFieldId()).onmouseover = function(){
showPopup(generatePopupId(getFieldId()));
};
document.getElementById(getFieldId()).onmouseout = function(){
hidePopup(generatePopupId(getFieldId()));
};
// read the X coordinate of the present position of the mouse
function getX(){
var e = window.event;
posX = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
return posX;
}
// read the Y coordinate of the present position of the mouse
function getY(){
var e = window.event;
posY = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
return posY;
}
// Show the popup element at the current mouse location
function showPopup(popupId){
var posX = getX();
var posY = getY();
var poppyElement = document.getElementById(popupId);
poppyElement.className = 'render';
poppyElement.style.left = posX;
poppyElement.style.top = poxY;
poppyElement.style.position = 'absolute';
poppyElement.style.display = '';
}
// hide the popup element
function hidePopup(popupId){
var poppyElement = document.getElementById(popupId);
poppyElement.className = 'hide';
}
My question is - Why does the element flash, and disappear immediately instead of hanging around for the mouse-out event?
Changing the elements in the JavaScript may be modifying the element being hovered over, which may trigger the mouse out event by changing, rather than actually moving the mouse out of the co-ordinates.
Firstly, you need to be more careful with case sensitivity. It should be clientWidth (capital W) and top (small t). Secondly, when you set CSS left and top you must add a +'px' suffix to the value; an integer on its own is not valid.
Also if you want to know the height of the viewport, document.body is the wrong place to look. This will only work in IE Quirks Mode, which you generally want to avoid like the plague. Add a Standards Mode <!DOCTYPE declaration and you can use document.documentElement across browsers. (Or branch on window.innerHeight for non-IE browsers.)
In any case unless there is more CSS you aren't showing us, setting the left and top styles will have no effect at all because the .render divs are not position: absolute. You're not showing how exactly they are attached to the document, but since they are apparently not absolutely positioned, they're part of the document flow and may cause the page to shift/reflow when they're unhidden. If that causes the element being moused over to move, it will no longer be under the pointer and you'll get a mouseout event immediately.
(This would also happen with absolute positioning if the hovered item was underneath the place the pop-up appeared.)
(Also, the hiding/unhiding is a bit redundant. Leave style.display alone and just set className to either 'render' or 'render hide'.)

Categories