2 Commits 907ebdb7e1 ... da79c90ebf

Autor SHA1 Mensagem Data
  HuangKai da79c90ebf 添加转换相关功能 1 semana atrás
  HuangKai df443299a2 添加历史轨迹功能 1 semana atrás

+ 11 - 0
package-lock.json

@@ -44,6 +44,7 @@
         "leaflet-polylinedecorator": "^1.6.0",
         "leaflet-textpath": "^1.2.0",
         "leaflet-toolbar": "^0.4.0-alpha.2",
+        "leaflet-trackplayer": "^2.0.2",
         "martinez-polygon-clipping": "^0.7.3",
         "mdi-react": "^5.5.0",
         "mousetrap": "^1.6.3",
@@ -14564,6 +14565,11 @@
         "leaflet": "*"
       }
     },
+    "node_modules/leaflet-trackplayer": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/leaflet-trackplayer/-/leaflet-trackplayer-2.0.2.tgz",
+      "integrity": "sha512-7Eor1jVXvjCLfhp71jC11ReWNjmWxqCsOukkPMnTMllAvDfldPtPJXbqhsYZ2ud8cVipWBDg2Sn7SB56spQ/7g=="
+    },
     "node_modules/left-pad": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
@@ -36849,6 +36855,11 @@
       "integrity": "sha512-g1KeU3DYGUOwXTS0vKIgJ8KgY0h/2B0qENNQUSYMFtSY2yzwaHWMbDyhDbk+aO8LgJ1iOX4fUt2bh1sYZbpmmQ==",
       "requires": {}
     },
+    "leaflet-trackplayer": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/leaflet-trackplayer/-/leaflet-trackplayer-2.0.2.tgz",
+      "integrity": "sha512-7Eor1jVXvjCLfhp71jC11ReWNjmWxqCsOukkPMnTMllAvDfldPtPJXbqhsYZ2ud8cVipWBDg2Sn7SB56spQ/7g=="
+    },
     "left-pad": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",

+ 1 - 0
package.json

@@ -60,6 +60,7 @@
     "leaflet-polylinedecorator": "^1.6.0",
     "leaflet-textpath": "^1.2.0",
     "leaflet-toolbar": "^0.4.0-alpha.2",
+    "leaflet-trackplayer": "^2.0.2",
     "martinez-polygon-clipping": "^0.7.3",
     "mdi-react": "^5.5.0",
     "mousetrap": "^1.6.3",

+ 4 - 4
src/index.js

@@ -10,12 +10,10 @@
  *
  */
 
-// import request from 'request-promise-native';
-// import LocationCard from './view/common/LocationCard';
 import App from './view/App'
-// import updateMarkerPos from './view/utils/moveMarker'
 // import connectTestTool from './view/utils/connectTestTool'
-// import uploadMapData from './view/utils/uploadMapdata'
+// import CoordinateConversion from './view/utils/CoordinateConversion';
+// import HistoryTrackControl from './view/utils/historyTrackControl';
 
 
 /*
@@ -68,5 +66,7 @@ new App({ el: 'root' }).init();
 // 	connectTestTool: connectTestTool,
 // 	// uploadMap: uploadMapData,
 // 	// moveMarker: updateMarkerPos,
+//	// CoordinateConver: CoordinateConversion,
+//	// HisTrackControl: HistoryTrackControl,
 // }
 // export { BunnyBlitz }

+ 20 - 8
src/view/Map.js

@@ -14,25 +14,20 @@ import React, { Component } from 'react';
 import 'leaflet/dist/leaflet.css';
 import L from 'leaflet';
 import 'leaflet-hash';
-import { Map, TileLayer, /*WMSTileLayer,*/ AttributionControl, ScaleControl } from 'react-leaflet';
-// import { BingLayer } from 'react-leaflet-bing';
+import { Map, TileLayer, AttributionControl, ScaleControl } from 'react-leaflet';
 import Spinner from 'react-bootstrap/Spinner';
 import PubSub from 'pubsub-js';
 
 import Body from './Body';
 import PACKAGE from '../../package.json';
 
