热力图


  // 通过npm 安装 heatmap.js
  npm install --save heatmap.js 
  import "heatmap.js";
  import HeatmapOverlay from "@/assets/Leaflet/leaflet-heatmap.js";
  var heatmapInstance = Heatmap.create({
        container: document.getElementById('heatmap'),
        gradient: {//渐变颜色
          "0": "rgba(255,255,255,1)",//value为0的颜色
          "0.3": "#82ff6d",//value为500的颜色
          "0.8": "#f3ff6d",//value为1000的颜色
          "1": "#ff6d6d",//value为2000的颜色
        },
        // radius: 10,
        maxOpacity: 1,
        minOpacity: 0,
        blur: .75,
        // radius:30, //半径
        // opacity:0.5, //透明
        // maxOpacity, //热图中最大值具有的最大不透明度
        // minOpacity, //热图中最小值的最小不透明度
        // onExtremaChange, //传递回调以接收极值更改更新
        // blur, //将应用于所有数据点的模糊因子。模糊因子越高,渐变将越平滑
        // xField, //数据点中x坐标的属性名称
        // yField, //数据点中y坐标的属性名称
        // valueField //数据点中y坐标的属性名称
      })


  // 将后台数据转成热力图需要的数据
      const hdata = self.heatmapData.map(v => {
        return [
          v.lat,
          v.lng,
          v.count
        ]
      })
        // 创建热力图
      self.heatmap = L.heatLayer(hdata, {
        radius: newRadius, // 半径
        max: maxNum, // 最大强度
        minOpacity: 0.4, // 最小透明度
        gradient: {
          // 热力值的颜色设置,范围是0-1,可以分段设置颜色
          0.5: 'blue',
          0.65: 'rgb(117, 211, 248)',
          0.7: 'rgb(0, 255, 0)',
          0.9: '#ffea00',
          1.0: 'red',
        },
      }).addTo(self.localHeatmap);
      // 定位至第一个热力图的位置
      if (self.heatmapData.length) {
        self.localHeatmap.setView([self.heatmapData[0]?.lat, self.heatmapData[0]?.lng], 10);
      } 




      
let cfg = {
        //热力图的配置项
        radius: 0.5, //设置每一个热力点的半径
        maxOpacity: 0.9, //设置最大的不透明度
        // minOpacity: 0.3,     //设置最小的不透明度
        scaleRadius: true, //设置热力点是否平滑过渡
        blur: 0.95, //系数越高,渐变越平滑,默认是0.85,
        //滤镜系数将应用于所有热点数据。
        useLocalExtrema: true, //使用局部极值
        latField: "lat", //维度
    }
// Leaflet官方文档中只给出了4种控件:Zoom、Attribution、Layers、Scale;它们都是继承自Control类,具体可以参考Control。


//------------------------------------------------------------------
// # 插件安装
npm i leaflet.heat
// # 引入热力图插件
import 'leaflet.heat'

let heatDataList = []
// 构造热力图数据
HeatData.features.forEach((v) => {
    // 纬度、经度、阈值
    let group = [v.properties.lat, v.properties.lon, v.properties.valve]
    heatDataList.push(group)
})
// 生成热力图图层,并添加到地图中
let heat = L.heatLayer(heatDataList, {
    radius: 12, 
    minOpacity: 0.2,
    gradient: { // 自定义渐变颜色,区间为 0~1 之间(也可以不指定颜色,使用默认颜色)
      '0.2': "#00f",
      '0.3': "#0ff",
      '0.5': "#0f0",
      '0.7': "#ff0",
      '1': "#f00"
    }
}).addTo(map);


/*
此外,Leaflet.heat插件还提供了几个别的方法:

方法	说明
setOptions(options)	设置新的热力图heatmap属性并重新绘制
addLatLng(latlng)	向热力图heatmap动态添加数据并重新绘制
setLatLngs(latlngs)	重置热力图heatmap数据并重新绘制
redraw()	重绘热力图 

*/


vue 父子组件传值

组合式API

  • 父组件通过ref定义子组件实例,通过调用实例获得子组件的数据和方法
https://blog.csdn.net/qq_56263094/article/details/124576055
 

 <!-- 父组件 app.vue -->
<template>
  <div class="itxst">
    <!-- 使用 ref  指令关联子组件 -->
    <child ref="childComp"/>
    <button @click="onTry">点击试一试</button>
  </div>
</template>
<script setup>
import { reactive, ref } from "vue";
import child from "./child.vue";
//定义子组件实例,名称要和上面的ref相同
const childComp = ref(null);
 
