I am trying to create an effect like the iphone touch screen drag scroll with inertia but for a desktop browser.
It seems like this is the code that I'm after:
smoothstep_eo(t) = 2*smoothstep((t+1)/2) - 1
From here - https://stackoverflow.com/a/196209/348174
But I'm having difficulty working out how to implement it.
I imagine using that code somehow to calculate the movement of a click, drag and release and then applying the value to scrollToTop() frame by frame.
Any advice on how to approach this.
I suggest you use Cubiq.org's iScroll 5.
It's a jQuery plugin that works really well and does all the emulating of touch-by-mouse perfectly fine.
Related
Since I´m working on a project where I need to be able to drag objects around my canvas but also to scroll the entire page by dragging the actual canvas 'background' behind my PIXI Sprites, i followed the findings of this guy here:
https://github.com/pixijs/pixi.js/issues/2483 :
By default, the Pixi canvas/display-area cannot be used to scroll the
webpage that contains it. Which is important on touch screens. (eg. If
you use the rest of the web-page to pinch-zoom into the Pixi canvas,
you can become trapped and unable to zoom back out (or pan away),
because there's no non-Pixi-canvas area of the page to "grab" with
your pinch gesture).
To enable this functionality, I use autoPreventDefault. But this comes
with some undesirable side-effects, like scroll/pinch-zoom actions
over the canvas registering "taps" or clicks in a way that doesn't
make sense. (ie. I'm attempting to zoom or scroll the outer page at
that point, not interact with the Pixi canvas)
To work around that, I modify and compile my own custom version of
Pixi where I can apply preventDefault in a more granular way...
To get page-scrolling functionality it seems I only need to
preventDefault in the InteractionManager.prototype.onTouchEnd
function. Whereas autoPreventDefault will also preventDefault on 3
other events. (onMouseDown, onTouchMove, onTouchStart).
Leaving autoPreventDefault = false and applying preventDefault only to
onTouchEnd, gives me the functionality I need. But it'd be nice to not
have to customize and rebuild Pixi in this way every release. (Sorry
if there's something else I'm missing here; I don't completely
understand the event system in Pixi, or what else to do about this
scroll-touch problem)
So i disabled e.preventDefault() on 'onTouchStart' and on 'onMouseMove' but left it as is on 'onTouchEnd'
This works perfect on IOS devices but not on Android, the only exception being a Samsung A7 using Adblock browser (fails on Chrome).
Would really appreciate some help on this.
TLDR:
Disabling PIXI´s e.preventDefault on onTouchStart and onMouseMove works on IOS devices and lets me scroll the page by draggin my canvas around but not on Android devices.
My solution for that was to use
renderer.plugins.interaction.autoPreventDefault = false
This should work on iOS and Android.
Docs for autoPreventDefault reads:
Should the manager automatically prevent default browser actions.
Using PIXI 4.5.6.
Take a look at the docs:
http://pixijs.download/dev/docs/PIXI.CanvasRenderer.html#plugins
http://pixijs.download/dev/docs/PIXI.interaction.InteractionManager.html
Using renderer.plugins.interaction.autoPreventDefault=true should do the trick.
Before you say this isn't possible, I know it is. Here's an example: http://victoriabeckham.landrover.com/INT
The main problem is that iOS freezes DOM manipulation on scroll, so you have to use some sort of technique to overcome the problem. The parallax plugin I was hoping to use is stellar.js, but the issue I am running into is that the "iOS demo" for that plugin isn't really usable on a desktop. I fiddled with it for 3 hours this morning, and couldn't get a setup that works correctly on both iOS and desktop.
I need some ideas, either a technique to configure stellar.js to work the same way on both (I'm not sure if that's possible), or another library that works on both, or maybe some insight on how I could program a workaround myself.
Any help is appreciated.
Step 1: Create and object like this
{
startFrameNumber: {
//first obj
id: idOfElement
duration: howeverManyFrames
startLeft: whatever
endLeft: whatever
startTop: stillWhatever
endTop: whateverAgain
},
nextStartFrameNumber: {
}
}
Step 2: Make the page unscrollable via CSS, ie 100% height and width with and overflow: hidden
Step 3: When the user scrolls (via custom scrollbar, keyboard action, or touch events) advance the animation x frames based on how far they scrolled or whatever. If your animation object you created has a key [frame] then add that to the queue of things that are visible and moving, and move all those things in the queue to their appropriate places and/or remove them from the queue of active objects
That's it. The function for moving things around should be pretty straight forward, except getting the animations smooth will take a little playing around with.
Simply scroll each layer of parallax effect manually and control them yourself without relying on browser's page scrolling.
I've successfully implemented cross device/browser parallax scrolling with the help of the Zynga Scroller js library.
It takes care of one of your main concerns which is the interoperability of click and touch events and scrolling on mobile webkit devices – this allows you to manipulate the DOM as you scroll.
Then, to create the parallax effect you have three options:
Simulating a real-world 3d parallax by using 3d transforms (with a parent/wrapper element that controls perspective and transform origin).
Using a 2d parallax library such as stellar.js or skrollr
Building your own parallax scrolling algorithm.
Here's a quick demo (using existing sample code) of option 1 showing how smooth parallax scrolling would work across desktop and mobile devices. Of course, you're limited to devices that have support for 3d transforms. Note that the Zynga Scroller works via click/touch and drag – it should probably not be used as a dekstop solution as the only thing that would be required is overflow: scroll in CSS.
Have a look at the jQuery-Plugin "Scroll Path" http://joelb.me/scrollpath and combine this with different layers and speeds. You will have recognized that the scrolling of the example page is not just a vertical parallax stage but also moves layers horizontally while you scroll up and down. This is possible with Scroll Path.
Try using http://cubiq.org/iscroll-4 and stellar.js together.
Do your parallax stuff for desktop normally and then add a 'touchmove' Event Listener to fire the scroll event:
document.body.addEventListener('touchmove', function(){$window.scroll()}, true);
Tested and working on iPad 2 with iOs 5.1.1
I currently use $(window).bind('scroll', foo); to monitor $(window).scrollTop() and do stuff to create a parallax effect.
In all desktop browsers foo() is called for each pixel the user scrolls, and everything is nice and dandy. In Safari on iOS, the scroll event is only fired AFTER the scrolling is finished.
I added $(window).bind('touchmove', foo); to make sure the function is called during the swipe in iOS, and it got me a little bit further. When user releases finger, the page continues to scroll, but the event stops firing.
Any ideas?
When I saw your question, I was planning to do a polyfill for this (if such does not exist?). Unfortunately I've had very little time.
The idea is to have a setInterval, which is initiated ontouchstart, and it checks whether document.body.scrollTop has changed since last time, eg. for every 20 milliseconds. And if it is, then we manually dispatch the scroll event. Otherwise we clearInterval since apparently there's no more scrolling happening.
This it would be in brief. If you got more time (than I do), then feel free to try with those guidelines.
Edit: Now, reading further, the same idea is seems to be suggested on the other answer. Are you certain that intervals are stopped whilst scrolling on iPad?
I highly recommend using the "Skrollr" javascript library. It is by far the best mobile scrolling animation option that I've found to date and is very easy to get up and running quickly. Create animations and manipulate CSS based on a start and end scroll position. Create as many data scroll positions and animations as you need for most standard CSS properties.
In the following example the background color would animate over the course of a 500 pixel scroll:
<div data-0="background-color:rgb(0,0,255);" data-500="background-color:rgb(255,0,0);">WOOOT</div>
Checkout the repository on Git: https://github.com/Prinzhorn/skrollr
Skrollr Demo Example: http://prinzhorn.github.io/skrollr/
Awesome real world example: http://www.fontwalk.de/03/
Apple's webpage for iPhone 5c uses some parallax scrolling effects that seem to continue with your finger still touching the screen and scrolling. So I guess javascript can't be entirely disabled during scroll. Tumult Hype provides this functionality too.
While this isn't possible out of the box, so to speak, you can do it using iscroll
So, you'd use iScroll for iOS and Android mobile devices / tablets, and use the way you're currently doing it for desktop devices.
iScroll has a bunch of options for callback functions to be called on certain events - such as 'onScrollMove', 'onBeforeScrollEnd', 'onTouchEnd', etc. Unfortunately, there's not an option to execute a callback on "EVERY position change, including changes cause by the momentum of scrolling after the user has stoped touching the screen". But, it's easy enough to add one.
In the iScroll source, around line 127, near the "//Events" comment, add a new variable:
onPosChange: null
Then, around line 308, at the end of the "_pos" function, add this line:
if (this.options.onPosChange) this.options.onPosChange.call();
(that will just call the function passed in the "onPosChange" option, if it exists).
Having done that, the following example code will set up iScroll for the div with id="iscroll_container", and will print the Y-offset to the console each time it changes:
var myScroll;
function loaded() {
myScroll = new iScroll('iscroll_container', { onPosChange: actOnScroll });
}
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
//Use this for high compatibility (iDevice + Android)
document.addEventListener('DOMContentLoaded', function () { setTimeout(loaded, 200); }, false);
function actOnScroll(){
console.log('got a scroll move! Vert offset is: ' + myScroll.y);
}
Note, Ben the Bodyguard Parallax Site works on iPad by using iScroll (they use a much older version of iscroll and don't do it exactly the way I described here)
Also, Life of Pi Parallax Site works on iPad really nicely - I can't figure out how they do it, but at least it proves it's possible!
This could be a bug with jQuery itself: http://bugs.jquery.com/ticket/6446
That ticket has been open for a while and pertains to iOS 4, but perhaps you should investigate calculating the scroll position with pure javascript.
As I know there is no javascript execution while scrolling on the most mobile devices.
There are some workarounds (f.e. iscroll) out there.
Iscroll is using css-technique "transform".
But there is no way to execute javascript while scrolling.
I suppose the smoothe scrolling-algorithm is too expensive.
I am designing a code snippet which will allow the user to scroll the items inside a div. Its more of a spinning wheel / slot machine. I know an existing solution for iPhone / iPod, but I wanted to have a simple stripped down code.
I have not used any images, and I believe this would involve CSS3 animations.
So far here is my code in jsbin. I have tried binding the touchmove event using jquery, but the alert is not popping up?
My main aim is to enable the user to scroll / swipe Up & down the items inside the div, without making the page scroll up and down. Any suggestion / edits to the code are appreciated.
My intended use for this is for mobile devices (iPhone / Android)
Thanks in advance.
you've almost been on the right side:
http://cubiq.org/iscroll-4
try iScroll.
only limitation that i encountered during my test was that you have to wrap your code in a list (ul) - though that could have been my bad
I think what you are looking for can be achieved by simply using the deafult behavior on IOS Safari (iPhone/iPad)
Just give some fixed height to the container div with overflow
e.g.
<div id="container" style="height:400px;overflow:auto">
Your content
</div>
It would scroll using 2-fingers on versions prior to IOS5 and with a single-finger move for IOS5 and later..
I have coded a jquery script where there is a small grid on screen and using drag and drop users can place tiles on the grid (snaps in place). Currently if you hover over a tile it fades in the option to rotate, but I would much prefer it if you could right click to rotate (making it more natural). I understand blocking right click completely is often frowned upon so was wondering if it was possible just within a particular element, then capturing that event, doing something in JS and disabling the context menu? - that works in every browser.
On a side note, currently I am using jQuery for effects and custom javascript for drag and drop, is it worth looking at a jQuery plugin for drag and drop?
Many thanks,
For capturing the right click, you can use this jquery:
$('#gridID').bind('contextmenu', function(e) {
// do stuff here instead of normal context menu
return false;
});
This works in chrome, firefox, and safari. Haven't tested IE. Works in IE too. Only caveat is it doesn't work in Opera apparently. So if you can live with that...
I'm not a fan of using the right mouse button on web pages. However, if you really want to do it, you could trap the right mouse button as described here. You could block the right mouse button (in other words return false in your event handler) conditionally if the mouse is over your grid cells.
Regarding your bonus question: jquery ui has drag & drop functionality. It's probably easier to use that than rolling your own.
"is it worth looking at a jQuery plugin for drag and drop?"
Only if you don't intend your application to be used on the iPhone O.S with safari, i.e. including iPad, see Safari Web Content Guide: Handling Events