mapbox路径回放

路径回放

import * as turf from '@turf/turf'

export default class RouteReplay {
    /**
     *
     * @param {*} map mapbox实例对象
     * @param {*} routejson 路径geojson type = lineString
     * @param {*} nsteps nsteps type = number
     * @param {*} realRouteLayerId 线条realRouteLayerId type = string
     * @param {*} animatePointLayerId animatePointLayerId type = string
     * @param {*} width 线条width type = number
     * @param {*} opacity 线条opacity type = number
     * @param {*} color 线条color type = string
     */

    map: any

    json: any

    realRouteId: string

    animatePointId: string

    animated: boolean

    counter: number

    steps: number

    nsteps: number

    newRouteGeoJson: any

    timer: any

    layerList: Array

    width: number

    opacity: number

    color: string

    finish: boolean

    constructor(map: any,
                routejson: {
                   type: string;
                   features: {
                       type: string;
                       geometry: {
                           type: string;
                           coordinates: number[][]
                       }
                   }[] | {
                       type: string;
                       geometry: {
                           type: string;
                           coordinates: number[][]
                       }
                   }[] },
                nsteps: number,
                realRouteLayerId: string,
                animatePointLayerId: string,
                width: {
                    type: number;
                    default: 5
                },
                opacity: {
                    type: number,
                    default: 1
                },
                color: {
                    type: string,
                    default: 'rgba(0,255,255,1)'
                }) {
        this.map = map
        this.json = routejson
        this.realRouteId = realRouteLayerId
        this.animatePointId = animatePointLayerId
        this.animated = false
        this.counter = 0
        this.steps = 0
        this.nsteps = nsteps
        this.newRouteGeoJson = null
        this.timer = null
        this.layerList = []
        this.width = width
        this.opacity = opacity
        this.color = color

        this.finish = false

        // 进中的路线
        this.realRouteGeoJson = {
            'type': 'FeatureCollection',
            'features': [{
                'type': 'Feature',
                'geometry': {
                    'type': 'LineString',
                    'coordinates': []
                }
            }]
        }
        // 实时点
        this.animatePointGeoJson = {
            'type': 'FeatureCollection',
            'features': [{
                'type': 'Feature',
                'properties': {},
                'geometry': {
                    'type': 'Point',
                    'coordinates': []
                }
            }]
        }

        this.init()
    }

    init() {

        // eslint-disable-next-line prefer-destructuring
        this.animatePointGeoJson.features[0].geometry.coordinates = this.json.features[0].geometry.coordinates[0]

        // 轨迹点json
        this.newRouteGeoJson = this.resetRoute(this.json.features[0], this.nsteps, 'kilometers')

        // 轨迹点json的点数量
        this.steps = this.newRouteGeoJson.geometry.coordinates.length

        this.addRealRouteSource(this.realRouteId) // 添加实时轨迹线图层

        this.addAnimatePointSource(this.animatePointId) // 添加动态点图层

        this.layerList.push(`realRouteLayer${this.realRouteId}`, `animatePointLayer${this.animatePointId}`,)
    }

    animate() {
        this.finish = false
        if (this.counter >= this.steps) {
            this.finish = true
            return
        }
        let startPnt
        let endPnt
        if (this.counter === 0) { // 开始
            this.realRouteGeoJson.features[0].geometry.coordinates = []
            startPnt = this.newRouteGeoJson.geometry.coordinates[this.counter]
            endPnt = this.newRouteGeoJson.geometry.coordinates[this.counter]
        } else if (this.counter !== 0) {
            startPnt = this.newRouteGeoJson.geometry.coordinates[this.counter - 1]
            endPnt = this.newRouteGeoJson.geometry.coordinates[this.counter]
        }

        this.animatePointGeoJson.features[0].geometry.coordinates = this.newRouteGeoJson.geometry.coordinates[this.counter]
        this.realRouteGeoJson.features[0].geometry.coordinates.push(this.animatePointGeoJson.features[0].geometry.coordinates)

        // 已经走过的轨迹更新
        this.map.getSource(`realRouteLayer${this.realRouteId}`).setData(this.realRouteGeoJson)
        if (this.animated) {
            this.timer = requestAnimationFrame(() => { this.animate() })
        }
        // eslint-disable-next-line no-plusplus
        this.counter++
    }

