0

I'm trying to animate canvas marker along the route on Mapbox map (mapbox-gl). But canvas animation looks really jerky, especially when animation is slow.

Here is the example https://codepen.io/vps-dev/pen/MWzqpRx

Canvas image creation:

const canvasMarker = {
      width: size,
      height: size,
      data: new Uint8Array(size * size * 4),
      context: null,

      // When the layer is added to the map,
      // get the rendering context for the map canvas.
      onAdd: function () {
        const canvas = document.createElement('canvas')
        canvas.width = this.width
        canvas.height = this.height
        this.context = canvas.getContext('2d')
      },

      // Call once before every frame where the icon will be used.
      render: function () {
        const context = this.context
        if (!context) return false

        context.clearRect(0, 0, context.canvas.width, context.canvas.height)
        context.beginPath()

        context.font = '30px Arial'
        context.fillText('Hello World', 0, 20)
        context.rect(0, 40, this.width, 10)
        context.rect(0, 55, this.width, 10)
        context.fillStyle = '#000'
        context.fill()

        this.data = context.getImageData(0, 0, this.width, this.height).data
        
        map.triggerRepaint()

        // Return `true` to let the map know that the image was updated.
        return true
      },
    };

Adding image on map:

map.addImage('canvas-marker', canvasMarker, { pixelRatio: 2 })
      
map.addLayer({
 'id': 'point',
 'source': 'point',
 'type': 'symbol',
 'layout': {
   'icon-image': 'canvas-marker',
   'icon-size': 1.5,
    'icon-allow-overlap': true,
    'icon-ignore-placement': true
  }
});

Then animating point with requestAnimationFrame

Can you please support, what am I doing wrong? Thank you for your help!

  • Btw the code you have included is not the relevant code. Your issue is in the `animate` function. Thanks for including the CodePen. – Steve Bennett Jul 26 '23 at 03:01

1 Answers1

1

I think your issue is that you are expecting requestAnimationFrame() to be called at precisely even intervals, and it won't.

You need to keep track of how long it was since the last animation update, and then move the marker the proportional distance. So if it was 5ms, you move 5km, and if it was 30ms, you move 30km, for instance.

You can see this in the example here: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame

So your animate() function should make use of the argument passed to it: animate(timeStamp) and then use that instead of incrementing a counter.

Steve Bennett
  • 114,604
  • 39
  • 168
  • 219
  • Thank you for the answer, Steve Bennett ! I've created an example using timestamp https://codepen.io/vps-dev/pen/wvQQEQo But the problem is still there! Does the animation code in the new example describe the solution you suggested? – Victoria Jul 29 '23 at 21:40
  • I thought the problem might be in the canvas, because it seems to animate quite smoothly, but the edges of the elements seem to move during the animation. I've also tried adding normal markers without canvas https://codepen.io/vps-dev/pen/MWzzqxV, and it seems to animate normally, or maybe I just don't see it :) Do you have any ideas? Really appreciate your help – Victoria Jul 29 '23 at 21:41
  • Um, that timestamp implementation is very confusing and complicated. It should just look something like progress = (timestamp - starttime) * speed – Steve Bennett Jul 31 '23 at 01:22