How to allow mousemove on image and prevent image dragging - javascript

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();
});

Related

Changing cursor while dragging HTML element

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)

moving an img with touch

I'm trying to drag the bucket image (left and right only) with touch.
I'm new to mobile developing so I'm not that acquainted with touch events.
bucket = document.getElementById("bucket");
window.addEventListener('load', function () {
var startx = 0;
var dist = 0;
bucket.addEventListener('touchstart', function (e) {
var touchobj = e.changedTouches[0]; // reference first touch point (ie: first finger)
startx = parseInt(touchobj.clientX); // get x position of touch point relative to left edge of browser
e.preventDefault();
}, false)
bucket.addEventListener('touchstart', function (e) {
var touchobj = e.changedTouches[0]; // reference first touch point for this event
var dist = parseInt(touchobj.clientX) - startx;
bucket.style.left = bucket.offsetLeft + dist;
e.preventDefault();
}, false)
}, false)
Thank you all the helpers.

vertical scrolling via scrollTo is jittery on mobile devices

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

draggable without jQuery ui

How to make a element draggable without using jQuery UI?
I have this code:
<script type="text/javascript">
function show_coords(event)
{
var x=event.clientX;
var y=event.clientY;
var drag=document.getElementById('drag');
drag.style.left=x;
drag.style.top=y
}
</script>
<body style="height:100%;width:100%" onmousemove="show_coords(event)">
<p id="drag" style="position:absolute">drag me</p>
</body>
The problem is that I want to drag while the user the pressing the mouse button. I tried onmousedown but results were negative.
It will be quite easy as you get the concept.
function enableDragging(ele) {
var dragging = dragging || false, //Setup a bunch of variables
x, y, Ox, Oy,
enableDragging.z = enableDragging.z || 1,
current;
ele.onmousedown = function(ev) { //When mouse is down
current = ev.target;
dragging = true; //It is dragging time
x = ev.clientX; //Get mouse X and Y and store it
y = ev.clientY; // for later use.
Ox = current.offsetLeft; //Get element's position
Oy = current.offsetTop;
current.style.zIndex = ++enableDragging.z; //z-index thing
window.onmousemove = function(ev) {
if (dragging == true) { //when it is dragging
var Sx = ev.clientX - x + Ox, //Add the difference between
Sy = ev.clientY - y + Oy; // 2 mouse position to the
current.style.top = Sy + "px"; // element.
current.style.left = Sx + "px";
return false; //Don't care about this.
}
};
window.onmouseup = function(ev) {
dragging && (dragging = false); //Mouse up, dragging done!
}
};
}
enableDragging(document.getElementById("drag")); //draggable now!
var ele = document.getElementsByTagName("div");
for(var i = 0; i < ele.length; i++){ //Every div's is draggable
enableDragging(ele[i]); // (only when its "position"
} // is set to "absolute" or
// "relative")
http://jsfiddle.net/DerekL/NWU9G/
The reason why your code is not working is because the <div> will always follow where your cursor goes, and you are not actually dragging it. The top left corner will always follow your cursor, and this is not we wanted.
UPDATE
Now if you only want a grabber or something similar, just change this part of the script:
ele.onmousedown = function(ev) {
current = ev.target;
to
var grabber = document.createElement("div");
grabber.setAttribute("class", "grabber");
ele.appendChild(grabber);
grabber.onmousedown = function(ev) {
current = ev.target.parentNode;
Now you can only click on the grabber to start the dragging process.
http://jsfiddle.net/DerekL/NWU9G/7/

Is there something like Jquery memory or cache?

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!

Categories