openlayers 地图组件封装

openlayers 地图组件封装

<template><div class="mapBox"><!-- 地图 --><div ref="map" id="map" class="map"></div><!-- 点位弹窗 --><div id="popup" class="ol-popup"><a href="#" id="popup-closer" class="ol-popup-closer"></a><div id="popup-content">{{ popup.content }}</div></div><!-- 地图操作 --><div v-if="false" class="optionsBox"><!-- GIS服务 --><el-dropdown @command="handleGisCommand"><el-button type="primary">GIS服务<i class="el-icon-arrow-down el-icon--right"></i></el-button><el-dropdown-menu slot="dropdown"><el-dropdown-item command="1">测距离</el-dropdown-item><el-dropdown-item command="2">测面积</el-dropdown-item><el-dropdown-item command="3">清空</el-dropdown-item><el-dropdown-item command="4">打印地图</el-dropdown-item></el-dropdown-menu></el-dropdown><!-- 矢量底图 / 卫星底图 --><el-radio-group v-model="checkUnderLayer" @change="handleUnderLayerChange"><el-radio-button label="sldt">矢量底图</el-radio-button><el-radio-button label="wxdt">卫星底图</el-radio-button></el-radio-group><!-- 注记层 / 行政区划 --><el-checkbox-group v-model="checkLayers" @change="handleLayerChange"><el-checkbox-button label="zjc">注记层</el-checkbox-button><el-checkbox-button label="xzqh">行政区划</el-checkbox-button></el-checkbox-group><!-- 全屏 --><el-button type="primary" @click="handleFullScreen">{{ isFullScreen ? "退出全屏" : "全屏" }}</el-button><!-- 回到原点 --><el-button type="primary" @click="handleBackCenter">回到原点</el-button><!-- 轨迹运动 --><el-button type="primary" @click="handleTrackStart">{{ mapTrack.isPlay ? "暂停" : "开始" }}</el-button><el-button type="primary" @click="handleTrackStop">停止</el-button></div></div>
</template><script>
import "ol/ol.css";
import request from "@/utils/request.js";
import domtoimage from "dom-to-image";
import Text from "ol/style/Text";import { getWidth, getTopLeft } from "ol/extent";
import View from "ol/View";
import Map from "ol/Map";
import WMTSTileGrid from "ol/tilegrid/WMTS";
import Feature from "ol/Feature";
import { WMTS, Vector as VectorSource, XYZ } from "ol/source";
import { Tile as TileLayer, Vector as VectorLayer, VectorImage } from "ol/layer";
import { getArea, getLength } from "ol/sphere";
import { unByKey } from "ol/Observable";
import { LineString, Polygon, Point, MultiLineString } from "ol/geom";
import { MousePosition, ScaleLine, ZoomSlider } from "ol/control";
import { createStringXY } from "ol/coordinate";
import * as olProj from "ol/proj";
import { Draw, Select, Modify } from "ol/interaction";
import Overlay from "ol/Overlay";import { Circle as CircleStyle, Fill, Stroke, Style, Icon } from "ol/style";
import { scale } from "ol/size";import GeoJSON from "ol/format/GeoJSON";
import SourceVector from "ol/source/Vector";
import { getDistance } from "ol/sphere";import { getVectorContext } from "ol/render";
import { EventBus } from "@/utils/eventBus.js";import { transform, fromLonLat, toLonLat } from "ol/proj";import LayerTile from "ol/layer/Tile";
import ImageLayer from "ol/layer/Image";
import { Raster as RasterSource } from "ol/source";
import { defaults as defaultControls } from "ol/control";
import { saveAs } from "file-saver";
export default {data() {return {map: null,mapCenter: [118.091838, 36.958653], // 地图中心点// 弹窗popup: {popupOverlay: null, // 点位弹窗content: "", // 弹窗显示内容},// 行政区划/注记层checkLayers: ["zjc", "xzqh"],mapLayers: {},// 底图underlayer: {sldt: { layer: null, show: true },wxdt: { layer: null, show: false },},checkUnderLayer: "sldt",// 测量距离/面积mapDraw: {helpTooltipElement: null,feature: null,helpTooltip: null,draw: null,measureTooltipElement: null,measureTooltip: null,listener: null,mapMouseMove: null,drawElements: [],drawLayers: [],},isFullScreen: false,// 轨迹mapTrack: {isPlay: false, // 开始或暂停运动isStop: false, // 停止运动, 复位route: null,featureMove: {},geometryMove: {},carPoints: [], //车还要走的点routeIndex: 0, //当前小车所在的路段timer: null,routeLayer: {},coordinates: [[117.98804853292008, 36.924719974587475],... ...],},};},mounted() {// this.initMap();this.initDeepColorMap();// this.initBlueColorMap();this.initEvent();this.initPointPopup();// 添加轨迹// this.addTrack();// 监听全屏状态window.addEventListener("resize", () => {// 是否全屏this.isFullScreen =document.fullscreenElement ||document.webkitFullscreenElement ||document.msFullscreenElement ||document.mozFullScreenElement ||null;});},methods: {handleTrackStart() {this.mapTrack.isPlay = !this.mapTrack.isPlay;if (this.mapTrack.isPlay) {//开始动this.trackMoveStart();} else {this.trackMovePause();}},handleTrackStop() {this.mapTrack.isPlay = false;this.mapTrack.isStop = true;this.resetTrack();this.addTrack();},/*** 切换底图*/handleUnderLayerChange(type) {for (let i in this.underlayer) {this.underlayer[i].layer.setVisible(false);this.underlayer[i].show = false;}this.underlayer[type].show = true;this.underlayer[type].layer.setVisible(true);},/*** 注记层/行政区划 显示与隐藏*/handleLayerChange() {for (let i in this.mapLayers) {this.mapLayers[i].layer.setVisible(false);}for (let i in this.checkLayers) {this.mapLayers[this.checkLayers[i]].layer.setVisible(true);}},/*** 切换全屏*/handleFullScreen() {if (this.isFullScreen) {this.exitfullscreen();} else {this.enterfullscreen();}},/*** 回到原点*/handleBackCenter() {this.map.getView().setCenter(this.mapCenter);},/*** 初始化地图*/initMap() {// 天地图图层const tdLayer = new TileLayer({source: new XYZ({crossOrigin: "anonymous",projection: "EPSG:4326",url: "https://t0.tianditu.gov.cn/DataServer?x={x}&y={y}&l={z}&T=vec_c&tk=地图的key",}),className: "dt",});// 天地图文字图层const tdTextLayer = new TileLayer({source: new XYZ({crossOrigin: "anonymous",projection: "EPSG:4326",url: "https://t0.tianditu.gov.cn/DataServer?x={x}&y={y}&l={z}&T=cva_c&tk=地图的key",}),className: "txt",});this.map = new Map({target: "map",view: new View({center: this.mapCenter,projection: olProj.get("EPSG:4326"),zoom: 13,maxZoom: 17,minZoom: 1,}),});this.map.addLayer(tdLayer);this.map.addLayer(tdTextLayer);this.mapLayers.zjc = { layer: tdTextLayer, show: true };//卫星影像图层const projection = olProj.get("EPSG:4326");const projectionExtent = projection.getExtent();const size = getWidth(projectionExtent) / 256;const resolutions = [];const matrixIds = [];for (let z = 0; z < 20; ++z) {resolutions[z] = size / Math.pow(2, z + 1);matrixIds[z] = z + 1;}const tdwxLayer = new TileLayer({opacity: 1,visible: false,source: new WMTS({crossOrigin: "anonymous",url: "http://t3.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=地图的key",layer: "wxt",matrixSet: "c",format: "tiles",style: "default",projection: this.projection,tileGrid: new WMTSTileGrid({origin: getTopLeft(projectionExtent),resolutions: resolutions,matrixIds: matrixIds,}),wrapX: true,}),});this.map.addLayer(tdwxLayer);this.underlayer.sldt = { layer: tdLayer, show: true };this.underlayer.wxdt = { layer: tdwxLayer, show: false };},/*** 初始化深颜色地图*/initDeepColorMap() {const view = new View({center: this.mapCenter,zoom: 12, //图层缩放大小projection: "EPSG:4326",});this.map = new Map({target: "map",view: view,controls: defaultControls({zoom: true,attribution: false,rotate: false,}),});// 添加矢量底图let url = "https://t0.tianditu.gov.cn/DataServer?x={x}&y={y}&l={z}";url = `${url}&T=vec_c&tk=地图的key`;const source = new XYZ({crossOrigin: "anonymous",url: url,projection: "EPSG:4326",});const tdtLayer = new TileLayer({className: "blueLayer",source: source,});this.map.addLayer(tdtLayer);// 添加矢量注记url = "https://t0.tianditu.gov.cn/DataServer?x={x}&y={y}&l={z}";url = `${url}&T=cva_c&tk=地图的key`;const sourceCVA = new XYZ({crossOrigin: "anonymous",url: url,projection: "EPSG:4326",});const tdtcvaLayer = new TileLayer({className: "blueLayer",source: sourceCVA,});this.map.addLayer(tdtcvaLayer);this.mapLayers.zjc = { layer: tdtcvaLayer, show: true };//卫星影像图层const projection = olProj.get("EPSG:4326");const projectionExtent = projection.getExtent();const size = getWidth(projectionExtent) / 256;const resolutions = [];const matrixIds = [];for (let z = 0; z < 20; ++z) {resolutions[z] = size / Math.pow(2, z + 1);matrixIds[z] = z + 1;}const tdwxLayer = new TileLayer({opacity: 1,visible: false,source: new WMTS({crossOrigin: "anonymous",url:"http://t0.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=地图的key",layer: "wxt",matrixSet: "c",format: "tiles",style: "default",projection: this.projection,tileGrid: new WMTSTileGrid({origin: getTopLeft(projectionExtent),resolutions: resolutions,matrixIds: matrixIds,}),wrapX: true,}),});this.map.addLayer(tdwxLayer);this.underlayer.sldt = { layer: tdtLayer, show: true };this.underlayer.wxdt = { layer: tdwxLayer, show: false };},initBlueColorMap() {let target = "map";let tileLayer = [new TileLayer({source: new XYZ({url: "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",}),}),];let view = new View({center: this.mapCenter,zoom: 12,});this.map = new Map({target: target,layers: tileLayer,view: view,});const TiandiMap_cia = new TileLayer({name: "天地图影像注记图层",source: new XYZ({url: "http://t0.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=地图的key", //parent.TiandituKey()为天地图密钥wrapX: false,}),});// 添加到地图上this.map.addLayer(TiandiMap_cia);},/*** 地图事件*/initEvent() {// 地图加载完成this.map.once("rendercomplete", () => {// 行政区划this.addProvinceBorder();// 添加点位//this.addPoint([[118.103288, 36.96607]], require("@/assets/image/homecar2.png"), -(Math.PI / 3));this.$emit("complete", this.map);});// 地图点击this.map.on("click", e => {// 点位弹窗var pixel = this.map.getEventPixel(e.originalEvent);console.log(e.coordinate);let feature = this.map.forEachFeatureAtPixel(pixel, feature => {return feature;});if (feature && feature.name && feature.name != "cityScope") {var coodinate = e.coordinate;this.popup.content = "你点击的坐标为:" + coodinate;this.popup.popupOverlay.setPosition(coodinate);this.map.addOverlay(this.popup.popupOverlay);this.$emit("pointClick", true, feature.name, e.coordinate, e.pixel);} else {this.$emit("pointClick", false, feature.name, e.coordinate, e.pixel);this.popup.popupOverlay.setPosition(undefined);}});},/*** 初始化点位弹窗*/initPointPopup() {var container = document.getElementById("popup");var popupCloser = document.getElementById("popup-closer");this.popup.popupOverlay = new Overlay({element: container,autoPan: true,});popupCloser.addEventListener("click", function() {this.popup.popupOverlay.setPosition(undefined);});},/**** 加行政区域边界* 获取geojson数据地址: https://datav.aliyun.com/portal/school/atlas/area_selector*/addProvinceBorder(geojson) {//行政区划边界图层const provinceLayer = new VectorLayer({renderMode: "vector",source: new VectorSource(),zIndex: 0,});this.map.addLayer(provinceLayer);this.mapLayers.xzqh = { layer: provinceLayer, show: true };// 加载geojsonlet qxn = geojson ? geojson : require("../mixins/370321.json");qxn.features.forEach(featureJSON => {let feature = new GeoJSON().readFeature(featureJSON);feature.set("name", feature.values_.NAME);feature.setStyle(new Style({stroke: new Stroke({//边框color: "rgba(3,15,83, 1)",width: 1,}),fill: new Fill({//填充color: "rgba(3,15,83, 0.5)", // "rgba(255, 255, 255, 0.5)"}),}));provinceLayer.getSource().addFeature(feature);});},/*** 添加点位* @param {*} list [[经度, 纬度], [经度, 纬度]]* @param {*} icon 点位图标图片路径* @param {*} angle 旋转角度* @param {*} popupType 弹窗类型  可以在template中自定义多种弹窗, 然后指定弹出哪个*/addPoint(list, icon, angle, popupType = 0) {// 设置图层const flagLayer = new VectorLayer({source: new VectorSource(),});// 添加图层this.map.addLayer(flagLayer);let featuresArr = [];// 循环添加featurefor (let i = 0; i < list.length; i++) {// 创建feature,一个feature就是一个点坐标信息let feature = new Feature({geometry: new Point([list[i][0], list[i][1]]),});feature.name = "point";feature.popupType = popupType;// 设置要素的图标feature.setStyle(new Style({// 设置图片效果image: new Icon({src: icon,anchor: [0.5, 0.9],scale: 1,rotation: angle || 0,}),zIndex: 6000,}));// feature.setStyle(//   new Style({//     // 设置图片效果//     image: new CircleStyle({//       radius: 10,//       stroke: new Stroke({//         color: '#fff'//       }),//       fill: new Fill({//         color: '#3399cc'//       })//     }),//     zIndex: 3000,//     name: '1111'//   }),// );featuresArr.push(feature);} // for 结束// 批量添加featureflagLayer.getSource().addFeatures(featuresArr);}, gishandleGisCommand(cmd) {switch (cmd) {case "1":this.drawDistance();break;case "2":this.drawArea();break;case "3":this.drawClear();break;case "4":this.printMap();break;default:break;}},/*** 测距离*/drawDistance() {let source = new VectorSource(); // 首先创建一个数据源,用来放置绘制过程中和绘制结束后的线段const layer = new VectorLayer({// 添加一个图层,用来放置数据源,样式自己随便设置就可以了,我这里默认的官网source: source,style: new Style({fill: new Fill({color: "rgba(255, 255, 255, 0.2)",}),stroke: new Stroke({color: "#ffcc33",width: 4,}),image: new CircleStyle({radius: 7,fill: new Fill({color: "#ffcc33",}),}),}),zIndex: 4000,});this.mapDraw.mapMouseMove = this.map.on("pointermove", ev => {// 给地图添加一个鼠标移动事件let helpMsg = "点击开始测量"; // 默认开始的操作提示文本if (this.mapDraw.feature) {// featuer 是全局的,判断有没有点击鼠标绘制过helpMsg = "双击结束测量"; // 如果之前点击绘制了就显示双击结束}this.mapDraw.helpTooltipElement.innerHTML = helpMsg; // 设置dom的提示文字this.mapDraw.helpTooltip.setPosition(ev.coordinate); // 设置位置跟着鼠标走this.mapDraw.helpTooltipElement.classList.remove("hidden"); // 让他显示出来});this.drawCreateHelpTooltip(); // 创建那个helpTooltipElement方法this.map.addLayer(layer); // 把图层添加到地图this.mapDraw.drawLayers.push(layer); // 保存起来// 开始绘制线this.mapDraw.draw = new Draw({source: source,type: "LineString", // 绘制线style: new Style({// 绘制完成之前线的样式,这是官网的样式,需要的话自己可以修改成自己想要的样子fill: new Fill({color: "rgba(255, 255, 255, 0.2)",}),stroke: new Stroke({color: "rgba(0, 0, 0, 0.5)",lineDash: [10, 10],width: 4,}),image: new CircleStyle({radius: 5,stroke: new Stroke({color: "rgba(0, 0, 0, 0.7)",}),fill: new Fill({color: "rgba(255, 255, 255, 0.2)",}),}),}),});this.map.addInteraction(this.mapDraw.draw); // draw 绑定到地图上面去// 格式化长度, 直接官网代码const formatLength = function(line) {const length = getLength(line);let output;if (length > 100) {output = Math.round((length / 1000) * 100) / 100 + " " + "km";} else {output = Math.round(length * 100) / 100 + " " + "m";}return output;};this.drawCreateMeasureTooltip(); // 创建那个距离的提示框// 开始监听绘制const _this = this;this.mapDraw.draw.on("drawstart", evt => {_this.mapDraw.feature = evt.feature; // feature就是全局的let tooltipCoord = evt.coordinate; // 鼠标当前的位置_this.mapDraw.listener = _this.mapDraw.feature.getGeometry().on("change", function(evt) {const geom = evt.target;let output = formatLength(geom); // 距离的格式tooltipCoord = geom.getLastCoordinate(); // 设置鼠标位置改变后的实时位置_this.mapDraw.measureTooltipElement.innerHTML = output; // 设置提示框的内容,就是距离_this.mapDraw.measureTooltip.setPosition(tooltipCoord); // 设置距离提示框的位置});});// 双击绘制完成this.mapDraw.draw.on("drawend", () => {this.mapDraw.measureTooltipElement.className = "ol-tooltip ol-tooltip-static";this.mapDraw.measureTooltip.setOffset([0, -7]);this.mapDraw.feature = null;this.mapDraw.measureTooltipElement = null;this.drawCreateMeasureTooltip();unByKey(this.mapDraw.listener);// 画完一次就终止(不连续画线)unByKey(this.mapDraw.mapMouseMove);setTimeout(() => {this.mapDraw.helpTooltipElement.classList.add("hidden");this.mapDraw.helpTooltipElement = null;this.map.removeInteraction(this.mapDraw.draw);}, 50);});},/*** 测距离提示信息*/drawCreateHelpTooltip() {if (this.mapDraw.helpTooltipElement) {this.mapDraw.helpTooltipElement.parentNode.removeChild(this.mapDraw.helpTooltipElement);}this.mapDraw.helpTooltipElement = document.createElement("div");this.mapDraw.helpTooltipElement.className = "ol-tooltip hidden";this.mapDraw.helpTooltip = new Overlay({element: this.mapDraw.helpTooltipElement,offset: [15, 0],positioning: "center-left",});this.map.addOverlay(this.mapDraw.helpTooltip);},/*** 测距离提示信息*/drawCreateMeasureTooltip() {if (this.mapDraw.measureTooltipElement) {this.mapDraw.measureTooltipElement.parentNode.removeChild(this.mapDraw.measureTooltipElement);}this.mapDraw.measureTooltipElement = document.createElement("div");this.mapDraw.measureTooltipElement.className = "ol-tooltip ol-tooltip-measure";this.mapDraw.measureTooltip = new Overlay({element: this.mapDraw.measureTooltipElement,offset: [0, -15],positioning: "bottom-center",stopEvent: false,insertFirst: false,});this.mapDraw.drawElements.push(this.mapDraw.measureTooltip);this.map.addOverlay(this.mapDraw.measureTooltip);},/*** 清空绘制*/drawClear() {for (let i = 0; i < this.mapDraw.drawLayers.length; i++) {this.map.removeLayer(this.mapDraw.drawLayers[i]);}for (let i = 0; i < this.mapDraw.drawElements.length; i++) {this.map.removeOverlay(this.mapDraw.drawElements[i]);}this.mapDraw.drawLayers = [];this.mapDraw.drawElements = [];this.map.removeInteraction(this.mapDraw.draw);unByKey(this.mapDraw.mapMouseMove);},/// 测面积drawArea() {let source = new VectorSource(); // 首先创建一个数据源,用来放置绘制过程中和绘制结束后的线段const layer = new VectorLayer({// 添加一个图层,用来放置数据源,样式自己随便设置就可以了,我这里默认的官网source: source,style: new Style({fill: new Fill({color: "rgba(255, 255, 255, 0.2)",}),stroke: new Stroke({color: "#ffcc33",width: 4,}),image: new CircleStyle({radius: 7,fill: new Fill({color: "#ffcc33",}),}),}),zIndex: 4000,});this.mapDraw.mapMouseMove = this.map.on("pointermove", ev => {// 给地图添加一个鼠标移动事件let helpMsg = "点击开始测量"; // 默认开始的操作提示文本if (this.mapDraw.feature) {// featuer 是全局的,判断有没有点击鼠标绘制过helpMsg = "双击结束测量"; // 如果之前点击绘制了就显示双击结束}this.mapDraw.helpTooltipElement.innerHTML = helpMsg; // 设置dom的提示文字this.mapDraw.helpTooltip.setPosition(ev.coordinate); // 设置位置跟着鼠标走this.mapDraw.helpTooltipElement.classList.remove("hidden"); // 让他显示出来});this.drawCreateHelpTooltip(); // 创建那个helpTooltipElement方法this.map.addLayer(layer); // 把图层添加到地图this.mapDraw.drawLayers.push(layer); // 保存起来// 开始绘制线this.mapDraw.draw = new Draw({source: source,type: "Polygon", // 绘制线style: new Style({// 绘制完成之前线的样式,这是官网的样式,需要的话自己可以修改成自己想要的样子fill: new Fill({color: "rgba(255, 255, 255, 0.2)",}),stroke: new Stroke({color: "rgba(0, 0, 0, 0.5)",lineDash: [10, 10],width: 4,}),image: new CircleStyle({radius: 5,stroke: new Stroke({color: "rgba(0, 0, 0, 0.7)",}),fill: new Fill({color: "rgba(255, 255, 255, 0.2)",}),}),}),});this.map.addInteraction(this.mapDraw.draw); // draw 绑定到地图上面去const _this = this;// 面积测量函数const formatArea = function(polygon) {var sourceProj = _this.map.getView().getProjection(); // 获取投影坐标系var area = getArea(polygon, {projection: sourceProj,});var output;if (area > 10000) {output = Math.round((area / 1000000) * 100) / 100 + " " + "km<sup>2</sup>";} else {output = Math.round(area * 100) / 100 + " " + "m<sup>2</sup>";}return output;};this.drawCreateMeasureTooltip(); // 创建那个距离的提示框// 开始监听绘制this.mapDraw.draw.on("drawstart", evt => {_this.mapDraw.feature = evt.feature; // feature就是全局的let tooltipCoord = evt.coordinate; // 鼠标当前的位置_this.mapDraw.listener = _this.mapDraw.feature.getGeometry().on("change", function(evt) {const geom = evt.target;let output = formatArea(geom); // 距离的格式tooltipCoord = geom.getInteriorPoint().getCoordinates(); // 设置鼠标位置改变后的实时位置_this.mapDraw.measureTooltipElement.innerHTML = output; // 设置提示框的内容,就是距离_this.mapDraw.measureTooltip.setPosition(tooltipCoord); // 设置距离提示框的位置});});// 双击绘制完成this.mapDraw.draw.on("drawend", () => {this.mapDraw.measureTooltipElement.className = "ol-tooltip ol-tooltip-static";this.mapDraw.measureTooltip.setOffset([0, -7]);this.mapDraw.feature = null;this.mapDraw.measureTooltipElement = null;this.drawCreateMeasureTooltip();unByKey(this.mapDraw.listener);// 画完一次就终止(不连续画线)unByKey(this.mapDraw.mapMouseMove);setTimeout(() => {this.mapDraw.helpTooltipElement.classList.add("hidden");this.mapDraw.helpTooltipElement = null;this.map.removeInteraction(this.mapDraw.draw);}, 50);});},/*** 打印地图(将地图保存为图片)*/printMap() {const that = this;let exportOptions = {filter: function(element) {var className = element.className || "";return (className.indexOf("ol-control") === -1 ||className.indexOf("ol-scale") > -1 ||(className.indexOf("ol-attribution") > -1 && className.indexOf("ol-uncollapsible")));},};that.map.once("rendercomplete", function(e) {// exportOptions.width = 1000;// exportOptions.height = 800;domtoimage.toJpeg(that.map.getViewport(), exportOptions).then(function(dataUrl) {saveAs(dataUrl, "map.jpg");});});that.map.updateSize();}, gis end/ 全屏enterfullscreen() {//进入全屏let docElm = document.documentElement;//FireFoxif (docElm.mozRequestFullScreen) {docElm.mozRequestFullScreen();}//Chrome等else if (docElm.webkitRequestFullScreen) {docElm.webkitRequestFullScreen();}//IE11else if (elem.msRequestFullscreen) {elem.msRequestFullscreen();}this.isFullScreen = true;},exitfullscreen() {//退出全屏if (document.mozCancelFullScreen) {document.mozCancelFullScreen();} else if (document.webkitCancelFullScreen) {document.webkitCancelFullScreen();} else if (document.msExitFullscreen) {document.msExitFullscreen();}this.isFullScreen = false;}, 全屏 end/// 轨迹回放,  轨迹运动//轨迹线addTrack() {this.mapTrack.route = new LineString(this.mapTrack.coordinates);this.mapTrack.geometryMove = new Point(this.mapTrack.route.getFirstCoordinate());this.mapTrack.featureMove = new Feature({type: "featureMove",geometry: this.mapTrack.geometryMove,});this.mapTrack.featureMove.name = "track_point";//坐标转换this.mapTrack.dotsData = this.mapTrack.coordinates.map(item => {return transform(item, "EPSG:3857", "EPSG:4326");});//深复制车的位置,不在原数组改变,方便重新播放// this.carPoints = JSON.parse(JSON.stringify(this.dotsData));this.mapTrack.carPoints = [...this.mapTrack.dotsData];this.mapTrack.routeLayer = new VectorLayer({source: new VectorSource({features: [new Feature({type: "route",geometry: this.mapTrack.route,}),this.mapTrack.featureMove,new Feature({type: "startIcon",geometry: new Point(this.mapTrack.route.getFirstCoordinate()),}),new Feature({type: "endIcon",geometry: new Point(this.mapTrack.route.getLastCoordinate()),}),new Feature({type: "featureMove",geometry: new Point(this.mapTrack.carPoints[0]),}),],}),style: feature => {if (feature.get("type") == "route") {return new Style({stroke: new Stroke({width: 6,color: [25, 59, 128, 1],}),});} else if (feature.get("type") == "startIcon") {return new Style({// image: new Icon({// 	anchor: [0.5, 1],// 	src: "",// 	// src: require("@/assets/image/map_start.png"),// 	// src: require("@/assets/image/homecar2.png"),// 	scale: 1, //设置大小// }),});} else if (feature.get("type") == "endIcon") {return new Style({// image: new Icon({// 	anchor: [0.5, 1],// 	src: "",// 	// src: require("@/assets/image/map_end.png"),// 	// src: require("@/assets/image/homecar2.png"),// 	scale: 1, //设置大小// }),});} else if (feature.get("type") == "featureMove") {return new Style({image: new Icon({//	src: "https://openlayers.org/en/v4.6.5/examples/data/icon.png",// src: require("@/assets/image/map_arrow.png"),src: require("@/assets/image/homecar2.png"),scale: 1,//anchor: [0.5, 0.5],rotation: this.trackCountRotate(),}),});}//return this.mapTrack.styles[feature.get("type")];},});this.map.addLayer(this.mapTrack.routeLayer);},/*** 小车开始运动*/trackMoveStart() {this.mapTrack.timer = setInterval(() => {if (this.mapTrack.routeIndex + 1 >= this.mapTrack.carPoints.length) {//重头开始this.mapTrack.routeIndex = 0;//移除要素// this.mapTrack.routeLayer.getSource().removeFeature(this.mapTrack.featureMove);clearInterval(this.mapTrack.timer);//重复运动// this.addTrack();// this.trackMoveStart();//this.open(); //自动开启功能return;}//到转折点旋转角度if (this.trackNextPoint() === this.mapTrack.carPoints[this.mapTrack.routeIndex + 1]) {this.mapTrack.routeIndex++;if (this.mapTrack.featureMove.getStyle()) {this.mapTrack.featureMove.getStyle().getImage().setRotation(this.trackCountRotate());}}//改变坐标点this.mapTrack.featureMove.getGeometry().setCoordinates(fromLonLat(this.mapTrack.carPoints[this.mapTrack.routeIndex]));// 经过的点位console.log(this.mapTrack.coordinates[this.mapTrack.routeIndex]);}, 10);},/*** 小车暂停运动*/trackMovePause() {clearInterval(this.mapTrack.timer);},//计算下一个点的位置//这里的算法是计算了两点之间的点   两点之间的连线可能存在很多个计算出来的点trackNextPoint() {let routeIndex = this.mapTrack.routeIndex;let p1 = this.map.getPixelFromCoordinate(fromLonLat(this.mapTrack.carPoints[routeIndex])); //获取在屏幕的像素位置let p2 = this.map.getPixelFromCoordinate(fromLonLat(this.mapTrack.carPoints[routeIndex + 1]));let dx = p2[0] - p1[0];let dy = p2[1] - p1[1];//打印可见  在没有走到下一个点之前,下一个点是不变的,前一个点以这个点为终点向其靠近let distance = Math.sqrt(dx * dx + dy * dy);if (distance <= 1) {return this.mapTrack.carPoints[routeIndex + 1];} else {let x = p1[0] + dx / distance;let y = p1[1] + dy / distance;let coor = transform(this.map.getCoordinateFromPixel([x, y]), "EPSG:3857", "EPSG:4326");this.mapTrack.carPoints[routeIndex] = coor; //这里会将前一个点重新赋值  要素利用这个坐标变化进行移动return this.mapTrack.carPoints[routeIndex];}},//计算两点之间的角度  算旋转角度trackCountRotate() {let i = this.mapTrack.routeIndex,j = i + 1;if (j === this.mapTrack.carPoints.length) {i--;j--;}let p1 = this.mapTrack.carPoints[i];let p2 = this.mapTrack.carPoints[j];return Math.atan2(p2[0] - p1[0], p2[1] - p1[1]);},resetTrack() {clearInterval(this.mapTrack.timer);this.mapTrack.routeLayer.getSource().clear();this.map.removeLayer(this.mapTrack.routeLayer);this.mapTrack.featureMove = {};this.mapTrack.geometryMove = {};this.mapTrack.timer = null;this.mapTrack.carPoints = [];this.mapTrack.routeIndex = 0;this.mapTrack.routeLayer = {};this.mapTrack.route = null;},},
};
</script><style lang="scss" scoped>
.mapBox {width: 100%;height: 100%;position: relative;
}
.map {width: 100%;height: 100%;
}/deep/.ol-control {display: none;
}/deep/.blueLayer {// filter: grayscale(100%) sepia(21%) invert(100%) saturate(150%) brightness(100%);filter: grayscale(98%) invert(100%) sepia(50%) hue-rotate(180deg) saturate(2000%) brightness(50%) contrast(90%) !important;
}.optionsBox {position: absolute;top: 20px;left: 20px;z-index: 1000;display: flex;align-items: center;
}
</style><!-- 修改提示框样式 -->
<style lang="scss" scoped>
/deep/.ol-tooltip {position: relative;background: rgba(0, 0, 0, 0.5);border-radius: 4px;color: white;padding: 4px 8px;opacity: 0.7;white-space: nowrap;font-size: 12px;cursor: default;user-select: none;
}/deep/ .hidden {display: none;
}/deep/.ol-tooltip-measure {opacity: 1;font-weight: bold;
}/deep/.ol-tooltip-static {background-color: #ffcc33;color: black;border: 1px solid white;
}/deep/.ol-tooltip-measure:before,
/deep/.ol-tooltip-static:before {border-top: 6px solid rgba(0, 0, 0, 0.5);border-right: 6px solid transparent;border-left: 6px solid transparent;content: "";position: absolute;bottom: -6px;margin-left: -7px;left: 50%;
}/deep/.ol-tooltip-static:before {border-top-color: #ffcc33;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/120698.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

React中如何提高组件的渲染效率

一、是什么 react 基于虚拟 DOM 和高效 Diff算法的完美配合&#xff0c;实现了对 DOM最小粒度的更新&#xff0c;大多数情况下&#xff0c;React对 DOM的渲染效率足以我们的业务日常 复杂业务场景下&#xff0c;性能问题依然会困扰我们。此时需要采取一些措施来提升运行性能&…

k8s-----26、细粒度权限管理 RBAC

0、导读 每一个用户对API资源进行操作都需要通经过以下三个步骤: 第一步:对客户端访问进行认证操作,确认是否具有访问k8s权限(也就是通过serviceaccount) token(共享秘钥) SSL(双向SSL认证) …通过任何一个认证即表示认证通过,进入下一步第二步:授权检查,确认是否对资源…

JAVAEE初阶相关内容第十六弹--网络编程

写在前 这一节的内容首先是对十五弹&#xff08;UDP回显服务器&#xff09;进行简单的改进&#xff0c;在这基础上开始介绍TCP流套接字编程。 目录 写在前 1.改进回显服务器 1.1完整代码实现 1.2运行输出结果 2.TCP流套接字编程 2.1ServerSocketAPI 2.2SocketAPI 3.TC…

echarts的柱状图的重叠和堆叠实现两个柱体的显示和之前的差值显示

效果图 主要思路 准备三个柱体&#xff08;原计划&#xff0c;实际进度&#xff0c;差值&#xff09; 原计划和实际进度设置成重叠 {barWidth: 20,// yAxisIndex: 1,z: 1,name: 原计划,type: bar,stack: ab,emphasis: { // 点击柱体其他柱体颜色会变浅disabled: true},label…

Docker Nginx安装使用以及踩坑点总结

Docker Nginx安装使用以及踩坑点总结 拉取nginx镜像 docker pull nginx:latest运行镜像 暂时不需要配置volume挂载 docker run --name nginx -p 80:80 -d nginx参数详解&#xff1a; --name nginx 指定容器的名称 -p 80:80 映射端口 -d 守护进程运行 创建volume目录 mk…

代码随想录打卡第五十天|198.打家劫舍 ● 213.打家劫舍II ● 337.打家劫舍III

198.打家劫舍 题目&#xff1a; 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报警。 …

APA——概述

目录 一、前言 二、AVM概述 三、APA概述 一、前言 AVM:Around View Monitor 全景环视系统,也叫360影像,低速摄像头ADAS,目前已经比较成熟,在很多OEM设计车型中已成为一种标配的泊车驾驶辅助功能。使用前后左右四摄像头传感器,包括联合标定、视图切换、视图投影、图像拼…

AWTK实现汽车仪表Cluster/DashBoard嵌入式GUI开发(六):一个AWTK工程

一个AWTK工程基于C/C++编写,可以分为如下几步: 结合下图,看懂启动的部分。一般一个AWTK工程,需要实现哪些部分,就是其中开始之后白色的部分,比如调用main函数和gui_app_start时会做一些操作,比如asset_init和application_init时要做一些设置,还有退出的函数application…

【ARM AMBA Q_Channel 详细介绍】

文章目录 1.1 Q_Channel 概述1.2 Q-Channel1.2.1 Q-Channel 接口1.2.2 Q-Channel 接口的握手状态1.2.3 握手信号规则 1.3 P_Channel的握手协议1.3.1 device 接受 PMU 的 power 请求1.3.2 device 拒绝 PMU 的 power 请求 1.4 device 复位信号与 Q _Channel 的结合1.4.1 RESETn 复…

Xcode iOS app启用文件共享

在info.plist中添加如下两个配置 Supports opening documents in place Application supports iTunes file sharing 结果都为YES&#xff0c;如下图所示&#xff1a; 然后&#xff0c;iOS设备查看&#xff0c;文件->我的iPhone列表中有一个和你工程名相同的文件夹出现&…

C#演示单例模式

单例模式的特点&#xff1a; 确保一个类只有一个实例,并提供一个全局访问点。 //单例模式的实现internal class Boss{//定义静态变量保存实例private static Boss uniqueBoss;//定义锁&#xff0c;确保线程访问安全private static readonly object _lock new object();//定义私…

linux查看内存的方式

1、显示内存状态:free -h  以合适的单位显示内存使用情况&#xff0c;最大为三位数&#xff0c;自动计算对应的单位值。单位有&#xff1a; B bytes K kilos M megas G gigas T teras $free -htotal used free shared buff/cache available Me…

工作小计-GPU硬编以及依赖库 nvcuvidnvidia-encode

工作小计-GPU编码以及依赖库 已经是第三篇关于编解码的记录了。项目中用到GPU编码很久了&#xff0c;因为yuv太大&#xff0c;所以编码显得很重要。这次遇到的问题是环境的搭建问题。需要把开发机上的环境放到docker中&#xff0c;以保证docker中同样可以进行GPU的编码。 1 定…

安装pandas报错

报错信息&#xff1a; C:\Users\Jordan>pip install pandas Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/ Collecting pandasUsing cached https://pypi.tuna.tsinghua.edu.cn/packages/3a/6e/6c9c197ec2da861ea8c9c6848f0f887b7563f16e607bc6a35506af6…

JKPacket权威指南——联系我们

各位在使用JKPacket的过程中遇到问题或者阅读本书发现有错误之处可以通过下方邮箱联系到我。 邮箱&#xff1a;zhangsande18163.com

三代自动驾驶系统及主流科技公司自动驾驶技术方案简介

截止目前&#xff0c;按技术特点&#xff0c;自动驾驶技术大致经历了三代发展&#xff1a;第一代自动驾驶技术以后融合感知技术&#xff0c;高精度地图&#xff0c;基于惯导、GPS定位系统&#xff0c;预测模块&#xff0c;基于优化、搜索的规控等组成。第一代比较成熟的自动驾驶…

是顺流还是逆流?未来物流作业是否将被机器人全面取代?

原创 | 文 BFT机器人 随着人工智能的加速发展&#xff0c;各行业为适应数字时代的潮流&#xff0c;纷纷引入智能制造&#xff0c;帮助企业实现产业升级。而物流行业也不例外&#xff0c;现今人们的生活速度加快&#xff0c;为了快捷便利&#xff0c;很多的人喜欢通过网购、快递…

JavaScript基础知识18——逻辑运算符之短路运算

哈喽&#xff0c;大家好&#xff0c;我是雷工。 本节学习JavaScript基础知识——逻辑运算符中的短路运算&#xff0c;以下为学习笔记。 规则&#xff1a; 1、如果是&&运算&#xff0c;只要遇到false&#xff0c;就立即短路&#xff0c;不会再执行了&#xff0c;直接返回…

Linux学习第24天:Linux 阻塞和非阻塞 IO 实验(一): 挂起

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 在正式开始今天的笔记之前谈一下工作中遇见的一个问题。 本篇笔记主要学习Linux 阻塞和非阻塞 IO 实验&#xff0c;主要包括阻塞和非阻塞简介、等待队列、轮询、…

Spring Authorization Server 1.1 扩展实现 OAuth2 密码模式与 Spring Cloud 的整合实战

目录 前言无图无真相创建数据库授权服务器maven 依赖application.yml授权服务器配置AuthorizationServierConfigDefaultSecutiryConfig 密码模式扩展PasswordAuthenticationTokenPasswordAuthenticationConverterPasswordAuthenticationProvider JWT 自定义字段自定义认证响应认…