anvaka / panzoom

Universal pan and zoom library (DOM, SVG, Custom)
https://anvaka.github.io/panzoom/demo/attach-via-script.html
MIT License
1.8k stars 290 forks source link

what does this error "ui element is required to be within the scene" mean? #47

Open MohammedAbdulMateen opened 6 years ago

MohammedAbdulMateen commented 6 years ago

I am getting the above mentioned error with centerOn() function, what am I supposed to pass to it?

this is my HTML structure

<div class="faqdesigner-container">
    <div class="faqdesigner">
        <div class="faqstart"></div>
        <div class="faqnode"></div>
        <svg class="connector"></svg>
        <div class="label-overlay"></div>
        <div class="faqend"></div>
    </div>
</div>

and this is my pan zoom initializer

function initPanzoom() {
    // just grab any DOM element
    var area = document.querySelector('.faqdesigner');

    var x = $('.faqdesigner-container').width() / 2;
    var y = $('.faqdesigner-container').height() / 2;

    // And pass it to panzoom
    var panzoomInstance = panzoom(area, {
        zoomDoubleClickSpeed: 1
    });

    panzoomInstance.moveTo(x, y);
}

To centerOn() I tried sending div (.faqnode) and svg (.connector) as argument

I am using this plugin for a flow designer, and I want to show flow in the center of the screen during page load, I tried doing that using zoomAbs() and moveTo() but no luck

so I thought centerOn() will be helpful, to just center to the starting node in the diagram

please help on how I can achieve this?

verilog15 commented 5 years ago

Did you solve the issue?

linus-amg commented 5 years ago

@MohammedAbdulMateen I had the same issue, centerOn only seems to work when your panzoom scene is inside an svg, I had a case similar to yours and had to write a custom centerOn which understands something else then svg. My centerOn function looks like this:

  function centerOn(ui) {
    const parent = ui.parentNode.parentNode;
    if (!parent) throw new Error('ui element is required to be within the scene');

    // TODO: should i use controller's screen CTM?
    const clientRect = ui.getBoundingClientRect();
    const cx = clientRect.left + clientRect.width / 2;
    const cy = clientRect.top + clientRect.height / 2;

    const container = parent.getBoundingClientRect();
    const dx = container.width / 2 - cx;
    const dy = container.height / 2 - cy;

    internalMoveBy(dx, dy, true);
  }

but it probably only works for me, since i have that specific nesting with .parentNode.parentNode. But you can use it to write your own.

linus-amg commented 5 years ago

Ideally the centerOn method accepts the parent as a second argument instead of having to figure it out, then you can remove the first 2 lines and pass parent through the arguments. Like so:

  function centerOn(ui, parent) {

    // TODO: should i use controller's screen CTM?
    const clientRect = ui.getBoundingClientRect();
    const cx = clientRect.left + clientRect.width / 2;
    const cy = clientRect.top + clientRect.height / 2;

    const container = parent.getBoundingClientRect();
    const dx = container.width / 2 - cx;
    const dy = container.height / 2 - cy;

    internalMoveBy(dx, dy, true);
  }