//访问demo组件的方法或对象
const onTry = () => {
  //获取到子组件的 title 数据 
  let msg = childComp.value.state.title;
  //调用子组件的 play方法
  childComp.value.play();
};
</script>

子组件通过defineExpose暴露对象和方法
xml复制代码<!--子组件名称  child.vue -->
<template>
  <div class="itxst">
    {{ state.title }}
  </div>
</template>
<script setup>
import { ref, reactive } from "vue";
//定义一个变量
const state = reactive({
  title: "www.itxst.com",
});
//定义一个方法
const play = () => {
  state.title = "你调用了子组件的方法";
};
 
//暴露state和play方法
defineExpose({
  state,
  play,
});
</script>

2,选项式API

<!-- 父组件 app.vue -->
<template>
  <div class="itxst">
    <!-- 使用 ref  命令 -->
    <child ref="childComp"/>
    <button @click="onClick">点击试一试</button>
  </div>
</template>
<script >
import child from "./child.vue";
export default {
  name: "app",
  //注册组件
  components: {
    child,
  },
  methods: {
    onClick: function () {
      //获取到 子组件的  数据
      let msg = this.$refs.childComp.message;
      //执行了子组件的 play方法
      this.$refs.childComp.play();
    },
  },
};
</script> 

 <!-- 子组件 child.vue -->
<template>
  <div class="itxst">
    {{ title }}
  </div>
</template>
<script>


const props = defineProps({
  foo: String
})


//选项式默认当前实例是全部暴露
export default {
  name: "demo",
  //默认全部暴露 也可以通过expose控制那些需要暴露
  //expose: ['play'],
  data() {
    return {
      title: "www.itxst.com",
    };
  },
  methods: {
    play: function () {
      this.title = "你调用了子组件的方法";
    },
  },
};
</script>
 

https://juejin.cn/post/6844903856275456013


var map = L.map("map", {
 
center: [31.59, 120.29],
 
zoom: 12,
 
zoomControl: true
 
});

多点创建

1.PruneCluster

创建

var pruneClusterView = new PruneClusterForLeaflet();
for(var key in data){
   var point = data[key];
   pruneClusterView.RegisterMarker(new PruneCluster.Marker(point.lat, point.lng, {
      title: 1,
      singleMarkerMode:true
   }));
}
map.addLayer(pruneClusterView);
pruneClusterView .ProcessView();
1.2 删除
// Remove all the markers
pruneClusterView.RemoveMarkers();
// Remove a list of markers
pruneClusterView.RemoveMarkers([markerA,markerB,...]);
2.markerClusterGroup

备注:markerCluster在数量多的时候初次创建会很卡,pruneClusterView不会很卡。

2.1创建

var markerCluster =new L.markerClusterGroup({
	singleMarkerMode: true//true:单个marker显示聚合数字1,false:显示单个marker  
});
var markerList =[];
for(var key in markers){
	var point = markers[key];
	var marker = L.marker(L.latLng(point.lat, point.lon));
	markerList.push(marker);
}
markerCluster.addLayers(markerList);
map.addLayer(markerCluster);
2.2删除
markerCluster.clearLayers();
//addLayer, removeLayer and clearLayers
2.3其他
markerCluster.refreshClusters();
markerCluster.refreshClusters([myMarker0, myMarker33]);
markerCluster.refreshClusters({id_0: myMarker0, id_any: myMarker33});
markerCluster.refreshClusters(myLayerGroup);
markerCluster.refreshClusters(myMarker);
 
// Use as many times as required to update markers,
// then call refreshClusters once finished.
for (i in markersSubArray) {
	markersSubArray[i].refreshIconOptions(newOptionsMappingArray[i]);
}
markers.refreshClusters(markersSubArray);
 
// If updating only one marker, pass true to
// refresh this marker's parent clusters right away.
myMarker.refreshIconOptions(optionsMap, true); 
 

监听 props

<script setup>
import { ref, watch } from 'vue';
const props = defineProps({
    listData: {
        type: Array,
        default: [],
    }
});
const childList = ref([])
watch(
    () => props.listData,
    (newProps) => {
        childList.value = newProps.listData
    }
);
</script>

缩放层级

// 指定中心点
let center = L.latLng(30.68, 113.98);
 
// 方式 1:跳到指定中心点,不缩放级数。第二参数说明文档没有说是可选,但我测试可用且不报错
this.map.setView(center); 
 
// 方式 2:跳到指定中心点,不缩放级数。这里第二个参数使用 map.getZoom() 获取当前缩放级数
this.map.setView(center, this.map.getZoom()); 
 
