Melkeydev / astrostation

https://astrostation.me
MIT License
214 stars 43 forks source link

Change z-index implementation for drag and drop #245

Closed royanger closed 1 year ago

royanger commented 1 year ago

Currently when dragging a widget the z-index just scales.

New behaviour:

Melkeydev commented 1 year ago

i feel i should be responsible for fixing this one lol

royanger commented 1 year ago

No

justnat3 commented 1 year ago

This function is run as a d-card(draggable-card) is held by the cursor. I am looking for some guidance here, this still seems wrong- but here is what I have so far. Not entirely sure if this is any better than the original- elements is only 7 elements in length in my testing.

Original Implementation

 function trackPosition() {
    setZ(++int);
  }

Refactored

  // FIXME: change name
  function trackPosition() {
    const elements = document.querySelectorAll(".react-draggable");
    let draggable = dref.current;
    let _dref = dref.current;

    if (typeof draggable === 'object' && draggable !== null && 'getBoundingClientRect' in draggable) {
      // @ts-ignore
      draggable = draggable.getBoundingClientRect();
    } else { return; }

    elements.forEach((node) => {
      // @ts-ignore
      const node_rect = node.getBoundingClientRect()

      // @ts-ignore
      // if we are the same element, return early
      if ((node_rect.width, node_rect.height) === (draggable.width, draggable.height)) return;

      // check bounds against the other elements 
      if (
        node_rect.bottom >= draggable.top &&
        node_rect.right >= draggable.left &&
        node_rect.left <= draggable.right &&
        node_rect.top <= draggable.bottom
      ) 
      {
        // only increment the zindex if we are overlapping another d-card
        const node_z = Number(window.getComputedStyle(node).zIndex);
        const dref_z = Number(window.getComputedStyle(_dref).zIndex);
        if(node_z > dref_z) {
          setZ(node_z + 1);
        }
      }
    });
  }

Let me know your thoughts :)

justnat3 commented 1 year ago

@Melkeydev @royanger @Hacksore

justnat3 commented 1 year ago

I did some profiling, here are the profiles.

My Implementation Original

I imagine there is a better more optimal way, but I am unsure of it right now.

justnat3 commented 1 year ago

What would be more optimal is if we already had access to all the refs ahead of time.

But even then, we have to repaint when we move a draggable, this will call the function connected to "OnDrag"

so in that case what is more optimal? Continuing to increment a computed style or discovering if we are overlaying another element. It seems like the ladder is more expensive, because we end up asking for more from the browser. Its not exactly cheap.

Do we care about optimal if it acts the same? The trade off is that we have to increment z-index far less.

in that case, z-index may cause a layout change because a computed style changed. Which is also expensive if we are doing it every inc of our zindex.

-braindump

justnat3 commented 1 year ago

Currently when dragging a widget the z-index just scales.

New behaviour:

add default new z-index of 50 in a new store

when a widget is dragged, grab z-index from store, increment it by 1 and use for z-index

after incrementation/drag, update store with new number (Ie, 51 on first widget drag, 52 on second, etc)

lel. did not see this. seems reasonable.

justnat3 commented 1 year ago

I imagine that we could have couple of interfaces, IDraggable, and IDraggableState. Track the state of each draggable object, then we can have a super quick check of what is on top. :)