Реагировать на родной mapbox с анимацией Точек вызывает отставание - PullRequest
0 голосов
/ 31 января 2019

Я пытаюсь реализовать довольно сложную функцию, которая бы анимировала несколько точек в 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 с кучей временных отметок.Я рассчитываю время начала и окончания, а затем интерполирую.

...