MapView goTo stops working on second call and does not support signal

522
4
11-20-2023 08:32 AM
ekotovich
New Contributor II

Hello there!

We are trying to implement a feature, where user can click on a button and after clicking on a button - it should smoothly move-and-zoom presentation to specific coordinates (array of 4 points).

For that purposes we are using "goTo" command in following way:

mapView.goTo(points, {
    animation: true,
    duration: 5000,
    easing: "ease-out"
});

When user click one button, during 5 seconds it should move presentation to position A. If user will click another button after 2 seconds after previous click, which should start move view to position B. But it doesn't. Instead it stoped in the middle on the way to position A.

I would expect, that "goTo" command should cancel previous animation and start new animation. For now it seems it does not work in that way.

I've created example on codesandbox: https://codesandbox.io/s/funny-brook-dxdkpt

Moreover, I can see from documentation, that "options" parameters in "goTo" callback supports a signal. But it looks like it does't work

const abortController = new AbortController();

const goToPromise = mapView.goTo(points.AFRICA, {
    animation: true,
    duration: 5000,
    easing: "ease-out",
    signal: abortController.signal
});

setTimeout(() => {
    abortController.abort();
}, 2000)

I would expect that "goToPromise" will be rejected and animation will be stopped after 2 seconds. But it doesn't. After calling "abort" it continue the animation.

0 Kudos
4 Replies
JoelBennett
MVP Regular Contributor

This same issue was reported here about a year and a half ago, where it doesn't seem to have gotten any traction...

ekotovich
New Contributor II

I've created the issue again at their github page. 

https://github.com/Esri/feedback-js-api-next/issues/268

Let's upvote it.

I did small research and found out that they does not subscribe to a "signal" abort event. So calling abort will never abort the animation...

Also I found out when you call "goTo", they create an Animation instance, which based on Promise under the hood and assign that instance it to the "this.animation" of the "MapView" .
When you call next "goTo" or "MapView.animation.stop", it does "this.animation = null" under the hood. But Promise created by Animation does not removed and does not rejected. So under the hood, the Promise of the previous animation continue work until it will resolved and, I suppose, conflicts with next animation, because logic of Animation instance written in scope of Promise refers to "this" (MapView) and change properties of "this" (MapView).

No sure if my assumption are pretty much correct, but at first glance it looks like it.

0 Kudos
ekotovich
New Contributor II

For anyone who looking for solution, this could help:

mapView.animation?.destroy();

// OR (depends on ES version)

if (mapView.animation) {
  mapView.animation.destroy();  
}

mapView.goTo(target, options);

So need just ensure that map view have an animation and, if it does have the animation, destroy it right before next "goTo" call.

If somebody looking for solution to stop animation by abort signal, it could be done it way like:

const abortController = new AbortController();

abortController.signal.addEventListener('abort', () => {
   mapView.animation?.destroy();
});

// Make animation for 5s
mapView.goTo(target, { duration: 5000 })

// Stop animation after 2s
setTimeout(() => {
  abortController.abort();
}, 2000)

 

Of course it's possible to call "destroy" directly in setTimeout. But sometimes you want do to it in some another, deep area of an application. So it would be better to create and pass signal into there instead of passing MapView instance.

In that example, "goTo" and "setTimeout" can located in different parts of application. "goTo" could be part of React component, while "setTimeout" (or any other stuff) could be a part of redux thunk. So thunk actually should know nothing about map.

ekotovich
New Contributor II

A small note here. This solution work only for 4.27 and above. "Destroy" and rest stuff does not work for version 4.26 and below

0 Kudos