局域网内PGIS地图的使用
局域网PGIS地图的使用:以天地图做打底,使用leaflet.js交互式地图 JavaScript 库做开发。
相关参考网址:https://leafletjs.cn/reference.html#map-example
区域回显:https://kklimczak.github.io/Leaflet.Pin/;
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/124026478
热力图:https://www.jb51.net/javascript/290354ppf.htm
轨迹:https://blog.51cto.com/BADAOLIUMANGQZ/6843897
PS:相关搜索可搜Leaflet.MovingMarker-master
主要功能包括点的标记,区域的展示,以及点的点击事件;点的添加展示,区域的绘制,回显,编辑,删除;热力图;PGIS轨迹回放功能。相关代码如下:
一、点的标记,区域的展示,以及点的点击事件
相关代码组件如下,此组件整合了热力图的展示,具体根据实际业务需要选择性展示:
<template> <!-- 该组件是展示点的添加,区域的添加以及点击事件 和热力图的展示的整合组件 --> <div class="data_map" style="height: 100%; position: relative"> <div class="bg_heights" style="position: relative; width: 100%" :style="{ height: height }" > <div :id="mapId" style="width: 100%" :style="{ height: height }"></div> </div> <div class="tabClickA" v-if="$route.path != '/index'"> <div class="tabList" @click="clickGrid('1')">警务区</div> <div class="tabList" @click="clickGrid('2')">网格</div> </div> </div> </template> <style scoped lang="scss"></style> <style> .anchorBL { display: none; } body, html, #map { height: 100%; margin: auto; font-family: "微软雅黑"; } .my-label-a { width: 100%; height: 20px; } </style> <script type="text/ecmascript-6"> // require('echarts/extension/bmap/bmap.min'); // import * as zrender from 'zrender' //引入zrender库 import 'leaflet.heat' import { loadBMap } from './map' var map; var T = window.T; export default { props:{ height:{ type:String, default:'100%' }, mapId:{ type:String, default:'mapId' }, //商圈区域 businessList:{ type:Array, default:()=>[] }, //绘制商铺点 shopList:{ type:Array, default:()=>[] }, //绘制设备点 equList:{ type:Array, default:()=>[] }, //警务区网格 policeArea:{ type:Array, default:()=>[] }, //综治网格 gridArea:{ type:Array, default:()=>[] }, //警务区展示与否 isShowPolice:{ type:Boolean, default:false }, //网格展示与否 isShowGrid:{ type:Boolean, default:false }, //热力地图数据 houtData:{ type:Array, default:()=>[ // {coor:[118.711996,37.440117], count: 45}, // {coor:[118.714751,37.439935], count: 56}, // {coor:[118.709006,37.442001], count: 127}, // {coor:[118.707861,37.438914], count: 89}, // {coor:[118.712757,37.434551], count: 13}, // {coor:[118.649018, 37.453269], count: 234}, // {coor:[118.718937,37.434179], count: 46}, // {coor:[118.718398,37.443677], count: 339}, // {coor:[118.713907,37.448061], count: 95}, // {coor:[118.713907,37.448061], count: 354}, ] }, //点击设备展示设备信息还是video isShowVideo:{ type:Boolean, default:false }, //是否展示商圈边界 isBusiness:{ type:Boolean, default:false }, //这是商圈地图的点击商圈的展示与否的 isMapEvery: { type: Boolean, default:false } }, data(){ return { mapLoading:false, bgHeight:'668px', map:'', currentLat:118.70034983319356, currentLon : 37.45030118084613, getZoom:16, //地图当前的等级 previousBusinessPolygons: [], // 存储之前绘制的业务描边图形 previousPolicePolygons: [], // 存储之前绘制的警察描边图形 previousGridPolygons: [] // 存储之前绘制的网格描边图形 } }, watch: { businessList: { handler: function (newObj, oldObj) { let that = this; that.addMarker(this.businessList,'business') }, deep: true, // 深度监听 immediate: true // 会在监测开始时调用一次该处理函数 }, shopList: { handler: function(newObj, oldObj) { let that=this; that.drawPoint(that.shopList,'shop') }, deep: true, // 深度监听 // immediate: true // 会在监测开始时调用一次该处理函数 }, equList: { handler: function(newObj, oldObj) { let that=this; that.drawPoint(that.equList,'camera') }, deep: true, // 深度监听 immediate: true // 会在监测开始时调用一次该处理函数 }, policeArea: { handler: function(newObj, oldObj) { let that=this; that.addMarker(that.policeArea,'police') }, deep: true, // 深度监听 immediate: true // 会在监测开始时调用一次该处理函数 }, gridArea: { handler: function(newObj, oldObj) { let that=this; that.addMarker(that.gridArea,'grid') }, deep: true, // 深度监听 immediate: true // 会在监测开始时调用一次该处理函数 }, houtData: { handler: function(newObj, oldObj) { let that=this; setTimeout(function(){ that.initHotMap() },100) }, deep: true, // 深度监听 immediate: true // 会在监测开始时调用一次该处理函数 }, }, methods:{ //初始化百度地图 initBdMap() { var that = this var cenPoint = [118.688,37.443] var map = L.map(this.mapId, { attributionControl:false, crs:L.CRS.EPSG4326, //要使用的坐标系 WGS84 是目前最流行的地理坐标系统 center:[cenPoint[1],cenPoint[0]], zoom: 16 }); //这里是加载的内网的瓦片地址 L.tileLayer('这是url', { // L.tileLayer(imageURL, { minZoom:0, maxZoom:19, zoomOffset:0, tms:false }).addTo(map); this.map = map }, //绘制点 drawPoint(data, type) { var that = this //获取所有的图层 let all = this.map._layers let arr = Object.values(all) arr.map(item=>{ if (item.class === "shopPointA") { //如果是点图层就删除相关的点图层 that.map.removeLayer(item); } }) //图标大小 var LeafIcon = L.Icon.extend({ options: { iconSize: [36, 47], } }); document.body.addEventListener('click', function(event) { //查看更多的跳转 if (event.target.innerText == '查看更多>>') { that.$router.push("/business/shopDetail?id="+event.target.id ); } }); var data_info = data,content,newPoint,mapUrl,shopName; for(var i = 0;i<data_info.length;i++){ //根据不同的类型展示不同的点的图片以及点击点的弹框的内容 if(type=='shop'){ mapUrl = require("../../assets/base/shop.png") shopName = data_info[i].shopName content = "<div class='skyDiv'>"+ "<div class='skyTitle'>"+shopName+"</div>"+ "<p class='skyP'>联系人:"+data_info[i].userName +' ('+data_info[i].phone+')'+"</p>"+ "<p class='skyP'>地址:"+data_info[i].addressName+"</p>"+ "<p class='skyP' style='color:#50b3ff;cursor: pointer' id='"+data_info[i].id+"'>查看更多>></p>"+ "</div>" }else{ mapUrl = require("../../assets/base/equ.png") shopName = data_info[i].name content = "<div class='skyDiv'>"+ "<div class='skyTitle'>"+shopName+"</div>"+ "</div>" } //申明点 var icon = new LeafIcon({iconUrl: mapUrl}); L.icon = function (options) { return new L.Icon(options); }; newPoint = [data_info[i].longitude, data_info[i].latitude] var shopPoint = L.marker([Number(newPoint[1]), Number(newPoint[0])], { icon: icon }) shopPoint.class='shopPointA' //确立点的标识,方便后期做相关的操作应用,具体看实际的业务逻辑 shopPoint.addTo(that.map).bindPopup(content); //bindPopup 在点上添加点击事件 } }, //绘制区域描边 addMarker(data, type) { let that = this //添加警务网格 var business = data; for(var i = 0;i<business.length;i++){ if(business[i].border!=''&&business[i].border!=null){ //整理绘制区域需要的数据格式 var policeGrid = business[i].border.split(';'),newArr = [],newArrNow = [],oneArr = [] if(policeGrid.length>0){ policeGrid.forEach(item=>{ var aa = [Number(item.split(',')[1]), Number(item.split(',')[0])] newArr.push(aa) }) //获取相关图层 let all = this.map._layers let arr = Object.values(all) var bus //此处是商圈的区域添加 --》》mxj 20231214 if (type == 'business') { bus = L.polygon(newArr, { color: "#FF5663", weight: 2, opacity: 1, fillColor: "#FF5663", fillOpacity: 0.5,lineStyle:'dashed', }) bus.class = 'businessA' //添加唯一标识 //isBusiness是在搜索的时候判断是否在次添加 --》》mxj 20231214 if (this.isBusiness == true) { bus.bindTooltip(business[i].name, { permanent: true, direction: 'top' }).openTooltip() bus.addTo(that.map) //添加区域展示 } else { if (that.isMapEvery == true) { //此处的业务逻辑是先删除,在添加区域展示,具体的根据实际业务逻辑来 arr.map(item=>{ if (item.class === "businessA") { //删除相关图层 that.map.removeLayer(item); } }) bus.bindTooltip(business[i].name, { permanent: true, direction: 'top' }).openTooltip() bus.addTo(that.map) } } } else if (type == 'police') { //此处是警务区的区域添加 --》》mxj 20231214 var police = L.polygon(newArr, { color: "#FF5663", weight: 2, opacity: 1, fillColor: "#FF5663", fillOpacity: 0.5,lineStyle:'dashed', }) police.class='policeA' //isShowPolice判断是添加还是隐藏 --》》mxj 20231214 if(this.isShowPolice){ police.bindTooltip(business[i].policeDistrictName,{ permanent:true, direction:'top' }).openTooltip() police.addTo(this.map) //添加 }else{ arr.map(item=>{ if (item.class === "policeA") { //删除 that.map.removeLayer(item); } }) } }else if(type=='grid'){ //此处是网格的区域添加 --》》mxj 20231214 var grid = L.polygon(newArr, { // color: "#FF642E", weight: 2, opacity: 1, fillColor: "#FF642E", fillOpacity: 0.5,lineStyle:'dashed', color: "#FF5663", weight: 2, opacity: 1, fillColor: "#FF5663", fillOpacity: 0.5,lineStyle:'dashed', }) grid.class='gridA' //isShowGrid判断是添加还是隐藏 --》》mxj 20231214 if(this.isShowGrid){ grid.bindTooltip(business[i].gridName,{ permanent:true, direction:'top' }).openTooltip() grid.addTo(this.map) //添加 }else{ arr.map(item=>{ if (item.class === "gridA") { //删除 that.map.removeLayer(item); } }) } } } } } }, clickGrid(data){ this.$emit('clickGrid',data) }, //热力图 initHotMap(){ var that = this //热力图添加之前先把之前的热力图层去掉,以防止多次重复添加 let all = this.map._layers let arr = Object.values(all) arr.map(item=>{ if (item.class === "heatA") { that.map.removeLayer(item); } }) let heatDataList = [ // { lat: 39.6408, lng: 116.7728, count: 1 }, // { lat: 39.75, lng: 116.55, count: 1 }, // { lat: 39.55, lng: 116.55, count: 100 }, // { lat: 39.65, lng: 116.45, count: 1 }, // { lat: 39.45, lng: 116.35, count: 1 }, // { lat: 39.35, lng: 116.25, count: 1 }, // { lat: 39.25, lng: 116.15, count: 1 } ] // 构造热力图数据 this.houtData.forEach((v) => { // 纬度、经度、阈值 var aa = v.coor let group = [aa[0], aa[1], v.count] heatDataList.push(group) }) // 生成热力图图层,并添加到地图中 let heat = L.heatLayer(heatDataList, { radius: 12, minOpacity: 0.2, gradient: { // 自定义渐变颜色,区间为 0~1 之间(也可以不指定颜色,使用默认颜色) '0.25': 'rgba(0, 0, 255, 1)', '0.55': 'rgba(0, 255, 0, 1)', '0.85': 'rgba(255, 255, 0, 1)', '1': 'rgba(255, 0, 0, 1)' } }); heat.class='heatA' heat.addTo(this.map) }, }, //调用方法 mounted() { var that = this that.$nextTick(() => { that.initBdMap(); }) } } </script> <style lang="scss"> .tabClickA { position: absolute; top: 20px; right: 20px; display: flex; z-index: 1000; cursor: pointer; .tabList { width: 93px; height: 38px; background: #53c9fc; color: #ffffff; font-size: 14px; text-align: center; line-height: 38px; margin-left: 10px; } } .divOutMap { width: 290px; height: 185px; background: url("http://218.56.180.213:8035/shopping/static/file/pic/202307/picrXBtW1uh1689581712300.png"); margin-top: -50px; margin-left: -145px; .topDiv { display: flex; padding: 25px 10px 0px 20px; justify-content: space-between; .closeDiv { margin-left: 10px; font-size: 14px; color: #53c9fc; text-decoration: underline; } opLeft { font-size: 16px; color: rgba(235, 251, 255, 0.8); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .topRight { font-size: 14px; color: #53c9fc; text-decoration: underline; width: 56px; } } .shopBoxMap { padding: 0px 10px 0px 20px; .shopOne { background: rgba(58, 129, 200, 0.26); border-radius: 5px; height: 40px; margin-top: 15px; box-shadow: 0px 0px 15px rgba(50, 121, 198, 1) inset; line-height: 40px; color: #ffffff; font-size: 14px; padding: 0px 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } } .mapShowImgA { width: 250px; height: 106px; margin-top: 10px; margin-left: 25px; } } </style>
二、点的添加展示,区域的绘制,回显,编辑,删除功能
在public页面引入如下代码:
<!-- 局域网 --> <link rel="stylesheet" href="leaflet.css"/> <script type="text/javascript" src="leaflet.js"></script> <script type="text/javascript" src="leaflet-hash.js"></script> <script type="text/javascript" src="MovingMarker.js"></script> <!-- 这是绘制区域 --> <script type="text/javascript" src="Leaflet.draw.js"></script> <link rel="stylesheet" href="leaflet.draw.css"/> <script src="leaflet.pin.js"></script> <!-- 天地图 --> <script type="text/javascript" src="https://api.tianditu.gov.cn/api?v=4.0&tk=d98028206b9637c8e3e21a7041c01b7a"></script>
组件代码:
<!-- * @Author: menxiaojin * @Date: 2023-07-14 10:24:08 * @LastEditors: menxiaojin * @LastEditTime: 2023-08-24 13:36:24 --> <template> <div class="appInner"> <form-back></form-back> <base-cont height="100%" :isScrollbar="false"> <template #head> <hy-header :importe="false" :exporte="false" :add="false" :deleted="false">绘制地图</hy-header> </template> <template #cont> <div > <titleTwo title="基础信息"></titleTwo> <disPlay> <listOne paddingLeft="0px" name="商铺名称" :content="detailObj.name"></listOne> <listOne name="是否绘制" :content="detailObj.border==''?'无':'是'"></listOne> <listOne paddingRight="0px" name="中心点坐标" :content="centerPoint.toString()"></listOne> <div class="newDrawEwar"> <el-form > <el-form-item label="拾取中心点坐标" class="labelItem" style="z-index: 30 !important;margin-bottom: 0 !important;padding-top:10px;padding-left:10px"> <el-switch v-model="getCenPoint" active-text="开始" inactive-text="关闭"></el-switch> </el-form-item> </el-form> </div> </disPlay> </div> <div id="adjustMap" class="adjustStyle" ></div> </template> </base-cont> <increasePop :centerDialogVisible.sync="tipsAlert" title="绘制数据" :ruleForm="ruleFormH" @resertClick="resertDetailH" @sureClick="sureClickH" > <form-textarea :value.sync="ruleFormH.areaStr" label="边界数据" preFixIcon="" placeholder="请输入边界数据"></form-textarea> </increasePop> </div> </template> <script> import { businessEdit,businessDetail } from "@/api/shop/business"; import titleTwo from '@/components/shopNew/title.vue'; import listOne from '@/components/shopNew/list.vue'; import disPlay from '@/components/shopNew/disPlay.vue'; // import twoMap from "@/components/map/twoMap.vue"; //百度地图绘制 import twoMap from "@/components/map/twoMapNei.vue"; //天地图 import increasePop from '@/components/form/increasePop.vue'; export default { components: {titleTwo,listOne,disPlay,twoMap,increasePop}, name: "Drawarea", data() { return { detailId:'', detailObj:{}, map:null, centerPoint:[], getCenPoint:false, //是否拾取中心点坐标 //绘制完成的弹框 tipsAlert:false, ruleFormH:{ areaStr:'', }, //地图 nowArrBorder:[], newBorder:'', //新绘制的边界数据 } }, mounted() { this.initDetail() }, created(){ this.detailId = this.$route.query.id; }, methods: { resertDetailH(){ this.tipsAlert = false this.ruleFormH.areaStr = '' }, //获取详情 initDetail(){ let that=this; businessDetail({id:this.detailId}).then((res) => { if (res.code == 0) { this.detailObj = res.data if(res.data.border!=''&&res.data.border!=null){ var aa = res.data.border.split(';'),newArrBOrder = [] aa.forEach(item=>{ var singArr = [Number(item.split(',')[0]),Number(item.split(',')[1])] newArrBOrder.push(singArr) }) that.nowArrBorder = newArrBOrder var bb = res.data.border.split(';')[0].split(',') that.centerPoint = res.data.centerPoint.split(','); }else{ that.centerPoint = [118.7241,37.45292] } that.$nextTick(() => { that.initBdMap(); }) } else { that.$global.tipMsg("error", res.msg); } }); }, cenPoint(data){ this.centerPoint = data var that = this businessEdit({id:this.detailId,centerPoint:data.toString()}).then(res=>{ if(res.code==0){ // this.$router.go(-1) this.$global.tipMsg("success", '中心点设置成功'); }else{ this.$global.tipMsg("error", res.msg); } }).catch() }, //展示地图 loadJson () { var data = this.nowArrBorder,newData = [] data.forEach(item=>{ var aa = JSON.stringify(item) newData.push(JSON.parse(aa)) }) return { "type": "FeatureCollection", "features": [{ "type": "Feature", "properties": {}, "geometry": { "type": "Polygon", "coordinates": [ // [ // [118.69159877773762,37.481140660363366], // [118.69102386221124,37.47756100936721], // [118.70011471397221,37.47747509561818], // [118.7004021717354,37.48016701241549], // [118.69838996739306,37.48185656980892], // [118.69159877773762,37.481140660363366] // this.nowArrBorder // [118.69159877773762, 37.481140660363366], // [118.69102386221124, 37.47756100936721], // [118.70011471397221, 37.47747509561818], // [118.7004021717354, 37.48016701241549], // [118.69838996739306, 37.48185656980892], // [118.69159877773762, 37.481140660363366], newData // ] ] } }, ] } }, //添加点 addPoint(data){ var that = this var center = JSON.parse(data) // 经度,维度的排序 var LeafIcon = L.Icon.extend({ options: { iconSize: [29, 25], } }); let mapUrl = 'http://218.56.180.213:8035/shopping/static/file/pic/202307/piclCI6umdv1689299533795.png' var icon = new LeafIcon({iconUrl: mapUrl}); L.icon = function (options) { return new L.Icon(options); }; L.marker([center[1],center[0]],{icon: icon}).addTo(that.map); }, //初始化百度地图 initBdMap() { //声明地图 var that = this var cenPoint = [Number(this.centerPoint[0]),Number(this.centerPoint[1])] var map = L.map('adjustMap', { attributionControl:false, crs:L.CRS.EPSG4326, //要使用的坐标系 WGS84 是目前最流行的地理坐标系统 center:[cenPoint[1],cenPoint[0]], zoom: 15, }); // L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { // L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { L.tileLayer('这是url', { // L.tileLayer(imageURL, { minZoom:0, maxZoom:19, zoomOffset:0, tms:false }).addTo(map); this.map = map //添加绘制图层 var drawnItems = new L.FeatureGroup(); map.addLayer(drawnItems); //添加绘制控件 var drawControl = new L.Control.Draw({ draw:{ // //绘制线 polyline:false, //绘制多边形 polygon:true, //绘制矩形 rectangle:false, //绘制圆 circle:false, //绘制标注 marker:false, //绘制圆形标注 circlemarker:false }, edit:{ //绘制图层 featureGroup:drawnItems, //图形编辑控件 edit:true, //图形删除控件 remove:true, } }); //添加绘制控件 map.addControl(drawControl); //这里时将已绘制的区域进行回显展示 if(this.nowArrBorder.length!=0){ L.geoJson(this.loadJson(), { onEachFeature: function (feature, layer) { //设置颜色,目前没有到,暂时留存,不影响功能 if(feature.geometry.type == "LineString") { layer.setStyle({ color: 'purple', weight: 5 }); } drawnItems.addLayer(layer); } }); map.addGuideLayer(drawnItems); map.removeGuideLayer(drawnItems); } //对中心点进行回显 this.addPoint(JSON.stringify(this.centerPoint)) // //绘制事件 map.on(L.Draw.Event.CREATED, function(e){ //获取绘制图形类型 var type = e.layerType, //获取绘制图层 drawlayer = e.layer; if (type === 'marker') { //显示Popup drawlayer.bindPopup('A popup!'); } //显示图层 drawnItems.addLayer(drawlayer); //几何信息字符串 var latlngsStr = ""; //获取多边形几何信息 if (type == 'polygon') { if (drawlayer._latlngs[0].length > 0) { for (var latlngslength = 0; latlngslength < drawlayer._latlngs[0].length; latlngslength++) { //获取几何信息 latlngsStr += drawlayer._latlngs[0][latlngslength].lng + "," + drawlayer._latlngs[0][latlngslength].lat + ";" } var bb = [latlngsStr.slice(0,latlngsStr.length-1)]; that.newBorder = bb.toString(); that.ruleFormH.areaStr = bb.toString(); that.tipsAlert = true } } //显示信息 }); this.map.addLayer(drawnItems); // 删除事件 this.map.on(L.Draw.Event.DELETED, this.handleDelete) // 编辑事件 this.map.on(L.Draw.Event.EDITED, this.handleEdited) //监听鼠标点击事件,点击拾取坐标,设置中心店 function onMapClick(e) { // console.log(e) if(that.getCenPoint == true){ that.centerPoint = [e.latlng.lng,e.latlng.lat] //清空之前全部的标记点,然后重新添加 $(".leaflet-marker-pane").empty() //点击的时候顺便加点 that.addPoint(JSON.stringify(that.centerPoint)) //设置中心点接口 that.cenPoint(that.centerPoint) } }; map.on('click',onMapClick); }, //删除 handleDelete(e){ this.nowArrBorder = [] }, //编辑 handleEdited(e){ var that = this if(e.layers._layer!=undefined){ var obj = e.layers._layers,newArr = [],arrSub=[],strSub = '' for(var i in obj) { newArr = obj[i]._latlngs[0] } for(var i = 0;i<newArr.length;i++){ strSub+=newArr[i].lng+','+newArr[i].lat+';' //strSu是上传所需要的数据 } var bb = [strSub.slice(0,strSub.length-1)]; businessEdit({id:this.detailId,border:bb.toString()}).then(res=>{ if(res.code==0){ this.$global.tipMsg("success", '保存成功'); }else{ this.$global.tipMsg("error", res.msg); } }).catch() } }, //提交绘制 sureClickH(){ var that = this businessEdit({id:this.detailId,border:this.ruleFormH.areaStr}).then(res=>{ if(res.code==0){ this.tipsAlert = false }else{ this.$global.tipMsg("error", res.msg); } }).catch() }, }, }; </script> <style lang="scss"> .appInner { min-width: 1055px; height: 100%; position: relative; } .adjustStyle{ width: 100%; height: calc(100% - 125px); margin-top: 20px; } .backBtnDraw{ position: absolute; top:200px; right: 40px; } .showSearch{ background: rgba(23, 114, 153, 1); padding: 10px; display: flex; border-radius: 5px; } .newDrawEwar{ .el-form-item__label{ width:100%; text-align: left; color: rgba(225, 225, 225, 0.5); } .el-form-item__content{ // widows: 100%; background:rgba(75, 173, 248, 0.33); height: 32px; margin-top:35px; .el-radio{ margin-left: 10px; } .el-switch{ margin-left: 10px; margin-top: -10px; .el-switch__label{ color: rgba(255,255,255,0.5); } .is-active{ color: #47d0f1; } } } } </style>
三、热力图的关键代码
在index.html页面引入js
<!-- 热力图 --> <script type="text/javascript" src="HeatmapOverlay.js"></script>
热力图相关主要代码:
//热力图 initHotMap(){ var that = this //热力图添加之前先把之前的热力图层去掉,以防止多次重复添加 let all = this.map._layers let arr = Object.values(all) arr.map(item=>{ if (item.class === "heatA") { that.map.removeLayer(item); } }) let heatDataList = [ // { lat: 39.6408, lng: 116.7728, count: 1 }, // { lat: 39.75, lng: 116.55, count: 1 }, // { lat: 39.55, lng: 116.55, count: 100 }, // { lat: 39.65, lng: 116.45, count: 1 }, // { lat: 39.45, lng: 116.35, count: 1 }, // { lat: 39.35, lng: 116.25, count: 1 }, // { lat: 39.25, lng: 116.15, count: 1 } ] // 构造热力图数据 this.houtData.forEach((v) => { // 纬度、经度、阈值 var aa = v.coor let group = [aa[0], aa[1], v.count] heatDataList.push(group) }) // 生成热力图图层,并添加到地图中 let heat = L.heatLayer(heatDataList, { radius: 12, minOpacity: 0.2, gradient: { // 自定义渐变颜色,区间为 0~1 之间(也可以不指定颜色,使用默认颜色) '0.25': 'rgba(0, 0, 255, 1)', '0.55': 'rgba(0, 255, 0, 1)', '0.85': 'rgba(255, 255, 0, 1)', '1': 'rgba(255, 0, 0, 1)' } }); heat.class='heatA' heat.addTo(this.map) },
四、PGIS局域网地图的轨迹回放
主要代码:
<!--首页地图组件--> <template> <!-- 该页面的逻辑是一开始展示轨迹,点击轨迹按钮出现播放轨迹动效的相关操作,点击返回重新返回轨迹静态展示页面 --> <div class="data_map" style="height: 100%"> <div class="bg_heights" style="position: relative; height: 100%"> <div :id="mapId" style="width: 100%; height: 100%"></div> <div class="bofang" v-if="markerArr.length != 0"> <el-button type="primary" size="mine" @click="plackBack" v-if="condition" >轨迹</el-button > <el-button type="primary" size="mine" @click="continueMap" >返回</el-button > </div> </div> </div> </template> <style lang="scss"> .bofang { position: absolute; top: 20px; left: 30px; z-index: 1000; } </style> <style lang="scss"> .anchorBL { display: none; } body, html, #map { height: 100%; margin: auto; font-family: "微软雅黑"; } .divLabelMApText { width: 36px; height: 36px; text-align: center; line-height: 16px; font-size: 14px; color: #ffffff; } .divOutMapA { width: 320px; height: 185px; background: url("http://218.56.180.213:8035/shopping/static/file/pic/202307/picrXBtW1uh1689581712300.png") no-repeat; background-size: 100% 100%; margin-top: -50px; margin-left: -145px; } .pointClassNum { color: #ffffff; font-size: 14px; line-height: 12px; width: 12px; text-align: center; } .mapFlexDivGis { display: flex; .flexLeftImg { width: 80px; height: 90px; } .flexRight { flex: 1; padding-left: 10px; .flexRightListOne { width: 100%; line-height: 20px; color: #333333; font-size: 13px; padding: 3px 10px; } .flexRightListTwo { background: rgba(41, 147, 207, 0.4); line-height: 20px; color: #ffffff; font-size: 13px; padding: 5px 10px; margin-top: 15px; } } } </style> <script type="text/ecmascript-6"> export default { props:{ mapId:{ type:String, default:'mapId' }, zoom:{ type:Number, default:17 }, markerArr:{ type:Array, default:()=>[ // { // imgurl: "http://218.56.180.213:8137/policeNewFormalFile/subFace/snapFace/202211/20221128/snapFace1ec55445-4abf-4a8d-a59d-17ada05b02b3-0.png", // visitTime: "2022-11-28 17:03:21", // longitude: 118.712444, // uptownName: "中国广饶今田小商品批发市场西门", // latitude: 37.43991, // cameraName: "花苑路交叉口朝东500m人脸", // type:'start' // }, // { // imgurl: "http://218.56.180.213:8137/policeNewFormalFile/subFace/snapFace/202211/20221128/snapFace1ec55445-4abf-4a8d-a59d-17ada05b02b3-0.png", // visitTime: "2022-11-28 17:03:21", // longitude: 118.713192, // uptownName: "中国广饶今田小商品批发市场西门", // latitude: 37.441471, // cameraName: "花苑路交叉口朝东500m人脸", // type:'' // }, // { // imgurl: "http://218.56.180.213:8137/policeNewFormalFile/subFace/snapFace/202211/20221128/snapFace1ec55445-4abf-4a8d-a59d-17ada05b02b3-0.png", // visitTime: "2022-11-28 17:03:21", // longitude: 118.710435, // uptownName: "中国广饶今田小商品批发市场西门", // latitude: 37.441478, // cameraName: "花苑路交叉口朝东500m人脸", // type:'' // }, // { // imgurl: "http://218.56.180.213:8137/policeNewFormalFile/subFace/snapFace/202211/20221128/snapFace1ec55445-4abf-4a8d-a59d-17ada05b02b3-0.png", // visitTime: "2022-11-28 17:03:21", // longitude: 118.710929, // uptownName: "中国广饶今田小商品批发市场西门", // latitude: 37.439616, // cameraName: "花苑路交叉口朝东500m人脸", // type:'' // }, // { // imgurl: "http://218.56.180.213:8137/policeNewFormalFile/subFace/snapFace/202211/20221128/snapFace1ec55445-4abf-4a8d-a59d-17ada05b02b3-0.png", // visitTime: "2022-11-28 17:03:21", // longitude: 118.709608, // uptownName: "中国广饶今田小商品批发市场西门", // latitude:37.4404, // cameraName: "花苑路交叉口朝东500m人脸", // type:'end' // }, ] }, //经纬度 currentLat:{ type:Number, default:0 }, currentLon:{ type:Number, default:0 } }, data(){ return { mapLoading:false, bgHeight:'668px', map:'', getZoom:15, //地图当前的等级 peopleLocus:'', trackAni:null, iconPeople:require('../../assets/base/flow_people.png'), condition:true, suspedContinueShow:true, playGis:null, } }, //关键 created(){ let that=this; window.bigImg=that.bigImg; }, watch: { currentLat: { handler: function (val) { let that=this; if(that.currentLat!=''&&that.map==''){ that.initAMap(); } //设置地图中心点 that.map.setView([this.currentLon,this.currentLat], 15) }, // immediate: true }, markerArr: { handler: function(newObj, oldObj) { let that=this; that.$nextTick(() => { that.peopleMap() }) }, deep: true, // 深度监听 immediate: true // 会在监测开始时调用一次该处理函数 } }, methods:{ initAMap(){ //声明地图 var that = this var cenPoint = [this.currentLat,this.currentLon] var map = L.map(this.mapId, { attributionControl:false, crs:L.CRS.EPSG4326, //要使用的坐标系 WGS84 是目前最流行的地理坐标系统 center:[cenPoint[1],cenPoint[0]], zoom: 15 }); map.setView([cenPoint[1],cenPoint[0]], 15) //设置中心点以及zoom L.tileLayer('这是URL', { //内网瓦片地址 minZoom:0, maxZoom:19, zoomOffset:0, tms:false }).addTo(map); this.map = map }, //清楚轨迹划线 clearMap() { const that = this; // 保存Vue组件的上下文 if (that.map) { that.map.eachLayer(function (layer) { if (layer instanceof L.Marker || layer instanceof L.Polyline) { that.map.removeLayer(layer); } }); } }, peopleMap(id){ var that = this this.clearMap(); this.peopleLocus = this.map //图标大小 var LeafIcon = L.Icon.extend({ options: { iconSize: [36, 47], } }); var data_info = this.markerArr,content,newPoint,mapUrl,shopName,num; for(var i = 0;i<data_info.length;i++){ if(data_info[i].type=='start'){ mapUrl=require('../../assets/base/start.png'); } else if(data_info[i].type=='end'){ mapUrl=require('../../assets/base/end.png'); } else{ mapUrl=require('../../assets/base/ing.png'); } content = "<div class='mapFlexDivGis'>"+ "<img class='flexLeftImg' src='"+ that.$global.imgPross(data_info[i].photo) +"' width='100%'/>"+ "<div class='flexRight'>"+ "<p class='flexRightListOne'>时间:"+data_info[i].snapTime +"</p>"+ "<p class='flexRightListOne'>设备名称:"+data_info[i].deviceName+"</p>"+ "</div>"+ "</div>" var icon = new LeafIcon({iconUrl: mapUrl}); L.icon = function (options) { return new L.Icon(options); }; newPoint = [data_info[i].longitude, data_info[i].latitude] num = i+1 L.marker([newPoint[1],newPoint[0]],{icon: icon}).addTo(that.map) .bindPopup(content); //添加点以及点的点击事件 // 写在初始化地图的方法里,必须放在mounted钩子中 var customLabel = L.divIcon({ html: '<div class="my-label">'+num+'</div>', className: 'pointClassNum' }); // 添加自定义文本标注到地图上 var labelMarker = L.marker([newPoint[1],newPoint[0]], { icon: customLabel, zIndexOffset: 0 // 防止标签与图标相互遮挡 }).addTo(this.map); } //绘制线 var points = new Array(); for (var i = 0; i < data_info.length; i++) { var p0 = data_info[i].longitude; var p1 = data_info[i].latitude; var newPoint = [p0, p1] var thePoint1 = [newPoint[1],newPoint[0]] points.push(thePoint1); } var polyline = L.polyline(points, { color: 'RGBA(255, 0, 0, 0.7)',//线的颜色 weight: 3 //线的粗细 }).addTo(this.map); }, // 回放按钮 plackBack(){ let that=this; that.suspedContinueShow = true; that.backShow = true; let mapData=that.markerArr,newArr = []; var newArrTime = [] for(var i = 0;i<mapData.length;i++){ var newPoint = [mapData[i].longitude, mapData[i].latitude] let item = [newPoint[1],newPoint[0]] newArr.push(item) newArrTime.push(5000) } that.map.fitBounds(newArr); var LeafIcon = L.Icon.extend({ options: { iconSize: [31, 36], } }); var mapUrl = this.iconPeople var icon = new LeafIcon({iconUrl: mapUrl}); L.icon = function (options) { return new L.Icon(options); }; var marker1 = L.Marker.movingMarker(newArr, newArrTime,{icon: icon}).addTo(that.map); L.polyline(newArr,{color:'RGBA(255, 0, 0, 0.7)'}).addTo(that.map); marker1.once('click', function () { marker1.start(); marker1.closePopup(); marker1.unbindPopup(); marker1.on('click', function() { if (marker1.isRunning()) { marker1.pause(); } else { marker1.start(); } }); setTimeout(function() { marker1.bindPopup('<b>点我暂停!</b>').openPopup(); }, 1000); }); marker1.bindPopup('<b>点我播放 !</b>', {closeOnClick: true}); marker1.openPopup(); that.playGis = marker1 }, //返回 清空播放轨迹的图层 continueMap(){ this.suspedContinueShow = !this.suspedContinueShow this.map.removeLayer(this.playGis) }, }, //调用方法 mounted() { } } </script>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· AI与.NET技术实操系列(六):基于图像分类模型对图像进行分类