在angularjs Google地图中旋转显示100多个标记

时间:2018-06-30 08:47:54

标签: angularjs google-maps ng-map

我一直在使用ngMap和我的angularjs代码来显示标记。但是,我注意到使用100多个标记时,性能显着下降,主要与ng重复和双向结合有关。我想添加带有与CustomMarker类似的自定义HTML元素的标记,但使用普通的标记,并在需要时从控制器进行修改。

面临的挑战:

  1. 我有需要根据条件动态着色的SVG图像(这些SVG并非单路径,因此与Symbol配合使用时似乎效果不佳)
  2. 这些是车辆标记,因此应该支持旋转

1 个答案:

答案 0 :(得分:1)

我已解决此问题,方法是使用Overlay创建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);
    }

}

checkElementVisibility 功能有助于识别是否应显示标记。

如果有更好的解决方案,请在此处添加。谢谢!