hopscotch icon indicating copy to clipboard operation
hopscotch copied to clipboard

Support for mobile devices and responsive sites

Open halloffame opened this issue 11 years ago • 7 comments

The bubbles should check to see if they are displaying off screen and if they are they should move and/or resize automatically.

halloffame avatar Sep 19 '13 18:09 halloffame

I added a pull request for this. Let me know what you think. https://github.com/linkedin/hopscotch/pull/31

halloffame avatar Sep 19 '13 23:09 halloffame

The pull request appears to only address bottom or top placed bubbles. What about left or right placed ones that show up off screen?

jrawlings avatar Oct 29 '13 17:10 jrawlings

Hi all - thanks for the great plugin. Has there been any progress made for responsive design?

snipe avatar May 15 '15 00:05 snipe

Sorry, not presently. @kate2753, I think we need to come to some sort of conclusion if this is a plugin candidate or core enhancement. Feels like this should be an update to core since all the placement logic is currently the responsibility of the core library... perhaps a broader rewrite of our placement logic to consider if a given bubble placement will end up off screen. Though, then what edge cases might we start crashing into if we start assuming alternate placements and bubble sizes for tour steps?

timlindvall avatar May 19 '15 22:05 timlindvall

I can partially address this by separating steps from placement and creating multiple placement configurations. However, it's not great because the same element might be in different positions depending on viewport size (line-wrapping) so I would need to either go even more granular on widths or just deal with it looking bad.

All this really needs to do is intelligently say, "If I am placed off-screen, how far do I need to move (x/y) to be on-screen and then readjust the arrow (if no hard-coded offset, or just override) to still point correctly."

It would be ideal to sort of define placement separately and responsively:

var responsiveTour = {
  id: "responsive",
  steps: [
    {
      target: ".target",
      xOffset: "center",
      arrowOffset: "target",
      media: {
        "min-width: 480px": {
        // exact same options as normal step, but cascades
        },
        "min-width: 768px": {
        // exact same options as normal step, but cascades
        }
      }
    }
  ]

Would use window.matchMedia if available or use matchMedia poly.

By the way, target option for arrow would have it try its best to position itself along x-axis of bubble closest to target element.

For this to work nicely, calculating positioning should always happen after calling onShow or if possible, onBeforeShow because I might take action that adjusts the DOM in preparation for a step (right now I do this in onShow).

kamranayub avatar May 29 '15 18:05 kamranayub

This is what I added after VERTICAL OFFSET conditional in setPosition.

// ADJUST FOR VIEWPORT
      var wd = { width: $(window).outerWidth(), height: $(window).outerHeight() };
      var right = (left + bubbleBoundingWidth),
          bottom = (top + bubbleBoundingHeight);

      if (right > wd.width) {
         left -= (right - wd.width + 20);
         if (arrowOffset !== 'center' && (step.placement === 'bottom' || step.placement === 'top')) {
            arrowEl.style.left = (arrowOffset + (right - wd.width + 20)) + "px";
         }
      }
      if (left < 0) {
         left += (-left + 20);
      }
      if (bottom > wd.height) {
         top -= (bottom - wd.height + 20);
      }

I know I'm missing a couple cases (moving arrow when top changes) but this fixed my issues. I combined it with the approach I mentioned above (though simpler), like this:

var isMobile = $("header.mobile").css("display") === "block";

// step
{
  target: isMobile ? "#toggle-sidebar" : "#sidebar header",
  placement: isMobile ? "bottom" : "right",
  title: "Foo",
  content: "Bar"
}

I could have just as easily done my own matchMedia query but I use bootstrap so some things are visible/hidden depending on screen size and I'd rather just test the display state of an element.

This pretty much resolves it for me. The code I added to bubbles will simply nudge it back into the viewport. If a user wants to handle special cases, they can do it themselves like I did. A more formal way to declare responsive placement would be the next step.

Note: this doesn't make the tour "responsive" when adjusting viewport because I don't need to handle that. The only use case that would make sense for is ensuring orientation change works.

kamranayub avatar May 29 '15 20:05 kamranayub

I just wanted to note that kamranayub's solution above worked perfectly for me, except I had some issues with the first line and ended up changing it to:

var wd = { width: screen.availWidth, height: screen.availHeight };

After that minor change, my tour bubbles all now stay within the viewport on mobile devices (though I haven't tested it extensively with every possible option or OS yet).

foxylearning avatar May 20 '17 05:05 foxylearning