angular - 提高地图绘制和过滤的性能 - Angular 8,LeafletJS
问题描述
我有一张leafletjs 地图,上面有8,200 个圆形标记。我有 8 个垫子选择列表,旁边有值。基本思想是您选择一个值,然后根据选择过滤标记。
一切正常,问题是性能不是最好的;用于加载屏幕并进行过滤。
角度组件代码:
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { MatSelectionList, MatSelectionListChange } from '@angular/material';
import { SelectionModel } from '@angular/cdk/collections';
import { DataService } from 'src/app/services/data.service';
import stores from 'src/assets/stores.json';
import filterTestStores from 'src/assets/filter-stores.json';
import filterTestRegions from 'src/assets/filter-regions.json';
import filterTestCities from 'src/assets/filter-cities.json';
import filterTestStates from 'src/assets/filter-states.json';
import filterTestRaces from 'src/assets/filter-races.json';
import filterTestAreas from 'src/assets/filter-urban.json';
import filterTestSeasons from 'src/assets/filter-season.json';
import filterTestPlanograms from 'src/assets/filter-planogram.json';
import filterTestTimes from 'src/assets/filter-time.json';
declare var $: any;
declare let L;
@Component({
selector: 'app-test-location',
templateUrl: './test-location.component.html',
styleUrls: ['./test-location.component.scss']
})
export class TestLocationComponent implements OnInit, OnDestroy {
@ViewChild('regions', {static: false}) regions: MatSelectionList;
@ViewChild('states', {static: false}) states: MatSelectionList;
@ViewChild('cities', {static: false}) cities: MatSelectionList;
@ViewChild('races', {static: false}) races: MatSelectionList;
@ViewChild('areas', {static: false}) areas: MatSelectionList;
@ViewChild('seasons', {static: false}) seasons: MatSelectionList;
@ViewChild('planograms', {static: false}) planograms: MatSelectionList;
@ViewChild('times', {static: false}) times: MatSelectionList;
constructor(public _dataService: DataService) {
}
map: any;
markers: any;
defaultMarkerGroup: any;
showDefault = true;
testFilterMarkerGroup: any;
myRenderer: any;
regionsList: string[] = filterTestRegions
statesList: string[] = filterTestStates
cityList: string[] = filterTestCities;
storeList: number[] = filterTestStores;
racesList: string[] = filterTestRaces;
areasList: string[] = filterTestAreas;
seasonsList: string[] = filterTestSeasons;
planogramsList: string[] = filterTestPlanograms;
timesList: string[] = filterTestTimes;
removeDuplicates(myArr, prop) {
return myArr.filter((obj, pos, arr) => {
return arr.map(mapObj => mapObj[prop]).indexOf(obj[prop]) === pos;
});
}
ngOnDestroy() {
this._dataService.setSelectedMapList("regionsList", this.regions.selectedOptions.selected);
this._dataService.setSelectedMapList("statesList", this.states.selectedOptions.selected);
this._dataService.setSelectedMapList("citiesList", this.cities.selectedOptions.selected);
this._dataService.setSelectedMapList("racesList", this.races.selectedOptions.selected);
this._dataService.setSelectedMapList("areasList", this.areas.selectedOptions.selected);
this._dataService.setSelectedMapList("seasonsList", this.seasons.selectedOptions.selected);
this._dataService.setSelectedMapList("planogramsList", this.planograms.selectedOptions.selected);
this._dataService.setSelectedMapList("timesList", this.times.selectedOptions.selected);
this._dataService.setSameLocationArea(true);
if(this.showDefault) {
this._dataService.setUniverseSize(this.defaultMarkerGroup.getLayers().length);
} else {
this._dataService.setUniverseSize(this.testFilterMarkerGroup.getLayers().length);
}
}
ngOnInit() {
// this.regionsList = this.removeDuplicates(stores, "MARKET UNIT");
// this.filteredRegions = this.removeDuplicates(stores, "MARKET UNIT");
// this.statesList = this.removeDuplicates(stores, "State Abbreviation");
// this.cityList = this.removeDuplicates(stores, "CITY");
// this.racesList = this.removeDuplicates(stores, "Race");
// this.areasList = this.removeDuplicates(stores, "Urbanicity");
// this.seasonsList = this.removeDuplicates(stores, "Seasonality");
// this.planogramsList = this.removeDuplicates(stores, "Planogram");
// this.timesList = this.removeDuplicates(stores, "Time Open");
this.map = L.map('map').setView([37.8, -96], 4);
this.myRenderer = L.canvas({ padding: 0.2 });
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token={accessToken}', {
attribution: 'Map data © <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
maxZoom: 18,
id: 'mapbox.light',
accessToken: 'pk.eyJ1IjoiY29sdHN0cmVldCIsImEiOiJjanFjZmZsODIwcDNoNDJud3gzMjI4OGF4In0.h9uLyByXir4aaTDxRxleiA'
}).addTo(this.map);
// setup a marker group
this.defaultMarkerGroup = L.featureGroup().addTo(this.map);
//Apply Markers
for (var i = 0; i < stores.length; i++) {
L.circleMarker([stores[i].LATITUDE, stores[i].LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.defaultMarkerGroup).bindPopup('marker ' + i);
}
let svc = this;
$(document).ready(function() {
// svc.regions.selectAll();
// svc.states.selectAll();
// svc.cities.selectAll();
// svc.races.selectAll();
});
this.map.fitBounds(this.defaultMarkerGroup.getBounds());
}
clearStoreMarkers() {
this.map.removeLayer(this.testFilterMarkerGroup);
this.map.addLayer(this.defaultMarkerGroup);
this.showDefault = true;
this.regions.deselectAll();
this.states.deselectAll();
this.cities.deselectAll();
this.races.deselectAll();
this.areas.deselectAll();
this.seasons.deselectAll();
this.planograms.deselectAll();
this.times.deselectAll();
}
filterMarkers() {
this.map.removeLayer(this.defaultMarkerGroup);
if (this.testFilterMarkerGroup) {
this.map.removeLayer(this.testFilterMarkerGroup);
}
// setup a marker group
this.testFilterMarkerGroup = L.featureGroup().addTo(this.map);
if (this.regions.selectedOptions.selected.length === 0 &&
this.states.selectedOptions.selected.length === 0 &&
this.cities.selectedOptions.selected.length === 0 &&
this.races.selectedOptions.selected.length === 0 &&
this.areas.selectedOptions.selected.length === 0 &&
this.seasons.selectedOptions.selected.length === 0 &&
this.planograms.selectedOptions.selected.length === 0 &&
this.times.selectedOptions.selected.length === 0) {
this.map.addLayer(this.defaultMarkerGroup);
this.showDefault = true;
this.map.fitBounds(this.defaultMarkerGroup.getBounds());
} else { //Apply Markers
this.showDefault = false;
for (var i = 0; i < stores.length; i++) {
let store = stores[i];
this.regions.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["MARKET UNIT"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
this.states.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["State Abbreviation"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
this.cities.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["CITY"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
this.races.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["Race"]["Ethnicity"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
this.areas.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["Urbanicity"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
this.seasons.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["Seasonality"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
this.planograms.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["Planogram"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
this.times.selectedOptions.selected.forEach((selection: any, key: any) => {
if (store["Time Open"].toLowerCase() === selection.value.toLowerCase()) {
//Add Marker
L.circleMarker([store.LATITUDE, store.LONGITUDE], {
radius: 5,
color: "green",
renderer: this.myRenderer
}).addTo(this.testFilterMarkerGroup).bindPopup('marker ' + i);
}
});
}
this.map.fitBounds(this.testFilterMarkerGroup.getBounds());
}
}
selectAll(filter) {
filter.selectAll();
this.filterMarkers();
}
deselectAll(filter) {
filter.deselectAll();
this.filterMarkers();
}
onSelection(evt, property) {
// this.filteredRegions = [];
// if (evt.option.selectionList.selectedOptions.selected.length === 0) {
// this.filteredRegions.push(...this.regionsList);
// } else {
// this.filteredRegions = stores.filter(function (region) {
// return region[property] === evt.option.value;
// });
// this.filteredRegions = this.removeDuplicates(this.filteredRegions, "MARKET UNIT");
// }
this.filterMarkers();
}
}
这是HTML:
<mat-toolbar class="header">
<mat-toolbar-row>
<a mat-icon-button matTooltip="Back to Step 3" routerLink="/stepThree" routerLinkActive="active">
<i class="far fa-caret-square-left fa-3x"></i>
</a>
<div class="header-img">
<img src="/assets/images/Dollar_Tree_logo.png">
</div>
<img class="dv-logo" src="/assets/images/DV-Transparent.png">
<!-- <span class="spacer"></span> -->
<a mat-icon-button matTooltip="Review and Submit" routerLink="/review" routerLinkActive="active">
<i class="far fa-caret-square-right fa-3x"></i>
</a>
</mat-toolbar-row>
</mat-toolbar>
<div class="col-12 p-0 step-header">
<button mat-icon-button class="export-button" matTooltip="Export Selected Stores">
<i class="fas fa-share"></i>
</button>
<div>Test & Control Universe Selection</div>
<button mat-icon-button class="export-all-button" matTooltip="Export All Stores">
<i class="fas fa-share-square"></i>
</button>
</div>
<div class="row filter-bk">
<div class="col-md-3 text-center store-filter-content">
<button mat-raised-button class="mt-1" (click)="clearStoreMarkers()">Reset</button>
<mat-card class="filter-section">
<div>Region</div>
<mat-divider></mat-divider>
<mat-selection-list #regions (selectionChange)="onSelection($event, 'MARKET UNIT')">
<mat-list-option *ngFor="let region of regionsList" [value]='region'>
<span>{{region}}</span>
</mat-list-option>
</mat-selection-list>
</mat-card>
<mat-card class="filter-section">
<div>State</div>
<mat-divider></mat-divider>
<mat-selection-list #states (selectionChange)="onSelection($event, 'State Abbreviation')">
<mat-list-option *ngFor="let state of statesList" [value]='state'>
{{state}}
</mat-list-option>
</mat-selection-list>
</mat-card>
<mat-card class="filter-section">
<div>City</div>
<mat-divider></mat-divider>
<mat-selection-list #cities (selectionChange)="onSelection()">
<mat-list-option *ngFor="let city of cityList" [value]='city'>
{{city}}
</mat-list-option>
</mat-selection-list>
</mat-card>
<mat-card class="filter-section">
<div>Race/Ethnicity</div>
<mat-divider></mat-divider>
<mat-selection-list #races (selectionChange)="onSelection()">
<mat-list-option *ngFor="let race of racesList" [value]='race'>
{{race}}
</mat-list-option>
</mat-selection-list>
</mat-card>
<mat-card class="filter-section">
<div>Urbanicity</div>
<mat-divider></mat-divider>
<mat-selection-list #areas (selectionChange)="onSelection()">
<mat-list-option *ngFor="let area of areasList" [value]='area'>
{{area}}
</mat-list-option>
</mat-selection-list>
</mat-card>
<mat-card class="filter-section">
<div>Seasonality</div>
<mat-divider></mat-divider>
<mat-selection-list #seasons (selectionChange)="onSelection()">
<mat-list-option *ngFor="let season of seasonsList" [value]='season'>
{{season}}
</mat-list-option>
</mat-selection-list>
</mat-card>
<mat-card class="filter-section">
<div>Planogram</div>
<mat-divider></mat-divider>
<mat-selection-list #planograms (selectionChange)="onSelection($event, 'Planogram')">
<mat-list-option *ngFor="let planogram of planogramsList" [value]='planogram'>
{{planogram}}
</mat-list-option>
</mat-selection-list>
</mat-card>
<mat-card class="filter-section">
<div>Store Open Duration</div>
<mat-divider></mat-divider>
<mat-selection-list #times (selectionChange)="onSelection()">
<mat-list-option *ngFor="let time of timesList" [value]='time'>
{{time}}
</mat-list-option>
</mat-selection-list>
</mat-card>
</div>
<div class="col-md-9 p-0 m-0">
<div id="map"></div>
</div>
</div>
解决方案
我将开始研究https://angular.io/api/core/ChangeDetectionStrategy和https://angular.io/api/core/ChangeDetectorRef
在第二个链接中有一个如何使用变化检测策略和变化检测参考的例子。试试看,让我们知道它是否有助于解决性能问题。
推荐阅读
- webpack - VSCode 扩展从开发中运行,但在使用 webpack 打包时不起作用
- mysql - 更新特定数据库(Mysql)的每个表中特定列的所有行
- html - 当我减小屏幕尺寸时,如何均匀地修剪图像的左右两侧?(@媒体查询)
- python - discord.py:你能从他们的 id 中获取不在你的机器人服务器中的用户的名字吗?
- c# - 我如何获得完全像这样的菜单控制?
- c# - 尝试使用 TryValidateModel 验证控制器中的输入对象时单元测试失败
- yocto - 如何使用 Yocto 修改 rootfs 配置文件?
- node.js - SequelizeDatabaseError:列“functionCode”不存在,当它存在时
- javascript - 在 Vue.js 中更改 DIV 网格上的背景颜色而不更改其他人的背景
- dart - 如何在 Dart 构造函数中设置 final/const 属性