From 6b49bfd2837ab02ca11625bb6bdc75782aefec21 Mon Sep 17 00:00:00 2001 From: Michael Barry Date: Wed, 13 Nov 2019 03:11:56 -0500 Subject: [PATCH] Fix animation performance (#8913) * reproduce animate jankiness * Fix animation performance * use isWorker --- debug/animate.html | 64 ++++++++++++++++++++++++++++++++++++---------- src/util/actor.js | 12 ++++++--- 2 files changed, 59 insertions(+), 17 deletions(-) diff --git a/debug/animate.html b/debug/animate.html index 552460ea2fd..5b9adfd066d 100644 --- a/debug/animate.html +++ b/debug/animate.html @@ -6,7 +6,7 @@ @@ -21,31 +21,54 @@ container: 'map', style: 'mapbox://styles/mapbox/streets-v11', center: [0, 0], - zoom: 2 + zoom: 4 }); -var radius = 20; +var radius = 30; -function pointOnCircle(angle) { +function line(angle, radius) { return { - "type": "Point", - "coordinates": [ - Math.cos(angle) * radius, - Math.sin(angle) * radius + "type": "Feature", + "geometry": { + "type": "LineString", + "coordinates": [ + [-Math.cos(angle) * radius, -Math.sin(angle) * radius + 1], + [Math.cos(angle) * radius, Math.sin(angle) * radius + 1], + ] + } + }; +} + +function crossWithAngle(angle) { + return { + "type": "FeatureCollection", + "features": [ + line(angle - Math.PI / 4, radius), + line(angle + Math.PI / 4, radius) ] }; } map.on('load', function () { // Add a source and layer displaying a point which will be animated in a circle. - map.addSource('point', { + map.addSource('lines', { "type": "geojson", - "data": pointOnCircle(0) + "data": crossWithAngle(0) }); map.addLayer({ - "id": "point", - "source": "point", + "id": "lines", + "source": "lines", + "type": "line", + "paint": { + "line-width": 4, + "line-color": "#007cbf" + } + }); + + map.addLayer({ + "id": "dot", + "source": "lines", "type": "circle", "paint": { "circle-radius": 10, @@ -53,10 +76,23 @@ } }); + var updates = 0; + + map.on('data', function (d) { + if (d.sourceDataType === 'content') { + updates++; + } + }); + + setInterval(function () { + console.log(updates + ' updates per second'); + updates = 0; + }, 1000); + function animateMarker(timestamp) { // Update the data to a new position based on the animation timestamp. The // divisor in the expression `timestamp / 1000` controls the animation speed. - map.getSource('point').setData(pointOnCircle(timestamp / 1000)); + map.getSource('lines').setData(crossWithAngle(timestamp / 1000)); // Request the next frame of the animation. requestAnimationFrame(animateMarker); @@ -68,4 +104,4 @@ - \ No newline at end of file + diff --git a/src/util/actor.js b/src/util/actor.js index 0095c6de136..bab734761e4 100644 --- a/src/util/actor.js +++ b/src/util/actor.js @@ -1,6 +1,6 @@ // @flow -import {bindAll} from './util'; +import {bindAll, isWorker} from './util'; import {serialize, deserialize} from './web_worker_transfer'; import ThrottledInvoker from './throttled_invoker'; @@ -107,7 +107,7 @@ class Actor { cancel(); } } else { - // Store the tasks that we need to process before actually processing them. This + // In workers, store the tasks that we need to process before actually processing them. This // is necessary because we want to keep receiving messages, and in particular, // messages. Some tasks may take a while in the worker thread, so before // executing the next task in our queue, postMessage preempts this and @@ -115,7 +115,13 @@ class Actor { // process() flow to one at a time. this.tasks[id] = data; this.taskQueue.push(id); - this.invoker.trigger(); + if (isWorker()) { + this.invoker.trigger(); + } else { + // In the main thread, process messages immediately so that other work does not slip in + // between getting partial data back from workers. + this.process(); + } } }