实现效果
初始化:
点击标识点时自动放大:
参考文章
Leaflet
https://github.com/Leaflet/Leaflet
https://leafletjs.com/index.html
中文文档:https://leafletjs.cn/
Leaflet Indoor
https://github.com/cbaines/leaflet-indoor
npm 安装 Leaflet
npm install leaflet
yarn 安装 Leaflet
yarn add leaflet
这将在你的项目中安装 Leaflet 库。安装完成后,你可以在你的 Vue 项目中按照以下方式引入 Leaflet:
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
leaflet可能会报错,我是在app.vue中做的demo,所以需要在vite-env.d.ts中声明
declare module 'leaflet';
<template>
<div class="mapBox">
<div id="map"></div>
<div id="warehouse2"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
import * as L from "leaflet";
import "leaflet/dist/leaflet.css";
import imageUrl from "./assets/warehouse1.png";
import warehouse2 from "./assets/warehouse2.png";
import marker from "./assets/jarMarker.png";
// const leftBottomLat = 0; // 左下角经度
// const leftBottomLng = 0; // 左下角纬度
const getRealitySize = (size: number) => {
// type: "Lat" | "Lng"
// return type === "Lat"
// ? leftBottomLat + size / (40008000 / 360)
// : leftBottomLng + size / (40008000 / 360);// 40008000 是地球周长
return size / (40008000 / 360);
};
const initMap1 = () => {
// 创建地图实例并设置初始视图
// Create the map
//地图底图
// var osmUrl = 'https://tile.openstreetmap.org/{z}/{x}/{y}.png',
// osm = new L.TileLayer(osmUrl, {
// maxZoom: 22,
// // attribution: "Map data © OpenStreetMap contributors"
// });
// 假设当前左下角坐标为 [leftBottomLat, leftBottomLng]
const factoryWidth = 1144; // 宽度,单位:米
const factoryHeight = 676; // 高度,单位:米
// 计算右上角的经纬度
const rightTopLng = getRealitySize(factoryWidth); //经度
const rightTopLat = getRealitySize(factoryHeight); //纬度
//[[最小底部纬度, 最左侧经度(左下角的点位)], [最大顶部纬度, 最右侧经度(右上角的点位)]];
// 坐标的顺序应该是[纬度, 经度]
var imageBounds = [
[0, 0],
[rightTopLat, rightTopLng],
];
var map = new L.Map("map", {
// layers: [osm],
center: new L.LatLng(0, 0),
zoom: 16,
maxBounds: imageBounds,
attributionControl: false,
minZoom: 16, // 设置最小缩放级别
maxZoom: 25, // 设置最大缩放级别
});
var imageOverlay = L.imageOverlay(imageUrl, imageBounds).addTo(map);
imageOverlay.setOpacity(0.5); // 设置不透明度为 0.5
// Add markers with custom icons
// var marker1 = L.marker([0, 0]).addTo(map);
// var popup1 = L.popup().setContent("Marker 1 Popup");
// marker1.bindPopup(popup1);
// var marker1 = L.marker([49.41873, 8.67689]).addTo(map);
// var popup1 = L.popup().setContent("Marker 1 Popup");
// marker1.bindPopup(popup1);
// var marker2 = L.marker([0.0002, 0.0003]).addTo(map);
// var popup2 = L.popup().setContent("Marker 2 Popup");
// marker2.bindPopup(popup2);
// L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
// maxZoom: 19,
// attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
// }).addTo(map);
// // 添加一个简单的标记
// L.marker([51.5, -0.09]).addTo(map)
// .bindPopup('A pretty CSS3 popup. <br> Easily customizable.')
// .openPopup();
// // 添加一个简单的圆
// L.circle([51.508, -0.11], {
// color: 'red',
// fillColor: '#f03',
// fillOpacity: 0.5,
// radius: 500
// }).addTo(map).bindPopup('I am a circle.');
// 添加一个多边形
const polygon = L.polygon(
[
[getRealitySize(45), getRealitySize(202)], // 左下角
[getRealitySize(48), getRealitySize(528)], // 右下角
[getRealitySize(156), getRealitySize(528)], // 右上角
[getRealitySize(156), getRealitySize(202)], // 左上角
],
{
color: "white", // 边框颜色
fillColor: "white", // 填充颜色
fillOpacity: 1, // 完全不透明
}
)
.addTo(map)
.bindTooltip(
"<div style='font-weight:bold'>Dirty Staging</br>Clean Room</div>",
{
permanent: true,
direction: "center",
}
) // 添加 Tooltip
.on("click", function () {
const bounds = polygon.getBounds();
map.fitBounds(bounds);
});
// 你可以使用 polygon.getBounds() 获取多边形的边界框
const polygonBounds = polygon.getBounds();
const numberOfMarkers = 50;
const customIcon = L.icon({
iconUrl: marker, // 图标的 URL
iconSize: [32, 32], // 图标的尺寸
iconAnchor: [16, 16], // 图标的锚点,即图标的中心点
});
for (let i = 0; i < numberOfMarkers; i++) {
// 随机生成一个在多边形内的点
const randomPoint = getRandomPointInsidePolygon(polygonBounds);
// 添加标记
L.marker([randomPoint.lat, randomPoint.lng], { icon: customIcon })
.addTo(map)
.bindPopup(
`<div><h3>Marker ${
i + 1
}</h3><p>Your custom HTML content goes here</p></div>`
)
.on("click", function () {
const bounds = polygon.getBounds();
map.fitBounds(bounds);
});
}
// 随机生成一个在多边形内的点
function getRandomPointInsidePolygon(bounds: {
getSouthWest: () => any;
getNorthEast: () => any;
}) {
const southWest = bounds.getSouthWest();
const northEast = bounds.getNorthEast();
const lat = Math.random() * (northEast.lat - southWest.lat) + southWest.lat;
const lng = Math.random() * (northEast.lng - southWest.lng) + southWest.lng;
return { lat, lng };
}
// // 例如,在多边形内的点的坐标
// const pointInsidePolygon = [getRealitySize(90), getRealitySize(200)];
// // 检查点是否在多边形内
// if (
// polygonBounds.contains(
// L.latLng(pointInsidePolygon[0], pointInsidePolygon[1])
// )
// ) {
// // 在多边形内,添加标记
// const marker = L.marker([pointInsidePolygon[0], pointInsidePolygon[1]])
// .addTo(map)
// .bindPopup("Marker inside the polygon");
// }
// const demoText = L.divIcon({
// className: "demo-text",
// html: `<div style=''>PM</br>WH</div>`,
// });
// const textMarker = L.marker(polygon.getBounds().getCenter(), {
// icon: demoText,
// }).addTo(map);
};
onMounted(() => {
initMap1();
});
</script>
<style>
/* 去掉 Leaflet Tooltip 的默认样式 */
.leaflet-tooltip {
box-shadow: none !important;
border: none !important;
background-color: transparent !important;
}
/* 设置 Tooltip 文字的样式 */
.leaflet-tooltip-content {
color: black; /* 文字颜色 */
font-size: 14px; /* 文字大小 */
}
</style>
<style scoped>
body {
padding: 0;
margin: 0;
}
html,
body {
height: 100%;
width: 100%;
}
.mapBox {
display: flex;
align-items: center;
height: 100vh;
}
#map {
height: 100%;
width: 50%;
}
.info {
width: 150px;
padding: 6px 8px;
font: 14px/16px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255, 255, 255, 1);
box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);
border-radius: 5px;
}
#warehouse2 {
width: 50%;
height: 100%;
}
</style>