【无标题】使用Leaflet 实现地图瓦片 离线地图功能

直接上代码 注意的点 需要引入css文件 不然地图会混乱 其他的代码简介可直接借鉴

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import L from 'leaflet'
import 'leaflet/dist/leaflet.css'
import { getLineinfos } from '@/api/dashboard/map/index'
import 'leaflet.markercluster' // 引入 MarkerCluster 插件

defineOptions({
  name: 'DashboardMap'
})
const mapContainer = ref(null)
const initMap = () => {
  if (mapContainer.value) {
    // 初始化 Leaflet 地图
    const map = L.map(mapContainer.value, {
      // center: [30.5928, 114.3055], // 地图中心坐标
      zoom: 13, // 默认缩放级别
      attributionControl: false // 禁用默认的版权信息
    })
    // 配置离线瓦片
    const offlineTilesUrl = 'http://113.57.103.251:5001/map?x={x}&y={y}&z={z}' // 离线瓦片的 URL 模板
    L.tileLayer(offlineTilesUrl, {
      minZoom: 0,
      maxZoom: 13,
      tileSize: 256,
      subdomains: 'abcd', // 使用多个子域名加载瓦片
      errorTileUrl: '/assets/imgs/logo.png' // 错误瓦片的 URL
    }).addTo(map)
    setValues(map)
  }
}

onMounted(initMap)
const setValues = async (map) => {
  const res = await getLineinfos()
  if (res.data) {
    // 创建 LayerGroup
    const layerGroup = L.layerGroup()

    // 处理数据
    res.data.forEach((item) => {
      const points = item.infos

      // 绘制线路
      const polyline = L.polyline(
        points.map((p) => [p.lat, p.lng]),
        {
          color: 'red',
          weight: 4,
          opacity: 0.9,
          smoothFactor: 1
        }
      ).addTo(map)

      // 创建标记并添加到组
      points.forEach((point) => {
        const marker = L.circleMarker([point.lat, point.lng], {
          radius: 5, // 可以根据需要调整半径
          fillColor: 'blue',
          color: 'blue',
          weight: 1,
          opacity: 1,
          fillOpacity: 0.8
        })

        // 将标记加入到组
        layerGroup.addLayer(marker)

        // 鼠标悬停事件
        marker.on('mouseover', function () {
          const popupContent = `<p style="font-size:18px;font-weight:700;text-align: center;margin:5px 0">${item.lname}</p>
          <span style="font-size:16px;font-weight:700;margin:2px 0">span:</span><span style="font-size:16px">  ${point.id}</span><br/>
          <span style="font-size:16px;font-weight:700;margin:2px 0">lon:</span> <span style="font-size:16px">  ${point.lng}°</span><br/>
          <span style="font-size:16px;font-weight:700;margin:2px 0">lat:</span> <span style="font-size:16px">  ${point.lat}°</span><br/> 
          <span style="font-size:16px;font-weight:700;margin:2px 0">alt:</span> <span style="font-size:16px">  ${point.alt}m</span>`
          marker.bindPopup(popupContent).openPopup()
        })

        // 鼠标移出事件
        marker.on('mouseout', function () {
          marker.closePopup()
        })
      })
    })

    // 将 LayerGroup 添加到地图
    map.addLayer(layerGroup)

    // 调整地图视野以适应所有点
    const allPoints = res.data.flatMap((item) => item.infos.map((p) => [p.lat, p.lng]))
    const bounds = L.latLngBounds(allPoints)
    map.fitBounds(bounds)
  }
}
</script>

<template>
  <div id="map-container" ref="mapContainer"></div>
</template>

<style scoped lang="less">
#map-container {
  padding: 0px;
  margin: 0px;
  width: 100%;
  height: 100%;
}

#map-container :deep(.description) {
  background-color: #fff;
  height: 50px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  box-sizing: border-box;
  border: 2px solid #f05b72;
  border-radius: 5px;
  font-size: 14px;
}

#map-container :deep(.point) {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background-color: #f05b72;
  margin-bottom: 1px;
  margin-right: 2px;
}

#map-container :deep(.name-box) {
  display: inline;
  margin-right: 8px;
}

#map-container :deep(.alarmDevice) {
  text-align: center;
  margin: 0 auto;
  width: 30px;
  height: 30px;
  background-color: #f13737;
  box-shadow: 0px 0px 15px #f61212;
  border-radius: 50%;
  --webkit-animation-name: 'alarmDeviceBreath'; /*动画属性名,也就是我们前面keyframes定义的动画名*/
  --webkit-animation-duration: 1s; /*动画持续时间*/
  --webkit-animation-timing-function: ease; /*动画频率,和transition-timing-function是一样的*/
  --webkit-animation-delay: 0s; /*动画延迟时间*/
  --webkit-animation-iteration-count: infinite; /*定义循环资料,infinite为无限次*/
  --webkit-animation-direction: alternate; /*定义动画方式*/
}
</style>

<style>
@keyframes alarmDeviceBreath {
  0% {
    margin-left: 0;
    margin-top: 0;
    width: 30px;
    height: 30px;
    box-shadow: 0px 0px 15px #f61212;
    opacity: 1.2;
  }

  100% {
    margin-left: 5px;
    margin-top: 5px;
    width: 20px;
    height: 20px;
    box-shadow: 0px 0px 10px #f61212;
    opacity: 0.6;
  }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值