Bläddra i källkod

地图功能修改

SunZehao 6 månader sedan
förälder
incheckning
8cff6e680a

BIN
src/assets/mapdarw/images/spritesheet-2x.png


BIN
src/assets/mapdarw/images/spritesheet.png


+ 156 - 0
src/assets/mapdarw/images/spritesheet.svg

@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   viewBox="0 0 600 60"
+   height="60"
+   width="600"
+   id="svg4225"
+   version="1.1"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="spritesheet.svg"
+   inkscape:export-filename="/home/fpuga/development/upstream/icarto.Leaflet.draw/src/images/spritesheet-2x.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata4258">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs4256" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1056"
+     id="namedview4254"
+     showgrid="false"
+     inkscape:zoom="1.3101852"
+     inkscape:cx="237.56928"
+     inkscape:cy="7.2419621"
+     inkscape:window-x="1920"
+     inkscape:window-y="24"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="svg4225" />
+  <g
+     id="enabled"
+     style="fill:#464646;fill-opacity:1">
+    <g
+       id="polyline"
+       style="fill:#464646;fill-opacity:1">
+      <path
+         d="m 18,36 0,6 6,0 0,-6 -6,0 z m 4,4 -2,0 0,-2 2,0 0,2 z"
+         id="path4229"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+      <path
+         d="m 36,18 0,6 6,0 0,-6 -6,0 z m 4,4 -2,0 0,-2 2,0 0,2 z"
+         id="path4231"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+      <path
+         d="m 23.142,39.145 -2.285,-2.29 16,-15.998 2.285,2.285 z"
+         id="path4233"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+    </g>
+    <path
+       id="polygon"
+       d="M 100,24.565 97.904,39.395 83.07,42 76,28.773 86.463,18 Z"
+       inkscape:connector-curvature="0"
+       style="fill:#464646;fill-opacity:1" />
+    <path
+       id="rectangle"
+       d="m 140,20 20,0 0,20 -20,0 z"
+       inkscape:connector-curvature="0"
+       style="fill:#464646;fill-opacity:1" />
+    <path
+       id="circle"
+       d="m 221,30 c 0,6.078 -4.926,11 -11,11 -6.074,0 -11,-4.922 -11,-11 0,-6.074 4.926,-11 11,-11 6.074,0 11,4.926 11,11 z"
+       inkscape:connector-curvature="0"
+       style="fill:#464646;fill-opacity:1" />
+    <path
+       id="marker"
+       d="m 270,19 c -4.971,0 -9,4.029 -9,9 0,4.971 5.001,12 9,14 4.001,-2 9,-9.029 9,-14 0,-4.971 -4.029,-9 -9,-9 z m 0,12.5 c -2.484,0 -4.5,-2.014 -4.5,-4.5 0,-2.484 2.016,-4.5 4.5,-4.5 2.485,0 4.5,2.016 4.5,4.5 0,2.486 -2.015,4.5 -4.5,4.5 z"
+       inkscape:connector-curvature="0"
+       style="fill:#464646;fill-opacity:1" />
+    <g
+       id="edit"
+       style="fill:#464646;fill-opacity:1">
+      <path
+         d="m 337,30.156 0,0.407 0,5.604 c 0,1.658 -1.344,3 -3,3 l -10,0 c -1.655,0 -3,-1.342 -3,-3 l 0,-10 c 0,-1.657 1.345,-3 3,-3 l 6.345,0 3.19,-3.17 -9.535,0 c -3.313,0 -6,2.687 -6,6 l 0,10 c 0,3.313 2.687,6 6,6 l 10,0 c 3.314,0 6,-2.687 6,-6 l 0,-8.809 -3,2.968"
+         id="path4240"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+      <path
+         d="m 338.72,24.637 -8.892,8.892 -2.828,0 0,-2.829 8.89,-8.89 z"
+         id="path4242"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+      <path
+         d="m 338.697,17.826 4,0 0,4 -4,0 z"
+         transform="matrix(-0.70698336,-0.70723018,0.70723018,-0.70698336,567.55917,274.78273)"
+         id="path4244"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+    </g>
+    <g
+       id="remove"
+       style="fill:#464646;fill-opacity:1">
+      <path
+         d="m 381,42 18,0 0,-18 -18,0 0,18 z m 14,-16 2,0 0,14 -2,0 0,-14 z m -4,0 2,0 0,14 -2,0 0,-14 z m -4,0 2,0 0,14 -2,0 0,-14 z m -4,0 2,0 0,14 -2,0 0,-14 z"
+         id="path4247"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+      <path
+         d="m 395,20 0,-4 -10,0 0,4 -6,0 0,2 22,0 0,-2 -6,0 z m -2,0 -6,0 0,-2 6,0 0,2 z"
+         id="path4249"
+         inkscape:connector-curvature="0"
+         style="fill:#464646;fill-opacity:1" />
+    </g>
+  </g>
+  <g
+     id="disabled"
+     transform="translate(120,0)"
+     style="fill:#bbbbbb">
+    <use
+       xlink:href="#edit"
+       id="edit-disabled"
+       x="0"
+       y="0"
+       width="100%"
+       height="100%" />
+    <use
+       xlink:href="#remove"
+       id="remove-disabled"
+       x="0"
+       y="0"
+       width="100%"
+       height="100%" />
+  </g>
+  <path
+     style="fill:none;stroke:#464646;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+     id="circle-3"
+     d="m 581.65725,30 c 0,6.078 -4.926,11 -11,11 -6.074,0 -11,-4.922 -11,-11 0,-6.074 4.926,-11 11,-11 6.074,0 11,4.926 11,11 z"
+     inkscape:connector-curvature="0" />
+</svg>

