Touch drag-and-drop positioning near tap with JS - javascript

I want to make function to drag and drop some elements on my page. When I use code below, the element moves by touch, but it is not staying near finger where I tapped (for expample in the center or left/right bottom of the element), but it moves to right bottom from the finger. What I want - is to be able to move element dragging it by point where I tapped.
function touchStart(e) {
e.preventDefault();
var whichArt = e.target;
resetZ();
whichArt.style.zIndex = 10;
}
function touchMove(e) {
e.preventDefault();
var dragElem = e.target;
var touch = e.touches[0];
var positionX = touch.pageX;
var positionY = touch.pageY;
dragElem.style.left = positionX + 'px';
dragElem.style.top = positionY + 'px';
}
document.querySelector('body').addEventListener('touchstart', touchStart, false);
document.querySelector('body').addEventListener('touchmove', touchMove, false);
<!--elements I want to drag-->
<img draggable="true" id="one" src="images/one.svg" style="position: absolute; left: 50px; top: 120px; z-index: 3;">
<img draggable="true" id="two" src="images/two.svg" style="position: absolute; left: 367px; top: 150px; z-index: 3;">
I also tried to different things to calculate left and right position, but it failed, for example:
var moveOffsetX = dragElem.offsetLeft - touch.pageX;
var moveOffsetY = dragElem.offsetTop - touch.pageY;
var positionX = touch.pageX - moveOffsetX; /* + also tried*/
var positionY = touch.pageY - moveOffsetY; /* + also tried*/
So how is it possible to accomplish the right behaviour?

It happens because the anchor point of the element is on the top left corner.
Try this in your touchMove function:
dragElem.style.left = positionX - dragElem.width / 2 + 'px';
dragElem.style.top = positionY - dragElem.height / 2 + 'px';
Here is a working fiddle. You can test it on chrome using the device mode in the developer tools.
PS. you should have a touchend event to re-initialize the z-index (if you did not already do that).
Edit
So, in the touchstart event , you must save the anchor of the element (where the user touched the element).
To do so, you can use getBoundingClientRect() function. It's better than to depend on the style, top/left attributes because they may not be specified :
var elementRect = whichArt.getBoundingClientRect();
anchor = {
top: touch.pageY - elementRect.top,
left: touch.pageX - elementRect.left
};
And then you use this anchor to compute top/left instead of the center of the element (as I thought at first).
Here is the updated fiddle

Related

When the drag event is fired in Firefox, the mouse coordinates are (0,0)

