Problem specification

In map development, after drawing a large number of marker points in the local map, no matter dragging or zooming, you will feel the obvious lag phenomenon. In daily work, the real-time monitoring page of the company needs to show the real-time positioning and tracking of 5000-20,000 vehicles, especially when it switches to ports with dense vehicles, the phenomenon of lag is very serious (as shown in the picture below), which looks very ugly and the user experience is very poor. Write down some of the development and optimization experience here (this article uses Amap for reference).

solution

  1. Firstly, we should add all overlay groups (including Marker,Icon,Text and Polygon) on the map to multiple overlay groups for unified management of each category. Some coverings are hidden by default and only displayed when needed.

  2. Instead of attaching a lot of overlay information directly to the map object, it can be loaded on demand, reducing the amount of work to re-render the map after it is moved

  3. Rational use of mulch polymerization (polymerization will reduce the lag, but too many mulches will still be stuck)

The solution

First of all, add a map setting check panel to classify all coverings except vehicle point markers by type and add them to a separate OverlayGroup. By default, they will not be mounted on the map, and then call the overlaygroup.setmap (map) method to add them to the map. The removal of these unnecessary coverings makes the first entry feel much cleaner.

Despite the removal of all kinds of dots, text, and other coverings, there are still a lot of vehicle markers we need to render. On this basis, we adopt on-screen loading to screen out the points in the screen, and do not render the points outside the screen. Monitor moveEnd, ZoomEnd and resize of each map, and recalculate the points in the screen after each change. When the points in the screen are less than 200 (this depends on personal needs), Directly on the map. When the number of markers on the screen is larger than 200, call the aggregation method to aggregate the markers and draw them on the map.

Reference code

/** Listen for map drags, zoom in on events, dynamically render points based on screen scope */reloadMarks(){
        AMap.event.addListener(this.map,'moveend',()=> {
          this.computeMarkers();
        })
        AMap.event.addListener(this.map,'zoomend',()=> {
          this.computeMarkers();
        })
        AMap.event.addListener(this.map,'resize',()=> { this.computeMarkers(); })}, /** Select marker */ based on the current screen rangecomputeMarkers(){ this.newViewData={}; // Get the current view rangeletnow_bounds = this.map.getBounds(); In order to reduce the duplicate data passed in the background, my vehicle information list is always saved using objectsfor(let sel_deviceNo in this.carDataObj0){
          letitem=this.carDataObj0[sel_deviceNo]; // Determine whether the current point coordinates exist in the viewif(now_bounds.contains(item.gcj02_coords.split(', '))){// Save this. NewViewData [sel_deviceNo] = item; } } this.renderMarker(); now_bounds=null; }, /** create aggregation **/ createCluser(markerArr) {amap.plugin (['AMap.MarkerClusterer'], () => { this.cluster = new AMap.MarkerClusterer(this.map, markerArr, { gridSize: 80, renderCluserMarker, minClusterSize: 1, maxZoom: 18 }); })}, /** put markers on the map */renderMarker(){// Determine if there is currently a current overlay group! this.overLayGroup && this.overLayGroup = new AMap.OverlayGroup([]);let MarkerAddArr = [];
        for(let sel_deviceNo inThis.newviewdata){/** All Marker point objects I create are permanently stored in this.markerobj and are not destroyedsetPosition(),setAngle(),setIcon() and other methods to change the state, and then select the need to mount together to add to the map **/if(this.markerObj[sel_deviceNo]){ MarkerAddArr.push(this.markerObj[sel_deviceNo]); } } this.overLayGroup.clearOverlays(); // If the number of points exceeds 200, aggregation mode is enabled and no panel display points are rendered in aggregation modeif(MarkerAddArr.length>=200){
            if(this.cluster){
              this.cluster.clearMarkers();
              this.cluster.setMarkers(MarkerAddArr);
            }else{ this.createCluser(MarkerAddArr); }}else{
            if(this.cluster){
                this.cluster.clearMarkers();
            }
            this.overLayGroup.addOverlays(MarkerAddArr);
            this.overLayGroup.setMap(this.map);
        }
        MarkerAddArr=null;
      },
Copy the code

The code is directly copied from the business, the coupling degree is relatively high, please forgive me. After loading markers by screen group, we added a simple anti-shake method to prevent computeMarkers methods from being triggered by continuous dragging or zooming, reducing the number of method calls

const debounce = (fn, wait= = > {500)return function() {
    clearTimeout(fn.timer)
    fn.timer = setTimeout(fn.bind(this, ... arguments),wait)}}Copy the code

The result is as follows: reduce the calculation and rendering of the map, only count the points in the field of view each time, so the size of the total number does not affect the map performance, when the field of view is more than 200 points will be aggregated, display below 200.