谷歌地图v3:使用自定义标记进行聚类

时间:2011-11-28 14:40:17

标签: javascript google-maps google-maps-api-3

我正在尝试使用MarkerClusterer对地图上的标记进行聚类。 问题是我没有使用默认标记( google.maps.Marker ),而是使用 google.maps.OverlayView 中的自定义类。 不幸的是,似乎该库是在假定使用基本标记的情况下开发的,事实上我得到错误,因为我的类没有实现 google.maps.Marker 中定义的方法。 是否可以通过保留自定义标记来使用 MarkerClusterer

编辑:它比我想象的容易得多,我通过在自定义类中实现2个方法解决了这个问题:

setVisible() getPosition()

为了帮助其他人,以下是我的完整界面(没有完整实现):

BFPushpin = function(config) 
{
    this.setMap(config.map);
    this.set("position", config.position);
    // other settings...
};

// my class extends google.maps.OverlayView
BFPushpin.prototype = new google.maps.OverlayView();

BFPushpin.prototype.getBounds = function() 
{
    return new google.maps.LatLngBounds(this.position, this.position); 
};

BFPushpin.prototype.getPoint = function() 
{
    var bounds = this.getBounds();
    var projection = this.getProjection();
    var sw = projection.fromLatLngToDivPixel(bounds.getSouthWest());  
        var ne = projection.fromLatLngToDivPixel(bounds.getNorthEast()); 

    return new google.maps.Point(sw.x, ne.y);
};

BFPushpin.prototype.getSuperContainer = function()
{
    var panes = this.getPanes();
    return jQuery(panes ? panes.overlayImage : "");
};

BFPushpin.prototype.getContainer = function()
{
    // return inner container
};

BFPushpin.prototype._generatePopupContent = function()
{
    // return markup for the popupwindow
};

BFPushpin.prototype._addListeners = function()
{
    // add handlers for the pushpin
};

BFPushpin.prototype.onAdd = function()
{
    // customize content here
};

BFPushpin.prototype.onRemove = function()
{
    // remove pin container here
};

BFPushpin.prototype.draw = function()
{
    // set display style here
};

BFPushpin.prototype.setVisible = function(visible)
{
    // set display block or hidden
};

BFPushpin.prototype.getPosition = function()
{
    return this.position;
};

3 个答案:

答案 0 :(得分:1)

或者只定义MarkerClusterer对标记所期望的功能。 setMap和getPosition()以及其他一些。

答案 1 :(得分:0)

您应该以这样的方式定义新的标记类,即它也从google.maps.Marker继承(即它实现了它的接口)。 MarkerClusterer使用这个接口是合乎逻辑的 - 它必须假设标记是标记才能使用它们: - )

答案 2 :(得分:0)

希望这也将有助于尝试使此解决方案起作用的人们。感谢@daveoncode的示例。我能够对其进行修改以使其对我有用:

renderMap() {
    const mapProperties = {
        center: new google.maps.LatLng(34.0234, -84.6155),
        zoom: 10,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    this.map = new google.maps.Map(this.mapElement.nativeElement, mapProperties);

    let markers = [];
    for (let i=0; i<this._sitesList.length; i++) {
        let bounds = new google.maps.LatLngBounds(
            new google.maps.LatLng(this._sitesList[i].lat, this._sitesList[i].lon)
        );
        let position = new google.maps.LatLng(this._sitesList[i].lat, this._sitesList[i].lon);
        let html = this.makeHtmlForSitePanel(i, this._sitesList[i]); // I have a function to return html for my OverlayView panels here.
        markers.push( this.generateSitePanel(bounds, html, this.map, position) );
    }

    var markerCluster = new MarkerClusterer(this.map, markers, {
        imagePath: 'https://developers.google.com/maps/documentation/javascript/examples/markerclusterer/m'
    });

}

generateSitePanel(bounds, html, map, position) {

    SitePanel.prototype = new google.maps.OverlayView();

    function SitePanel (bounds, html, map, position) {
        this.bounds_ = bounds;
        this.set('position', position);
        this.html_ = html;
        this.map_ = map;
        this.div_ = null;
        this.setMap(map);
    }

    SitePanel.prototype.getBounds = function() {
        return new google.maps.LatLngBounds(this.position, this.position); 
    };

    SitePanel.prototype.getPoint = function() {
        var bounds = this.getBounds();
        var projection = this.getProjection();
        var sw = projection.fromLatLngToDivPixel(bounds.getSouthWest());  
            var ne = projection.fromLatLngToDivPixel(bounds.getNorthEast()); 

        return new google.maps.Point(sw.x, ne.y);
    };

    SitePanel.prototype.getSuperContainer = function(){
        var panes = this.getPanes();
        return $(panes ? panes.overlayImage : '');
    };

    SitePanel.prototype.getContainer = function()
    {
        // return inner container
        // I don't have anything for this one
    };

    SitePanel.prototype.getPosition = function() {
        return this.position;
    };

    SitePanel.prototype.onAdd = function() {
        var div = document.createElement('div');
        div.className = 'tooltip-container-';
        div.innerHTML = this.html_;
        div.style.position = 'absolute';
        this.div_ = div;
        var panes = this.getPanes();
        panes.overlayImage.appendChild(div);
    };

    SitePanel.prototype.draw = function() {
        var overlayProjection = this.getProjection();
        var sw = overlayProjection.fromLatLngToDivPixel(this.bounds_.getSouthWest());
        var ne = overlayProjection.fromLatLngToDivPixel(this.bounds_.getNorthEast());

        var div = this.div_;
        div.style.left = sw.x + 'px';
        div.style.top = ne.y + 20 + 'px';
    };

    SitePanel.prototype.onRemove = function() {
        this.div_.parentNode.removeChild(this.div_);
        this.div_ = null;
    };

    return new SitePanel(bounds, html, map, position);
}