// 方式 3:跳到指定中心点和指定的缩放级数
this.map.setView(center, 8); 




// 缩放到指定级数
this.map.setZoom(8);
 
// 放大:每次调用默认放大 1 个级数
this.map.zoomIn();
// 放大:每次调用放大 3 个级数
this.map.zoomIn(3);
 
// 缩小:每次调用默认缩小 1 个级数
this.map.zoomOut();
// 缩小:每次调用缩小 3 个级数
this.map.zoomOut(3);
 
/*
panTo 和 flyTo
panTo:平移到指定中心点;
flyTo:与 panTo 相比,在平移时,多了一个可设置缩放级数的功能;
*/


 // 中心点
let center = L.latLng(30.68, 113.98);
 
// 平移
this.map.panTo(center);
 
// 平移,与上面的 panTo 功能一样
this.map.flyTo(center);
// 平移,且缩放到指定级数
this.map.flyTo(center, 3);



图层添加与删除(两种方式)

  • 方式一 通过 L.Map 对象的方法添加或删除 L.Layer 对象。 map.removeLayer(remark);
  • 方式二 通过 L.Layer 对象的方法添加或删除 L.Map 对象中。
function removeLayer() {
    // 通过 id 获取地图对象
    let tdtLayerGroup = map._layers[leafletId];
    map.removeLayer(layer);
}

map添加监听事件

// String 类型,监听单个事件
map.on('click', onClick);
 
// String 类型,监听单个事件,多次添加,与方法 onClick 按照顺序执行
map.on('click', onClick02);
 
// String 类型,监听多个事件,使用同一个方法,可以用回调参数 e.type 判断当前是哪个事件
map.on('click dblclick', onClick);
 
// Object 类型,键值对方式,监听一个或多个事件
map.on({
    click: onClick,
    dblclick: ondblClick
});
 

map删除监听事件

// 删除 click 全部的监听事件
map.off('click');
 
// 删除 click 对应的 onClick 监听事件
map.off('click', onClick);
 
// 删除多个事件,用空格隔开
map.off('click dblclick');
 
// 键值对方式删除
map.off({
    click: onClick,
    dblclick: ondblClick
});
 
// 删除全部事件 慎用!!!
map.off();

markerClusterGroup


  hospitalMarkers = new L.markerClusterGroup({
    singleMarkerMode: false,
  });

  for (var i = 0; i < map.value.length; i++) {
    var info = map.value[i];
    var title = info.address;
    var marker = null;

    let popup = L.popup().setContent(
      `<div style="font-size: .25rem;color:blue; ">${title},'chery'</div>`
    );

    if (info.areas_degree == "hos") {
      marker = L.marker(new L.LatLng(info.lat, info.lon), {
        icon: hospitalIcon,
      });
      //绑定点击弹窗事件
      marker.bindPopup(popup);

      marker
        .bindTooltip(L.tooltip({ direction: "top", offset: L.point(0, -10) }))
        .setTooltipContent(
          `<div style='font-size: .25rem;height:.5rem; background-color: #577ed9;'>${title}</div>`
        );

      // if (info.areas_degree == "hos") {
      //   marker.addTo(map_dom);
      // } else {
      //   markers.addLayer(marker);
      // }

      hospitalMarkers.addLayer(marker);
    } else {
      /*
      marker = L.marker(new L.LatLng(info.lat, info.lon), {
        icon: myIcon,
      });
      */
    }
    /*
    //绑定点击弹窗事件
    marker.bindPopup(popup);

    marker
      .bindTooltip(L.tooltip({ direction: "top", offset: L.point(0, -10) }))
      .setTooltipContent(
        `<div style='font-size: .25rem;height:.5rem; background-color: #577ed9;'>${title}</div>`
      );
      if (info.areas_degree == "hos") {
      marker.addTo(map_dom);
    } else {
      markers.addLayer(marker);
    }
    markers.addLayer(marker);
*/
  }
  //将markerClusterGroup添加到地图上

  map_dom.addLayer(hospitalMarkers);

  // 左下角  距离缩放比例
  //   L.control.scale({ maxWidth: 200, metric: true, imperial: false  }).addTo(map_dom)

geojson

leaflet-geoJSON图层

var geojsonFeature = {
    "type": "Feature",
    "properties": {
        "name": "Coors Field",
        "amenity": "Baseball Stadium",
        "popupContent": "This is where the Rockies play!"
    },
    "geometry": {
        "type": "Point",
        "coordinates": [-104.99404, 39.75621]
    }
};

 
L.geoJSON(geojsonFeature).addTo(map);
 
