Code Monkey home page Code Monkey logo

Comments (12)

goneale avatar goneale commented on May 18, 2024 3

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.

elmasry avatar elmasry commented on May 18, 2024 1

@niklasramo What do you suggest for this issue in muuri 0.8 since hammerjs is not used anymore?

from muuri.

niklasramo avatar niklasramo commented on May 18, 2024

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.

niklasramo avatar niklasramo commented on May 18, 2024

Just for kicks, here's the v0.3.0 dragStartPredicate documentation: https://github.com/haltu/muuri/tree/dev#dragstartpredicate-

from muuri.

coffeebite avatar coffeebite commented on May 18, 2024

@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.

niklasramo avatar niklasramo commented on May 18, 2024

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.

niklasramo avatar niklasramo commented on May 18, 2024

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.

coffeebite avatar coffeebite commented on May 18, 2024

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.

niklasramo avatar niklasramo commented on May 18, 2024

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.

coffeebite avatar coffeebite commented on May 18, 2024

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.

 avatar commented on May 18, 2024

Not working! Please pay attention

from muuri.

abishekreddy avatar abishekreddy commented on May 18, 2024

@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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.