热力图
// 通过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);
},