支持实现的功能

  • 限制3天的时间跨度
  • 小车在运动中改变速度
  • 小车重新运动
  • 小车运动的点位支持打开详情信息

这是自己当时刚从后端切到前端时,实现的第一个功能,当时都没有接触过前后端分离的开发模式,更不知道react,抱着现学现做的态度做的.....,可能有需要的同学,做个参考吧。

import React, {Component} from 'react';
import {DatePicker, Input, Icon, Button, Table, Progress, Slider, notification} from 'antd';
import ol from 'openlayers';
import moment from 'moment';
import axios from 'axios';
import playback from '../../Images/playback.png';
import speedcar from '../../Images/car.png';
import move from '../../Images/move.png';
import direction from '../../Images/direction.png';
import stop from '../../Images/stop.png';
import daemarker from '../../Images/direction.png';
import './CarMove.less';
import 'openlayers/css/ol.css';const RangePicker = DatePicker.RangePicker;//地图上原先的vector
let prevVector;
//确定地图放缩级别
let zoomSize = [100, 200, 500, 1000, 2000, 8000, 14000, 20000, 25000, 50000, 100000, 200000, 500000, 1000000, 2000000];
let zoomlevel = [17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3];class CarMove extends Component {constructor(props) {super(props);this.state = {columns: [],                   //table的表头信息DAENumber: '',                 //默认的编号DAEStatus: '',                 //默认的状态DEAAddress: '',                //默认的地址queryKeyWord: this.props.keyword === undefined ? '' : this.props.keyword,             //用户输入的查询关键字pathTableData: [],             //table中的数据scrollPathTableHeight: '',     //设置table出现滑动条的高度userChooseStartTime: this.props.starttime === undefined ? '' : this.props.starttime,  //用户选择的起始时间userChooseEndTime: this.props.endtime === undefined ? '' : this.props.endtime,        //用户选择的结束时间defaultShowBtnFlag: this.props.showBtnFlag === undefined ? false : this.props.showBtnFlag, //用户传入是否显示返回按钮defaultModeFlag: this.props.modeFlag === undefined ? false : this.props.modeFlag,     //区分用户进入方式tableBodyData: [],             //默认查询到的数据的总条数showAdjustSpeed: false,        //默认的调节小车行驶的进度条不显示carProgerss: 0,                //默认的小车在轨迹上行驶的进度canRefreshAnimation: true,     //默认小车的重新运动按钮可用mapCenterLongitude: 105.442574, //默认的地图显示中心的经度mapCenterLatitude: 28.871718,  //默认的地图显示中心的纬度mapUrl: 'http://www.google.cn/maps/vt/pb=!1m4!1m3!1i{z}!2i{x}!3i{y}!2m3!1e0!2sm!3i345013117!3m8!2szh-CN!3scn!5e1105!12m4!1e68!2m2!1sset!2sRoadmap!4e0'//默认的在线地图的服务地址}this.map = null;                          //定义的地图容器句柄this.marker = null;                       //默认点击出现弹出框this.index = 0;                    //默认的小车在轨迹的位置this.defaultCarSpeed = 12;         //默认小车的行驶速度}//构造查询轨迹table的头信息// eslint-disable-next-line react/sort-compgenerateTableHeaderData() {const columns = [{title: '采集时间', dataIndex: 'column0', key: '1', width: 150, align: 'center'},{title: '采集器序列号', dataIndex: 'column1', key: '2', width: 150, align: 'center'},{title: '位置', dataIndex: 'column2', key: '3', width: 180, align: 'center'}];this.setState({columns: columns})}// 输入插叙的关键字userInputKeyWord = (e) => {this.setState({queryKeyWord: e.target.value})}//清空输入的查询关键词clearUserKeyWord = () => {this.setState({queryKeyWord: ''})}//用户选择查询的时间时userChangeQueryTime = (date, dateString) => {this.setState({userChooseStartTime: dateString[0],userChooseEndTime: dateString[1]})}//用户点击查询轨迹getPathDatas = () => {let mapData = [], tableData = [];let queryKey = this.state.queryKeyWord;//当用户选择的时间间隔超过三天的给出提示let startTime = this.state.userChooseStartTime;let endTime = this.state.userChooseEndTime;//把时间转化为毫秒,计算差值let time = new Date(endTime).getTime() - new Date(startTime).getTime();//必填项的校验if (queryKey === "" || queryKey == null) {notification.warn({message: '输入的车牌号或标签号不能为空',description: `请重新输入车牌号或者标签号进行查询`,duration: 3,placement: 'bottomRight'});return;}if (startTime === "" || endTime === "") {notification.warn({message: '请选择查询的时间段',description: `查询的时间段不能为空,请重新选择时间进行查询`,duration: 3,placement: 'bottomRight'});return;}if (time > 259200000) {notification.warn({message: '时间间隔不能超过三天',description: `查询的时间段不能超过三天,请重新选择时间进行查询`,duration: 3,placement: 'bottomRight'});return;}//数据请求的方法var url = "http://localhost:8080/getAllDaeInfo";axios.get(url).then(function (response) {console.log("response-------------->", response.data);}).catch(function (error) {console.log(error);});let enterTime, daeStatus, longitude, latitude, maxDistance = 0, distance = 0;let carPathData = new Array();//生成模拟数据for (let i = 0; i < 20; i++) {let time = Date.now() + i * 1000;let carPathDataItem = {};carPathDataItem.collectTime = time;carPathDataItem.devStatus = 0;carPathDataItem.devId = 'ts10001' + i;carPathDataItem.devAddr = 'XX市市测试区测试街道' + i;carPathDataItem.longitude = 107.4425790689 + Math.random() * (i + 1) / 500;carPathDataItem.latitude = 29.8717183035 + Math.random() * (i + 1) / 500;carPathData.push(carPathDataItem);}for (let i = 0; i < carPathData.length; i++) {enterTime = moment(carPathData[i].collectTime).format("YYYY-MM-DD HH:mm:ss");if (carPathData[i].devStatus === 0) {daeStatus = "离线";} else {daeStatus = "在线";}//计算经纬度之间最大的距离if (i < carPathData.length - 1) {distance = this.getDistance(carPathData[i].latitude, carPathData[i].longitude, carPathData[i + 1].latitude, carPathData[i + 1].longitude);if (distance > maxDistance) {maxDistance = distance;}}//表格数据的构造tableData.push({key: `${i}`,column0: enterTime,column1: carPathData[i].devId,column2: carPathData[i].devAddr});longitude = carPathData[i].longitude;latitude = carPathData[i].latitude;//地图数据的构造mapData.push([longitude, latitude, carPathData[i].devId, daeStatus, carPathData[i].devAddr]);}if (mapData.length > 0) {let level = 13;//确定地图的放缩等级for (let i = 0; i < zoomSize.length; i++) {if (maxDistance > 100) {if (maxDistance < zoomSize[i]) {level = zoomlevel[i - 1];break;}} else {if (maxDistance === 0) {level = 5;break;} else {level = 17;break;}}}this.setState({tableBodyData: tableData,canRefreshAnimation: true})//每次添加新的坐标点时清空原先的坐标点this.map.removeLayer(prevVector);//清空以移动的小车this.map.un('postcompose', this.moveFeature);//当用户打开弹出窗口的时候,点击查询的情况情况this.closeMapMarker();this.map.getView().setZoom(level);//重新设置地图的中心(不设置的话小车移动报错)this.map.getView().setCenter(ol.proj.transform([mapData[0][0], mapData[0][1]], 'EPSG:4326', 'EPSG:3857'));this.generateCarMoveOnMap(mapData);} else {this.setState({tableBodyData: tableData,carProgerss: 0,canRefreshAnimation: false})//每次添加新的坐标点时清空原先的坐标点this.map.removeLayer(prevVector);//清空以移动的小车this.map.un('postcompose', this.moveFeature);//当用户打开弹出窗口的时候,点击查询的情况情况this.closeMapMarker();//重新设置地图的中心(不设置的话小车移动报错)this.map.getView().setCenter(ol.proj.transform([this.state.mapCenterLongitude, this.state.mapCenterLatitude], 'EPSG:4326', 'EPSG:3857'));this.generateCarMoveOnMap(mapData);notification.info({message: '没有查询到轨迹信息',description: `根据你输入车牌号或者标签号以及时间没有查询到信息`,duration: 3});}}//计算经纬度之间的距离(单位米)getDistance = (lat1, lng1, lat2, lng2) => {let radLat1 = lat1 * Math.PI / 180.0;let radLat2 = lat2 * Math.PI / 180.0;let a = radLat1 - radLat2;let b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));s = s * 6378.137;// EARTH_RADIUS;s = Math.round(s * 10000) / 10;return s;}componentDidMount() {//设置表格默认滚动区域this.setState({scrollPathTableHeight: this.tableContrainer.clientHeight - 60});//监听窗口的放缩,动态的设置table出现出现滚动的高度window.onresize = () => {let tableContainer = this.tableContrainer;if (tableContainer) {let tableHeight = tableContainer.clientHeight - 60;this.setState({scrollPathTableHeight: tableHeight})}}//调用构造table头信息的函数this.generateTableHeaderData();//生成地图层let raster = new ol.layer.Tile({source: new ol.source.XYZ({url: this.state.mapUrl})});//总地图this.map = new ol.Map({target: 'pathMapContainer', layers: [raster],view: new ol.View({center: ol.proj.transform([this.state.mapCenterLongitude, this.state.mapCenterLatitude], 'EPSG:4326', 'EPSG:3857'),//指定地图投影类型projection: 'EPSG:3857',//定义地图显示的层级zoom: 13, maxZoom: 18, minZoom: 5})});//用户打开坐标显示this.openMapMarker(this.map);}//构造轨迹回放动画generateCarMoveOnMap = (coordinate) => {let that = this;//标记层let layer = new ol.layer.Vector({source: new ol.source.Vector()});let styles = {//线路的样式'route': new ol.style.Style({stroke: new ol.style.Stroke({width: 5, color: "#66ACED"})}),//起点的样式'start': new ol.style.Style({image: new ol.style.Icon({scale: 0.75, src: direction})}),//起点的样式'end': new ol.style.Style({image: new ol.style.Icon({scale: 0.8, anchor: [0.5, 0.82], src: stop})}),//小车的样式'geoMarker': new ol.style.Style({image: new ol.style.Icon({scale: 0.65, anchor: [0.5, 0.8], src: move})}),//真实点的样式'point': new ol.style.Style({image: new ol.style.Icon({scale: 1, src: daemarker})})}let animating = false, now, speed;let routeCoords, routeLength, geoMarker;let startButton = document.getElementById('start-animation');let traversed = 0;      //走过的路程let elapsedTime = 0;    //用过的时间let retime = 0;         //保存上次运动所用的时间if (coordinate.length > 2) {let geometry = new ol.geom.LineString();let anchor;let minScale = 0.001;let lngValue, latValue, times;let lnglatArray = new Array();//构造坐标点之间的线路for (let i = 0; i < coordinate.length; i++) {//构造坐标点的时候构造路径if (i > 0) {//构造坐标点之间的路径lngValue = coordinate[i][0] - coordinate[i - 1][0];latValue = coordinate[i][1] - coordinate[i - 1][1];//有一种特殊的情况当相邻的两个坐标点重合,或者当两个坐标点非常近的时候let zLength = Math.sqrt(lngValue * lngValue + latValue * latValue);if (zLength === 0 || Math.round(zLength / minScale) === 0) {geometry.appendCoordinate(ol.proj.transform([coordinate[i][0], coordinate[i][1]], 'EPSG:4326', 'EPSG:3857'));} else {times = Math.round(zLength / minScale);let xminScale = lngValue / times;let yminScale = latValue / times;for (let j = 0; j < times; j++) {lnglatArray[0] = coordinate[i - 1][0] + j * xminScale;lnglatArray[1] = coordinate[i - 1][1] + j * yminScale;// eslint-disable-next-line no-use-before-defineanchor = setAnchorStyle(geometry, lnglatArray);layer.getSource().addFeature(anchor);}}}}//设置坐标点之间连线点的坐标// eslint-disable-next-line no-inner-declarationsfunction setAnchorStyle(geometry, lnglatArray) {geometry.appendCoordinate(ol.proj.transform(lnglatArray, 'EPSG:4326', 'EPSG:3857'));let anchor = new ol.Feature({geometry: new ol.geom.Point(ol.proj.transform(lnglatArray, 'EPSG:4326', 'EPSG:3857'))});return anchor;}//标记小车运动轨迹上真实的坐标点let reallyGeometry = new ol.geom.LineString();//从第二个点到倒数第二个点for (let i = 1; i < coordinate.length - 1; i++) {reallyGeometry.appendCoordinate(ol.proj.transform([coordinate[i][0], coordinate[i][1]], 'EPSG:4326', 'EPSG:3857'));}let reallyCoords = reallyGeometry.getCoordinates();let reallyPoint = new Array();for (let i = 0; i < reallyCoords.length; i++) {//构造小车运动的线路上真实经过的坐标点reallyPoint.push(new ol.Feature({type: 'point', state: 0,num: coordinate[i + 1][2],status: coordinate[i + 1][3],address: coordinate[i + 1][4],geometry: new ol.geom.Point(reallyCoords[i])}));}routeCoords = geometry.getCoordinates();routeLength = routeCoords.length;//小车行走的线路let routeFeature = new ol.Feature({type: 'route', state: 1,geometry: geometry});//运动的小车geoMarker = new ol.Feature({type: 'geoMarker', state: 1,geometry: new ol.geom.Point(routeCoords[0])});//轨迹开始坐标let startMarker = new ol.Feature({type: 'start', state: 0,num: coordinate[0][2],status: coordinate[0][3],address: coordinate[0][4],geometry: new ol.geom.Point(routeCoords[0])});//轨迹终止坐标let endMarker = new ol.Feature({type: 'end', state: 0,num: coordinate[coordinate.length - 1][2],status: coordinate[coordinate.length - 1][3],address: coordinate[coordinate.length - 1][4],geometry: new ol.geom.Point(routeCoords[routeLength - 1])});//轨迹上所有的坐标的集合let vector = new ol.layer.Vector({source: new ol.source.Vector({features: [routeFeature, ...reallyPoint, geoMarker, startMarker, endMarker]}),style: function (feature) {if (animating && feature.get('type') === 'geoMarker') {return null;}return styles[feature.get('type')];}});//保存上一次的layerprevVector = vector;//在地图上添加坐标的点集that.map.addLayer(vector);// eslint-disable-next-line no-use-before-definestartButton.addEventListener('click', startAnimation, false);// eslint-disable-next-line no-use-before-definesetTimeout(() => startAnimation(), 50);} else if (coordinate.length > 0 && coordinate.length < 3) {//当做标点小于3个大于0个的时候let geometry = new ol.geom.LineString();for (let i = 0; i < coordinate.length; i++) {geometry.appendCoordinate(ol.proj.transform([coordinate[i][0], coordinate[i][1]], 'EPSG:4326', 'EPSG:3857'));}routeCoords = geometry.getCoordinates();routeLength = routeCoords.length;//小车行走的线路let routeFeature = new ol.Feature({type: 'route', state: 1,geometry: geometry});//运动的小车geoMarker = new ol.Feature({type: 'geoMarker', state: 1,geometry: new ol.geom.Point(routeCoords[0])});//轨迹开始坐标let startMarker = new ol.Feature({type: 'start', state: 0,num: coordinate[0][2],status: coordinate[0][3],address: coordinate[0][4],geometry: new ol.geom.Point(routeCoords[0])});//轨迹终止坐标let endMarker = new ol.Feature({type: 'end', state: 0,num: coordinate[coordinate.length - 1][2],status: coordinate[coordinate.length - 1][3],address: coordinate[coordinate.length - 1][4],geometry: new ol.geom.Point(routeCoords[routeLength - 1])});//轨迹上所有的坐标的集合let vector = new ol.layer.Vector({source: new ol.source.Vector({features: [routeFeature, geoMarker, startMarker, endMarker]}),style: function (feature) {if (animating && feature.get('type') === 'geoMarker') {return null;}return styles[feature.get('type')];}});//保存上一次的layerprevVector = vector;//在地图上添加坐标的点集that.map.addLayer(vector);// eslint-disable-next-line no-use-before-definestartButton.addEventListener('click', startAnimation, false);// eslint-disable-next-line no-use-before-definesetTimeout(() => startAnimation(), 50);}//小车运动函数this.moveFeature = function (event) {let vectorContext = event.vectorContext;let frameState = event.frameState;if (animating) {if (retime === 0) {elapsedTime = frameState.time - now;} else {elapsedTime = frameState.time - retime;}retime = frameState.time;let index = Math.round(that.defaultCarSpeed * elapsedTime / 1000);traversed += index;that.index = traversed;if (traversed >= routeLength) {//当小车运动到终点的时候// eslint-disable-next-line no-use-before-definemoveEnd(true);return;}let currentPoint = new ol.geom.Point(routeCoords[traversed]);let feature = new ol.Feature(currentPoint);vectorContext.drawFeature(feature, styles.geoMarker);}//设置运动的进度条that.setState({carProgerss: Math.round((that.index + 1) / routeLength * 100)})that.map.render();};//开始小车的运动function startAnimation() {traversed = 0;      //走过的路程elapsedTime = 0;    //用过的时间retime = 0;         //保存上次运动所用的时间if (animating) {// eslint-disable-next-line no-use-before-definerefreshAnimation();} else {animating = true;now = new Date().getTime();//speed = that.defaultCarSpeed;geoMarker.setStyle(null);that.map.on('postcompose', that.moveFeature);that.map.render();}}//当小车运动到终点function moveEnd(isend) {animating = false;let coord = isend ? routeCoords[routeLength - 1] : routeCoords[0];(geoMarker.getGeometry()).setCoordinates(coord);//防止出现问题当调用次函数的时在设置一下进度条为100%that.setState({carProgerss: 100})that.map.un('postcompose', that.moveFeature);}//小车重新运动function refreshAnimation() {if (that.state.carProgerss === 100) {that.setState({carProgerss: 0})}animating = false;if (that.state.canRefreshAnimation) {startAnimation();}}}//显示调节小车运动速度adjustSpeed = () => {this.setState((prevState) => ({showAdjustSpeed: !prevState.showAdjustSpeed}))}//改变小车队的行驶速度setNewSpeed = (value) => {this.defaultCarSpeed = value + 4;}//关闭用户打开的显示框closeMapMarker = () => {this.marker.setPosition(undefined);return false;}//监听地图的点击事件openMapMarker = (map) => {let that = this;let element = that.alertContainer;that.marker = new ol.Overlay({element: element,positioning: 'bottom-center',stopEvent: true,offset: [-5, -24],autoPan: true,autoPanAnimation: {duration: 250}});map.addOverlay(that.marker);let dom = document.createElement('div');dom.setAttribute('id', 'closeAlert');that.alertContainer.appendChild(dom);map.on('click', function (event) {let feature = map.forEachFeatureAtPixel(event.pixel, function (feature) {return feature;})if (feature) {//点击地图上大的坐标点的时候出现弹出框if (feature.get("state") === 0) {let coordinatePoint = feature.getGeometry().getCoordinates();that.marker.setPosition(coordinatePoint);//弹出框显示出来element.style.display = "block";dom.onclick = that.closeMapMarker;that.setState({DAENumber: feature.get("num"),DAEStatus: feature.get("status"),DEAAddress: feature.get("address")})}}});}//返回上一级菜单goBackUpperLevel = () => {this.props.backPrevLavel(this.state.defaultModeFlag);}render() {let {queryKeyWord} = this.state;const suffix = queryKeyWord ? <Icon type="close-circle" onClick={this.clearUserKeyWord}/> : null;return (<div className="pathContainer"><div className="headerContainer"><Inputplaceholder="请输入车牌号进行查询"suffix={suffix}onChange={this.userInputKeyWord}value={queryKeyWord}className="userInputKeyWord"/><RangePickeronChange={this.userChangeQueryTime}format="YYYY-MM-DD HH:mm"showTimeclassName="userSelectQueryTime"value={this.state.userChooseStartTime ? [moment(this.state.userChooseStartTime), moment(this.state.userChooseEndTime)] : null}/><Button onClick={this.getPathDatas} icon="search" className="queryButton">查询轨迹</Button></div><div className="displayContainer"><div className="displayLeftContainer"><div id="pathMapContainer" className="pathMapContainer">{this.state.defaultShowBtnFlag &&<Button onClick={this.goBackUpperLevel} icon="left" className="goBack">返回</Button>}<div className="alertContainer" ref={(box) => {this.alertContainer = box}}><br/><div className="alertItem"><span className="alertSpan">采集器编号:</span><spanclassName="alertSpanValue">{this.state.DAENumber}</span></div><div className="alertItem"><span className="alertSpan">采集器状态:</span><spanclassName="alertSpanValue">{this.state.DAEStatus}</span></div><div className="alertItem"><span className="alertSpan">采集器地址:</span><spanclassName="alertSpanValue">{this.state.DEAAddress}</span></div><div className="triangleDown"></div></div><div className="adjustSpeed"><img src={playback} className="imgSize" id="start-animation"/><Progress percent={this.state.carProgerss} status="active" className="progress"/><img src={speedcar} className="carImgSize" onClick={this.adjustSpeed}/>{this.state.showAdjustSpeed && <div className="adjustSlider"><Slider vertical min={1} defaultValue={this.defaultCarSpeed}className="sliderChoose" onChange={this.setNewSpeed}/></div>}</div></div></div><div className="displayRightContainer"><div className="pathTitle"><span className="spanTitle">车辆轨迹查询</span></div><div className="pathTable" ref={(box) => {this.tableContrainer = box}}><Tablepagination={false}columns={this.state.columns}dataSource={this.state.tableBodyData}scroll={{y: this.state.scrollPathTableHeight}}/></div></div></div></div>)}
}export default CarMove;
复制代码
.pathContainer{width: 100%;height: calc(~'100% - 60px');margin-top: 60px;
}
.headerContainer{width: 100%;height: 40px;padding-top: 4px;
}
.displayContainer{width:100%;height: calc(~'100% - 40px');
}
.userInputKeyWord{width: 280px;margin-left: 10px;
}
.userSelectQueryTime{width: 280px;margin-left: 4px;
}
.queryButton{margin-left: 4px;width: 100px;
}
.displayLeftContainer{width: calc(~'100% - 480px');height: 100%;float: left;
}
.displayRightContainer{width: 480px;height: 100%;z-index: 1;float: right;background-color: rgb(236, 236, 236);
}
.pathTitle{width: 100%;height: 35px;padding: 7px;
}
.spanTitle{font-size: 14px;color: #4291E9;margin-left: 5px;
}
.pathTable{width: 100%;height: calc(~'100% - 35px');
}
.pathMapContainer{height: 100%;position: relative;.ol-zoom{left: calc(~'100% - 46px');top: calc(~'100% - 72px');padding: 0px;box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.15);.ol-zoom-in{height: 26px;width: 26px;background-color: rgb(255, 255, 255);font-size: 20px;color: rgb(150, 150, 150);cursor: pointer;overflow: hidden;::selection{color: white !important;}}.ol-zoom-out{cursor: pointer;height: 26px;width: 26px;background-color: rgb(255, 255, 255);font-size: 20px;color: rgb(150, 150, 150);overflow: hidden;}}.ol-attribution{display: none;}}
.goBack{position: absolute;top: 17px;left: 35px;z-index: 1;color: rgb(100, 173, 255);
}
.adjustSpeed{width: 500px;height: 40px;position: absolute;z-index: 1;bottom: 2.7%;border-radius: 5px;background-color: rgb(254, 254, 254);left: 50%;margin-left: -250px;
}
.imgSize{width: 35px;height: 35px;margin-top: 4px;margin-left: 5px;cursor: pointer;
}
.progress{width: 400px;margin-left: 4px;position: absolute;margin-top: 11px;
}
.carImgSize{width: 35px;height: 35px;position: absolute;cursor: pointer;margin-left: 414px;margin-top: 2px;
}
.adjustSlider{background-color: snow;width: 28px;height: 181px;position: absolute;margin-top: -229px;border-radius: 6px;margin-left: 456px;padding-bottom: 16px;padding-top: 5px;
}
.alertContainer{width: 190px;height: 120px;background-color:white;border-radius: 5px;display: none;border: 1px solid lightgrey;-moz-user-select: text;user-select: text;
}
#closeAlert{position: absolute;right: 5%;top: 3%;width: 15px;height: 15px;cursor: pointer;background: url('../../Images/loginout.png') no-repeat ;
}
.alertItem{width: 93.6%;white-space: normal;word-break: break-all;margin-left: 8px;
}
.alertSpan{font-family: 'Microsoft YaHei';font-size: 12px;color: #111111;
}
.alertSpanValue{font-family: 'Microsoft YaHei';font-size: 12px;margin-left: 7px;
}
.triangleDown{position: absolute;width: 0;height: 0;border-left: 15px solid transparent ;border-right: 15px solid transparent ;border-top: 20px solid white;left: 50%;margin-left: -10px;bottom: -13px;
}复制代码

