naver / egjs-flicking

🎠 ♻️ Everyday 30 million people experience. It's reliable, flexible and extendable carousel.
https://naver.github.io/egjs-flicking/
MIT License
2.75k stars 128 forks source link

Multiple Carousels scrolling together indexes broken #611

Closed CameronJArch closed 2 years ago

CameronJArch commented 2 years ago

Description

Im got 3 carousels stacked, where when 1 scrolls, the other two scroll as well. However, it seems that when I scroll one, Im moving the camera of the other two, but not the actual panels I believe. For instance I could move all carousels 5 panels over, and then switch to move a different carousel, and it would jump back to the panel it was on before it moved.

Steps to check or reproduce

const lastPosition: Array = []; const isEven = (key: number) => !(key % 2);

const handleWrapping = (flickingEvent: any, key: number) => { if (flickingArray.current[key].animating && !flickingEvent.isTrusted) { return; }

const position = (flickingArray.current[key].camera as CircularCamera).position;
const moveBy = (lastPosition[key] || position) - position;

flickingArray.current.forEach((carousel: Flicking, index: number) => {
  if (key !== index) {
    const moveWithCurrent = isEven(key) !== isEven(index);
    const eachPosition = (carousel.camera as CircularCamera).position;
    const camRange = carousel.camera.range;

    const newPos = eachPosition + (moveWithCurrent ? moveBy : moveBy * -1);
    const correctedPos = circulatePosition(newPos, camRange.min, camRange.max);
    (carousel.camera as CircularCamera).lookAt(correctedPos);

    carousel.disableOnInit;
  }
});
lastPosition[key] = position;

}

https://user-images.githubusercontent.com/75447489/149859662-3ef36847-9d3b-4989-b775-3694796f9a77.mov

;

WoodNeck commented 2 years ago

Hello @CameronJArch! I remember this UI :)

Anyway, it looks like it's the case that the other Flickings are not properly updated. You can call flicking.control.updateInput() in the moveEnd event to update the parameters.

Check our Sync plugin's code

CameronJArch commented 2 years ago

Haha great!

Ive added in into the moveEnd event like so

onMoveEnd: () => {
        flickingArray.current.forEach((flicking, index) => {
          if (key !== index) {
            flicking.control.updateInput();
          }
        });
      },

targets the 2 not being held, however now it seems that when changing from holding one to another, the newly grabbed Flicking works fine, but the other 2 then get messed up

https://user-images.githubusercontent.com/75447489/150006963-819845d9-088b-4106-8d8d-9d4658611876.mov

CameronJArch commented 2 years ago

1st carousel has defaultIndex of 0, then next one has 3, and the last has 6. i set them all to 0, and moving 1 carousel then switching would make the other 2 move 1 space, I think it has something to with where the active panel index is for each of them but I cant quite figure it out.

WoodNeck commented 2 years ago

Well, I think there's something wrong with the position calculation. Is it the same as the snippet you wrote in your first comment?

CameronJArch commented 2 years ago

I believe so, this is it currently however

const lastPosition: Array<number> = [];
const isEven = (key: number) => !(key % 2);

const handleWrapping = (flickingEvent: MoveEvent, key: number) => {
  if (flickingArray.current[key].animating && !flickingEvent.isTrusted) {
    return;
  }

  const position = (flickingArray.current[key].camera as CircularCamera).position;
  const moveBy = (lastPosition[key] || position) - position;

  flickingArray.current.forEach((carousel: Flicking, index: number) => {
    if (key !== index) {
      const moveWithCurrent = isEven(key) !== isEven(index);
      const eachPosition = (carousel.camera as CircularCamera).position;
      const camRange = carousel.camera.range;

      const newPos = eachPosition + (moveWithCurrent ? moveBy : moveBy * -1);
      const correctedPos = circulatePosition(newPos, camRange.min, camRange.max);
      (carousel.camera as CircularCamera).lookAt(correctedPos);
    }
  });
  lastPosition[key] = position;
};
WoodNeck commented 2 years ago

I found it, you should update lastPosition in the moveEnd handler.

onMoveEnd: () => {
  flickingArray.current.forEach((flicking, index) => {
    if (key !== index) {
      flicking.control.updateInput();
      lastPosition[index] = flicking.camera.position;
    }
  });
}

And, I think you'll need also to call disableInput on other carousels when moveStart is triggered. See https://github.com/naver/egjs-flicking-plugins/blob/master/src/Sync.ts#L154

CameronJArch commented 2 years ago

That works beautifully! Thanks again for your help!