Comments (12)
Guys I drew a lot from what @niklasramo had wrote, and I came up with the following. The key winner for me was actually setting the touchAction
as advised but via the dragHammerSetttings.
This has allowed dragging via touch and hold and scrolling on mobile.
let grid = new Muuri('.grid', {
dragEnabled: true,
dragHammerSettings: {
touchAction: 'pan-y'
},
dragStartPredicate: (item, hammerEvent) => {
// Whenever the user starts to drag an item this function is called
// on each move until the the resolve callback is executed (with the
// hammerEvent as it's argument). When the resolve callback is
// executed Muuri's own dragging process starts and the item starts
// to actually move.
//console.log(hammerEvent.pointerType);
// For mouse interactions let's just start dragging immediately.
if (hammerEvent.pointerType === 'mouse') {
this.isResolved = true;
return true;
}
// For other type of interactions (touch) let's wait 500ms before dragging starts.
else {
if (hammerEvent.deltaTime >= 500) {
this.isResolved = true;
return true;
}
}
}
});
from muuri.
@niklasramo What do you suggest for this issue in muuri 0.8 since hammerjs is not used anymore?
from muuri.
Actually I though about this issue a lot when creating Muuri and originally developed a solution exactly as you described. For desktop browsers the dragging started as it starts now, but on touch devices you needed to hold the item a while before dragging would start. However, the result turned out to be a bit of an unreliable hack and then I also started thinking that what if the user wants to use some other logic for starting the drag.
So I created the dragPredicate option to solve the problem. It's not documented well (there's only a mention of it in the docs) but with it you can define when the dragging should start.
For starters you can check out the default predicate here: https://github.com/haltu/muuri/blob/master/muuri.js#L3004
Here's a bit more in-depth explanation:
var grid = new Muuri({
container: document.getElementsByClassName('grid')[0],
items: [].slice.call(document.getElementsByClassName('item')),
dragEnabled: true,
dragPredicate: function (hammerEvent, item, resolve) {
// Whenever the user starts to drag an item this function is called
// on each move until the the resolve callback is executed (with the
// hammerEvent as it's argument). When the resolve callback is
// executed Muuri's own dragging process starts and the item starts
// to actually move.
// Let's do nothing if the predicate is already resolved.
if (this.isResolved) {
return;
}
// For mouse interactions let's just start dragging immediately.
if (hammerEvent.pointerType === 'mouse') {
this.isResolved = true;
resolve(hammerEvent);
}
// For other type of interactions (touch) let's wait 500ms before dragging starts.
else {
if (hammerEvent.deltaTime >= 500) {
this.isResolved = true;
resolve(hammerEvent);
}
}
}
});
Alrighty, so with the dragPredicate you can create any kind of custom logic for starting the drag, and also target mouse and touch events. Cool. But that still leaves us with the problem of "touch-action: none". That style should be only set to the items so you should be able to scroll the page when swiping the grid container but not the items. If you want to allow swiping over the items also you have to manually remove the "touch-action:none" style from the items after initiating the muuri instance or changing it something else: https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action. I reckon "pan-y" would be good for vertically scrolling page and "pan-x" for horizontally scrolling page.
So yep, it's a bit of a hassle to make it work nicely with scrolling, but should be doable. I'm open to any suggestions to make this process easier for the users of Muuri ;) Btw. the drag predicate system has been completely revamped in v0.3.0 and has some nice improvements.
from muuri.
Just for kicks, here's the v0.3.0 dragStartPredicate documentation: https://github.com/haltu/muuri/tree/dev#dragstartpredicate-
from muuri.
@niklasramo Thanks. That really helped. One last trouble I am having is that the page isn't scrolling as I am dragging an item below the viewport. The same problem happens on desktop sometimes.
from muuri.
Yep, that's a known issue or more specifically a feature that is not yet implemented. There's already an open issue related to that: #9
from muuri.
If you need the the scrolling while dragging feature asap you could try to implement it yourself outside muuri, as a muuri plugin. Should not be massively hard.
from muuri.
More than happy to contribute. I wonder if the right approach, though, would be to let muuri handle all the positioning logic (including how items move as other items are dragged around) and outsource the dragging and dropping functionality to something like jquery draggable.
from muuri.
Awesome!! 👍
The right approach would be not including jQuery into this =) In all it's simplicity I'd just hook on to the muuri's drag events and (based on the position of the dragged item) scroll the viewport (or whatever element you wish) whenever necessary.
Here's a good plugin boilerplate to get you started:
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
define(['muuri'], function (Muuri) {
factory(global, Muuri);
});
}
else if (typeof module === 'object' && module.exports) {
factory(global, require('muuri'));
}
else {
factory(global, global.Muuri);
}
}(this, function (global, Muuri) {
'use strict';
// Add the plugin code/logic here...
Muuri.prototype.scrollOnDrag = function (options) {
this
.on('dragstart', function (item, data) {
})
.on('dragmove', function (item, data) {
})
.on('dragscroll', function (item, data) {
})
.on('dragend', function (item, data) {
});
return this;
};
return Muuri;
}));
Then you would init this plugin, just by including the plugin file after muuri.js and calling muuri.scrollOnDrag()
to any muuri instance you want to bind the plugin functionality to.
The above boilerplate is for v0.2.0, but it should be easily portable to v0.3.0 after it's released. The only big difference is that in v0.3.0 you just get the item and hammer event as the arguments for the drag events. In the current v0.2.0 version you receive some additional data.
from muuri.
Thanks very much.
The reason I suggested that approach is because dragging well requires a lot of little things that a good dragging library would have taken care of. So muuri can do the hard parts of binpacking and rearranging.
from muuri.
Not working! Please pay attention
from muuri.
@niklasramo @goneale - The approach you suggested seems to work fine on iOS (pan-y is supported in versions > 13.1) but on android we are having to initiate the drag in the horizontal direction before we can move it vertically. I am unable to drag it vertically directly after the long press. Do you have any workaround for this issue?
from muuri.
Related Issues (20)
- 卡片
- Issue with horizontal alignment of items
- TypeError: Cannot read properties of undefined (reading 'eventController')
- fillGaps property does not seem to work HOT 1
- Reset grid layout? (draggable grid)
- dragSortPredicate does not seem to work properly HOT 2
- question: drag/sort behaviour without the drag & sort HOT 1
- Retrieve the position of hidden grid items in custom layout function
- Is this maintained ? HOT 6
- Scaling Effects during dragging
- vue
- Add a new Item and snap to grid
- Drag Start Delay On Touch
- throws an error "window is not defined" HOT 1
- Muuri Doesn't Work on Tailwindcss Classe HOT 2
- grid.show() doesn't toggle items on, but grid.hide() toggles off. HOT 1
- Incompatible with zoom HOT 1
- Chrome app on iOS. Element glitching when placed in sortable container HOT 2
- How to keep a specific item of a grid frozen in the same position while the grid is being sorted from a dragSort? HOT 2
- How to initiate a grid.move() based on the dragged item's position, even when the item is outside the grid? HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from muuri.