效果:

OpenLayers实现小车的轨迹查询的功能相关推荐

  1. 使用高德地图API实现历史轨迹查询

        欢迎大家关注我的公众号,有问题可以及时和我交流. 使用高德地图API完成历史轨迹查询 创作背景 相关技术 设计思路 实现难点 编码实现 实现效果 创作背景 因为对历史轨迹查询比较好奇,所以使用 ...

  2. api实现鹰眼轨迹 php,技术教程| 百度鹰眼历史轨迹查询:轨迹抽稀功能

    本文作者:用****9 本篇教程中,我们将详细地说明鹰眼历史轨迹查询(gettrack接口)中,如何通过vacuate_grade选项对轨迹进行抽稀,以及不同的抽稀力度对轨迹产生的影响. 上一篇教程中 ...

  3. Android项目实战视频教程_快递轨迹查询应用开发

    基于Android平台的快递轨迹查询应用开发全程实录(MenuDrawer.DbUtils.HttpUtils.讯飞语音识别) 课程分类:Android 适合人群:中级 课时数量:10(17节)课时 ...

  4. APISpace 快递物流地图轨迹查询API

    APISpace 的 快递物流地图轨迹查询API,支持全球全国的超过1500+的外快递公司的物流地图轨迹查询,并预估送达时间,实时展示包裹运输过程中的轨迹.包括顺丰.圆通.申通等主流快递公司.自动识别 ...

  5. PHP版物流快递公司轨迹查询实现-中小快递公司适用

    最近在商城物流项目中发现国内有好多快递公司,除大家日常熟悉的几家京东.EMS.顺丰等之外,还有N多地方性的中小快递公司,他们也非常活跃.可是没有纳入大的电商平台的物流供应商名单中.结果就是只能在下拉选 ...

  6. 手机活动轨迹查询,究竟是什么原理?

    当前,国内新型冠状病毒肺炎的防控工作进入关键时期. 随着各地陆续有企业开始复工复业,人员流动也开始有所增加. 如何对人员流动加以管控,如何准确识别潜在的传染风险,成为摆在各地防控部门面前的难题. 小枣 ...

  7. APISpace 全球快递物流地图轨迹查询API

    快递物流在我们的生活工作当中无处不在,今天我来分享一下 APISpace 的全球快递物流地图轨迹查询API,让我们的快递物流可视化~ 应用场景 电商订单查询:适用于电商商城用户端快递包裹轨迹查询,提升 ...

  8. 快递的旅行日记 - 深度挖掘快递物流地图轨迹查询API 的使用场景

    写在前面 全球化经济的不断发展使得快递业变得越来越重要,而快递物流地图轨迹查询 API 也因此应运而生. 该 API 可以帮助用户追踪物流信息,了解快递的运输状态,方便快递企业.个人用户以及电商平台等 ...

  9. 免费物流轨迹查询 对接接口

    物流轨迹查询 对接接口 功能说明 物流轨迹查询-使用的物流单号和快递单号即可实现查询物流信息. 接口规则 (1).查询接口支持按照运单号查询(单个查询,并发不超过10个/S). (2).指定的物流运单 ...

