使用 Leaflet 和 Leaflet.markercluster 数千个标记的 Vue 性能问题
Performance issue Vue with Leaflet and Leaflet.markercluster thousands Markers
Leaflet 这是一个流行的地理图书馆。
出于某种原因,我在将此库与 Vue 一起使用时遇到了严重的性能问题。
问题一:
超过 500 个标记,页面已经开始出现问题,2,000 个标记 - 严重中断,10,000 个标记 - 无法加载。
在 HTML 网页上,和平加载了 50,000 个。
问题二:
Leaflet.markercluster插件很弱,它不会折叠标记。
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map('map').setView([38.63, -90.23], 12);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
this.map.locate({
setView: true,
maxZoom: 17
});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
for (let i = 0; i < 500; i++) {
let marker = L.marker([r(53.82477192, 53.97365592), r(27.3878027, 27.70640622)], {
icon: icon
}).addTo(this.map);
markers.addLayer(marker);
}
this.map.addLayer(markers);
},
}
不要将您的 marker
同时添加到 this.map
和 markers
标记集群组 (MCG)。
仅将它们添加到 MCG,并让它根据需要处理添加到您的地图。
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//this.map.locate({setView: true, maxZoom: 17});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
}) /*.addTo(this.map)*/ ; // <= do not add individual `marker` to map!
markers.addLayer(marker); // <= but only to MCG
}
this.map.addLayer(markers);
},
},
});
<script src="https://unpkg.com/vue@2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster@1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 180px"></div>
</div>
为了更好的表现
处理大量标记时,请确保使用 markercluster
的缩放功能。他们在 markerClusterGroup
上有 batch methods for adding and removing lots of markers: addLayers()
, removeLayers()
, and clearLayers()
. They are much more performant. Also note that you can use the chunkedLoading
选项。允许您经常 return 主线程,使 UI 更敏捷。
所以扩展上面 @ghybs 的答案。我会像这样调整代码段:
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//Leaflet.markercluster
const markerClusterGroup = L.markerClusterGroup({
chunkedLoading: true
}); // <= Add chunked loading here
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
const markers = []
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
})
markers.push(marker)
// markers.addLayer(marker); // <= do not add individual marker to MCG
}
markerClusterGroup.addLayers(markers) // <= use batch method to add markers to MCG
this.map.addLayer(markerClusterGroup);
},
},
});
<script src="https://unpkg.com/vue@2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster@1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 300px"></div>
</div>
希望对其他人有所帮助。
Leaflet 这是一个流行的地理图书馆。
出于某种原因,我在将此库与 Vue 一起使用时遇到了严重的性能问题。
问题一:
超过 500 个标记,页面已经开始出现问题,2,000 个标记 - 严重中断,10,000 个标记 - 无法加载。
在 HTML 网页上,和平加载了 50,000 个。
问题二:
Leaflet.markercluster插件很弱,它不会折叠标记。
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map('map').setView([38.63, -90.23], 12);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
this.map.locate({
setView: true,
maxZoom: 17
});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
for (let i = 0; i < 500; i++) {
let marker = L.marker([r(53.82477192, 53.97365592), r(27.3878027, 27.70640622)], {
icon: icon
}).addTo(this.map);
markers.addLayer(marker);
}
this.map.addLayer(markers);
},
}
不要将您的 marker
同时添加到 this.map
和 markers
标记集群组 (MCG)。
仅将它们添加到 MCG,并让它根据需要处理添加到您的地图。
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//this.map.locate({setView: true, maxZoom: 17});
//Leaflet.markercluster
let markers = L.markerClusterGroup();
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
}) /*.addTo(this.map)*/ ; // <= do not add individual `marker` to map!
markers.addLayer(marker); // <= but only to MCG
}
this.map.addLayer(markers);
},
},
});
<script src="https://unpkg.com/vue@2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster@1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 180px"></div>
</div>
为了更好的表现
处理大量标记时,请确保使用 markercluster
的缩放功能。他们在 markerClusterGroup
上有 batch methods for adding and removing lots of markers: addLayers()
, removeLayers()
, and clearLayers()
. They are much more performant. Also note that you can use the chunkedLoading
选项。允许您经常 return 主线程,使 UI 更敏捷。
所以扩展上面 @ghybs 的答案。我会像这样调整代码段:
new Vue({
el: '#app',
data: {
map: null,
tileLayer: null,
},
mounted() {
this.initMap();
setTimeout(() => {
this.initLocation()
}, 100)
},
methods: {
initMap() {
this.map = L.map(this.$refs.map).setView([53.9, 27.6], 9);
this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 19,
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
});
this.tileLayer.addTo(this.map);
},
initLocation() {
//Leaflet.markercluster
const markerClusterGroup = L.markerClusterGroup({
chunkedLoading: true
}); // <= Add chunked loading here
function r(min, max) {
return Math.random() * (max - min) + min;
}
let icon = L.divIcon({
className: 'icon'
});
const markers = []
// Quick test with 5k markers:
for (let i = 0; i < 5000; i++) {
let marker = L.marker([
r(53.82477192, 53.97365592),
r(27.3878027, 27.70640622)
], {
icon: icon
})
markers.push(marker)
// markers.addLayer(marker); // <= do not add individual marker to MCG
}
markerClusterGroup.addLayers(markers) // <= use batch method to add markers to MCG
this.map.addLayer(markerClusterGroup);
},
},
});
<script src="https://unpkg.com/vue@2"></script>
<!-- Leaflet assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<!-- Leaflet.markercluster assets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet.markercluster@1.3.0/dist/MarkerCluster.Default.css">
<script src="https://unpkg.com/leaflet.markercluster@1.3.0/dist/leaflet.markercluster-src.js"></script>
<div id="app">
<div ref="map" style="height: 300px"></div>
</div>
希望对其他人有所帮助。