I know there has been numerous similiar questions on stackoverflow, I've read several of them, but none provided there answers worked in my case. I want to change cursor while dragging HTML element. I tried this:
var startX = null;
var startY = null;
var element = document.getElementById('bla');
element.addEventListener('dragstart', onDragStart, true);
element.addEventListener('dragend', onDragEnd, true);
element.addEventListener('drag', onDrag, true);
function onDragStart(e){
startX = e.screenX;
startY = e.screenY;
e.target.style.cursor = "move";
}
function onDrag(e){
e.target.style.cursor = "move";
}
function onDragEnd(e){
var style = document.defaultView.getComputedStyle(element);
var newLeft = parseInt(style.left) + e.screenX - startX;
var newTop = parseInt(style.top) + e.screenY - startY;
e.target.style.left = newLeft + 'px';
e.target.style.top = newTop + 'px';
e.target.style.cursor = "default";
}
But it doesn't work. I have no idea why on earth e.target.style.cursor = "move" doesn't work. I tried changing it to document.body.style.cursor = "move", but it doesn't work either. Any help with solving this problem with explanation why my code doesn't work will be greatly appreciated.
JS Fiddle link: https://jsfiddle.net/4w20xxvp/59/
Ps. I'm looking for pure JS solution, no JQuery.
Ps2. I couldn't get answers from to work in my case. And I don't want to use custom cursor images, just standard css ones.
Try to preventDefault on the other drag events. Also, you might want to consider adding a drop target that would handle dragover events.
document.addEventListener('dragover', (e) => e.preventDefault(), true)
(Fiddle)
Related
All I m using the below code snippet to make a pop draggable. the issue im facing is scroll bar is not being detected, the pop up moves instead of scroll. I did see some similar questions, but the implementation seems to be different in their case, Can you help?
$('#Div1').mousedown(function(ev) {
divToMove = document.getElementById('Div1');
var divName = '#Div1';
dragHandler(ev,divName);
});
function dragHandler(e,divName){
var offSet = $(divName).position();
dragOK = true;
dragXoffset = e.clientX - offSet.left;
dragYoffset = e.clientY - offSet.top;
$(divName).mousemove(function(ev){ moveHandler(ev) });
$(divName).mouseup(function(ev){ cleanup(ev, divName) });
return false;
}
function cleanup(e, divName) {
$(divName).mousemove = null;
$(divName).mouseup = null;
dragOK = false;
}
function moveHandler(e) {
if (e == null) { e = window.event }
if (e.button <= 1 && dragOK) {
divToMove.style.left = e.clientX - dragXoffset + 'px';
divToMove.style.top = e.clientY - dragYoffset + 'px';
return false;
}
}
Please see this example in js fiddle. The issue doesnt happen in chrome, happens only in IE and ff.
http://jsfiddle.net/6g6Xr/74/
I was wanting to comment but do not have enough points. I see you have included jQuery UI in the jsfiddle, is it possible to use its draggable component if you are using UI already? If so you could use the handle property shown here in the second part of this answer:
https://stackoverflow.com/a/8793280/2603735
jQuery UI handle reference
I have seen this question but it wasn't answered.
I have a object on a webpage that I want you to be able to drag and scroll the page. Reason behind this is that I set it up to be a swipe'able window but on some mobile devices the window takes up most of the screen. So in addition to horizontal "swiping" I want you to be able to vertically scroll the page as well.
This works great on a PC with a mouse. Everything is smooth and as expected. However, once you go to a mobile device (I have tried on Safari on an iPhone and the native browser on an Android 4 and both have the same issue) vertical scrolling is very "jittery".
At first I thought that it had to do with the fact that after you scroll the page, the next touchmove / MSPointerMove event will return a Ycord that different even though your finger might not have moved (due to the scrolling). But trying to accomidate for this didn't help.
Anyway, a demo of the whole thing can be found at http://www.leecolpi.com/NEW/m/
The full javascript can be found at http://www.leecolpi.com/NEW/m/JAVASCRIPT/slide_window.js
The relivant javascript is (might be easier to read via the link above):
function mouseMoveTrigger(evt)
{
if (!isDragging) return;
if (!touchEvents && !pointerEvents)
if (window.event) evt=window.event;
if (evt.preventDefault)
evt.preventDefault();
else
evt.returnValue = false;
var newX;
var newY;
if (touchEvents)
{
newX = offsetX - evt.changedTouches[0].pageX;
offsetX = evt.changedTouches[0].pageX;
newY = offsetY - evt.changedTouches[0].pageY;
offsetY = evt.changedTouches[0].pageY;
}
else
{
newX = offsetX - evt.clientX;
offsetX = evt.clientX;
newY = offsetY - evt.clientY;
offsetY = evt.clientY;
}
var thingsToSlide = document.getElementById("pictureFrame").getElementsByTagName("li");
newX = parseInt(thingsToSlide[0].style.right.replace(/px/g,'')) + newX;
if (newX < 0)
newX = 0;
if (newX > ((thingsToSlide[0].offsetWidth * (thingsToSlide.length - 1))) + 30)
newX = (thingsToSlide[0].offsetWidth * (thingsToSlide.length - 1)) + 30;
window.scrollBy(0, newY);
for (var i=0; i<thingsToSlide.length; i++)
thingsToSlide[i].style.right = newX + "px";
return false;
}
As you can see, all I am doing is a scrollBy of the difference of the Yvalue for the current and previous "move" events. Again, this works like a champ on a computer which is exactly where I don't care if it works or not. Only problem is every mobile device I have tried it on.
I am using preventDefault() (or setting the return value = false if I can't do that), but could I be triggering another event and not knowing it? I tried with my init to only listen for certian events. Here is my init function (might be easier to read via the link above):
function initSlider()
{
var pageBody = document.getElementsByTagName("body")[0];
var thingsToSlide = document.getElementById("pictureFrame");
if (thingsToSlide)
{
var thingsToSlideList = document.getElementById("pictureFrame").getElementsByTagName("li");
for (var i=0; i<thingsToSlideList.length; i++)
thingsToSlideList[i].style.right = "0px";
if (touchEvents)
{
thingsToSlide.addEventListener("touchstart", onTouchStart, false);
}
else if (pointerEvents)
{
thingsToSlide.addEventListener("MSPointerDown", onTouchStart, false);
}
else
{
thingsToSlide.ondrag=function() { return false; };
thingsToSlide.onselectstart=function() { return false; };
thingsToSlide.onmousedown=function(event) { mouseDownTrigger(this,event); };
}
if (touchEvents)
{
pageBody.addEventListener("touchmove", mouseMoveTrigger, false);
pageBody.addEventListener("touchend", mouseUpTrigger, false);
pageBody.addEventListener("touchcancle", mouseUpTrigger, false);
}
else if (pointerEvents)
{
pageBody.addEventListener("MSPointerMove", mouseMoveTrigger, false);
pageBody.addEventListener("MSPointerUp", mouseUpTrigger, false);
pageBody.addEventListener("MSPointerCancel", mouseUpTrigger, false);
}
else
{
document.onmousemove = mouseMoveTrigger;
document.onmouseup = mouseUpTrigger;
}
}
}
Any help would be greatly appreciated. Thanks in advance
I've got a very simple image resizing script. What I am trying to figure out is how to prevent the ghost image dragging while still allowing the user to drag the cursor on mousedown /mousemove and resize the image. Here is what I have so far, and is this possible? Currently I have it set on double click to allow the resizing with mousemove but I would like to get it set up where on mousedown allow mousemove to resize the image, and then on mouseup, cancel the resizing.
Thanks in advance.
Code:
$(".grid_content > img").live('mousedown',function(e){
$(this).attr('id','image');
$(this).css('cursor','se-resize');
var positionX;
var startWidth;
var image = document.getElementById('image');
if(!e){e = window.event};
positionX = (e.clientX);
startWidth = image.width;
image.onmousemove = function(e) {
if(!e){e = window.event};
image.style.width = (startWidth + (e.clientX - positionX)) + 'px';
};
image.onmousedown = function() {
image.onmousemove = null;
positionX = null;
startWidth = null;
};
});
Tried this but no luck, disables the whole dragging thing:
$('.grid_content > img').bind("dragstart",function(e){
e.preventDefault();
});
I've wrote a Script with jQuery for 360deg product preview. It works just fine. But if I "play" with it for a long time (dragging, zooming in, zooming out etc.) it becames slower and slower. If I'm dragging mouse slowly it works ok, but it freezes on fast mousemoves. After page reload it works again fine for several minutes and then become slower.
What can cause such behaviour? Is there something like jQuery memory that becomes full?
Per request, some parts of code:
Loading images:
$.getJSON("load.php", {dir: 'images/'}, function(output) {
var imagelist = jQuery.makeArray(output.imagelist);
var zoomlist = jQuery.makeArray(output.zoomlist);
var cache = [];
function preload(arrayOfImages) {
$(arrayOfImages).each(function(){
var im = $("<img>").attr("src",this);
cache.push(im);
image.attr('src', this);
});
}
preload(imagelist);
Rotation part
holder.mousedown(function(e){
var enterPosition = e.pageX - this.offsetLeft;
isDown = true;
$(document).mousemove(function(e){
if(isDown && !isZoom){
var cursorPosition = e.pageX - contOffset.left;
var xOffset = cursorPosition - enterPosition;
var step = Math.round(contWidth/countFrames);
var frameOffset = Math.round(xOffset/step);
var cycles = Math.abs(Math.floor((frameOffset+startFrame)/countFrames));
currentFrame = startFrame + frameOffset;
if(currentFrame >= countFrames){
currentFrame = currentFrame - countFrames*cycles;
}
if(currentFrame < 0){
currentFrame = countFrames*cycles + currentFrame;
}
image.attr('src', imagelist[currentFrame]);
$('#info').html(currentFrame);
var corner = Math.floor(360/countFrames);
var degrees = corner*currentFrame;
var radians=degrees*Math.PI/180;
var sine=Math.sin(radians);
var cose=Math.cos(radians);
var poinx = rotCenter+rotRadius*sine*-1;
var poiny = rotCenter+rotRadius*cose
$('#pointer').css('left',poinx);
$('#pointer').css('top',poiny);
};
});
$(document).mouseup(function(){
isDown = false;
startFrame = currentFrame;
});
});
Zooming part
$('#zoom').click(function(e){
var isZoom = true;
var offset = holder.offset();
var startXpos = e.pageX - offset.left;
var startYpos = e.pageY - offset.top;
var zoomImg = new Image();
zoomImg.onload = function() {
zoomHeight = zoomImg.height;
zoomWidth = zoomImg.width;
var leftOverflow = (zoomWidth - contWidth)/-2;
var topOverflow = (zoomHeight - contHeight)/-2;
image.attr('src', zoomlist[currentFrame]);
image.css('left', leftOverflow);
image.css('top', topOverflow);
$('#round').fadeOut();
$('#zoom').fadeOut();
holder.addClass('zoomout');
holder.mousemove(function(e){
if(isZoom){
var currentXpos = e.pageX - offset.left;
var currentYpos = e.pageY - offset.top;
var xlimit = (zoomWidth-contWidth)*-1;
var ylimit = (zoomHeight-contHeight)*-1;
var xSpeedCoeff = Math.floor(zoomWidth/contWidth);
var ySpeedCoeff = Math.floor(zoomHeight/contHeight);
var moveLeft = startXpos - currentXpos;
var moveTop = startYpos - currentYpos;
var leftOffset = leftOverflow + moveLeft*xSpeedCoeff;
var topOffset = topOverflow + moveTop*ySpeedCoeff;
var hMoveLock = false;
var vMoveLock = false;
if(leftOffset >= 0){
hMoveLock = true;
startXpos = startXpos - leftOffset;
}
if(leftOffset <= xlimit){
hMoveLock = true;
startXpos = startXpos - leftOffset + xlimit;
}
if(topOffset >= 0){
vMoveLock = true;
startYpos = startYpos - topOffset;
}
if(topOffset <= ylimit){
vMoveLock = true;
startYpos = startYpos - topOffset + ylimit;
}
if(!hMoveLock) {
image.css('left', leftOffset);
}
if(!vMoveLock) {
image.css('top', topOffset);
}
holder.mousedown(function(){
image.attr('src', imagelist[currentFrame]);
image.css('left', 0);
image.css('top', 0);
$('#round').fadeIn();
$('#zoom').fadeIn();
holder.removeClass('zoomout');
pan = false;
isZoom = false;
});
}
});
}
zoomImg.src = zoomlist[currentFrame];
});
I know, the code is not clear, and as it here now, I would be thankful for any advice.
There are lots of reasons this might happen, it's impossible to say without seeing the code see below for an update now that you've posted the code:
A couple of possibilities off the top of my head:
Yes, you could be allocating lots of objects and then either not releasing them, or the garbage collector is being slow.
You could be inadvertently re-attaching event handlers over and over, and so the events (which end up triggering all attached handlers) slow down because of the number of (redundant) handlers attached.
Update after you posted your code:
It's #2, this is the offending code (it may not be the only offending code):
holder.mousedown(function(e){
var enterPosition = e.pageX - this.offsetLeft;
isDown = true;
$(document).mousemove(function(e){
// ...
});
$(document).mouseup(function(){
// ...
});
});
What you're doing there is when the mousedown event fires on the holder element(s), you're adding a new handler for mousemove and mouseup to the document, on top of any handlers that are already there. So every mousedown introduces a new handler to the chain. Since mousemove happens a lot, that ever-increasing chain of handlers gets called a lot.
You should either only be attaching the mousemove and mouseup handlers once, not on every mousedown, or you should be sure to remove them on mouseup. (The latter will require that you don't use anonymous functions as you are currently, because you need to pass the same function reference into unbind that you passed [indirectly] into bind. Edit: Or you can use jQuery's "namespaced" event stuff.)
FWIW, this should get you started on the attach-it-once version:
(function() { // Scoping function so isDown and enterPosition aren't globals
var isDown = false,
enterPosition;
// I don't know where `holder` or `startFrame` come from, but presumably you do
// Hook up mousedown on holder
holder.mousedown(function(e){
enterPosition = e.pageX - this.offsetLeft;
isDown = true;
});
// Hook up mousemove on document (just once)
$(document).mousemove(function(e){
// Flag controls whether we do anything
if(isDown && !isZoom){
var cursorPosition = e.pageX - contOffset.left;
var xOffset = cursorPosition - enterPosition;
var step = Math.round(contWidth/countFrames);
var frameOffset = Math.round(xOffset/step);
var cycles = Math.abs(Math.floor((frameOffset+startFrame)/countFrames));
currentFrame = startFrame + frameOffset;
if(currentFrame >= countFrames){
currentFrame = currentFrame - countFrames*cycles;
}
if(currentFrame < 0){
currentFrame = countFrames*cycles + currentFrame;
}
image.attr('src', imagelist[currentFrame]);
$('#info').html(currentFrame);
var corner = Math.floor(360/countFrames);
var degrees = corner*currentFrame;
var radians=degrees*Math.PI/180;
var sine=Math.sin(radians);
var cose=Math.cos(radians);
var poinx = rotCenter+rotRadius*sine*-1;
var poiny = rotCenter+rotRadius*cose
$('#pointer').css('left',poinx);
$('#pointer').css('top',poiny);
};
});
// Hook mouseup on document (just once)
$(document).mouseup(function(){
isDown = false;
startFrame = currentFrame;
});
})();
If your code is already within a scoping function, you don't need the new one I introduced.
There is a cache - you can access it with $.cache. And as T.J. Crowder said - it's most likely cause of you aren't cleaning up after yourself properly.
Do a Object.keys($.cache).length; in your console to check the size of cache - play for a while and check again to confirm that the cache grows to confirm jquery based leaks
and you are leaking cause on mouseup you are not unbinding your mouseup and mmousemove events
$(document).mouseup(function(){
$(document).unbind('mouseup').unbind('mousemove');
isDown = false;
startFrame = currentFrame;
});
this should help a lot
Problem was that basically every time you were pressing mouse down you were binding mousemove and mouseup again and again so after clicking few times all the computation was multiplied by amount of times you've pressed mouse down. You could also namespace the mousemove and mouseup events to unbind by namespace rather then two events separately.
Also caching variables might help a bit - especially with this kind of heavy operations - mousemove fires a lot
edit:
to remove events with anonymous functions use namespaces
var doc = $(document);
doc.bind('mousedown', function(e) {
doc.bind('mousemove.namespace', function(e) { ... });
doc.bind('mouseup.namespace', function(e) {
doc.unbind('.namespace');
// do whatever else you need to do on mouseup
});
});
just change namespace to whatever fits you best! Check jQuery docs for more info on namespaced events http://docs.jquery.com/Namespaced_Events
apart of that if you don't pass any function to the event type you want to unbind it will unbind all the events of given type regardless of its namespace or if it was named function or anonymous one
So, the problem was caused by the zoom function. What i did to solve it:
I have moved this part
holder.mousedown(function(){
image.attr('src', imagelist[currentFrame]);
image.css('left', 0);
image.css('top', 0);
$('#round').fadeIn();
$('#zoom').fadeIn();
holder.removeClass('zoomout');
pan = false;
isZoom = false;
});
outside of
holder.mousemove(function(e){
if(isZoom){
I've used namespaces to unbind mouse events.
holder.on('mousemove.dragpan', (function(e){
}));
holder.mousedown(function(){
holder.off('mousemove.dragpan');
});
Thx again for all the tipps!
I am trying to monitor dragStart and dragEvent javascript, in order to conclude its direction, UP or DOWN.
However i could not get any detail in arguments passed by the event -- that help to conclude.
Is there any better way to check drag direction , up or down?
Note:
my problem is specifically happening at mojo javascript at webos
Thanks,
-iwan
I didn't know about dragStart and dragEvent, but why not use onmousedown, onmousemove and onmouseup?
I made a modified version of http://dunnbypaul.net/js_mouse/. The direction is displayed in #status when you drag the image. Tested and works in IE5.5, IE6, IE7, IE8, Safari 5, Chrome 6 and Navigator 9. Works with Strict Doctype (probably other Doctypes also, didn't test them).
JavaScript:
var dragobj = null;
function getCurY(e) {
if (!e) e = window.event;
if (e.pageX || e.pageY)
return e.pageY;
else if (e.clientX || e.clientY)
return e.clientY + document.body.scrollTop;
}
function drag(context, e) {
dragobj = context;
document.onmousedown = function() { return false };
document.onmouseup = function() {
if (dragobj) dragobj = null;
document.getElementById('status').innerHTML = 'Direction: n/a';
}
var graby = getCurY(e);
var oriy = dragobj.offsetTop;
document.onmousemove = function(e) {
if (dragobj) {
dragobj.style.position = 'absolute';
var newy = oriy + getCurY(e) - graby;
var dir = newy > parseInt(dragobj.style.top, 10) ? 'down' : 'up';
dragobj.style.top = newy + 'px';
document.getElementById('status').innerHTML = 'Direction: ' + dir;
}
return false;
}
}
HTML:
<p onmousedown="drag(this, event)">
<img src="http://1.bp.blogspot.com/-u3FKHnFg8cA/Td56DmfliyI/AAAAAAAAAJ8/fTCFNCTs7iE/s1600/trollface%255B1%255D.jpg" alt="Trollface" />
</p>
<p id="status" style="position:absolute; top:0">Direction: n/a</p>
It won't tell you the direction, but you can get the position of the element you're dragging and figure out which direction it's going.
This might be helpful: http://dunnbypaul.net/js_mouse/.
You want to use dragOver. You could do something like this if you're only interested in vertical position:
Javascript:
<script type="text/javascript">
function getPosY(event) {
console.log(event.clientY);
}
</script>
HTML:
<body ondragover="getPosY(event)">
EDIT: Here's a jsfiddle. Make sure your js console is open.
You could have your function compare the clientY values to determine which direction the mouse is moving.