案例 综合案例_绘制图层
先说报错:
当前 leaflet 1.9.4 版本使用 npm 下载 leaflet-draw 会出现部分 bug,下面视频中会展示出来
解决办法:
使用 cdn 引入可以正常使用,Vite+Vue 中同理,在 index.html 中引入 cdn 资源
bash
# 引入Leaflet CSS
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
# 引入Leaflet Draw CSS
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
# 引入Leaflet JS
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
# 引入Leaflet Draw JS
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
Vue 下载依赖
该案例存在问题,矩形绘制无效,详见视频
bash
npm install leaflet-draw
展开代码
vue
<template>
<div class="map-wrapper">
<div class="control-panel">
<div class="info-display">
<p>
最近绘制的图形类型: <strong>{{ lastDrawnType || "无" }}</strong>
</p>
<p>
绘制的图形数量: <strong>{{ drawnItemsCount }}</strong>
</p>
</div>
<button @click="clearAllDrawings" class="action-button clear-button">
清除所有绘制
</button>
<button @click="resetMapView" class="reset-button">重置地图视图</button>
</div>
<div id="map-drawing" class="map-container"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import "leaflet/dist/leaflet.css";
import "leaflet-draw/dist/leaflet.draw.css"; // Leaflet.draw 插件的CSS
import L from "leaflet";
import "leaflet-draw"; // 引入 Leaflet.draw 插件JS
let map = null;
let drawnItems = null; // 用于存储绘制的图层
let drawControl = null; // 绘制工具控制器
const lastDrawnType = ref("");
const drawnItemsCount = ref(0);
const initialView = [39.909186, 116.397479];
const initialZoom = 12;
onMounted(() => {
map = L.map("map-drawing").setView(initialView, initialZoom);
L.tileLayer(
"https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
{
maxZoom: 18,
minZoom: 3,
attribution: '© <a href="https://www.amap.com/">高德地图</a>',
}
).addTo(map);
// 初始化绘制图层组,用于存储用户绘制的图形
drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// 初始化绘制工具控制器
drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems, // 指定可编辑的图层组
remove: true, // 允许删除
},
draw: {
polyline: {
shapeOptions: {
color: "#f357a1",
weight: 10,
},
},
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: "#e1e100", // Color the shape will turn when intersects
message: "<strong>Oh snap!<strong> you can't draw that!", // Message that will show when intersect
},
shapeOptions: {
color: "#bada55",
},
},
circle: {
shapeOptions: {
weight: 5,
color: "#000",
},
},
rectangle: {
shapeOptions: {
clickable: false,
},
},
marker: true,
},
});
map.addControl(drawControl);
// 监听绘制完成事件
map.on(L.Draw.Event.CREATED, (e) => {
const type = e.layerType;
const layer = e.layer;
// 将绘制的图层添加到 drawnItems 图层组
drawnItems.addLayer(layer);
lastDrawnType.value = type;
drawnItemsCount.value = drawnItems.getLayers().length;
// 打印绘制的GeoJSON数据
console.log(`绘制了 ${type} 类型图形:`, layer.toGeoJSON());
});
// 监听删除事件
map.on(L.Draw.Event.DELETED, (e) => {
drawnItemsCount.value = drawnItems.getLayers().length;
console.log("图形被删除:", e.layers);
});
});
onUnmounted(() => {
if (map) {
map.off(L.Draw.Event.CREATED);
map.off(L.Draw.Event.DELETED);
map.removeControl(drawControl); // 移除绘制控制器
map.remove();
map = null;
drawnItems = null;
drawControl = null;
}
});
const clearAllDrawings = () => {
if (drawnItems) {
drawnItems.clearLayers(); // 清除所有绘制的图层
lastDrawnType.value = "";
drawnItemsCount.value = 0;
console.log("所有绘制已清除。");
}
};
const resetMapView = () => {
if (map) {
map.setView(initialView, initialZoom);
}
};
</script>
<style scoped>
.map-wrapper {
display: flex;
flex-direction: column;
height: 100vh;
width: 100vw;
font-family: sans-serif;
box-sizing: border-box;
}
@media (min-width: 768px) {
.map-wrapper {
flex-direction: row;
}
}
.control-panel {
flex-shrink: 0;
width: 100%;
background-color: #f8f8f8;
border-right: 1px solid #eee;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 15px;
}
@media (min-width: 768px) {
.control-panel {
width: 280px;
height: 100%;
}
}
.info-display {
background-color: #e9ecef;
padding: 15px;
border-radius: 8px;
border: 1px solid #dee2e6;
color: #495057;
}
.info-display p {
margin: 5px 0;
font-size: 0.95em;
}
.info-display strong {
color: #007bff;
}
.map-container {
flex-grow: 1;
height: 100%;
min-height: 300px;
background-color: #e0e0e0;
}
.action-button {
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
transition: background-color 0.3s ease;
}
.clear-button {
background-color: #dc3545;
color: white;
}
.clear-button:hover {
background-color: #c82333;
}
.reset-button {
background-color: #007bff;
color: white;
margin-top: auto; /* 将按钮推到底部 */
}
.reset-button:hover {
background-color: #0056b3;
}
.reset-button:active {
background-color: #004085;
}
</style>
Vue 使用 CDN 正常
html 展开代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue</title>
<!-- 引入Leaflet CSS -->
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
/>
<!-- 引入Leaflet Draw CSS -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"
/>
<!-- 引入Leaflet JS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<!-- 引入Leaflet Draw JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
vue 展开代码
vue
<template>
<div class="map-wrapper">
<div class="control-panel">
<div class="info-display">
<p>
最近绘制的图形类型: <strong>{{ lastDrawnType || "无" }}</strong>
</p>
<p>
绘制的图形数量: <strong>{{ drawnItemsCount }}</strong>
</p>
</div>
<button @click="clearAllDrawings" class="action-button clear-button">
清除所有绘制
</button>
<button @click="resetMapView" class="reset-button">重置地图视图</button>
</div>
<div id="map-drawing" class="map-container"></div>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
// import "leaflet/dist/leaflet.css";
// import "leaflet-draw/dist/leaflet.draw.css"; // Leaflet.draw 插件的CSS
// import L from "leaflet";
// import "leaflet-draw"; // 引入 Leaflet.draw 插件JS
let map = null;
let drawnItems = null; // 用于存储绘制的图层
let drawControl = null; // 绘制工具控制器
const lastDrawnType = ref("");
const drawnItemsCount = ref(0);
const initialView = [39.909186, 116.397479];
const initialZoom = 12;
onMounted(() => {
map = L.map("map-drawing").setView(initialView, initialZoom);
L.tileLayer(
"https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
{
maxZoom: 18,
minZoom: 3,
attribution: '© <a href="https://www.amap.com/">高德地图</a>',
}
).addTo(map);
// 初始化绘制图层组,用于存储用户绘制的图形
drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// 初始化绘制工具控制器
drawControl = new L.Control.Draw({
edit: {
featureGroup: drawnItems, // 指定可编辑的图层组
remove: true, // 允许删除
},
draw: {
polyline: {
shapeOptions: {
color: "#f357a1",
weight: 10,
},
},
polygon: {
allowIntersection: false, // Restricts shapes to simple polygons
drawError: {
color: "#e1e100", // Color the shape will turn when intersects
message: "<strong>Oh snap!<strong> you can't draw that!", // Message that will show when intersect
},
shapeOptions: {
color: "#bada55",
},
},
circle: {
shapeOptions: {
weight: 5,
color: "#000",
},
},
rectangle: {
shapeOptions: {
clickable: false,
},
},
marker: true,
},
});
map.addControl(drawControl);
// 监听绘制完成事件
map.on(L.Draw.Event.CREATED, (e) => {
const type = e.layerType;
const layer = e.layer;
// 将绘制的图层添加到 drawnItems 图层组
drawnItems.addLayer(layer);
lastDrawnType.value = type;
drawnItemsCount.value = drawnItems.getLayers().length;
// 打印绘制的GeoJSON数据
console.log(`绘制了 ${type} 类型图形:`, layer.toGeoJSON());
});
// 监听删除事件
map.on(L.Draw.Event.DELETED, (e) => {
drawnItemsCount.value = drawnItems.getLayers().length;
console.log("图形被删除:", e.layers);
});
});
onUnmounted(() => {
if (map) {
map.off(L.Draw.Event.CREATED);
map.off(L.Draw.Event.DELETED);
map.removeControl(drawControl); // 移除绘制控制器
map.remove();
map = null;
drawnItems = null;
drawControl = null;
}
});
const clearAllDrawings = () => {
if (drawnItems) {
drawnItems.clearLayers(); // 清除所有绘制的图层
lastDrawnType.value = "";
drawnItemsCount.value = 0;
console.log("所有绘制已清除。");
}
};
const resetMapView = () => {
if (map) {
map.setView(initialView, initialZoom);
}
};
</script>
<style scoped>
.map-wrapper {
display: flex;
flex-direction: column;
height: 100vh;
width: 100vw;
font-family: sans-serif;
box-sizing: border-box;
}
@media (min-width: 768px) {
.map-wrapper {
flex-direction: row;
}
}
.control-panel {
flex-shrink: 0;
width: 100%;
background-color: #f8f8f8;
border-right: 1px solid #eee;
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 15px;
}
@media (min-width: 768px) {
.control-panel {
width: 280px;
height: 100%;
}
}
.info-display {
background-color: #e9ecef;
padding: 15px;
border-radius: 8px;
border: 1px solid #dee2e6;
color: #495057;
}
.info-display p {
margin: 5px 0;
font-size: 0.95em;
}
.info-display strong {
color: #007bff;
}
.map-container {
flex-grow: 1;
height: 100%;
min-height: 300px;
background-color: #e0e0e0;
}
.action-button {
padding: 10px 15px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
transition: background-color 0.3s ease;
}
.clear-button {
background-color: #dc3545;
color: white;
}
.clear-button:hover {
background-color: #c82333;
}
.reset-button {
background-color: #007bff;
color: white;
margin-top: auto; /* 将按钮推到底部 */
}
.reset-button:hover {
background-color: #0056b3;
}
.reset-button:active {
background-color: #004085;
}
</style>
HTML
使用 html,使用 cdn 引入反而可以正常绘制,从这里,我就开始怀疑是不是依赖的问题,后续测试了下,果然是依赖存在问题
展开代码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vue3 + Leaflet 地图绘制功能</title>
<!-- 引入Leaflet CSS -->
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
/>
<!-- 引入Leaflet Draw CSS -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"
/>
<!-- 引入Font Awesome图标 -->
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"
/>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<!-- 引入Leaflet JS -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<!-- 引入Leaflet Draw JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
}
#app {
width: 100%;
max-width: 1200px;
background-color: rgba(255, 255, 255, 0.95);
border-radius: 20px;
box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
overflow: hidden;
display: flex;
flex-direction: column;
height: 90vh;
}
.app-header {
background: linear-gradient(to right, #1a2a6c, #b21f1f);
color: white;
padding: 20px;
text-align: center;
}
.app-header h1 {
font-size: 2.2rem;
margin-bottom: 10px;
}
.app-header p {
font-size: 1.1rem;
opacity: 0.9;
max-width: 800px;
margin: 0 auto;
}
.app-container {
display: flex;
flex: 1;
overflow: hidden;
}
.map-container {
flex: 1;
position: relative;
}
#map {
height: 100%;
width: 100%;
z-index: 1;
}
.controls-panel {
width: 320px;
background: #f8f9fa;
border-left: 1px solid #dee2e6;
padding: 20px;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.panel-section {
margin-bottom: 25px;
background: white;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
padding: 20px;
border-left: 4px solid #1a2a6c;
}
.panel-section h2 {
color: #1a2a6c;
margin-bottom: 15px;
font-size: 1.4rem;
display: flex;
align-items: center;
gap: 10px;
}
.panel-section h2 i {
font-size: 1.2rem;
}
.draw-buttons {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.draw-btn {
padding: 12px;
background: #1a2a6c;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
}
.draw-btn i {
font-size: 1.5rem;
margin-bottom: 8px;
}
.draw-btn:hover {
background: #b21f1f;
transform: translateY(-2px);
}
.draw-btn.active {
background: #b21f1f;
box-shadow: 0 0 0 3px rgba(178, 31, 31, 0.3);
}
.features-list {
max-height: 300px;
overflow-y: auto;
}
.feature-item {
padding: 12px;
margin-bottom: 10px;
background: #e9ecef;
border-radius: 8px;
display: flex;
justify-content: space-between;
align-items: center;
}
.feature-item .feature-info {
flex: 1;
}
.feature-item .feature-actions {
display: flex;
gap: 8px;
}
.feature-btn {
background: #1a2a6c;
color: white;
border: none;
border-radius: 5px;
padding: 6px 10px;
cursor: pointer;
transition: background 0.2s;
}
.feature-btn:hover {
background: #b21f1f;
}
.feature-btn.delete {
background: #dc3545;
}
.feature-btn.delete:hover {
background: #bd2130;
}
.coordinate-box {
background: #e9ecef;
padding: 15px;
border-radius: 8px;
font-family: monospace;
font-size: 0.9rem;
max-height: 150px;
overflow-y: auto;
}
.coordinates {
line-height: 1.6;
}
.stat-box {
display: flex;
justify-content: space-between;
background: #1a2a6c;
color: white;
padding: 15px;
border-radius: 8px;
margin-top: auto;
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 1.8rem;
font-weight: bold;
}
.stat-label {
font-size: 0.9rem;
opacity: 0.8;
}
.map-legend {
position: absolute;
bottom: 20px;
right: 20px;
background: rgba(255, 255, 255, 0.9);
padding: 10px;
border-radius: 8px;
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
z-index: 1000;
font-size: 14px;
}
.legend-title {
font-weight: bold;
margin-bottom: 8px;
text-align: center;
color: #1a2a6c;
}
.legend-item {
display: flex;
align-items: center;
margin: 5px 0;
}
.legend-color {
width: 20px;
height: 20px;
margin-right: 8px;
border-radius: 4px;
}
@media (max-width: 768px) {
.app-container {
flex-direction: column;
}
.controls-panel {
width: 100%;
height: 40%;
}
.map-container {
height: 60%;
}
.draw-buttons {
grid-template-columns: repeat(3, 1fr);
}
}
</style>
</head>
<body>
<div id="app">
<div class="app-header">
<h1>
<i class="fas fa-map-marked-alt"></i> Vue3 + Leaflet 地图绘制工具
</h1>
<p>
使用Leaflet和Leaflet-Draw插件创建交互式地图绘制应用。绘制点、线、面等地理要素并管理它们。
</p>
</div>
<div class="app-container">
<div class="map-container">
<div id="map"></div>
<div class="map-legend">
<div class="legend-title">图例</div>
<div class="legend-item">
<div
class="legend-color"
style="background-color: #ff7800;"
></div>
<span>点标记</span>
</div>
<div class="legend-item">
<div
class="legend-color"
style="background-color: #3388ff;"
></div>
<span>线条</span>
</div>
<div class="legend-item">
<div
class="legend-color"
style="background-color: #33a02c;"
></div>
<span>多边形</span>
</div>
<div class="legend-item">
<div
class="legend-color"
style="background-color: #e31a1c;"
></div>
<span>矩形</span>
</div>
<div class="legend-item">
<div
class="legend-color"
style="background-color: #6a3d9a;"
></div>
<span>圆形</span>
</div>
</div>
</div>
<div class="controls-panel">
<div class="panel-section">
<h2><i class="fas fa-pencil-alt"></i> 绘制工具</h2>
<div class="draw-buttons">
<button class="draw-btn" @click="activateDrawTool('marker')">
<i class="fas fa-map-marker-alt"></i>
<span>点标记</span>
</button>
<button class="draw-btn" @click="activateDrawTool('polyline')">
<i class="fas fa-draw-polygon"></i>
<span>线条</span>
</button>
<button class="draw-btn" @click="activateDrawTool('polygon')">
<i class="fas fa-draw-polygon"></i>
<span>多边形</span>
</button>
<button class="draw-btn" @click="activateDrawTool('rectangle')">
<i class="fas fa-vector-square"></i>
<span>矩形</span>
</button>
<button class="draw-btn" @click="activateDrawTool('circle')">
<i class="fas fa-circle"></i>
<span>圆形</span>
</button>
<button class="draw-btn" @click="deactivateDrawTool">
<i class="fas fa-times"></i>
<span>取消绘制</span>
</button>
</div>
</div>
<div class="panel-section">
<h2><i class="fas fa-layer-group"></i> 已绘制要素</h2>
<div class="features-list">
<div
v-for="(feature, index) in drawnItems"
:key="feature.id"
class="feature-item"
>
<div class="feature-info">
<strong>{{ getFeatureType(feature) }}</strong>
<div>ID: {{ feature.id.slice(0, 8) }}</div>
</div>
<div class="feature-actions">
<button class="feature-btn" @click="zoomToFeature(feature)">
<i class="fas fa-search"></i>
</button>
<button
class="feature-btn delete"
@click="removeFeature(feature)"
>
<i class="fas fa-trash"></i>
</button>
</div>
</div>
<div
v-if="drawnItems.length === 0"
class="feature-item"
style="justify-content: center;"
>
暂无绘制要素
</div>
</div>
</div>
<div class="panel-section">
<h2><i class="fas fa-map-marker"></i> 当前坐标</h2>
<div class="coordinate-box">
<div class="coordinates">经度: {{ currentLng }}</div>
<div class="coordinates">纬度: {{ currentLat }}</div>
<div class="coordinates">缩放级别: {{ currentZoom }}</div>
</div>
</div>
<div class="stat-box">
<div class="stat-item">
<div class="stat-value">{{ drawnItems.length }}</div>
<div class="stat-label">要素总数</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ markersCount }}</div>
<div class="stat-label">点标记</div>
</div>
<div class="stat-item">
<div class="stat-value">{{ polygonsCount }}</div>
<div class="stat-label">多边形</div>
</div>
</div>
</div>
</div>
</div>
<script>
const { createApp, ref, reactive, onMounted, computed } = Vue;
createApp({
setup() {
// 地图实例
let map = null;
let drawControl = null;
// 当前坐标信息
const currentLat = ref(0);
const currentLng = ref(0);
const currentZoom = ref(0);
// 已绘制的要素
const drawnItems = ref([]);
// 计算不同类型要素的数量
const markersCount = computed(() => {
return drawnItems.value.filter((item) => item.type === "marker")
.length;
});
const polygonsCount = computed(() => {
return drawnItems.value.filter(
(item) =>
item.type === "polygon" ||
item.type === "rectangle" ||
item.type === "circle"
).length;
});
// 初始化地图
const initMap = () => {
// 创建地图实例
map = L.map("map", {
center: [39.9042, 116.4074], // 北京
zoom: 12,
});
// 添加底图图层
L.tileLayer(
"https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}"
).addTo(map);
// 初始化要素图层
const drawnItemsLayer = new L.FeatureGroup();
map.addLayer(drawnItemsLayer);
// 初始化绘制控件
drawControl = new L.Control.Draw({
position: "topright",
draw: {
polygon: {
shapeOptions: {
color: "#33a02c",
},
},
polyline: {
shapeOptions: {
color: "#3388ff",
},
},
rectangle: {
shapeOptions: {
color: "#e31a1c",
},
},
circle: {
shapeOptions: {
color: "#6a3d9a",
},
},
marker: {
icon: L.icon({
iconUrl:
"https://unpkg.com/leaflet@1.9.4/dist/images/marker-icon.png",
shadowUrl:
"https://unpkg.com/leaflet@1.9.4/dist/images/marker-shadow.png",
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41],
}),
},
},
edit: {
featureGroup: drawnItemsLayer,
},
});
map.addControl(drawControl);
// 监听绘制事件
map.on(L.Draw.Event.CREATED, (event) => {
const layer = event.layer;
const featureType = event.layerType;
// 为要素添加自定义属性
layer.featureType = featureType;
layer.id = `feature_${Date.now()}`;
// 添加到图层
drawnItemsLayer.addLayer(layer);
// 添加到状态管理
drawnItems.value.push({
id: layer.id,
type: featureType,
layer: layer,
});
});
// 监听编辑事件
map.on(L.Draw.Event.EDITED, () => {
// 更新要素列表
drawnItems.value = [...drawnItems.value];
});
// 监听删除事件
map.on(L.Draw.Event.DELETED, (event) => {
const deletedIds = event.layers
.getLayers()
.map((layer) => layer.id);
drawnItems.value = drawnItems.value.filter(
(item) => !deletedIds.includes(item.id)
);
});
// 监听地图移动事件
map.on("mousemove", (event) => {
currentLat.value = event.latlng.lat.toFixed(6);
currentLng.value = event.latlng.lng.toFixed(6);
});
// 监听缩放事件
map.on("zoomend", () => {
currentZoom.value = map.getZoom();
});
// 初始值
const center = map.getCenter();
currentLat.value = center.lat.toFixed(6);
currentLng.value = center.lng.toFixed(6);
currentZoom.value = map.getZoom();
};
// 激活绘制工具
const activateDrawTool = (toolType) => {
if (drawControl) {
drawControl.setDrawingOptions({
[toolType]: true,
});
drawControl._toolbars.draw._modes[toolType].handler.enable();
}
};
// 取消绘制
const deactivateDrawTool = () => {
if (drawControl) {
drawControl._toolbars.draw._modes[
drawControl._toolbars.draw._activeMode
].handler.disable();
}
};
// 获取要素类型名称
const getFeatureType = (feature) => {
const typeMap = {
marker: "点标记",
polyline: "线条",
polygon: "多边形",
rectangle: "矩形",
circle: "圆形",
};
return typeMap[feature.type] || feature.type;
};
// 缩放到要素
const zoomToFeature = (feature) => {
if (feature.layer) {
map.fitBounds(feature.layer.getBounds());
}
};
// 移除要素
const removeFeature = (feature) => {
if (feature.layer) {
map.removeLayer(feature.layer);
drawnItems.value = drawnItems.value.filter(
(item) => item.id !== feature.id
);
}
};
// 组件挂载后初始化地图
onMounted(() => {
initMap();
});
return {
currentLat,
currentLng,
currentZoom,
drawnItems,
markersCount,
polygonsCount,
activateDrawTool,
deactivateDrawTool,
getFeatureType,
zoomToFeature,
removeFeature,
};
},
}).mount("#app");
</script>
</body>
</html>
issues
issurs 中也有人遇到了该问题,理性使用第三方插件
看了下 npm 周下载量挺高,难道有别的方式解决绘制问题吗?可以一起讨论一下