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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Mapbox提供了一个叫做Mapbox Directions的服务,可以用来进行路径规划。你可以通过该服务的API来进行自定义导航路径规划。 以下是一个简单的示例代码,展示如何在Mapbox地图上自定义路径规划: ``` // 初始化地图 mapboxgl.accessToken = 'YOUR_ACCESS_TOKEN'; var map = new mapboxgl.Map({ container: 'map', style: 'mapbox://styles/mapbox/streets-v11', center: [-77.04, 38.907], zoom: 11 }); // 添加导航控件 var nav = new mapboxgl.NavigationControl(); map.addControl(nav, 'top-left'); // 自定义路径规划 var url = 'https://api.mapbox.com/directions/v5/mapbox/driving/'; var origin = [-77.036, 38.897]; var destination = [-77.009, 38.889]; var waypoints = [ [-77.054, 38.889], [-77.049, 38.891], [-77.045, 38.888] ]; var accessToken = mapboxgl.accessToken; var xhr = new XMLHttpRequest(); xhr.open('GET', url + origin.join(',') + ';' + waypoints.map(function(point) { return point.join(','); }).join(';') + ';' + destination.join(',') + '?access_token=' + accessToken, true); xhr.onload = function() { if (xhr.status === 200) { // 在地图上绘制路径 var data = JSON.parse(xhr.responseText); var route = data.routes[0].geometry; map.addLayer({ "id": "route", "type": "line", "source": { "type": "geojson", "data": { "type": "Feature", "properties": {}, "geometry": route } }, "layout": { "line-join": "round", "line-cap": "round" }, "paint": { "line-color": "#888", "line-width": 8 } }); } else { console.log('Request failed. Returned status of ' + xhr.status); } }; xhr.send(); ``` 需要注意的是,这里的`YOUR_ACCESS_TOKEN`需要替换为你自己的Mapbox Access Token。另外,该示例中的路径规划请求使用了XMLHttpRequest对象,你也可以使用fetch或其他方式来发送请求。在请求返回后,我们需要解析返回的数据,并在地图上添加一条线来表示路径。你可以通过修改该示例中的起点、终点、途经点等参数来自定义路径规划。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值