Я пытаюсь реализовать довольно сложную функцию, которая бы анимировала несколько точек в geoJSON featureCollection одновременно (аналогичный проект в Интернете: https://hvv.live/).Я попытался использовать официальный пример Drive the line, предоставленный библиотекой реагировать с собственным mapbox, и изменил его для работы с несколькими точками.
Проблема в том, что после более чем 6-7 анимированных точек производительность значительно падает, аточки обновляются только несколько раз в секунду, а не анимируются плавно.Я предполагаю, что это вызвано большим количеством вызовов setState для геометрии geoJSON, вызванной несколькими слушателями, которые запускаются в методе requestAnimationFrame в классе RouteSimulator.
Я думаю, что решением было бы как-то дождатьсяRouteSimulator для расчета следующих точек для всех точек и последующего обновления состояния с помощью нового источника geoJSON, однако я не могу понять, как это сделать.Любая помощь будет принята с благодарностью.
Класс RouteSimulator, который обрабатывает все анимации:
import { Animated, Easing } from 'react-native'
import MapboxGL from '@mapbox/react-native-mapbox-gl'
import cheapRuler from 'cheap-ruler'
var ruler = cheapRuler(55.7)
class Polyline {
constructor(lineStringFeature) {
this._trip = lineStringFeature.properties.trip
this._coordinates = lineStringFeature.geometry.coordinates
this._timestamps = lineStringFeature.properties.time
this._lineStringFeature = lineStringFeature
this._totalDistance = 0
this._departureTime = lineStringFeature.properties.time[0] / 1000
this._arrivalTime =
lineStringFeature.properties.time[
lineStringFeature.properties.time.length - 1
] / 1000
this._totalTime = this._arrivalTime - this._departureTime
this._totalDistance += ruler.lineDistance(this._coordinates)
this._speed = this._totalDistance / this._totalTime / 30
}
coordinateFromStart(distance) {
const pointAlongCheap = ruler.along(this._coordinates, distance)
const trip = this._trip
const pointAlong = MapboxGL.geoUtils.makePoint(pointAlongCheap, {
distance,
trip
})
return pointAlong
}
get totalDistance() {
return this._totalDistance
}
}
class RouteSimulator {
constructor(lineStrings) {
this._lineStrings = lineStrings.map(line => ({
polyline: new Polyline(line),
curDist: 0,
prevDist: 0
}))
}
addListener(listener) {
this._listener = listener
}
start() {
this.tick()
}
reset() {
this._previousDistance = 0
this._currentDistance = 0
this.start()
}
stop() {
if (this._anim) {
this._anim.stop()
}
}
tick() {
requestAnimationFrame(() => {
const animArray = []
this._lineStrings.forEach(line => {
line.prevDist = line.curDist
line.curDist += line.polyline._speed
const listener = step => {
const currentPosition = line.polyline.coordinateFromStart(
step.value
)
this.emit(currentPosition)
}
line._animatedValue = new Animated.Value(line.prevDist)
line._animatedValue.addListener(listener)
line._listener = listener
animArray.push(
Animated.timing(line._animatedValue, {
toValue: line.curDist,
duration: 1,
easing: Easing.linear,
useNativeDriver: false
})
)
})
Animated.parallel(animArray).start(() => {
this._lineStrings.forEach(line => {
line._animatedValue.removeListener(line.listener)
})
this.tick()
})
})
}
emit(pointFeature) {
this._listener(pointFeature)
}
}
export default RouteSimulator
И затем я вызываю этот класс на своем экране с картой
class MainMap extends React.Component {
constructor() {
super()
this.state = {
stopsAround: Mapbox.geoUtils.makeFeatureCollection(),
zoomLevel: 13,
fetching: false,
routes: null,
newRoutes: Mapbox.geoUtils.makeFeatureCollection(),
bounds: null,
currentPoint: null,
routeSimulator: null
}
}
componentDidMount() {
this.setState(
{
routes: nowTrips
},
() => {
this.onStart()
}
)
}
onStart() {
const routeSimulator = new RouteSimulator(this.state.routes)
routeSimulator.addListener(currentPoint => {
//Check if zoomed in to show the animation
if (this.state.zoomLevel >= 13) {
const newTransit = this.state.newRoutes
//Check if element was already added to the feature collection or is it the first time the function was called
const index = newTransit.features.findIndex(
element =>
element.properties.trip.id ===
currentPoint.properties.trip.id
)
if (index > -1) {
newTransit.features[index] = currentPoint
} else {
Mapbox.geoUtils.addToFeatureCollection(
newTransit,
currentPoint
)
}
//This is fired as much as possible and I think is causing all of the lag and problems
this.setState({ newRoutes: newTransit })
}
})
routeSimulator.start()
}
renderCurrentPoint() {
if (!this.state.newRoutes) {
return
}
return (
<Mapbox.ShapeSource id="animatable" shape={this.state.newRoutes}>
<Mapbox.CircleLayer
id="animatableStop"
style={{
circleRadius: 7,
circleColor: '#266ef1',
circleStrokeWidth: 3,
circleStrokeColor: '#FFFFFF'
}}
/>
</Mapbox.ShapeSource>
)
}
Исходные данные - это просто массив строк строк GeoJSON с кучей временных отметок.Я рассчитываю время начала и окончания, а затем интерполирую.