taye / interact.js

JavaScript drag and drop, resizing and multi-touch gestures with inertia and snapping for modern browsers (and also IE9+)
http://interactjs.io/
MIT License
12.19k stars 782 forks source link

Handle draggables from outside <object> into SVG #1009

Open emmernme opened 9 months ago

emmernme commented 9 months ago

Expected behavior

In order to seamlessly have dropzones inside embedded SVG files in HTML Object elements, rectChecker() needs a custom function. It would be great if this functionality was included in the plugin.

Actual behavior

When embedding SVG in <object> and creating dropzones, the dropzones are, by default, positioned relative to the <object> inner dimensions. When creating draggables outside of the <object>, these are relative to the main window. The draggables and dropzones will then not interact properly.

System configuration

interact.js version: Browser name and version: Operating System:

Solution

Setting a custom rectChecker() for the dropzones inside the <object> resolves this, e.g.:

const objectElement = document.getElementById("svgParentObject");
zone.rectChecker((element) => {
  // Adapted from main rectChecker in interactjs, accounting from space from parent SVG object to the rest of the page
  const rect = element.getBoundingClientRect();
  const clientRect = (
    rect && {
      left: rect.left,
      right: rect.right,
      top: rect.top,
      bottom: rect.bottom,
      width: rect.width || rect.right - rect.left,
      height: rect.height || rect.bottom - rect.top,
    }
  );
    const scroll = {
      x: window.scrollX || window.document.documentElement.scrollLeft,
      y: window.scrollY || window.document.documentElement.scrollTop,
    };
    clientRect.left += scroll.x;
    clientRect.right += scroll.x;
    clientRect.top += scroll.y;
    clientRect.bottom += scroll.y;

  const parentRect = objectElement.getBoundingClientRect();
  clientRect.left += parentRect.left;
  clientRect.right += parentRect.left;
  clientRect.top += parentRect.top;
  clientRect.bottom += parentRect.top;

  return clientRect;
});