(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.mapboxgl1.TrackLayer = factory()); }(window, (function () { const icon = 'data:image/png;base64,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' const arrow = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAnElEQVQ4T63TsQ0CMQyF4f/NgMQQ0CBR0FIx190cFIiWhhFoKdgEiRUeSoF0gO8cjkub+Evs2OLPpc9422dgBRwlNZn/BtjeApdOUJsh0QuuwKYWiYAFcAKWHaSR1EbpfAHlkO0ICdMJgV+QXmAAmUu6v9IZA8wkPVKgtg7TF7H25t4UbN+A9ahGmqqVD8AO2GdzUF45+I3ZJJb9JxbwRhEhB66xAAAAAElFTkSuQmCC' function base64ToImg(base64) { return new Promise((resolve, reject) => { const img = new Image() img.src = base64 img.onload = function () { resolve(img) } img.onerror = function (e) { reject(e) } }) } return class { constructor(map, json, fields = { lng: 'l', lat: 'a' },callback) { this._data = json || []; this._map = map; this._callback = callback; this._features = this._data.map(i => turf.point([i.l,i.a].map(Number),i)); this._json = turf.lineString(json.map(i => [i[fields.lng], i[fields.lat]].map(Number))); this._play = true; this.init(); } init() { if (this._data.length <= 1) return; this.destory(); const that = this that._index = 0 that._count = 5500 that._step = turf.length(that._json) / that._count that._flag = 0 that._playId = 'play-' + Date.now() // 添加路径图层 that._map.addSource(that._playId, { type: 'geojson', data: that._json }) that._map.addLayer({ id: that._playId, type: 'line', source: that._playId, 'layout': { 'line-cap': 'round', 'line-join': 'round' }, 'paint': { 'line-color': '#aaaaaa', 'line-width': 5 } }) // 添加已播放路径 that._map.addSource(that._playId + '-played', { type: 'geojson', data: that._json }) that._map.addLayer({ id: that._playId + '-played', type: 'line', source: that._playId + '-played', 'layout': { 'line-cap': 'round', 'line-join': 'round' }, 'paint': { 'line-color': '#09801a', 'line-width': 5 } }) // 添加路径上的箭头 base64ToImg(arrow).then(img => { that._map.addImage(that._playId + '-arrow', img) that._map.addLayer({ 'id': that._playId + '-arrow', 'source': that._playId, 'type': 'symbol', 'layout': { 'symbol-placement': 'line', 'symbol-spacing': 50, 'icon-image': that._playId + '-arrow', 'icon-size': 0.6, 'icon-allow-overlap': true } }) }) // 添加动态图标 base64ToImg(icon).then(img => { that._map.addImage(that._playId + '-icon', img) that._map.addSource(that._playId + '-point', { 'type': 'geojson', 'data': that._getDataByCoords() }) that._map.addLayer({ 'id': that._playId + '-point', 'source': that._playId + '-point', 'type': 'symbol', 'layout': { // 'icon-image': 'pz-point', 'icon-image': that._playId + '-icon', 'icon-size': 0.4, 'icon-allow-overlap': true, 'icon-rotation-alignment': 'map', 'icon-pitch-alignment': 'map', 'icon-rotate': 50 } }) that._animatePath() }) } _animatePath() { if (this._index > this._count) { window.cancelAnimationFrame(this._flag) } else { const coords = turf.along(this._json, this._step * this._index).geometry.coordinates // 已播放的线 const start = turf.along(this._json, 0).geometry.coordinates this._map.getSource(this._playId + '-played').setData(turf.lineSlice(start, coords, this._json)) // 车的图标位置 this._map.getSource(this._playId + '-point').setData(this._getDataByCoords(coords)) // 计算旋转角度 const nextIndex = this._index === this._count ? this._count - 1 : this._index + 1 const coordsNext = turf.along(this._json, this._step * nextIndex).geometry.coordinates let angle = turf.bearing(turf.point(coords), turf.point(coordsNext)) - 90 if (this._index === this._count) angle += 180 this._map.setLayoutProperty(this._playId + '-point', 'icon-rotate', angle) this._index++ const feature = turf.nearestPoint(this._getDataByCoords(coords),turf.featureCollection(this._features)); this._callback && this._callback(feature.properties,this._index); if (this._play) this._flag = requestAnimationFrame(() => { this._animatePath() }) } } _getDataByCoords(coords) { if (!coords || coords.length !== 2) return null return turf.point(coords, { 'label': this._formatDistance(this._step * this._index) }) } _formatDistance(dis) { if (dis < 1) { dis = dis * 1000 return dis.toFixed(0) + '米' } else { return dis.toFixed(2) + '千米' } } status(flag = true) { this._play = flag; this._animatePath() } restart() { this.init(); } show() { this.setLayerParams(this._playId + '-point', { visibility: 'visible' }); this.setLayerParams(this._playId + '-played', { visibility: 'visible' }); this.setLayerParams(this._playId, { visibility: 'visible' }); this.status(); } hide() { this.setLayerParams(this._playId + '-point', { visibility: 'none' }); this.setLayerParams(this._playId + '-played', { visibility: 'none' }); this.setLayerParams(this._playId, { visibility: 'none' }); this.status(false); } setOpacity(opacity) { this.setLayerParams(this._playId + '-point', {}, { 'raster-opacity': opacity }); this.setLayerParams(this._playId + '-played', {}, { 'raster-opacity': opacity }); this.setLayerParams(this._playId, {}, { 'raster-opacity': opacity }); } destory() { window.cancelAnimationFrame(this._flag); if (!(this._playId)) return; if (this._map.getSource(this._playId + '-point')) { this._map.removeLayer(this._playId + '-point') // this._map.removeLayer(this._playId + '-label') this._map.removeSource(this._playId + '-point') } if (this._map.getSource(this._playId)) { this._map.removeLayer(this._playId); this._map.removeLayer(this._playId + '-arrow'); this._map.removeSource(this._playId) } if (this._map.getSource(this._playId + '-played')) { this._map.removeLayer(this._playId + '-played') this._map.removeSource(this._playId + '-played') } this._popup && this._popup.remove(); } setLayerParams(id, layout = {}, paint = {}) { let layoutKeys = Object.keys(layout); let paintKeys = Object.keys(paint); layoutKeys.forEach(key => this._map.setLayoutProperty(id, key, layout[key])); paintKeys.forEach(key => this._map.setPaintProperty(id, key, paint[key])); } } })));