I am trying to create a sort of plugin or event that css transitions (moves) elements via swipe on ipad. For this I am using so far the brillant working little code snippet of cocco:
(function(D){
var M=Math,abs=M.abs,max=M.max,
ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
f={
touchstart:function(e){
t=e.touches[0];
sx=t.pageX;
sy=t.pageY
},
touchmove:function(e){
m=1;
t=e.touches[0];
ex=t.pageX;
ey=t.pageY
},
touchend:function(e){
ce=D.createEvent("CustomEvent");
ce.initCustomEvent(m?(
max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
):'fc',true,true,e.target);
e.target.dispatchEvent(ce);
m=0
},
touchcancel:function(e){
m=0
}
}
for(l in f)D.addEventListener(l,f[l],false)
})(document);
For the transitions rico st.cruz’ plugin jquery-transit.js is implemented on my site (and jquery of course)
// usage (example)
$("body").on( 'swu', function() {
fullscreenSwipeUp = true;
$("#Fullscreen").transition( { y: '-100%' }, 900, 'easeInSine' )
} );
So far so good.
Now my idea was to indicate the possible „swipe up“ with an additional touch move event that moves the element along while the finger tap is going on. And I succeeded in doing so adding the following js:
// js parts to integrate in a cooler way
var startY;
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
}, false );
window.addEventListener( 'touchmove', function(e) {
e.preventDefault();
// check if transition is going on and animations are ready
if ( !fullscreenSwipeUp ) { // find better solution f.e. to dispatch event on fullscreen transition?
var diffY = e.changedTouches[0].pageY - startY;
// fullscreen transition
if ( diffY <= 0 ) {
$("#Fullscreen").css( { y: diffY } );
} else {
// snap to clean starting value at bottom
$("#Fullscreen").css( { y: 0 } );
};
// do something else to indicate that swipe will be concluded when finger leaves
// min value based on variable th from custom swipe event
if ( diffY < -20 ) {
// indicate that swipe will be concluded
} else {
// indicate that swipe will not conclude
};
};
}, false );
// fullscreen fall back to bottom if swipe not concluded
window.addEventListener( 'touchend', function(e) {
e.preventDefault();
if ( !fullscreenSwipeUp ) {
// fall back to starting values / dequeue for smoother transition on second time
$("#Fullscreen").dequeue().transition( { y: 0 }, 150, 'easeInSine' );
};
}, false );
Now I see also that in this code various parts overlap each other as the double touch move event from the base custom event and my stuff. It would be so awesome if someone could offer me an idea of how to integrate the two codes. Or maybe something likes this exists? I couldn’t find the right thing.
Thanks for a helping hand!
PS I tried to create a fiddle, also, here: http://jsfiddle.net/Garavani/9zosg3bx/1/
but sadly I am too stupid to make it work with all the external scripts :-(
jquery-transit.js:
http://ricostacruz.com/jquery.transit/
EDIT:
So I changed my code in the following way.
I guess I was confused between the original swipe event (which incorporates the touch move event also) and what I wanted to do with the element.
It works although probably still a mess.
I had to set kind of flag to check if the swipe is executed to disable the touch move event temporarily. Is there a better way to do that? Thanks for your patience!
var startY;
var swipeY = false; // for condition if condition for swipe is fullfilled
var swiped = false; // for check if swipe has been executed
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
}, false );
window.addEventListener( 'touchmove', function(e) {
e.preventDefault();
// check if swipe already executed
if ( !swiped ) { // find better solution f.e. to dispatch event when swiped?
var diffY = e.changedTouches[0].pageY - startY;
// check for final swipe condition
if ( diffY < -30 ) {
swipeY = true;
// do something with an element to indicate swipe will be executed
} else {
swipeY = false;
// do something with an element to indicate swipe will NOT be executed
};
};
}, false );
window.addEventListener( 'touchend', function(e) {
e.preventDefault();
if ( swipeY ) {
swiped = true;
// trigger the swipe action
} else {
// let the element fall back to original state
};
}, false );
EDIT 2:
var startY;
var swipeY = false;
var swiped = false;
var wh = $(window).height();
// fullscreen move on touchmove
function fm(e) {
e.preventDefault();
// check if transition is going on and animations are ready
if ( !swiped && ready ) { // !swiped is necessary, also / why?
var diffY = e.changedTouches[0].pageY - startY;
var scaleY = diffY/wh;
// calculate transition intermediate values
var osh = 0.91 - ( 0.09 * scaleY );
var ofsc = 0.86 - ( 0.14 * scaleY );
// fullscreen transition
if ( diffY <= 0 ) {
tfs(osh,[1,-scaleY],ofsc,diffY,0) // an extra module that does the animation with the calculated values
} else {
// snap to clean starting values at bottom
tfs(0.91,[1,0],0.86,0,0)
};
// rotate arrow to indicate surpassing minimum touch move leading to swipe
if ( diffY < -30 ) {
swipeY = true;
$arrowDown.addClass('rotation');
} else {
swipeY = false;
$arrowDown.removeClass('rotation');
};
};
};
// fullscreen swipe
function fs(e) {
e.preventDefault();
window.removeEventListener( 'touchmove', fm, false );
if ( !swiped ) { // this is necessary, also / why?
if ( swipeY ) {
$arrowbottomField.trigger('touchstart'); // trigger the full swipe (also available as element direct touch (on touch swiped is set to true in touchstart event handler, also)
window.removeEventListener( 'touchend', fs, false );
} else {
// fall back of animation to starting values
tfs(0.91,[1,0],0.86,0,0);
};
};
};
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
window.addEventListener( 'touchmove', fm, false );
}, false );
window.addEventListener( 'touchend', fs, false );
Explanation (as good as I can)
Thanks Cocco for your patience again.
In the meantime I modified the code again.
It works :-) I know it will be a mess in your eyes.
On my site (supposed to work also on ipad, but not only) there is a field where you can touch and a fullscreen is moving up covering the whole window (similar to www.chanel.com -> „more“).
Additionally it is (on ipad) possible to swipe on the whole body to do the same thing.
Phases:
Phase 1) User taps and swipes (keeping the finger on) The fullscreen div follows his finger.
Pause 2) If a certain distance of the swipe is reached (still with the finger on) a little arrow also turns to indicate: if you leave now, swipe will be executed
Pause 3) still with finger on the distance becomes less than the one to complete the swipe, the arrow turns back
Phase 4) Leave with the finger the distance already covered decides if the fullscreen will move up completely or fall back down (if distance not sufficient)
For the little arrow to turn I could use a class toggle as you told me (way better than what I did! Thanks) but for the rest of the animation not because the values strongly depend on the window size. And the idea of my whole site is that the browser window can have any sizes or relations, all contents adapt themselves (containing horizontal AND vertical centerings at any time)
For mobile phones everything changes completely.
If you want to take a look: www.stefanseifert.com (if you want to see the effect (on ipad) you will have to skip the intro by touching the arrow in the right corner on the bottom of the trailer div)
I know that there is tons of other stuff that is note state of the art programming (to say this very carefully :-) but in a way it works.
And I can not afford to hire a programmer for weeks to redo everything. ;-)
It’s kind of learning by doing (for as you can guess I never programmed before in my life ;-)
so I am very thankful for every bit of information and help to do little things better.
If someone will pass here I will get some down votes for sure :-)
Thanks Cocco
Merry Christmas!
The code is actually made for low cpu devices , high performance .. leaving out complex calculations inside the touchmove. Anyway to animate your elements (between touchstart & touchend) a simple solution is to use css (not jquery or other resourceintensive plugins).
then just think logically... you can't determine in wich direction you swipe at the touchstart... you can do that at the touchend event after doing some math. OR while touchmove wich destroys the whole code, as mentioned above.
OPTION 1 (simple & high performance)
DEMO
http://jsfiddle.net/z7s8k9r4/
Add some lines....
(function(D){
var M=Math,abs=M.abs,max=M.max,
ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
T, //<- THE TARGET
f={
touchstart:function(e){
t=e.touches[0];
sx=t.pageX;
sy=t.pageY;
T=e.target; T.classList.add('sw'); //<- ADD A CUSTOM CLASS FOR SWIPES
},
touchmove:function(e){
m=1;
t=e.touches[0];
ex=t.pageX;
ey=t.pageY
},
touchend:function(e){
ce=D.createEvent("CustomEvent");
ce.initCustomEvent(m?(
max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
):'fc',true,true,e.target);
e.target.dispatchEvent(ce);
m=0;
T.classList.remove('sw'); //<- REMOVE THE CLASS
},
touchcancel:function(e){
m=0
}
}
for(l in f)D.addEventListener(l,f[l],false)
})(document);
now define the css class
element.sw{
background-color:yellow;
}
use the proper (HW) animation for mobile devices on your element
element{
background-color:green;
-webkit-transition:background-color 200ms ease;
}
this is a simple and dirty solution , it works. just keep it simple.
the class will apply only on defined elements. ;)
OPTION 2
forget the code above...
Here is another "performant" way to do a "snap" animation using "bounce".
the code is a little more complex... and uses the mouse.. replace the mouse events with touch events.
http://jsfiddle.net/xgkbjwxb/
and with more data points
http://jsfiddle.net/xgkbjwxb/1/
note: don't use jquery or complex js plugins in mobile devices.
Extra
As it's really problematic to work on pc without a touch interface i added some lines that force the mouse to simulate touches based on my function requisites.
http://jsfiddle.net/agmyjwb0/
EDIT
this code should do what you want...
http://jsfiddle.net/xgkbjwxb/3/
Related
I have an iframe that takes up the entire window (100% wide, 100% high), and I need the main window to be able to detect when the mouse has been moved.
Already tried an onMouseMove attribute on the iframe and it obviously didn't work. Also tried wrapping the iframe in a div like so:
<div onmousemove="alert('justfortesting');"><iframe src="foo.bar"></iframe></div>
.. and it didn't work. Any suggestions?
If your target isn't Opera 9 or lower and IE 9 or lower you can use css attribute pointer-events: none.
I found it the best way just to ignore iframe. I add class with this attribute to iframe in onMouseDown event and remove in onMouseUp event.
Works perfect for me.
Iframes capture mouse events, but you can transfer the events to the parent scope if the cross-domain policy is satisfied. Here's how:
// This example assumes execution from the parent of the the iframe
function bubbleIframeMouseMove(iframe){
// Save any previous onmousemove handler
var existingOnMouseMove = iframe.contentWindow.onmousemove;
// Attach a new onmousemove listener
iframe.contentWindow.onmousemove = function(e){
// Fire any existing onmousemove listener
if(existingOnMouseMove) existingOnMouseMove(e);
// Create a new event for the this window
var evt = document.createEvent("MouseEvents");
// We'll need this to offset the mouse move appropriately
var boundingClientRect = iframe.getBoundingClientRect();
// Initialize the event, copying exiting event values
// for the most part
evt.initMouseEvent(
"mousemove",
true, // bubbles
false, // not cancelable
window,
e.detail,
e.screenX,
e.screenY,
e.clientX + boundingClientRect.left,
e.clientY + boundingClientRect.top,
e.ctrlKey,
e.altKey,
e.shiftKey,
e.metaKey,
e.button,
null // no related element
);
// Dispatch the mousemove event on the iframe element
iframe.dispatchEvent(evt);
};
}
// Get the iframe element we want to track mouse movements on
var myIframe = document.getElementById("myIframe");
// Run it through the function to setup bubbling
bubbleIframeMouseMove(myIframe);
You can now listen for mousemove on the iframe element or any of its parent elements -- the event will bubble up as you would expect.
This is compatible with modern browsers. If you need it to work with IE8 and below, you'll need to use the IE-specific replacements of createEvent, initMouseEvent, and dispatchEvent.
Another way to solve this that work well for me is to disable mouse move events on the iframe(s) with something like on the mouse down:
$('iframe').css('pointer-events', 'none');
and then, re-enable mouse move events on the iframe(s) on the mouse up:
$('iframe').css('pointer-events', 'auto');
I tried some of the other approaches above and they work, but this seems to be the simplest approach.
Credit to: https://www.gyrocode.com/articles/how-to-detect-mousemove-event-over-iframe-element/
MouseEvent.initMouseEvent() is now deprecated, so #Ozan's answer is a bit dated. As an alternative to what's provided in his answer, I'm now doing it like this:
var bubbleIframeMouseMove = function( iframe ){
iframe.contentWindow.addEventListener('mousemove', function( event ) {
var boundingClientRect = iframe.getBoundingClientRect();
var evt = new CustomEvent( 'mousemove', {bubbles: true, cancelable: false})
evt.clientX = event.clientX + boundingClientRect.left;
evt.clientY = event.clientY + boundingClientRect.top;
iframe.dispatchEvent( evt );
});
};
Where I'm setting clientX & clientY you'll want to pass any info from the content window's event to the event we'll be dispatching (i.e., if you need to pass something like screenX/screenY, do it there).
The page inside your iframe is a complete document. It will consume all events and have no immediate connection to it's parent document.
You will need to catch the mouse events from javascript inside the child document and then pass this somehow to the parent.
I have been faced with a similar issue, where I had div's that I wanted to drag around over an iFrame. Problem was that if the mouse pointer moved outside the div, onto the iFrame, the mousemove events were lost and the div stopped dragging. If this is the sort of thing you want to do (as opposed to just detecting the user waving the mouse over the iFrame), I found a suggestion in another question thread which seems to work well when I tried it.
In the page that contains the and the things you want to drag, also include a like this:
<div class="dragSurface" id="dragSurface">
<!-- to capture mouse-moves over the iframe-->
</div>
Set it's initial style to be something like this:
.dragSurface
{
background-image: url('../Images/AlmostTransparent.png');
position: absolute;
z-index: 98;
width: 100%;
visibility: hidden;
}
The z-index of '98' is because I set the div's I want to drag around to be z-index:99, and the iFrame at z-index:0.
When you detect the mousedown in the to-be-dragged object (not the dragSurface div), call the following function as part of your event handler:
function activateDragSurface ( surfaceId )
{
var surface = document.getElementById( surfaceId );
if ( surface == null ) return;
if ( typeof window.innerWidth != 'undefined' )
{ viewportheight = window.innerHeight; }
else
{ viewportheight = document.documentElement.clientHeight; }
if ( ( viewportheight > document.body.parentNode.scrollHeight ) && ( viewportheight > document.body.parentNode.clientHeight ) )
{ surface_height = viewportheight; }
else
{
if ( document.body.parentNode.clientHeight > document.body.parentNode.scrollHeight )
{ surface_height = document.body.parentNode.clientHeight; }
else
{ surface_height = document.body.parentNode.scrollHeight; }
}
var surface = document.getElementById( surfaceId );
surface.style.height = surface_height + 'px';
surface.style.visibility = "visible";
}
Note: I cribbed most of that from somebody else's code I found on the internet! The majority of the logic is just there to set the size of the dragSurface to fill the frame.
So, for example, my onmousedown handler looks like this:
function dragBegin(elt)
{
if ( document.body.onmousemove == null )
{
dragOffX = ( event.pageX - elt.offsetLeft );
dragOffY = ( event.pageY - elt.offsetTop );
document.body.onmousemove = function () { dragTrack( elt ) };
activateDragSurface( "dragSurface" ); // capture mousemoves over the iframe.
}
}
When dragging stops, your onmouseup handler should include a call to this code:
function deactivateDragSurface( surfaceId )
{
var surface = document.getElementById( surfaceId );
if ( surface != null ) surface.style.visibility = "hidden";
}
Finally, you create the background image (AlmostTransparent.png in my example above), and make it anything except completely transparent. I made an 8x8 image with alpha=2.
I have only tested this in Chrome so far. I need to get it working in IE as well, and will try and update this answer with what I discover there!
I found a relatively simple solution to this for a similar issue I was having where I wanted to resize the iframe and a long with a div sitting next to it. Once the mouse went over the iframe jquery would stop detecting the mouse.
To fix this I had a div sitting with the iframe both filling the same area with the same styles except for the z-index of the div (set to 0) and the iframe (set to 1). This allowed for the iframe to be used normally when not resizing.
<div id="frameOverlay"></div>
<iframe></iframe>
When resizing, the div z-index gets set to 2 and then back to 0 afterwards. This meant the iframe was still visible but the overlay was blocking it, allowing for the mouse to be detected.
On your "parent" frame, select your "child" iframe and detect the event you are interested, in your case mousemove
This an example of code to be used in your "parent" frame
document.getElementById('yourIFrameHere').contentDocument.addEventListener('mousemove', function (event) {
console.log(, event.pageX, event.pageY, event.target.id);
}.bind(this));
<script>
// dispatch events to the iframe from its container
$("body").on('click mouseup mousedown touchend touchstart touchmove mousewheel', function(e) {
var doc = $("#targetFrame")[0].contentWindow.document,
ev = doc.createEvent('Event');
ev.initEvent(e.originalEvent.type, true, false);
for (var key in e.originalEvent) {
// we dont wanna clone target and we are not able to access "private members" of the cloned event.
if (key[0] == key[0].toLowerCase() && $.inArray(key, ['__proto__', 'srcElement', 'target', 'toElement']) == -1) {
ev[key] = e.originalEvent[key];
}
}
doc.dispatchEvent(ev);
});
</script>
<body>
<iframe id="targetFrame" src="eventlistener.html"></iframe>
</body>
Here is my solution with jQuery. You can detect multiple events as I do below. Putting the .on() event handler inside the .on('load') event handler is necessary, because it would stop detecting the iframe content events when the iframe navigates to a new page otherwise. Additionally, I believe this only works if the iframe content is on the same domain as the parent page due to security, and there is no way around that.
$(document).ready(function() {
$('#iframe_id').on('load', function() {
$('#iframe_id').contents().on('click mousemove scroll', handlerFunction);
});
});
handlerFunction() {
//do stuff here triggered by events in the iframe
}
Basic way in document
var IE = document.all?true:false;
// If NS -- that is, !IE -- then set up for mouse capture
if (!IE) document.captureEvents(Event.MOUSEMOVE);
// Set-up to use getMouseXY function onMouseMove
document.onmousemove = getMouseXY;
// Temporary variables to hold mouse x-y pos.s
var tempX = 0;
var tempY = 0;
// Main function to retrieve mouse x-y pos.s
function getMouseXY(e) {
if (IE) { // grab the x-y pos.s if browser is IE
tempX = event.clientX + document.body.scrollLeft;
tempY = event.clientY + document.body.scrollTop;
} else { // grab the x-y pos.s if browser is NS
tempX = e.pageX;
tempY = e.pageY;
}
// catch possible negative values in NS4
if (tempX < 0){tempX = 0}
if (tempY < 0){tempY = 0}
// show the position values in the form named Show
// in the text fields named MouseX and MouseY
console.log(tempX, tempY);
return true;
}
Detect Mouse Move over Iframe
window.frames['showTime'].document.onmousemove = getMouseXY;
Detect Mouse Move over in Child Iframe under parent's Iframe
window.frames['showTime'].document.getElementById("myFrame").contentWindow.onmousemove = getMouseXY;
Trigger an IDLE detect function when no mouse move in Browser.
you can add a overlay on top of iframe when drag begin ( onmousedown event ) , and remove it when drag end ( on mouserup event ).
the jquery UI.layout plugin use this method to solve this problem.
Sorry for bad english.
Here's link to site.
My task is to create site with no scroll. When user clicks to right part of screen car starts to move forward. When it reaches middle of screen - car stops and fixed content-block starts to move in opossite direction. if user moves cursor to left side of screen (while holding mouse button clicked) car should move backward.
Desktop version works as expected. But mobile version is slow. (it's not exactly slow, it's not as smooth as desktop i guess)
What can i do fix this problem?
On touchstart event i get event.pageX value to check what part of screen user touched. (so i would know what direction car should move) and store this value in variable "mousePos". Then i call setInterval with movement function
On touchend event i clear interval to stop car from moving.
On touchmove i will rewrite "mousePos" var with new event.pageX value. For example: user clicked, car starts to move, if user moved cursor to left i will use this var to check direction and turn car back.
In mouseMove function i will check car position and decide what action should be done - either move car or move background and i'll check if it reached start of end points
events:
$(document).on('mousedown touchstart', '.mouse-click', function(event){
clicking = true;
mousePos = event.pageX;
if ( event.target.className == 'helper' ) {
showModal();
} else {
moveStuff = setInterval(mouseMove, 1);
}
});
$(document).on('mouseup touchend', function(){
clicking = false;
carLights.removeClass('blink');
clearInterval(moveStuff);
})
$(document).on('mousemove touchmove', '.mouse-click', function(event){
if(clicking == false) {
return;
} else {
mousePos = event.pageX;
}
});
function:
function mouseMove() {
let offset = parseInt( mainContent.css('left') );
let offsetCar = parseInt( car.css('left') );
if ( mousePos > middleScreen ) {
carLights.removeClass('blink');
if ( offset < - ( contentWidth ) ) {
return;
} else {
rotateWheelsForward();
if ( offsetCar < middleScreen ) {
car.css('left', (offsetCar + mouseSpeed) + 'px');
} else {
mainContent.css('left', (offset - mouseSpeed) + 'px');
}
}
} else if ( mousePos < middleScreen ) {
carLights.addClass('blink');
if ( offset > 0 ) {
carLights.removeClass('blink');
return;
} else {
rotateWheelsBackward();
if ( offsetCar > minCarLeft ) {
car.css('left', (offsetCar - mouseSpeed) + 'px');
} else {
mainContent.css('left', (offset + mouseSpeed) + 'px');
}
}
}
}
So how can i make movement smoother in mobile? (i use iphone 5s safari, but tested in iphone 6, still works bad)
What changes should i implement to this code?
I suggest to use transform rather than position eg: left, top cause thats really affect layer reflow-repaint. Use requestAnimationFrame (wisely) to perform smooth event animation like scroll, mouseup, or any other event.
Then use will-change: transform; to element which will "transformed" on the future. This will creates new layer and prepare for the element changes later.
In my case, relative position impact reflow or green flash on the rendering tool chrome. So I prefer use fixed/absolute position to prevent this.
Here's some great article for you to get Leaner, Meaner, Faster Animations with requestAnimationFrame and how to achieving 60 fps animations with css
Hope this help ;)
I have custom buttons that replaces the browser scrollbar. The idea is so that scrolling oversize elements in a page wouldn't result to a dozen scroll bar on a page.
See: https://jsfiddle.net/bwgxs6ng/
Since I must show some code sample (according to some SO error message), see this:
$('.right').on('click', function(event) {
var target = $(".image-container");
var current_x = target.scrollLeft();
if( target.length ) {
event.preventDefault();
$(target).animate({
scrollLeft: current_x+100
}, 500);
}
});
It's very simple, basically it takes current scroll position of the parent, and add x to it based on the direction that's clicked.
However, going further, I want it to imitate the hold and continuous scroll, but I'm not sure how to do it.
1) What is the mouse hold event called? (OK, this part is answered, it's called MouseDown as someone point out of the duplicate)
2) What is the continuous scrolling called, and how can I do something that'd imitate the browser's continuous scroll?
You can just call .animate() repeatedly (with easing set to linear, for smooth movement) inside your setInterval() callback. Just arrange for the interval to be equal to the animation duration, so that the next animation starts just when the previous one ends.
Or, better yet, make the interval shorter (say, 50 ms or less) and just call .prop() instead of .animate(), effectively performing your own animation. (This is how jQuery implements animation internally, anyway.)
Anyway, here's how I'd rewrite your code to support smooth continuous scrolling:
var speed_x = 0, speed_y = 0;
var timer = null;
var target = $(".image-container");
function scroll() {
if (speed_x == 0 && speed_y == 0) return;
var current_x = target.scrollLeft();
var current_y = target.scrollTop();
target.prop({
scrollLeft: current_x - speed_x,
scrollTop: current_y - speed_y
});
}
$('.control').on('mouseover mouseout', function (event) {
var $this = $(this);
var speed = (event.type == 'mouseover' ? 10 : 0)
if ($this.hasClass('left')) speed_x = +speed;
if ($this.hasClass('right')) speed_x = -speed;
if ($this.hasClass('up')) speed_y = +speed;
if ($this.hasClass('down')) speed_y = -speed;
}).on( 'mousedown', function () {
scroll();
if (timer !== null) clearInterval(timer);
timer = setInterval(scroll, 50);
return false;
});
$(document).on('mouseup', function () {
if (timer !== null) clearInterval(timer);
timer = null;
});
Note how the animation is started and stopped in the mousedown and mouseup handlers, but the direction of movement is set on mouseover and mouseout. This allows you to change the scrolling direction while holding the mouse down, by dragging the cursor from one edge to another.
(For bonus points, add divs with e.g. class="control up left" in the corners of the scroll area, so that holding the mouse down over those corners will allow you to scroll diagonally. The JS code above already supports it.)
you need to set an interval on mousedown, and clear the interval on mouseup, as done in this fiddle for left and right.
The relevant code change is that we removed the click event and replaced it with
$('.left').on('mousedown', function(event) {
... scroll code ...
interval = setInterval(function(){
... scroll code ...
},500);
})
.on('mouseup',function(){clearInterval(interval);});
I am using event.preventDefault but after some checks, I want the event to continue.
For eg, For the
touchmove
event I am using event.preventDefault() as I don't want the browser to scroll horizontally, but after determining the direction of swipe, if the direction turns out to be up/down, whatever event i have prevented, i want to nullify the effect. Is that possible?
My scenario
This is my html
<div id="teazer" class="globalTeaser" ontouchcancel="touchCancel(event);" ontouchmove="touchMove(event);" ontouchend="touchEnd(event,'gTeaser');" ontouchstart="touchStart(event,'teazer');">
This is my js after removing the irrelevant part
function touchMove(event) {
if(fingerCount==1){
event.preventDefault();
if ( event.touches.length == 1 ) {
curX = event.touches[0].pageX;
curY = event.touches[0].pageY;
}
else {
touchCancel(event);
}
}else {
touchCancel(event);
alert("hi");
}
}
function touchEnd(event,eventType) {
//I get the swipe direction here,after some calculations
//I get the directions fine,now
//if the swipe direction is up/down whatever event i have prevented in touch move I need to nullify
}
Please note, if anyone is gonna suggest window.scrollBy, for some reason its not working for me. Any other solutions I am happy to try.
I don't know how your code behaves exactly, but this is the general principle:
// Keep a reference for last point both events can access
var start;
$( 'body' ).on( {
// On start, assign the event data to start
touchstart : function touchStart( touchstartEvent ){
start = touchstartEvent.touches[ 0 ];
},
touchmove : function touchMove( touchmoveEvent ){
// The difference between both events positions
var delta = {};
// The end event's position
var end = touchmoveEvent.touches[ 0 ];
// Calculate the offset compared to start for this move event
delata.pageX = start.pageX - end.pageX;
delata.pageY = start.pageY - end.pageY;
// If pageX is less than or greater than 0, it means there has been horizontal movement,
// and this if condition will pass
if( delta.pageX ){
touchmoveEvent.preventDefault();
}
}
} );
This isn't perfect, because in practice it's very difficult to create a perfect downward or upward swipe — my finger might move a couple of pixels left or right even if the main movement is downwards. But then you have the problem of preventing horizontal motion but not vertical! In any case, the general principal for testing different properties of a touch event and only preventing default in certain conditions is illustrated.
My touchMove() function has been rewritten as follows
function touchMove(event) {
if (event.touches.length == 1) {
curX = event.touches[0].pageX;
curY = event.touches[0].pageY;
if (Math.abs((curX - startX)) > 10) {
//default acion is prevented only if the
//finger count is one and change in
//x coordinatesis greater than 10 px
event.preventDefault();
}
}
else {
touchCancel(event);
}
}
This code will make sure of two things
1)Pinch to zoom is not affected
2)default action for vertical swipe is not affected
I have a series of buttons of fixed height and width, those need to be draggable and droppable anywhere inside the parent div.
As per client request, I cannot use any external libraries, meh... I could have done this with jQuery in seconds but, I guess this is one of its drawbacks: you don't get to learn more basic stuff...
How would I go about doing it? A problem with this is that those buttons are inside a div that is also draggable so I need to be careful about positioning, I can only probably use relative.
Any ideas how I can go about doing it? Thanks in advance.
Peter-Paul Koch wrote an excellent how-to on drag and drop. I only remembered this 3/4 of the way through writing my own, so I wrapped that up in a fiddle.
function makeDraggable(draggable, container){
// In case you don't want to have a container
var container = container || window;
// So we know what to do on mouseup:
// At this point we're not sure the user wants to drag
var dragging = false;
// The movement listener and position modifier
function dragHandler(moveEvent){
moveEvent.preventDefault();
dragging = true;
// Ascertain where the mouse is
var coordinates = [
moveEvent.clientX,
moveEvent.clientY
];
// Style properties we need to apply to the element
var styleValues = {
position : 'absolute',
left : coordinates[0] + 'px',
top : coordinates[1] + 'px'
};
// Apply said styles
for(property in styleValues){
if(styleValues.hasOwnProperty(property)){
draggable.style[property] = styleValues[property];
}
}
}
function dropHandler(upEvent){
// Only interfere if we've had a drag event
if(dragging === true){
// We don't want the button click event to fire!
upEvent.preventDefault();
// We don't want to listen for drag and drop until this is clicked again
container.removeEventListener('mousemove', dragHandler, false);
draggable.removeEventListener('mouseup', dropHandler, false);
dragging = false;
}
}
// Where all the fun happens
draggable.addEventListener('mousedown', function dragListener(downEvent){
downEvent.preventDefault();
// The drag event
container.addEventListener('mousemove', dragHandler, false);
// The end of drag, if dragging occurred
draggable.addEventListener('mouseup', dropHandler, false);
}, false);
}