// or ***************************************
var myLayer = L.geoJSON().addTo(map);
myLayer.addData(geojsonFeature);



// 还可以用geoJSON()的第二个参数options定义样式
L.geoJSON(geojsonFeature, {
    style: {
    "color": "#ff7800",
    "weight": 5,
    "opacity": 0.65
	}
}).addTo(map);


// /用onEachFeature属性,在加入图层之前对feature进行调用处理,如绑定泡泡


function onEachFeature(feature, layer) {
    // does this feature have a property named popupContent?
    if (feature.properties && feature.properties.popupContent) {
        layer.bindPopup(feature.properties.popupContent);
    }
}

L.geoJSON(geojsonFeature, {
    style: {
    "color": "#ff7800",
    "weight": 5,
    "opacity": 0.65
	},
	onEachFeature:onEachFeature
}).addTo(map);

WMS

ArcGIS WMS
let layer = L.tileLayer.wms('http://127.0.0.1:6080/arcgis/services/hbbzFloder/HBBZ/MapServer/WmsServer', {
    layers: '10,11,12,13,14,15,35,36,37,38,39,40',
    format: "image/png",
    transparent: true
}).addTo(map);
 GeoServer WMS
let layer = L.tileLayer.wms('http://127.0.0.1:8181/geoserver/topp/wms', {
    layers: 'states,tasmania_state_boundaries',
    format: "image/png",
    transparent: true
}).addTo(map);

图层创建

  • 在实际项目中地图数据分为不同类型,这时如果把所有数据同时加载到地图上来进行操作会带来各种问题,
  • 所以此时需要利用L.featureGroup方法创建不同的图层,用来加载不同类型的数据,以方便操作,具体方法如下:

// featureGroup图层创建



var _viewSpotLayer=new L.featureGroup([]);
_map.addLayer(_viewSpotLayer);
// 如需要清除图层上的数据集合,使用内置方法即可:
_viewSpotLayer.clearLayers();
 



//  --------------------------示例:



var pointFeature = new L.marker([39.905,116.399],{ icon: viewIcon,title:"故宫"}).bindLabel("故宫",{noHide:true}).addTo(_viewSpotLayer);
// 参数说明:
icon             //用于渲染标记的图标实例。使用L.icon创建,下面会有详细讲解
title            //鼠标悬停时提示文本
alt              //图像文本
riseOnHover      //true/false(默认),为true时当您将鼠标悬停在其上时,标记将会显示在其他标记之上。
 
方法说明:
.addTo(layer)    //添加到指定图层当中
.bindLabel()     //给marker绑定label,使用方法及参数下面详解
 
事件说明:
marker支持各种鼠标事件,使用方法为
marker.on("event",function(){
    //do something
})

  • 如果通过ajax请求加载多个marker
  • 并且都需要添加点击事件,请使用 **【封闭空间】**循环加载数据点
// 使用示例:
$.ajax({
        url:"js/demo.json",
        type:"POST",
        success:function(data){
            for(var i=0;i<data.rows.length;i++){
                (function (index){ //封闭空间开始
                    var row=data.rows[index];
                    var pointFeature = new L.marker([row.lat,row.lng],{ icon:     
                        viewIcon,title:row.name}).bindLabel(row.name,{noHide:true});
                    pointFeature.options.sm_sid = "rwjg";
                    pointFeature.on("click",function(){
                        alert(row.name)
                    });
                    pointFeature.addTo(_viewSpotLayer)
                })(i) //封闭空间结束
            }
        }
    })

polyLine

使用示例
 
new L.polyline(数据集合,{options})
 
var lineArr=[[39.920969009399414, 116.38572692871094],[39.91101264953613,         
    116.3862419128418],[39.91161346435547, 116.39636993408203],[39.9217414855957,    
    116.3957691192627],[39.9213981628418, 116.38589859008789]];
var line =newL.polyline(lineArr,{color:'red',opacity:'0.8',weight:'3'})
    .addTo(_viewSpotLayer);
 
参数说明:
 
color:线段颜色
weight:线段宽度
opacity:线段透明度
dashArray:虚线间隔
fill:是否填充内部(true/false)
fillColor:内部填充颜色,如不设置,默认为color颜色
fillOpacity:内部填充透明度
 
方法:
.setStyle()    设置样式;
 
事件:
line.on("event",function(){
    //do something
})
// ps:线段的事件,是能在鼠标位于线段上方时操作才会触发

