在带有旋转的angularjs谷歌地图中显示100多个标记

在带有旋转的angularjs谷歌地图中显示100多个标记,angularjs,google-maps,ng-map,Angularjs,Google Maps,Ng Map,我一直在使用ngMap和我的angularjs代码来显示标记。然而,对于100多个标记,我注意到性能有相当大的下降,主要与ng重复和双向绑定有关。我想添加带有自定义HTML元素的标记,类似于CustomMarker,但使用普通标记,并在需要时从controller进行修改 面临的挑战: 我有SVG图像,需要根据条件动态着色(这些SVG不是单路径图像,因此当我将其与Symbol一起使用时,似乎无法正常工作) 这些是车辆标记,因此应支持旋转 我通过创建带有覆盖的CustomMarker解决了这个问题

我一直在使用ngMap和我的angularjs代码来显示标记。然而,对于100多个标记,我注意到性能有相当大的下降,主要与ng重复和双向绑定有关。我想添加带有自定义HTML元素的标记,类似于CustomMarker,但使用普通标记,并在需要时从controller进行修改

面临的挑战:

  • 我有SVG图像,需要根据条件动态着色(这些SVG不是单路径图像,因此当我将其与Symbol一起使用时,似乎无法正常工作)
  • 这些是车辆标记,因此应支持旋转

  • 我通过创建带有覆盖的CustomMarker解决了这个问题,然后将仅存在于当前地图边界中的标记添加到地图中,这样地图就不会滞后

    下面是我实现它的代码片段

    createCustomMarkerComponent();
    
    /**
     * options  : [Object]  : options to be passed on
     *                                          -   position    : [Object]  : Google maps latLng object
     *                                          -   map             : [Object]  : Google maps instance
     *                                          -   markerId    : [String]  : Marker id
     *                                          - innerHTML : [String]  : innerHTML string for the marker
     **/
    function CustomMarker(options) {
        var self = this;
    
        self.options = options || {};
    
        self.el = document.createElement('div');
        self.el.style.display = 'block';
        self.el.style.visibility = 'hidden';
    
        self.visible = true;
        self.display = false;
    
        for (var key in options) {
            self[key] = options[key];
        }
    
        self.setContent();
    
        google.maps.event.addListener(self.options.map, "idle", function (event) {
            //This is the current user-viewable region of the map
            var bounds = self.options.map.getBounds();
            checkElementVisibility(self, bounds);
        });
    
        if (this.options.onClick) {
            google.maps.event.addDomListener(this.el, "click", this.options.onClick);
        }
    
    }
    
    function checkElementVisibility(item, bounds) {
        //checks if marker is within viewport and displays the marker accordingly - triggered by google.maps.event "idle" on the map Object
        if (bounds.contains(item.position)) {
            //If the item isn't already being displayed
            if (item.display != true) {
                item.display = true;
                item.setMap(item.options.map);
            }
        } else {
            item.display = false;
            item.setMap(null);
        }
    }
    
    var supportedTransform = (function getSupportedTransform() {
        var prefixes = 'transform WebkitTransform MozTransform OTransform msTransform'.split(' ');
        var div = document.createElement('div');
        for (var i = 0; i < prefixes.length; i++) {
            if (div && div.style[prefixes[i]] !== undefined) {
                return prefixes[i];
            }
        }
        return false;
    })();
    
    
    function createCustomMarkerComponent() {
    
        if (window.google) {
    
            CustomMarker.prototype = new google.maps.OverlayView();
    
            CustomMarker.prototype.setContent = function () {
                this.el.innerHTML = this.innerHTML;
                this.el.style.position = 'absolute';
                this.el.style.cursor = 'pointer';
                this.el.style.top = 0;
                this.el.style.left = 0;
            };
    
            CustomMarker.prototype.getPosition = function () {
                return this.position;
            };
    
            CustomMarker.prototype.getDraggable = function () {
                return this.draggable;
            };
    
            CustomMarker.prototype.setDraggable = function (draggable) {
                this.draggable = draggable;
            };
    
            CustomMarker.prototype.setPosition = function (position) {
                var self = this;
                return new Promise(function () {
                    position && (self.position = position); /* jshint ignore:line */
                    if (self.getProjection() && typeof self.position.lng == 'function') {
                        var setPosition = function () {
                            if (!self.getProjection()) {
                                return;
                            }
                            var posPixel = self.getProjection().fromLatLngToDivPixel(self.position);
                            var x = Math.round(posPixel.x - (self.el.offsetWidth / 2));
                            var y = Math.round(posPixel.y - self.el.offsetHeight + 10); // 10px for anchor; 18px for label if not position-absolute
                            if (supportedTransform) {
                                self.el.style[supportedTransform] = "translate(" + x + "px, " + y + "px)";
                            } else {
                                self.el.style.left = x + "px";
                                self.el.style.top = y + "px";
                            }
                            self.el.style.visibility = "visible";
                        };
                        if (self.el.offsetWidth && self.el.offsetHeight) {
                            setPosition();
                        } else {
                            //delayed left/top calculation when width/height are not set instantly
                            setTimeout(setPosition, 300);
                        }
                    }
                });
            };
    
            CustomMarker.prototype.setZIndex = function (zIndex) {
                if (zIndex === undefined) return;
                (this.zIndex !== zIndex) && (this.zIndex = zIndex); /* jshint ignore:line */
                (this.el.style.zIndex !== this.zIndex) && (this.el.style.zIndex = this.zIndex);
            };
    
            CustomMarker.prototype.getVisible = function () {
                return this.visible;
            };
    
            CustomMarker.prototype.setVisible = function (visible) {
                if (this.el.style.display === 'none' && visible) {
                    this.el.style.display = 'block';
                } else if (this.el.style.display !== 'none' && !visible) {
                    this.el.style.display = 'none';
                }
                this.visible = visible;
            };
    
            CustomMarker.prototype.addClass = function (className) {
                var classNames = this.el.className.trim().split(' ');
                (classNames.indexOf(className) == -1) && classNames.push(className); /* jshint ignore:line */
                this.el.className = classNames.join(' ');
            };
    
            CustomMarker.prototype.removeClass = function (className) {
                var classNames = this.el.className.split(' ');
                var index = classNames.indexOf(className);
                (index > -1) && classNames.splice(index, 1); /* jshint ignore:line */
                this.el.className = classNames.join(' ');
            };
    
            CustomMarker.prototype.onAdd = function () {
                this.getPanes().overlayMouseTarget.appendChild(this.el);
                // this.getPanes().markerLayer.appendChild(label-div); // ??
    
            };
    
            CustomMarker.prototype.draw = function () {
                this.setPosition();
                this.setZIndex(this.zIndex);
                this.setVisible(this.visible);
            };
    
            CustomMarker.prototype.onRemove = function () {
                this.el.parentNode.removeChild(this.el);
                // this.el = null;
            };
    
        } else {
            setTimeout(createCustomMarkerComponent, 200);
        }
    
    }
    
    createCustomMarkerComponent();
    /**
    *选项:[对象]:要传递的选项
    *-位置:[对象]:谷歌地图定位对象
    *-map:[对象]:谷歌地图实例
    *-markerId:[字符串]:标记id
    *-innerHTML:[字符串]:标记的innerHTML字符串
    **/
    功能自定义标记(选项){
    var self=这个;
    self.options=options |{};
    self.el=document.createElement('div');
    self.el.style.display='block';
    self.el.style.visibility='hidden';
    self.visible=true;
    self.display=false;
    for(变量输入选项){
    自[键]=选项[键];
    }
    self.setContent();
    google.maps.event.addListener(self.options.map,“idle”,函数(事件){
    //这是地图的当前用户可查看区域
    var bounds=self.options.map.getBounds();
    checkElementVisibility(自、边界);
    });
    if(this.options.onClick){
    google.maps.event.addDomListener(this.el,“click”,this.options.onClick);
    }
    }
    函数checkElementVisibility(项、边界){
    //检查标记是否在视口中,并相应地显示标记-由地图对象上的google.maps.event“idle”触发
    if(边界包含(项目位置)){
    //如果项目尚未显示
    如果(item.display!=true){
    item.display=true;
    setMap(item.options.map);
    }
    }否则{
    item.display=false;
    item.setMap(空);
    }
    }
    var supportedTransform=(函数getSupportedTransform(){
    var前缀='transform webkitttransform mozortransform msTransform'.split('');
    var div=document.createElement('div');
    for(var i=0;i