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

实现效果
初始化:


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>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350