https://openwhatevermap.xyz/#3/39.64/210.50 (多图层 各种 xyz 瓦片)

  leaflet有两种类型的图层:

(1)base layer:互斥的图层(在地图上同一时间只能有一个图层可见),比如tile layers;

(2)overlayers:在base layer之上放置的其他东西。
var baseLayers = {
    "Mapbox": mapbox,
    "OpenStreetMap": osm
};
 
var overlays = {
    "Marker": marker,
    "Roads": roadsLayer
};
 
L.control.layers(baseLayers, overlays).addTo(map);



// ls 切换图层工具
var baseLayers = {
    'Sputnik': L.tileLayer('http://{s}.tiles.maps.sputnik.ru/{z}/{x}/{y}.png', {
        maxZoom: 18
    }),
 
    "CartoDB Positron": L.tileLayer('http://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
        maxZoom: 18
    }),
 
    "OSM": L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 18
    }).addTo(map),
 
    "OpenTopoMap": L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
        maxZoom: 18
    }),
};


var layerControl = L.control.layers(baseLayers, {}, {
    position: 'topleft',
    collapsed: true
}).addTo(map)

绘制的多个图形组合成一个整体通过 layerGroup 作为 overlayer 添加上去

  • https://blog.csdn.net/sinat_36226553/article/details/107287753 加载各种服务
  • 加载WMTS服务加载WMS服务 加载TMS服务 加载Geojson数据
    • 注:如果手上有shp数据,可以通过mapshaper转换得到geojson数据
    • leaflet本身并不支持WMTS服务,需要借助 leaflet-tilelayer-wmts 插件实现
var bj = L.marker([39.92,116.46]).bindPopup('这里是北京');
    sh = L.marker([31.213,121.445]).bindPopup('这里是上海');
    gz = L.marker([23.16,113.23]).bindPopup('这里是广州');
var cities = L.layerGroup([bj, sh, gz]).addTo(map);
/**  三方库地址:https://github.com/lin-123/leaflet.migration
 * 中心点向外点位辐射分离
 * @author Lou
 * @param { Array } arr 点位数据(一个中心点) 
 * @param { String } color 点位颜色
 * @param { String } centerName 中心点名称
 * @param { String } centerNameProp 中心点对应的属性
 * @param { Number } value 点位数值大小
 * @returns { Array }
 */
export function classifyPointData(arr, color = "rgb(101, 169, 249)", centerName, centerNameProp, value = 6) {
  const { jd: centerJD, wd: centerWD } = arr.find((i) => i[centerNameProp] === centerName);
  return arr.filter((i) => i.name !== centerName).map(({ jd, wd }) => ({
      color,
      from: [centerJD, centerWD],
      to: [jd, wd],
      value,
    }));
}

// 飞线的配置项(可以直接看github上的文档)
migrationOptions = {
  marker: {
    radius: [5, 10],
    pulse: false,
    textVisible: false
  },
  line: {
    width: 1,
    order: false,
    icon: {
      type: 'arrow',
      imgUrl: '',
      size: 10
    },
  },
}

// 地图上的绘制
initPoint() {
  this.markerLayer && this.map.removeLayer(this.markerLayer);
  const migrationData = classifyPointData(this.pointList, "rgb(101, 169, 249)", "分指挥部", "name");
  this.migrationGymLayer = L.migrationLayer(migrationData, migrationOptions);
  this.migrationGymLayer.addTo(this.map);
  let markericon = []
  this.pointList.forEach(item => {
    const myIcon = L.divIcon({
      html: `<div class="marker-box flex flex-col items-center">
              <div class="board-box flex flex-col items-center">
                <div class="board">
                  ${ item.name }
                  ${ item.distance ? `<div>距离分指挥部:${ item.distance }</div>` : '' }
                  <div class="logo">
                    <img src="${ pointLogo }"/>
                  </div>
                </div>
                <img class="line" src="${ pointLine }"/>
              </div>
              ${JSON.parse(item.image).length ? `<img src="${ '/sys/sysFile/download?fileId=' + JSON.parse(item?.image)[0]?.id }"/>` : ''}
              <div class="circle-box">
                <div class="circle1"></div>
                <div class="circle2" style="animation-delay: 0.5s;"></div>
                <div class="circle3" style="animation-delay: 1.5s;></div>
              </div>
              </div>
            `,
      // iconSize: [50 , 70], // icon大小
    });

    const m = L.marker([item.wd, item.jd], { icon: myIcon });
    markericon.push(m);
  })
  this.markerLayer = L.layerGroup(markericon);
  this.map.addLayer(this.markerLayer);
},