最新文章

  1. PyTorch在64位Windows下的Conda包
  2. 三层交换机实现VLAN互通实例
  3. openstack登陆dashboard提示认证发生错误
  4. 【dfs】P1036 选数
  5. mysql 开放远程连接权限连不上
  6. Boost:gzifstream和gzofstream的测试程序
  7. 《ArcGis地图数据资料》(DataMap)ArcGis 9.0
  8. jpa mysql乐观锁_【快学springboot】8.JPA乐观锁OptimisticLocking
  9. 2013款MacBook Air装Windows7单系统
  10. 为什么计算机时间要从1970年1月1日开始算起
  11. python变量回收_Python变量的引用、拷贝和回收机制
  12. 【转】现代浏览器的工作原理
  13. 因果推断与反事实预测——盒马KDD2021的一篇论文(二十三)
  14. hibernate第一天
  15. 23.MySQL 函数
  16. 十大网络安全策略 打造坚固的内网
  17. WPF/Silverlight深度解决方案:(四)基于像素的图像合成(For WPF)
  18. PDCA是什么意思?
  19. 【BZOJ5109】【CodePlus2017】大吉大利,晚上吃鸡!
  20. puzzle(1321)时间旅人

热门文章

  1. 沪深逐笔、快照推送规则总结
  2. 金融领域数据模型实例
  3. 在某点邻域有定义_z = f(x, y) 在点 (x0, y0) 的某一邻域内有定义, 当x从x0 取.PPT...
  4. C#控制电脑注销、关机、重启
  5. 2022/03/21hackthebox取证emo
  6. es java 删除索引_使用java中的elasticSearch 2.3.3按索引名称和类型删除索引
  7. pr cpu100%_PR插件LUT Mixer2.1.1安装教程
  8. idea 公共方法抽取快捷键
  9. HP 380 G9 固件升级
  10. js删除指定html及子标签,js中如何删除某个元素下面的所有子元素?(两种方法)...