在vite+ts中使用leftlet做工厂平面(室内)地图

2023-11-20  本文已影响0人  zZ_d205

实现效果
初始化:


image.png

点击标识点时自动放大:


image.png

参考文章
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';
image.png
<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 &copy; 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: '&copy; <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>
上一篇 下一篇

猜你喜欢

热点阅读