I want to make a mobile phone theme effect on the browser, and I need to make the icon get the current mouse position when it is dragged. In order to judge whether the user wants to insert the currently dragged icon at the mouse position, but I use the event object (#drag($event) ) of the drag method in the Firefox browser to get the mouse coordinates (event. pageX, event.screenX), it shows (0,0) or a fixed value, but when I use Google Chrome, the above situation does not occur, it immediately gives me the coordinates of the current mouse. Regarding the problem of the value of layerXY in the picture, this value will only be updated once at the beginning of dragging, and will not change at the rest of the time. Since I personally like to use the Firefox browser, I want to solve this problem, can anyone help me? Or give me some other suggestions to implement this function (my English is not very good, from google translate)
You could update the mouse coordinate on a global variable when the mouse moves so that it will be ready for you when mouse is down.
let drag = document.querySelector('.note');
var pageX, pageY
drag.onmousedown = function(e) {
let coord = getCoord(drag);
let shiftX = pageX - coord.left;
let shiftY = pageY - coord.top;
drag.style.position = 'absolute';
document.body.appendChild(drag);
moveNote(e);
drag.style.zIndex = 1000;
function moveNote(e) {
drag.style.left = pageX - shiftX + 'px';
drag.style.top = pageY - shiftY + 'px';
var position = {
x: drag.style.left,
y: drag.style.top
}
}
document.onmousemove = function(e) {
moveNote(e);
};
drag.onmouseup = function() {
document.onmousemove = null;
drag.onmouseup = null;
};
}
function getCoord(elem) {
let main = elem.getBoundingClientRect();
return {
top: main.top,
left: main.left
};
}
window.onload = function() {
document.addEventListener("mousemove", function(e) {
pageX = e.pageX
pageY = e.pageY
});
drag.style.position = 'absolute';
document.body.appendChild(drag);
drag.style.display = 'block'
}
.note {
width: 50px;
height: 50px;
background: red;
display: none;
}
<div class="note"></div>

Detect how much browser changed in width on resize and update position of element

There is one div element positioned absolutely in a relative container. It is initially positioned under one of four buttons. Based on which button is clicked, I calculate with JS the x coordinate of the button and move the div element underneath that button. Here's my markup and JS:
<div id='container-of-four-buttons' style="width: 100%; position: relative;">
<button>Foo</button>
<button>Buzz</button>
<button>Foo</button>
<button>Buzz</button>
</div>
<div id='followAlong-container' style="width: 100%; position: relative;">
<div class='followAlong-div' style="position:absolute; width: 15px; height: 13px;">Some stylized arrow</div>
</div>
var initialDiv = /* selected the second button to be initial */
var followAlongDiv = document.querySelector('followAlong-div');
var buttons = document.querySelectorAll('button');
followAlongDiv.style.left = initialDiv + 89 + 'px';
buttons.forEach(function(btn) {
btn.addEventListener('click', function() {
let xCoord = 0;
xCoord += (div.offsetLeft - div.scrollLeft + div.clientLeft);
followAlongDiv.style.left = xPos + 17 + 'px';
});
});
However, if I resize the browser, the four button elements shrink towards eachother, but the followAlongDiv stays at the same spot because it is positioned absolutely in its relative container.
How do I calculate the amount of width the browser has resized and update the position of the followAlongDiv?
I will use window.addEventListener('resize', updatePosition), but I just don't know how to approach the formulation of the updatePosition function.
First, 'followAlong-div' is a class (needs '.' before the className ):
var followAlongDiv = document.querySelector('.followAlong-div');
Second, I do not understand why you have this line:
xCoord += (div.offsetLeft - div.scrollLeft + div.clientLeft);
For resizing just needs:
window.onresize = ()=>{
var xCoord = 0;
xCoord += (selectedButton.offsetLeft);
followAlongDiv.style.left = xCoord + 'px';
}
Based on your code, I think this is what you want: https://jsfiddle.net/vua4eLhc/
Hope it helps!

Panning DIV element around using javascript

I am trying to have a div in a container which when the user clicks and drags somewhere in the document area, the .room element pans around inside the .viewport element by holding down the middle click button.
Here is the issue: (Hold right click for this one, middle click didn't work for some reason)
http://jsfiddle.net/JeZj5/2/
JS
var mouseX = 0;
var mouseY = 0;
var scale = 1.0;
$(document).mousemove(function (e) {
var offset = $('.room').offset();
//relative mouse x,y
mouseX = parseFloat((e.pageX - offset.left) / scale, 2);
mouseY = parseFloat((e.pageY - offset.top) / scale, 2);
//absolute mouse x,y
mouseXRaw = e.pageX;
mouseYRaw = e.pageY;
$(".room").html(mouseX + ', ' + mouseY + '<br />Right click document and pan');
switch (e.which) {
case 3:
$('.room').css({
left: mouseX,
top: mouseY
});
break;
}
return true;
});
$(document).on('contextmenu', function () {
return false;
});
This should be more along the lines of what you're looking for. Key change:
delta.x = e.pageX - drag.x;
delta.y = e.pageY - drag.y;
Using the delta to change the position. The .room's position should be moving with respect to it's current location, minus the mouse drag position (not the other way around).
http://jsfiddle.net/X2PZP/3/

clientX and clientY not giving correct mouse pointer location

I wrote this simple code to print a small dot on the location where I clicked with the mouse pointer:-
$(document).ready(function(){
$('#pane').click(function(e){
var pixel = $('<div />')
.addClass('pixel')
.css({
top: e.clientY,
left: e.clientX
});
$('#pane').append(pixel)
});
});
See this fiddle I created. When I click anywhere inside the rectangle, a small dot is printed in that location. But the problem is that dot is not printed where the mouse pointer's tip was. See the below image to see what I meant:-
I tried in both Firefox and Chrome.
Your code is working correctly,
Zoom your page and check,
i have changed pixel height and width for better understanding from 2px to 3px.
and drawing from e.clientX -1 and e.clientY -1 position so it looks exactly center.
You can find Fiddle
The most examples I've found don't work if there are a scrolled page... I used this algorythm in order to get the position:
var getOffsets = function($event){
var p = {};
var body = "search the document for the body element";
p.x = body.offsetLeft;
p.y = body.offsetTop;
while (body.offsetParent) {
p.x = p.x + body.offsetParent.offsetLeft;
p.y = p.y + body.offsetParent.offsetTop;
if (body == document.getElementsByTagName("body")[0]) {
break;
}
else {
body = body.offsetParent;
}
}
return p;
}
However, after that you have to consider also other elements, im my case:
var GetExactClickPosition = function($event){
var tr = $($event.target);
if ($event.target.localName != 'tr'){
tr = $($event.target).closest('tr');
}
var listDiv = $($event.target).closest('div');
var p = getOffsets($event);
var container = $('#mailingListExcludeMenuContainer');
container.css({
top: p.y - listDiv.scrollTop() - tr.height() - container.height() + $event.offsetY + "px",
left: p.x + $event.offsetX + "px"
});
container.show();
};
I have a list with scroller inside the main scroller of the page...
I used it in order to show a little menu at the position of the mouse click.

Qtip tooltips not appearing

I made the navbar on the top of my page static (the rest of the page is dynamic)
The navbar is in a div that is given the ID "header" and and everything else is in a div with the ID "main".
I use this code to make tooltips.
This is the Javascript/jquery/qtip
$(document).ready(function() {
//Tooltips
$(".tiptrigger").hover(function(){
tip = $(this).find('.tip');
tip.show(); //Show tooltip
}, function() {
tip.hide(); //Hide tooltip
}).mousemove(function(e) {
var mousex = e.pageX + 20; //Get X coodrinates
var mousey = e.pageY + 20; //Get Y coordinates
var tipWidth = tip.width(); //Find width of tooltip
var tipHeight = tip.height(); //Find height of tooltip
//Distance of element from the right edge of viewport
var tipVisX = $(window).width() - (mousex + tipWidth);
//Distance of element from the bottom of viewport
var tipVisY = $(window).height() - (mousey + tipHeight);
if (tipVisX < 20) { //If tooltip exceeds the X coordinate of viewport
mousex = e.pageX - tipWidth - 20;
} if (tipVisY < 20) { //If tooltip exceeds the Y coordinate of viewport
mousey = e.pageY - tipHeight - 20;
}
//Absolute position the tooltip according to mouse position
tip.css({ top: mousey, left: mousex });
});
});
$(document).ready(function() {
//Tooltips
$(".tipheader").hover(function(){
tip = $(this).find('.tip');
tip.show(); //Show tooltip
}, function() {
tip.hide(); //Hide tooltip
}).mousemove(function(e) {
var mousex = e.pageX + 30; //Get X coodrinates
var mousey = e.pageY + -20; //Get Y coordinates
var tipWidth = tip.width(); //Find width of tooltip
var tipHeight = tip.height(); //Find height of tooltip
//Distance of element from the right edge of viewport
var tipVisX = $(window).width() - (mousex + tipWidth);
//Distance of element from the bottom of viewport
var tipVisY = $(window).height() - (mousey + tipHeight);
if (tipVisX < 20) { //If tooltip exceeds the X coordinate of viewport
mousex = e.pageX - tipWidth - 20;
} if (tipVisY < 20) { //If tooltip exceeds the Y coordinate of viewport
mousey = e.pageY - tipHeight - 20;
}
//Absolute position the tooltip according to mouse position
tip.css({ top: mousey, left: mousex });
});
});
Then this is the CSS
.tip {
color: #fff;
background: #1d1d1d;
display: none; /*--Hides by default--*/
padding: 10px;
position: absolute;
z-index: 1000;
-webkit-border-radius: 6px;
-moz-border-radius: 6px;
border-radius: 6px;
}
This is the HTML that calls the tooltip.
The first line is for the main section, the second is for the header.
<img src="IMAGE URL" alt="" /><span class="tip">CONTENT</span>
<img src="IMAGE URL" alt="" /><span class="tip">CONTENT</span>
The reason I used two different javascript sections is because the tooltips in the header and the tooltips in the main section needed different parameters.
Now, the problem is that the tooltips work fine in the header, but they're not working in the main section and I can't think of any possible reason why, I tried everything I could think of and it's not working. Does anyone else know how to fix it?
Do you need absolute positioning on your div elements (it doesn't appear so since you aren't specifying any top or left values)? Since the tooltip uses absolute positioning and is nested within another element which also uses absolute positioning, it can't "break out" from the parent element.
I recommend that you remove the position: absolute rule from the #header and #main styles. Alternatively, removing the overflow: auto rule from the #header style seems to work as well.
http://jsfiddle.net/tz59G/3/
I was finally able to fix it by setting the #header div to fixed positioning (so it stays at the top of the window without absolute positioning) and I made the #main div static positioned and moved it down with just page breaks.
*I decided it would be more efficient to only use one type of tooltip, so I removed one.
*Note how I set the min-height so I can display how the #header div stays at the top when you scroll, that is the effect I wanted.
http://jsfiddle.net/tz59G/5/
to see the finished result, go here: ultimatemmo.webege.com
The navbar on top is my header div and everything else is my main div.
Note: that site isn't a normal traffic site, I made it for a school project, now it's just a personal project that I'm constantly improving. The only reason it's on the internet is so my friends and girlfriend can see my progress on it.

Categories