-// import Building from './layers/Building';
 import Features from './layers/Features';
 import FloorImagery from './layers/FloorImagery';
-// import Levels from './layers/Levels';
 import MoveableObject from './layers/MoveableObject';
-
 import MapStyler from '../model/mapcss/MapStyler';
 import LevelSelector from './common/LevelSelector';
 import NorthPointer from './common/NorthPointer';
-// import SidePanelButton from './common/SidePanelButton';
-// import PreviewButton from './common/PreviewButton';
+import HistoryTrack from './layers/HistoryTrack';
 
 
 const MAP_MAX_ZOOM = 22;
@@ -111,12 +106,14 @@ L.Hash.prototype.update = function() {
  * Map component handles the whole map and associated widgets.
  */
 class MyMap extends Component {
+	static map;
 	constructor() {
 		super();
 
 		this.state = {
 			loading: false,
-			dataready: false
+			dataready: false,
+			initHisTrack: false,
 		};
 
 		this.mapStyler = new MapStyler();
@@ -451,6 +448,12 @@ class MyMap extends Component {
 						floor={this.props.floor}
 					/>
 				}
+
+				{this.state.initHisTrack &&
+					<HistoryTrack
+						map={this.elem}
+					/>
+				}
 			</Map>
 		</div>;
 	}
@@ -470,6 +473,8 @@ class MyMap extends Component {
 
 		window.mapUUID = this.props.uuid;
 
+		MyMap.map = this.elem.leafletElement;
+
 		// URL hash for map
 		this._mapHash = new L.Hash(this.elem.leafletElement);
 
@@ -554,6 +559,13 @@ class MyMap extends Component {
 				this.elem.leafletElement.panTo(data.coordinates);
 			}
 		});
+
+		PubSub.subscribe("map.his.init", (msg, data) => {
+			// console.log('init his');
+			this.setState({
+				initHisTrack: true
+			});
+		});
 	}
 
 	componentDidUpdate(fromProps) {

+ 115 - 0
src/view/layers/HistoryTrack.js

@@ -0,0 +1,115 @@
+import React, { Component } from 'react';
+import PubSub from 'pubsub-js';
+import { withLeaflet } from 'react-leaflet';
+import L, { LatLng } from 'leaflet';
+import 'leaflet-trackplayer';
+
+/**
+ * HistoryTrack layer allows to show 
+ */
+class HistoryTrack extends Component {
+	static HIS_PLAY = 0;
+	static HIS_PAUSE = 1;
+	static HIS_CLEAR = 2;
+	static HIS_SET_SPEED = 3;
+	static HIS_SET_PROGRESS = 4;
+	path = [];
+	cur_index = 0;
+	cur_speed = 1;
+	cur_multi = 1;
+	componentDidMount(){
+		this.map = this.props.map.leafletElement;
+		// console.log(this.map, this.props);
+
+		PubSub.subscribe("his.play.ctrl", (msg, data) => {
+			console.log(data.state);
+			if(!this.track){
+				console.error("需要先设置track数据!")
+				alert("需要先设置track数据!");
+				return;
+			}
+
+			switch (data.state) {
+				case HistoryTrack.HIS_PLAY:
+					this.track.start();
+					break;
+				case HistoryTrack.HIS_PAUSE:
+					this.track.pause();
+					break;
+				case HistoryTrack.HIS_CLEAR:
+					this.track.remove();
+					break;
+				case HistoryTrack.HIS_SET_SPEED:
+					this.cur_multi = data.speedMultiply;
+					this.track.setSpeed(this.cur_multi * this.cur_speed);
+					break;
+				case HistoryTrack.HIS_SET_PROGRESS:
+					this.track.setProgress(data.progress);
+					break;
+			
+				default:
+					console.error("HistoryTrack 未知状态!")
+					break;
+			}
+		});
+
+		PubSub.subscribe("map.his.set", (msg, data) => {
+			this.cur_index = 0;
+			this.cur_distance = 0;
+			this.cur_speed = 1;
+			// console.log('set his');
+			this.path = data.path;
+			if(this.track){
+				this.track.remove();
+			}
+			console.log(data.src);
+			let hisIcon = L.icon({
+				iconSize: [20, 20],
+				iconUrl: data.src,
+				iconAnchor: [10, 10]
+			});
+			this.cur_multi = data.speedMultiply;
+			this.cur_speed = this.getSpeed(this.cur_index);
+			this.track = new L.TrackPlayer(this.path, {
+				markerIcon: hisIcon,
+				speed: this.cur_multi * this.cur_speed,
+				weight: 10,
+				passedLineColor: '#32CD32',
+				notPassedLineColor: '#00BFFF',
+				panTo: false,
+				markerRotate: true,
+			});
+			this.track.addTo(this.map);
+			this.track.on('progress', this.deal);
+		});
+	}
+
+	deal = (a, b, c) => {
+		if(this.cur_index !== c){
+			this.cur_index = c;
+			this.cur_speed = this.getSpeed(this.cur_index);
+			this.track.setSpeed(this.cur_multi * this.cur_speed);
+			// console.log(c, "speed ", this.cur_speed, "千米/h");
+		}
+	}
+
+	getSpeed(index){
+		if(index + 1 === this.path.length) return 0;
+		let ll1 = new LatLng(this.path[index].lat, this.path[index].lng);
+		let ll2 = new LatLng(this.path[index + 1].lat, this.path[index + 1].lng);
+		let distance = ll1.distanceTo(ll2) / 1000;
+		let speed = distance / (this.path[index + 1].time - this.path[index].time) * 3600000;
+		// console.log((this.path[index + 1].time - this.path[index].time));
+		return speed;
+	}
+
+	componentWillUnmount(){
+		PubSub.unsubscribe("map.his.set");
+		PubSub.unsubscribe("map.play.ctrl");
+	}
+
+	render(){
+		return <></>;
+	}
+}
+export default withLeaflet(HistoryTrack);

+ 86 - 0
src/view/utils/CoordinateConversion.js

@@ -0,0 +1,86 @@
+import { LatLng, Point } from 'leaflet';
+import MyMap from '../Map';
+
+export default class CoordinateConversion {
+    /** 
+     * 将地理坐标投影到给定缩放的像素坐标中。
+     * @param {[lat: number, lng: number]} latlng - 经纬度
+     * @returns {[x:number, y:number]} - 像素点坐标
+     */
+    static latLngToPoint(latlng){
+        if(!MyMap.map){ console.error("请先初始化地图!"); }
+        let ll = new LatLng(latlng.lat, latlng.lng);
+        let p = MyMap.map.latLngToLayerPoint(ll);
+        return {x: p.x, y: p.y};
+    }
+
+    /** 
+     * latLngToPoint的倒数。 将给定缩放上的像素坐标投影到地理坐标中。
+     * @param {[x:number, y:number]} point - 像素点坐标
+     * @returns {[lat: number, lng: number]} - 经纬度
+     */
+    static pointToLatLng(point){
+        if(!MyMap.map){ console.error("请先初始化地图!"); }
+        let p = new Point(point.x, point.y);
+        let ll = MyMap.map.layerPointToLatLng(p);
+        return {lat: ll.lat, lng: ll.lng};
+    }
+
+    /** 
+     * 将地理坐标投影为接受单位的坐标 此 CRS(例如 EPSG:3857 的仪表,用于将其传递给 WMS 服务)。
+     * @param {[lat: number, lng: number]} latlng - 经纬度
+     * @param {number} zoom - 缩放级别
+     * @returns {[x:number, y:number]} - 像素点坐标
+     */
+    static project(latlng, zoom){
+        if(!MyMap.map){ console.error("请先初始化地图!"); }
+        return MyMap.map.project(latlng, zoom);
+    }
+
+    /** 
+     * 给定一个投影坐标返回相应的 LatLng。。
+     * @param {[x:number, y:number]} latlng - 像素点坐标
+     * @param {number} zoom - 缩放级别
+     * @returns {[lat: number, lng: number]} - 经纬度
+     */
+    static unproject(point, zoom){
+        if(!MyMap.map){ console.error("请先初始化地图!"); }
+        return MyMap.map.unproject(point, zoom);
+    }
+
+    /** 
+     * 返回将投影坐标转换为特定缩放的像素坐标时使用的比例。
+     * @param {number} toZoom - 缩放级别
+     * @param {number} fromZoom - 缩放级别
+     * @returns {number} - 比例因子
+     */
+    static scale(toZoom, fromZoom){
+        if(!MyMap.map){ console.error("请先初始化地图!"); }
+        return MyMap.map.getZoomScale(toZoom, fromZoom);
+    }
+
+    /** 
+     * 返回与 scale的比例因子对应的缩放级别。
+     * @param {number} scale - 比例因子
+     * @param {number} fromZoom - 缩放级别
+     * @returns {number} - 缩放级别
+     */
+    static zoom(scale, fromZoom){
+        if(!MyMap.map){ console.error("请先初始化地图!"); }
+        return MyMap.map.getScaleZoom(scale, fromZoom);
+    }
+
+    /** 
+     * 返回两个地理坐标之间的距离
+     * @param {[lat: number, lng: number]} latlng1 - 经纬度1
+     * @param {[lat: number, lng: number]} latlng2 - 经纬度2
+     * @returns {number} - 距离(单位:米)
+     */
+    static distance(latlng1, latlng2){       
+        if(!MyMap.map){ console.error("请先初始化地图!"); } 
+		let ll1 = new LatLng(latlng1.lat, latlng1.lng);
+		let ll2 = new LatLng(latlng2.lat, latlng2.lng);
+		// let distance = ll1.distanceTo(ll2) / 1000;
+        return MyMap.map.distance(ll1, ll2);
+    }
+}

+ 62 - 0
src/view/utils/historyTrackControl.js

@@ -0,0 +1,62 @@
+import PubSub from "pubsub-js";
+import HistoryTrack from "../layers/HistoryTrack";
+
+export default class HistoryTrackControl{
+    /** 
+     * 打开历史轨迹。
+     */
+    initHistoryTrack(){
+        PubSub.publish("map.his.init");
+    }
+
+    /** 
+     * 清空历史轨迹。
+     */
+    clearHistoryTrack(){
+        PubSub.publish("his.play.ctrl", {state: HistoryTrack.HIS_CLEAR});
+    }
+
+    /** 
+     * 播放历史轨迹。
+     */
+    playHistoryTrack(){
+        setTimeout(() => {
+            PubSub.publish("his.play.ctrl", {state: HistoryTrack.HIS_PLAY});
+        }, 100);
+    }
+
+    /** 
+     * 暂停历史轨迹。
+     */
+    pauseHistoryTrack(){
+        PubSub.publish("his.play.ctrl", {state: HistoryTrack.HIS_PAUSE});
+    }
+
+    /** 
+     * 设置历史轨迹进度。
+     * @param {number} value - 进度值0到1
+     */
+    setHistoryTrackProgress(value){
+        PubSub.publish("his.play.ctrl", {progress: value, state: HistoryTrack.HIS_SET_PROGRESS});
+    }
+
+    /** 
+     * 设置历史轨迹速度。
+     * @param {number} speed - 速度值
+     */
+    setHistoryTrackSpeedMultiply(multi){
+        PubSub.publish("his.play.ctrl", {speedMultiply: multi, state: HistoryTrack.HIS_SET_SPEED});
+    }
+
+    /** 
+     * 设置历史轨迹。
+     * @param {Array<[lat: number, lng: number]>} path - 经纬度坐标数组
+     * @param {String} src - 移动标识图标路径
+     * @param {number} speed - 标识移动速度
+     */
+    setHistoryPath(path, src, multi = 1){
+        setTimeout(() => {
+            PubSub.publish("map.his.set", {path: path, src: src, speedMultiply: multi});
+        }, 50);
+    }
+}