    addRealRouteSource(layerId) {
        this.map.addLayer({
            'id': `realRouteLayer${layerId}`,
            'type': 'line',
            'source': {
                'type': 'geojson',
                'lineMetrics': true,
                'data': this.realRouteGeoJson
            },
            'paint': {
                'line-width': this.width,
                'line-opacity': this.opacity,
                'line-color': this.color,
            }
        })
    }

    // 添加动态点图层
    addAnimatePointSource(layerId) {
        this.map.addLayer({
            'id': `animatePointLayer${layerId}`,
            'type': 'symbol',
            'source': {
                'type': 'geojson',
                'data': this.animatePointGeoJson
            },
            // 'layout': {
            //     'icon-image': '',
            //     'icon-size': 0,
            //     'icon-rotate': ['get', 'bearing'],
            //     'icon-rotation-alignment': 'map',
            //     'icon-allow-overlap': true,
            //     'icon-ignore-placement': true
            // }
        })
    }

    resetRoute(route, nstep, units) {
        const newroute = {
            'type': 'Feature',
            'geometry': {
                'type': 'LineString',
                'coordinates': []
            }
        }
        // 指定点集合的总路长
        const lineDistance = turf.lineDistance(route)

        // 每一段的平均距离
        const nDistance = lineDistance / nstep
        const {length} = this.json.features[0].geometry.coordinates
        // eslint-disable-next-line no-plusplus
        for (let i = 0; i < length - 1; i++) {
            let from = turf.point(route.geometry.coordinates[i]) // type 为 point的feature
            let to = turf.point(route.geometry.coordinates[i + 1])
            let lDistance = turf.distance(from, to, { // 两个点之间的距离
                units: units
            })
            if (i === 0) { // 起始点直接推入
                newroute.geometry.coordinates.push(route.geometry.coordinates[0])
            }
            if (lDistance > nDistance) { // 两点距离大于每段值,将这条线继续分隔
                let rings = this.splitLine(from, to, lDistance, nDistance, units)
                newroute.geometry.coordinates = newroute.geometry.coordinates.concat(rings)
            } else { // 两点距离小于每次移动的距离,直接推入
                newroute.geometry.coordinates.push(route.geometry.coordinates[i + 1])
            }
        }
        return newroute
    }

    // 过长的两点轨迹点分段
    // eslint-disable-next-line class-methods-use-this
    splitLine(from, to, distance, splitLength, units) {
        var step = parseInt(distance / splitLength, 10)

        const leftLength = distance - step * splitLength
        const rings = []
        const route = turf.lineString([from.geometry.coordinates, to.geometry.coordinates])
        // eslint-disable-next-line no-plusplus
        for (let i = 1; i <= step; i++) {
            let nlength = i * splitLength
            // turf.alone返回沿着route<LineString>距离为nlength<number>的点
            let pnt = turf.along(route, nlength, {
                units: units
            });
            rings.push(pnt.geometry.coordinates)
        }
        if (leftLength > 0) {
            rings.push(to.geometry.coordinates)
        }
        return rings
    }

    start() {
        if (!this.animated) {
            this.animated = true
            this.animate()
        }
    }

    pause() {
        this.animated = false
        this.animate()
    }

    end() {
        window.cancelAnimationFrame(this.timer)
        this.animated = false
        this.counter = 0
        this.animate()
    }

    remove() {
        window.cancelAnimationFrame(this.timer)
        // eslint-disable-next-line array-callback-return
        this.layerList.map(layer => {
            // console.log(layer)
            if (this.map.getSource(layer)) {
                this.map.removeLayer(layer)
                this.map.removeSource(layer)
            }
        })
    }

    finished(){
        return this.finish
    }
}

使用

new RouteReplay(map对象, 数据, 50, `${index}`, `${index}`, 5,1,'rgba(0,255,255,1)')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值