+ 325 - 0
src/assets/mapdarw/leaflet.draw-src.css

@@ -0,0 +1,325 @@
+/* ================================================================== */
+/* Toolbars
+/* ================================================================== */
+
+.leaflet-draw-section {
+	position: relative;
+}
+
+.leaflet-draw-toolbar {
+	margin-top: 12px;
+}
+
+.leaflet-draw-toolbar-top {
+	margin-top: 0;
+}
+
+.leaflet-draw-toolbar-notop a:first-child {
+	border-top-right-radius: 0;
+}
+
+.leaflet-draw-toolbar-nobottom a:last-child {
+	border-bottom-right-radius: 0;
+}
+
+.leaflet-draw-toolbar a {
+	background-image: url('./images/spritesheet.png');
+	background-image: linear-gradient(transparent, transparent), url('./images/spritesheet.svg');
+	background-repeat: no-repeat;
+	background-size: 300px 30px;
+	background-clip: padding-box;
+}
+
+.leaflet-retina .leaflet-draw-toolbar a {
+	background-image: url('./images/spritesheet-2x.png');
+	background-image: linear-gradient(transparent, transparent), url('./images/spritesheet.svg');
+}
+
+.leaflet-draw a {
+	display: block;
+	text-align: center;
+	text-decoration: none;
+}
+
+.leaflet-draw a .sr-only {
+	position: absolute;
+	width: 1px;
+	height: 1px;
+	padding: 0;
+	margin: -1px;
+	overflow: hidden;
+	clip: rect(0, 0, 0, 0);
+	border: 0;
+}
+
+/* ================================================================== */
+/* Toolbar actions menu
+/* ================================================================== */
+
+.leaflet-draw-actions {
+	display: none;
+	list-style: none;
+	margin: 0;
+	padding: 0;
+	position: absolute;
+	left: 26px; /* leaflet-draw-toolbar.left + leaflet-draw-toolbar.width */
+	top: 0;
+	white-space: nowrap;
+}
+
+.leaflet-touch .leaflet-draw-actions {
+	left: 32px;
+}
+
+.leaflet-right .leaflet-draw-actions {
+	right: 26px;
+	left: auto;
+}
+
+.leaflet-touch .leaflet-right .leaflet-draw-actions {
+	right: 32px;
+	left: auto;
+}
+
+.leaflet-draw-actions li {
+	display: inline-block;
+}
+
+.leaflet-draw-actions li:first-child a {
+	border-left: none;
+}
+
+.leaflet-draw-actions li:last-child a {
+	-webkit-border-radius: 0 4px 4px 0;
+	border-radius: 0 4px 4px 0;
+}
+
+.leaflet-right .leaflet-draw-actions li:last-child a {
+	-webkit-border-radius: 0;
+	border-radius: 0;
+}
+
+.leaflet-right .leaflet-draw-actions li:first-child a {
+	-webkit-border-radius: 4px 0 0 4px;
+	border-radius: 4px 0 0 4px;
+}
+
+.leaflet-draw-actions a {
+	background-color: #919187;
+	border-left: 1px solid #AAA;
+	color: #FFF;
+	font: 11px/19px "Helvetica Neue", Arial, Helvetica, sans-serif;
+	line-height: 28px;
+	text-decoration: none;
+	padding-left: 10px;
+	padding-right: 10px;
+	height: 28px;
+}
+
+.leaflet-touch .leaflet-draw-actions a {
+	font-size: 12px;
+	line-height: 30px;
+	height: 30px;
+}
+
+.leaflet-draw-actions-bottom {
+	margin-top: 0;
+}
+
+.leaflet-draw-actions-top {
+	margin-top: 1px;
+}
+
+.leaflet-draw-actions-top a,
+.leaflet-draw-actions-bottom a {
+	height: 27px;
+	line-height: 27px;
+}
+
+.leaflet-draw-actions a:hover {
+	background-color: #A0A098;
+}
+
+.leaflet-draw-actions-top.leaflet-draw-actions-bottom a {
+	height: 26px;
+	line-height: 26px;
+}
+
+/* ================================================================== */
+/* Draw toolbar
+/* ================================================================== */
+
+.leaflet-draw-toolbar .leaflet-draw-draw-polyline {
+	background-position: -2px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polyline {
+	background-position: 0 -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-draw-polygon {
+	background-position: -31px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polygon {
+	background-position: -29px -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-draw-rectangle {
+	background-position: -62px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-rectangle {
+	background-position: -60px -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-draw-circle {
+	background-position: -92px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-circle {
+	background-position: -90px -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-draw-marker {
+	background-position: -122px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-marker {
+	background-position: -120px -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-draw-circlemarker {
+	background-position: -273px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-circlemarker {
+	background-position: -271px -1px;
+}
+
+/* ================================================================== */
+/* Edit toolbar
+/* ================================================================== */
+
+.leaflet-draw-toolbar .leaflet-draw-edit-edit {
+	background-position: -152px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit {
+	background-position: -150px -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-edit-remove {
+	background-position: -182px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove {
+	background-position: -180px -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
+	background-position: -212px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled {
+	background-position: -210px -1px;
+}
+
+.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
+	background-position: -242px -2px;
+}
+
+.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled {
+	background-position: -240px -2px;
+}
+
+/* ================================================================== */
+/* Drawing styles
+/* ================================================================== */
+
+.leaflet-mouse-marker {
+	background-color: #fff;
+	cursor: crosshair;
+}
+
+.leaflet-draw-tooltip {
+	background: rgb(54, 54, 54);
+	background: rgba(0, 0, 0, 0.5);
+	border: 1px solid transparent;
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	color: #fff;
+	font: 12px/18px "Helvetica Neue", Arial, Helvetica, sans-serif;
+	margin-left: 20px;
+	margin-top: -21px;
+	padding: 4px 8px;
+	position: absolute;
+	visibility: hidden;
+	white-space: nowrap;
+	z-index: 6;
+}
+
+.leaflet-draw-tooltip:before {
+	border-right: 6px solid black;
+	border-right-color: rgba(0, 0, 0, 0.5);
+	border-top: 6px solid transparent;
+	border-bottom: 6px solid transparent;
+	content: "";
+	position: absolute;
+	top: 7px;
+	left: -7px;
+}
+
+.leaflet-error-draw-tooltip {
+	background-color: #F2DEDE;
+	border: 1px solid #E6B6BD;
+	color: #B94A48;
+}
+
+.leaflet-error-draw-tooltip:before {
+	border-right-color: #E6B6BD;
+}
+
+.leaflet-draw-tooltip-single {
+	margin-top: -12px
+}
+
+.leaflet-draw-tooltip-subtext {
+	color: #f8d5e4;
+}
+
+.leaflet-draw-guide-dash {
+	font-size: 1%;
+	opacity: 0.6;
+	position: absolute;
+	width: 5px;
+	height: 5px;
+}
+
+/* ================================================================== */
+/* Edit styles
+/* ================================================================== */
+
+.leaflet-edit-marker-selected {
+	background-color: rgba(254, 87, 161, 0.1);
+	border: 4px dashed rgba(254, 87, 161, 0.6);
+	-webkit-border-radius: 4px;
+	border-radius: 4px;
+	box-sizing: content-box;
+}
+
+.leaflet-edit-move {
+	cursor: move;
+}
+
+.leaflet-edit-resize {
+	cursor: pointer;
+}
+
+/* ================================================================== */
+/* Old IE styles
+/* ================================================================== */
+
+.leaflet-oldie .leaflet-draw-toolbar {
+	border: 1px solid #999;
+}

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 4774 - 0
src/assets/mapdarw/leaflet.draw-src.js


+ 2 - 2
src/main.ts

@@ -42,8 +42,8 @@ import Logger from '@/utils/Logger'
 
 import L from "leaflet"
 import "leaflet/dist/leaflet.css"
-import "leaflet-draw";
-import "leaflet-draw/dist/leaflet.draw.css";
+// import "leaflet-draw";
+// import "leaflet-draw/dist/leaflet.draw.css";
 
 
 import VueDOMPurifyHTML from 'vue-dompurify-html' // 解决v-html 的安全隐患

+ 14 - 3
src/views/mapAnalysis/index.vue

@@ -33,7 +33,10 @@
             </div>
           </div>
           <!-- 多边形区域 -->
-          <div class="detailMsgBot" v-if="it.layerType === 'polygon'">
+          <div
+            class="detailMsgBot"
+            v-if="it.layerType === 'polygon' || it.layerType === 'rectangle'"
+          >
             <div v-for="(iv, idx) in it.layer._latlngs[0]" :key="idx" style="margin: 5px 0">
               <span style="margin-right: 10px">精度:{{ iv.lat }}</span>
               <span>纬度:{{ iv.lng }}</span>
@@ -54,6 +57,9 @@ import { CanvasLabel } from '@panzhiyue/leaflet-canvaslabel'
 import img from '@/assets/mapdarw/images/marker-icon.png'
 import nodata from '@/assets/mapdarw/images/noData.png'
 
+import '@/assets/mapdarw/leaflet.draw-src.js'
+import '@/assets/mapdarw/leaflet.draw-src.css'
+
 const map = ref(null)
 const drawLayerGroup = ref(null)
 const drawLayers = ref([])
@@ -104,7 +110,7 @@ const initMap = () => {
           color: '#bada55'
         }
       },
-      rectangle: false,
+      rectangle: {},
       marker: {
         icon: new MyCustomMarker()
       }
@@ -198,6 +204,8 @@ const layerTypeFn = (type) => {
     name = '多边形区域'
   } else if (type === 'circle') {
     name = '圆形区域'
+  } else if (type === 'rectangle') {
+    name = '矩形区域'
   }
   return name
 }
@@ -207,7 +215,10 @@ const getData = (map) => {
     [39.094994, 106.742496],
     [33.503718, 103.05109]
   ]
-  L.polyline(latlngs, { color: 'red' }).addTo(map)
+  // L.polyline(latlngs, { color: 'red' }).addTo(map)
+  drawLayerGroup.value.addLayer(L.polyline(latlngs, { color: 'red' }))
+  map.value.fitBounds(latlngs.getBounds())
+  // drawLayers.value.push(e)
 }
 
 onMounted(() => {

+ 188 - 0
src/views/mapAnalysis/mapjs2.vue

@@ -0,0 +1,188 @@
+<template>
+  <div>
+    <div id="map" class="map-main"></div>
+    <div class="btn-list">
+      <button @click="initDrawCtrl">初始化绘制控件</button><br />
+      <button @click="destoryDrawCtr">销毁绘制控件</button><br />
+      <button @click="startDraw(0)">点</button>
+      <button @click="startDraw(1)">圆</button>
+      <button @click="startDraw(2)">线</button>
+      <button @click="startDraw(3)">矩形</button>
+      <button @click="startDraw(4)">多边形</button>
+      <button @click="stopDraw">清除</button>
+    </div>
+  </div>
+</template>
+ 
+<script>
+import 'leaflet'
+import 'leaflet-draw'
+
+export default {
+  data() {
+    return {
+      // L.map 对象
+      map: null,
+      // L.Control.Draw 控件对象
+      drawControl: null,
+      // 绘制对象
+      drawObj: null,
+      // 图形图层组
+      drawLayerGrounp: null
+    }
+  },
+  methods: {
+    // 启动绘制
+    startDraw(idx) {
+      // 先取消
+      if (this.drawObj) {
+        this.drawObj.disable()
+      }
+      switch (idx) {
+        case 0: {
+          // 点
+          this.drawObj = new L.Draw.Marker(this.map, this.drawControl.options.draw.marker)
+          break
+        }
+        case 1: {
+          // 圆
+          this.drawObj = new L.Draw.Circle(this.map, this.drawControl.options.draw.circle)
+          break
+        }
+        case 2: {
+          // 线
+          this.drawObj = new L.Draw.Polyline(this.map, this.drawControl.options.draw.polyline)
+          break
+        }
+        case 3: {
+          // 矩形
+          this.drawObj = new L.Draw.Rectangle(this.map, this.drawControl.options.draw.rectangle)
+          break
+        }
+        case 4: {
+          // 多边形
+          this.drawObj = new L.Draw.Polygon(this.map, this.drawControl.options.draw.polygon)
+          break
+        }
+      }
+      // 启动
+      this.drawObj.enable()
+    },
+    //清除绘制
+    stopDraw() {
+      // 删除全部绘制的图层
+      if (this.drawLayerGrounp) {
+        this.drawLayerGrounp.clearLayers()
+      }
+      // 取消绘制操作
+      this.drawObj.disable()
+    },
+    // 初始化地图
+    ininMap() {
+      // 初始化地图容器并显天地图
+      this.map = L.map('map', {
+        //参考坐标系
+        crs: L.CRS.EPSG4326,
+        //不添加属性说明控件
+        attributionControl: false,
+        //限制显示地理范围
+        maxBounds: L.latLngBounds(L.latLng(-180, -180), L.latLng(180, 180))
+      })
+
+      // 设置范围(这里是武汉)
+      this.map.setView([30.59, 114.32], 10)
+      // 矢量图+注记
+      // let mapTypes = ['vec_c', 'cva_c'];
+      // 影像图+注记
+      let mapTypes = ['img_c', 'cia_c']
+      // 天地图 token
+      let tdtToken = 'xxxxxxxxxxxxxxxx'
+      let layers = []
+      for (let i = 0, len = mapTypes.length; i < len; i++) {
+        let tdtUrl = `http://t0.tianditu.gov.cn/DataServer?T=${mapTypes[i]}&x={x}&y={y}&l={z}&tk=${tdtToken}`
+        let layer = L.tileLayer(tdtUrl, {
+          zoomOffset: 1,
+          noWrap: true,
+          bounds: [
+            [-90, -180],
+            [90, 180]
+          ]
+        })
+        layers.push(layer)
+      }
+      L.layerGroup(layers).addTo(this.map)
+    },
+    // 交互绘制回调
+    drawCreatedBack(e) {
+      console.log('绘制完成', e)
+      // 绘制的图形图层对象
+      let drawLayer = e.layer
+      // 判断当前没有图层组,需先添加
+      if (!this.drawLayerGrounp) {
+        //图层组
+        this.drawLayerGrounp = new L.FeatureGroup()
+        // 添加
+        this.map.addLayer(this.drawLayerGrounp)
+      }
+      // 添加到图层组
+      this.drawLayerGrounp.addLayer(drawLayer)
+    },
+    // 初始化绘制控件
+    initDrawCtrl() {
+      //初始化绘制控件
+      this.drawControl = new L.Control.Draw({
+        position: 'topright', //控件位置 'topleft'(默认), 'topright', 'bottomleft' or 'bottomright'
+        draw: {
+          polyline: true,
+          polygon: true,
+          rectangle: true,
+          circle: true,
+          marker: true
+        }
+      }).addTo(this.map) // 要添加到 L.map 对象中
+      // 添加绘制完监听事件
+      this.map.on(L.Draw.Event.CREATED, this.drawCreatedBack)
+    },
+    // 销毁绘制控件
+    destoryDrawCtr() {
+      // L.Control.Draw 控件对象
+      this.drawControl = null
+      // 绘制对象
+      this.drawObj = null
+      // 删除全部绘制的图层
+      if (this.drawLayerGrounp) {
+        this.drawLayerGrounp.clearLayers()
+      }
+      // 取消绘制完监听事件,避免在真正开发中,其它地方也监听了 CREATED 事件
+      this.container.map.off(L.Draw.Event.CREATED, this.drawCreatedBack)
+    }
+  },
+  mounted() {
+    // 初始化地图
+    this.ininMap()
+    // 初始化绘制控件
+    this.initDrawCtrl()
+  }
+}
+</script>
+ 
+<style lang="stylus" scoped>
+@import '~leaflet/dist/leaflet.css';
+@import '~leaflet-draw/dist/leaflet.draw.css';
+
+.map-main {
+  position: absolute;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: #CCC;
+}
+
+.btn-list {
+  z-index: 2000;
+  position: absolute;
+  top: 2px;
+  left: 80px;
+}
+</style>

+ 98 - 36
src/views/mapAnalysis/mapts.vue

@@ -5,16 +5,46 @@
     </div>
     <div class="mapDetail">
       <span class="title">数据详情</span>
-      <div class="detailMsg" v-for="(it, index) in drawLayers" :key="index">
-        <div class="detailMsgTop">
-          <span style="margin-right: 10px">绘制图形:{{ it.name }}</span>
-          <span>绘制ID:{{ it.id }}</span>
-        </div>
-        <div class="detailMsgBot">
-          <span style="margin-right: 10px">精度:{{ it.lat }}</span>
-          <span>纬度:{{ it.lng }}</span>
+      <div v-if="drawLayers.length > 0">
+        <div class="detailMsg" v-for="(it, index) in drawLayers" :key="index">
+          <div class="detailMsgTop">
+            <span style="margin-right: 10px">绘制图形:{{ layerTypeFn(it.layerType) }}</span>
+            <span>绘制ID:{{ it.layer._leaflet_id }}</span>
+          </div>
+          <!-- 标记和圆形标记 -->
+          <div
+            class="detailMsgBot"
+            v-if="it.layerType === 'marker' || it.layerType === 'circlemarker'"
+          >
+            <span style="margin-right: 10px">精度:{{ it.layer._latlng.lat }}</span>
+            <span>纬度:{{ it.layer._latlng.lng }}</span>
+          </div>
+          <!-- 圆形区域 -->
+          <div class="detailMsgBot" v-if="it.layerType === 'circle'">
+            <span>半径:{{ it.layer._mRadius }}m</span>
+            <span style="margin-right: 10px">精度:{{ it.layer._latlng.lat }}</span>
+            <span>纬度:{{ it.layer._latlng.lng }}</span>
+          </div>
+          <!-- 线段 -->
+          <div class="detailMsgBot" v-if="it.layerType === 'polyline'">
+            <div v-for="(iv, idx) in it.layer._latlngs" :key="idx" style="margin: 5px 0">
+              <span style="margin-right: 10px">精度:{{ iv.lat }}</span>
+              <span>纬度:{{ iv.lng }}</span>
+            </div>
+          </div>
+          <!-- 多边形区域 -->
+          <div class="detailMsgBot" v-if="it.layerType === 'polygon'">
+            <div v-for="(iv, idx) in it.layer._latlngs[0]" :key="idx" style="margin: 5px 0">
+              <span style="margin-right: 10px">精度:{{ iv.lat }}</span>
+              <span>纬度:{{ iv.lng }}</span>
+            </div>
+          </div>
         </div>
       </div>
+      <div class="nodata" v-else>
+        <img :src="nodata" alt="" />
+        <p class="nodataText">暂无数据,敬请期待</p>
+      </div>
     </div>
   </div>
 </template>
@@ -22,8 +52,10 @@
 import { ref, nextTick, onMounted, reactive, watch } from 'vue'
 import { CanvasLabel } from '@panzhiyue/leaflet-canvaslabel'
 import img from '@/assets/mapdarw/images/marker-icon.png'
-// import L from 'leaflet'
-// import 'leaflet/dist/leaflet.css'
+import nodata from '@/assets/mapdarw/images/noData.png'
+
+import '@/assets/mapdarw/leaflet.draw-src.js'
+import '@/assets/mapdarw/leaflet.draw-src.css'
 
 const map = ref(null)
 const drawLayerGroup = ref(null)
@@ -31,7 +63,7 @@ const drawLayers = ref([])
 const tilsUrl = ref('./static/kMapTiles/{z}/{x}/{y}.jpg')
 
 const initMap = () => {
-  map.value = L.map('map', {
+  var map = L.map('map', {
     center: [39.918758195008294, 116.3972282409668], // 地图中心--北京
     zoom: 16, //缩放比列
     // drawControl: true
@@ -42,10 +74,10 @@ const initMap = () => {
   })
   let name = L.tileLayer(
     'http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}'
-  ).addTo(map.value)
+  ).addTo(map)
 
   drawLayerGroup.value = new L.FeatureGroup()
-  map.value.addLayer(drawLayerGroup.value)
+  map.addLayer(drawLayerGroup.value)
 
   var MyCustomMarker = L.Icon.extend({
     options: {
@@ -75,13 +107,7 @@ const initMap = () => {
           color: '#bada55'
         }
       },
-      // circle: false, // Turns off this drawing tool
       rectangle: false,
-      // rectangle: {
-      //   shapeOptions: {
-      //     clickable: false
-      //   }
-      // },
       marker: {
         icon: new MyCustomMarker()
       }
@@ -94,9 +120,9 @@ const initMap = () => {
 
   initDrawTooltip()
   var drawControl = new L.Control.Draw(options)
-  map.value.addControl(drawControl)
+  map.addControl(drawControl)
 
-  map.value.on(L.Draw.Event.CREATED, function (e) {
+  map.on(L.Draw.Event.CREATED, function (e) {
     let type = e.layerType,
       layer = e.layer
 
@@ -107,26 +133,28 @@ const initMap = () => {
     }
 
     drawLayerGroup.value.addLayer(layer)
-    // getDrawArr(e)
+    drawLayers.value.push(e)
   })
 
-  map.value.on(L.Draw.Event.EDITED, function (e) {
+  map.on(L.Draw.Event.EDITED, function (e) {
     let type = e.layerType,
       layer = e.layer
 
     console.log('editmove====>>>', e)
   })
-}
-const getDrawArr = (value) => {
-  if (value) {
-    let obj = {
-      id: value._leaflet_id,
-      name: value.layerType,
-      lat: value.layer._latlng.lat,
-      lng: value.layer._latlng.lng
+
+  map.on(L.Draw.Event.DELETED, function (e) {
+    console.log('deleted====>>>', e)
+    for (let i in e.layers._layers) {
+      drawLayers.value.forEach((it, index) => {
+        if (it.layer._leaflet_id.toString() === i) {
+          drawLayers.value.splice(index, 1)
+        }
+      })
     }
-    drawLayers.value.push(obj)
-  }
+  })
+
+  getData()
 }
 const initDrawTooltip = () => {
   L.drawLocal.draw.handlers.polygon = {
@@ -163,13 +191,31 @@ const initDrawTooltip = () => {
   L.drawLocal.edit.handlers.edit.tooltip.subtext = '点击取消以撤消更改'
   L.drawLocal.edit.handlers.edit.tooltip.text = '拖动标记以编辑图形'
 }
+const layerTypeFn = (type) => {
+  let name = ''
+  if (type === 'marker') {
+    name = '标记'
+  } else if (type === 'circlemarker') {
+    name = '圆形标记'
+  } else if (type === 'polyline') {
+    name = '线段'
+  } else if (type === 'polygon') {
+    name = '多边形区域'
+  } else if (type === 'circle') {
+    name = '圆形区域'
+  }
+  return name
+}
 const getData = (map) => {
   var latlngs = [
     [40.912569, 111.840153],
     [39.094994, 106.742496],
     [33.503718, 103.05109]
   ]
-  L.polyline(latlngs, { color: 'red' }).addTo(map)
+  // L.polyline(latlngs, { color: 'red' }).addTo(map)
+  drawLayerGroup.value.addLayer(L.polyline(latlngs, { color: 'red' }))
+  map.value.fitBounds(latlngs.getBounds())
+  // drawLayers.value.push(e)
 }
 
 onMounted(() => {
@@ -199,21 +245,37 @@ onMounted(() => {
   width: calc(20vw - 20px)
   height: calc(100% - 10px)
   background: #fff
+  overflow-y: auto
   .title
-    font-size: 16px
+    font-size: 15px
     font-weight: bold
   .detailMsg
     margin: 10px 0
+    border-bottom: 1px solid #000
     .detailMsgTop
       span
         font-size: 14px
         font-weight: bold
+        opacity: 0.7
     .detailMsgBot
+      margin-bottom: 10px
       span
         display: inline-block
         font-size: 14px
         font-weight: bold
-
+        opacity: 0.7
+  .nodata
+    width: 70%
+    position: relative
+    left: 30%
+    top: 30%
+    img
+      margin-left: 20px
+    .nodataText
+      line-height: 30px
+      position: relative
+      top: -10px
+      font-size: 14px
 #map
   width: 100%
   height: 100%

+ 375 - 0
src/views/mapAnalysis/testMap.vue

@@ -0,0 +1,375 @@
+<template>
+  <!-- leaflet 地图组件,内嵌于页面中
+      功能: 支持手动绘制区域、编辑区域、删除区域,以及渲染 geoJson 面图
+   -->
+  <div class="map-box">
+    <div :id="id" :style="{ width, height }" />
+    <div v-show="isShowClearBtn" @click="clearAreaLayer()" class="button" title="删除已保存的区域">
+      <a-icon type="delete" />
+    </div>
+  </div>
+</template>
+<script>
+import * as L from 'leaflet'
+import 'leaflet/dist/leaflet.css'
+import 'proj4leaflet'
+import 'leaflet.chinatmsproviders'
+import '@/assets/map/leaflet.ChineseTmsProviders'
+import 'leaflet-draw'
+export default {
+  name: 'TxMap',
+  props: {
+    id: {
+      type: String,
+      default: () => ''
+    },
+    width: {
+      type: String,
+      default: () => '100%'
+    },
+    height: {
+      type: String,
+      default: () => '280px'
+    },
+    center: {
+      type: Object,
+      default: () => {
+        return {
+          latitude: '36.70261',
+          longitude: '119.16160'
+        }
+      }
+    },
+    geoJson: {
+      type: String,
+      default: () => ''
+    },
+    // 操作类型: add-新增  edit-编辑
+    operateType: {
+      type: String,
+      default: () => ''
+    },
+    visible: {
+      type: Boolean,
+      default: () => false
+    }
+  },
+  data() {
+    return {
+      isShowClearBtn: false,
+      // L.map 对象
+      map: null,
+      // L.Control.Draw 控件对象
+      drawControl: null,
+      // 图形图层组
+      drawLayerGroup: null
+    }
+  },
+  watch: {
+    visible(newVal) {
+      if (newVal) {
+        if (this.isAdd()) {
+          // 新增
+          this.init()
+          this.clearAreaLayer()
+        } else if (this.isEdit()) {
+          // 编辑
+          this.init()
+          this.addLayers(this.geoJson)
+        } else {
+          // 查看详情,没有绘图控件
+          this.init('noControl')
+          this.addLayers(this.geoJson)
+        }
+        this.handleClearBtn()
+      }
+    }
+  },
+  mounted() {
+    if (this.isDetail()) {
+      this.init('noControl')
+    } else {
+      this.init()
+    }
+
+    this.handleClearBtn()
+
+    this.addLayers(this.geoJson)
+  },
+  methods: {
+    init(data) {
+      // 初始化地图
+      this.initMap()
+      if (data !== 'noControl') {
+        // 初始化绘制控件
+        this.initDrawCtrl()
+      }
+    },
+
+    initMap() {
+      const { latitude, longitude } = this.center
+      if (!this.map) {
+        this.map = L.map(document.getElementById(this.id), {
+          center: [latitude || '36.70261', longitude || '119.16160'],
+          zoom: 9,
+          //不添加属性说明控件
+          attributionControl: false
+        })
+      }
+
+      this.tileLayer = [
+        L.tileLayer.chinaProvider('GaoDe.Normal.Map', {
+          maxZoom: 16,
+          minZoom: 4
+        })
+      ]
+
+      this.tileLayer.map((layer) => {
+        this.map.addLayer(layer)
+      })
+    },
+
+    handleClearBtn() {
+      if (this.isAdd() || this.isDetail()) {
+        this.isShowClearBtn = false
+      } else {
+        if (this.hasGeoJson()) {
+          this.isShowClearBtn = true
+        } else {
+          this.isShowClearBtn = false
+        }
+      }
+    },
+
+    // 初始化绘制控件
+    initDrawCtrl() {
+      // 判断当前没有图层组,需先添加
+      if (!this.drawLayerGroup) {
+        //图层组
+        this.drawLayerGroup = new L.FeatureGroup()
+      }
+
+      if (!this.map.hasLayer(this.drawLayerGroup)) {
+        // 添加
+        this.map.addLayer(this.drawLayerGroup)
+      }
+
+      // 初始化绘制控件
+      if (!this.drawControl) {
+        this.initDrawTooltip()
+        this.drawControl = new L.Control.Draw({
+          position: 'topleft', // 控件位置 'topleft'(默认), 'topright', 'bottomleft' or 'bottomright'
+          draw: {
+            polygon: true,
+            polyline: false,
+            rectangle: false,
+            circle: false,
+            marker: false,
+            circlemarker: false
+          },
+          edit: {
+            // 绘制图层
+            featureGroup: this.drawLayerGroup,
+            // 图形编辑控件
+            edit: true,
+            // 图形删除控件
+            remove: true
+          }
+        }).addTo(this.map) // 要添加到 L.map 对象中
+
+        this.Edit = new L.EditToolbar.Edit(this.map, { featureGroup: this.drawLayerGroup })
+
+        this.Delete = new L.EditToolbar.Delete(this.map, { featureGroup: this.drawLayerGroup })
+      }
+
+      // 添加绘制完监听事件
+      this.map.on(L.Draw.Event.CREATED, this.drawCreatedBack)
+      // 删除事件
+      this.map.on(L.Draw.Event.DELETED, this.handleDelete)
+      // 编辑事件
+      this.map.on(L.Draw.Event.EDITED, this.handleEdited)
+    },
+
+    // 交互绘制回调
+    drawCreatedBack(e) {
+      // 绘制的图形图层对象
+      let drawLayer = e.layer
+
+      // 添加到图层组
+      this.drawLayerGroup.addLayer(drawLayer)
+
+      let { lat, lng } = drawLayer.getCenter()
+      lat = parseFloat(lat).toFixed(5)
+      lng = parseFloat(lng).toFixed(5)
+      // 更新中心点坐标
+      this.$emit('submitCenterMarker', lat, lng)
+
+      this.$emit('submitLatlngs', this.drawLayerGroup._layers, this.isHasAreaLayer())
+    },
+
+    handleDelete() {
+      this.$emit('submitLatlngs', this.drawLayerGroup._layers, this.isHasAreaLayer())
+    },
+
+    handleEdited() {
+      this.$emit('submitLatlngs', this.drawLayerGroup._layers, this.isHasAreaLayer())
+    },
+
+    isHasAreaLayer() {
+      let flag
+      if (this.areaLayer) {
+        flag = this.map.hasLayer(this.areaLayer)
+      } else {
+        flag = false
+      }
+      return flag
+    },
+
+    // 改变绘制控件的按钮文本及提示语
+    initDrawTooltip() {
+      L.drawLocal.draw.handlers.polygon = {
+        tooltip: {
+          start: '点击地图开始绘制多边形',
+          cont: '继续选择',
+          end: '点击第一个顶点完成绘制'
+        }
+      }
+      L.drawLocal.draw.toolbar.buttons.polygon = '绘制'
+      L.drawLocal.edit.toolbar.actions.save.text = '保存'
+      L.drawLocal.edit.toolbar.actions.save.title = '保存'
+      L.drawLocal.edit.toolbar.actions.cancel.text = '取消'
+      L.drawLocal.edit.toolbar.actions.cancel.title = '取消'
+      L.drawLocal.edit.toolbar.actions.clearAll.text = '清除全部'
+      L.drawLocal.edit.toolbar.actions.clearAll.title = '清除全部'
+      L.drawLocal.edit.toolbar.buttons.editDisabled = '暂无区域可编辑'
+      L.drawLocal.edit.toolbar.buttons.removeDisabled = '暂无区域可删除'
+      L.drawLocal.edit.handlers.remove.tooltip.text = '选中一个区域去清除'
+      L.drawLocal.edit.toolbar.buttons.edit = '编辑'
+      L.drawLocal.edit.toolbar.buttons.remove = '删除'
+      L.drawLocal.edit.toolbar.buttons.cancel = '取消'
+      L.drawLocal.edit.toolbar.buttons.save = '保存'
+      L.drawLocal.draw.toolbar.actions.text = '取消'
+      L.drawLocal.draw.toolbar.actions.title = '取消绘制'
+      L.drawLocal.draw.toolbar.finish.text = '完成'
+      L.drawLocal.draw.toolbar.finish.title = '完成绘制'
+      L.drawLocal.draw.toolbar.undo.text = '撤销'
+      L.drawLocal.draw.toolbar.undo.title = '撤销'
+      L.drawLocal.edit.handlers.edit.tooltip.subtext = '点击取消以撤消更改'
+      L.drawLocal.edit.handlers.edit.tooltip.text = '拖动标记以编辑图形'
+    },
+
+    // 销毁地图以及绘制控件
+    destroyDrawCtrl() {
+      // 移除地图上的控制组件
+      if (this.drawControl) {
+        this.map.removeControl(this.drawControl)
+      }
+      // L.Control.Draw 控件对象
+      this.drawControl = null
+      // 删除全部绘制的图层
+      if (this.drawLayerGroup) {
+        this.drawLayerGroup.clearLayers()
+      }
+      // 移除已保存的区域
+      if (this.map.hasLayer(this.areaLayer)) {
+        this.map.removeLayer(this.areaLayer)
+      }
+
+      // 取消监听事件,避免其它地方也监听了 CREATED 事件
+      this.map.off(L.Draw.Event.CREATED, this.drawCreatedBack)
+      this.map.off(L.Draw.Event.DELETED, this.handleDelete)
+      this.map.off(L.Draw.Event.EDITED, this.handleEdited)
+      // 销毁该地图
+      this.map.remove()
+      this.map = null
+    },
+
+    addLayers(geoJson) {
+      if (this.hasGeoJson()) {
+        this.areaLayer = L.geoJSON(JSON.parse(geoJson), {
+          style: (feature) => {
+            return {
+              fillOpacity: 0.3,
+              weight: 2,
+              fillColor: '#40a9ff'
+            }
+          }
+        })
+
+        if (!this.map.hasLayer(this.areaLayer)) {
+          this.map.addLayer(this.areaLayer)
+        }
+
+        this.map.fitBounds(this.areaLayer.getBounds())
+
+        // this.Delete.options.featureGroup._layers = this.areaLayer._layers
+        // this.Edit.options.featureGroup._layers = this.areaLayer._layers
+        // this.map.removeControl(this.drawControl)
+        // L.Control.Draw 控件对象
+        // this.drawControl = null
+        // this.initDrawCtrl()
+      }
+    },
+
+    hasGeoJson() {
+      return (
+        this.geoJson &&
+        this.geoJson.length > 0 &&
+        JSON.parse(this.geoJson).features &&
+        JSON.parse(this.geoJson).features.length > 0
+      )
+    },
+
+    // 删除已保存的区域
+    clearAreaLayer() {
+      if (this.map.hasLayer(this.areaLayer)) [this.map.removeLayer(this.areaLayer)]
+      this.isShowClearBtn = false
+      this.$emit('submitLatlngs', [], false)
+    },
+
+    isAdd() {
+      return this.operateType === 'add'
+    },
+
+    isEdit() {
+      return this.operateType === 'edit'
+    },
+
+    isDetail() {
+      return this.operateType === 'detail'
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+@import '~leaflet-draw/dist/leaflet.draw.css';
+  .map-box {
+    width: auto;
+    height: auto;
+    position: relative;
+  }
+  .button {
+    position: absolute;
+    top: 203px;
+    left: 10px;
+    z-index: 1001;
+    width: 34px;
+    padding: 0;
+    height: 30px;
+    background: #ffffff;
+    line-height: 30px;
+    text-align: center;
+    border: 1px solid #a79f9f;
+    border-radius: 3px;
+    cursor: pointer;
+    &:hover {
+      background: #efefef;
+    }
+  }
+  ::v-deep .ant-btn:hover,
+  ::v-deep .ant-btn:focus {
+    color: rgba(0, 0, 0, 0.65);
+    ">#fff;
+  }
+</style>