使用sebm-angular2-google-map实现OverlappingMarkerSpidifier [英] Implementing OverlappingMarkerSpidifier with sebm-angular2-google-map

查看:166
本文介绍了使用sebm-angular2-google-map实现OverlappingMarkerSpidifier的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过 OverlappingMarkerSpidifier / SebastianM / angular2-google-mapsrel =nofollow> SebM Angular 2 Google Maps on angular2 2.0.0。

我已经使用从sebm模块导入的GoogleMapsAPIWrapper成功加载了google maps API。一旦它被加载,我正在执行从仓库下载的OMW脚本,我添加了一个module.exports语句。但是,我收到以下错误消息:

pre $ uncaught TypeError:this.constructor.ProjHelper不是构造函数

以下是OMW代码:

  / ** @preserve OverlappingMarkerSpiderfier 
https://github.com/jawj/OverlappingMarkerSpiderfier
Copyright(c)2011 - 2013 George MacKerron
根据MIT许可证发布:http: //opensource.org/licenses/mit-license
注意:必须在此代码之前包含Google Maps API v3 * b

$ b module.exports = function( ){

var __hasProp = {} .hasOwnProperty,__slice = [] .slice;
var ge,gm,lcH,lcU,mt,p,twoPi,x,_i,_len,_ref;

p = _Class.prototype;

_ref = [_Class,p]; $ _ b $ for(_i = 0,_len = _ref.length; _i <_len; _i ++){
x = _ref [_i];
x ['VERSION'] ='0.3.3';
}

gm = google.maps;

ge = gm.event;

mt = gm.MapTypeId;

twoPi = Math.PI * 2;

p ['keepSpiderfied'] = false;

p ['markersWontHide'] = false;

p ['markersWontMove'] = false;

p ['nearbyDistance'] = 20;

p ['circleSpiralSwitchover'] = 9;

p ['circleFootSeparation'] = 23;

p ['circleStartAngle'] = twoPi / 12;

p ['spiralFootSeparation'] = 26;

p ['spiralLengthStart'] = 11;

p ['spiralLengthFactor'] = 4;

p ['spiderfiedZIndex'] = 1000;

p ['usualLegZIndex'] = 10;

p ['highlightedLegZIndex'] = 20;

p ['event'] ='点击';

p ['minZoomLevel'] = false;

p ['legWeight'] = 1.5;

p ['legColors'] = {
'通常':{},
'突出显示':{}
};

lcU = p ['legColors'] ['usual'];

lcH = p ['legColors'] ['highlight'];

lcU [mt.HYBRID] = lcU [mt.SATELLITE] ='#fff';

lcH [mt.HYBRID] = lcH [mt.SATELLITE] ='#f00';

lcU [mt.TERRAIN] = lcU [mt.ROADMAP] ='#444';

lcH [mt.TERRAIN] = lcH [mt.ROADMAP] ='#f00';

函数_Class(map,opts){
var e,k,v,_j,_len1,_ref1;
this.map = map;
if(opts == null){
opts = {};
}
for(k in opts){
if(!__ hasProp.call(opts,k))continue;
v = opts [k];
this [k] = v;
}
this.projHelper = new this.constructor.ProjHelper(this.map);
this.initMarkerArrays();
this.listeners = {};
_ref1 = ['click','zoom_changed','maptypeid_changed']; $ _ b $ for(_j = 0,_len1 = _ref1.length; _j <_len1; _j ++){
e = _ref1 [_j];
ge.addListener(this.map,e,(function(_this){
return function(){
return _this ['unspiderfy']();
};
})(this));



p.initMarkerArrays = function(){
this.markers = [];
返回this.markerListenerRefs = [];
};

p ['addMarker'] = function(marker){
var listenerRefs;
if(marker ['_ oms']!= null){
return this;
}
marker ['_ oms'] = true;
listenerRefs = [
ge.addListener(marker,this ['event'],(function(_this){
return function(event){
return _this.spiderListener(marker ,event);
};
})(this))
];
if(!this ['markersWontHide']){
listenerRefs.push(ge.addListener(marker,'visible_changed',(function(_this){
return function(){
return _this.markerChangeListener(marker,false);
};
})(this)));

if(!this ['markersWontMove']){
listenerRefs.push(ge.addListener(marker,'position_changed',(function(_this){
return function (){
return _this.markerChangeListener(marker,true);
};
})(this)));
}
this.markerListenerRefs.push(listenerRefs);
this.markers.push(marker);
返回此;
}; $(){

p.markerChangeListener = function(marker,positionChanged){
if((marker ['_ omsData']!= null)&&(positionChanged ||!marker.getVisible() )&&!((this.spiderfying!= null)||(this.unspiderfying!= null))){
return this ['unspiderfy'](positionChanged?marker:null);
}
};

p ['getMarkers'] = function(){
return this.markers.slice(0);
};

p ['removeMarker'] = function(marker){
var i,listenerRef,listenerRefs,_j,_len1;
if(marker ['_ omsData']!= null){
this ['unspiderfy']();
}
i = this.arrIndexOf(this.markers,marker);
if(i <0){
return this;
}
listenerRefs = this.markerListenerRefs.splice(i,1)[0]; $ _ b $ for(_j = 0,_len1 = listenerRefs.length; _j< _len1; _j ++){
listenerRef = listenerRefs [_j];
ge.removeListener(listenerRef);
}
删除标记['_ oms'];
this.markers.splice(i,1);
返回此;
};

p ['clearMarkers'] = function(){
var i,listenerRef,listenerRefs,marker,_j,_k,_len1,_len2,_ref1;
this ['unspiderfy']();
_ref1 = this.markers;
for(i = _j = 0,_len1 = _ref1.length; _j< _len1; i = ++ _ j){
marker = _ref1 [i];
listenerRefs = this.markerListenerRefs [i]; $ _ b $ for(_k = 0,_len2 = listenerRefs.length; _k <_len2; _k ++){
listenerRef = listenerRefs [_k];
ge.removeListener(listenerRef);
}
删除标记['_ oms'];
}
this.initMarkerArrays();
返回此;
};

p ['addListener'] =函数(event,func){
var _base;
((_base = this.listeners)[event]!= null?_base [event]:_base [event] = [])。push(func);
返回此;
};

p ['removeListener'] = function(event,func){
var i;
i = this.arrIndexOf(this.listeners [event],func); (!(i <0)){
this.listeners [event] .splice(i,1);
if(!
}
返回此;
};

p ['clearListeners'] = function(event){
this.listeners [event] = [];
返回此;
};

p.trigger = function(){
var args,event,func,_j,_len1,_ref1,_ref2,_results;
event = arguments [0],args = 2 <= arguments.length? __slice.call(arguments,1):[];
_ref2 =(_ref1 = this.listeners [event])!= null? _ref1:[];
_results = []; (_j = 0,_len1 = _ref2.length; _j< _len1; _j ++){
func = _ref2 [_j];
;
_results.push(func.apply(null,args));
}
return _results;
};

p.generatePtsCircle = function(count,centerPt){
var angle,angleStep,circumference,i,legLength,_j,_results;
circumference = this ['circleFootSeparation'] *(2 + count);
legLength =周长/ twoPi;
angleStep = twoPi / count;
_results = [];
for(i = _j = 0; 0< = count?_j< count:_j> count; i = 0< = count?++ _ j: - _ j){
angle = this ['circleStartAngle'] + i * angleStep;
_results.push(new gm.Point(centerPt.x + legLength * Math.cos(angle),centerPt.y + legLength * Math.sin(angle)));
}
return _results;
};

p.generatePtsSpiral = function(count,centerPt){
var angle,i,legLength,pt,_j,_results;
legLength = this ['spiralLengthStart'];
angle = 0;
_results = [];
for(i = _j = 0; 0< = count?_j< count:_j> count; i = 0< = count?++ _ j: - _ j){
angle + = this ['spiralFootSeparation'] / legLength + i * 0.0005;
pt = new gm.Point(centerPt.x + legLength * Math.cos(angle),centerPt.y + legLength * Math.sin(angle));
legLength + = twoPi * this ['spiralLengthFactor'] / angle;
_results.push(pt);
}
return _results;
};

p.spiderListener = function(marker,event){
var $ this,clear,m,mPt,markerPt,markerSpiderfied,nDist,nearbyMarkerData,nonNearbyMarkers,pxSq,_j,_len1,_ref1 ;
markerSpiderfied = marker ['_ omsData']!= null;
if(!(markerSpiderfied&& this ['keepSpiderfied'])){
if(this ['event'] ==='mouseover'){
$ this = this ;
clear = function(){
return $ this ['unspiderfy']();
};
window.clearTimeout(p.timeout);
p.timeout = setTimeout(clear,3000);
} else {
this ['unspiderfy']();


if(markerSpiderfied || this.map.getStreetView()。getVisible()|| this.map.getMapTypeId()==='GoogleEarthAPI'){
返回this.trigger('click',marker,event);
} else {
nearbyMarkerData = [];
nonNearbyMarkers = [];
nDist = this ['nearbyDistance'];
pxSq = nDist * nDist;
markerPt = this.llToPt(marker.position);
_ref1 = this.markers; (_j = 0,_len1 = _ref1.length; _j< _len1; _j ++){
m = _ref1 [_j]; (!((m.map!= null)&& m.getVisible())){
continue;
if
}
mPt = this.llToPt(m.position); (this.ptDistanceSq(mPt,markerPt)< pxSq){
nearbyMarkerData.push({
marker:m,
markerPt:mPt
});
if
} else {
nonNearbyMarkers.push(m);


if(nearbyMarkerData.length === 1){
return this.trigger('click',marker,event);
} else {
return this.spiderfy(nearbyMarkerData,nonNearbyMarkers);
}
}
};

['markersNearMarker'] = function(marker,firstOnly){
var m,mPt,markerPt,markers,nDist,pxSq,_j,_len1,_ref1,_ref2,_ref3;
if(firstOnly == null){
firstOnly = false;

if(this.projHelper.getProjection()== null){
throw在调用markersNearMarker之前必须等待'idle'事件在地图上;
}
nDist = this ['nearbyDistance'];
pxSq = nDist * nDist;
markerPt = this.llToPt(marker.position);
markers = [];
_ref1 = this.markers; (_j = 0,_len1 = _ref1.length; _j< _len1; _j ++){
m = _ref1 [_j];
if(m === marker ||(m.map == null)||!m.getVisible()){
continue;
}
mPt = this.llToPt((_ ref2 =(_ref3 = m ['_ omsData'])!= null?_ref3.usualPosition:void 0)!= null?_ref2:m.position); (this.ptDistanceSq(mPt,markerPt)< pxSq){
markers.push(m);
if
if(firstOnly){
break;
}
}
}
返回标记;
};

p ['markersNearAnyOtherMarker'] = function(){
var i,i1,i2,m,m1,m1Data,m2,m2Data,mData,nDist,pxSq,_j,_k,_l ,_len1,_len2,_len3,_ref1,_ref2,_ref3,_results;
if(this.projHelper.getProjection()== null){
throw在调用markersNearAnyOtherMarker之前,必须在地图上等待'idle'事件';
}
nDist = this ['nearbyDistance'];
pxSq = nDist * nDist;
mData =(function(){
var _j,_len1,_ref1,_ref2,_ref3,_results;
_ref1 = this.markers;
_results = [];
为(_j = 0,_len1 = _ref1.length; _j <_len1; _j ++){
m = _ref1 [_j];
_results.push({
pt:this.llToPt (_ref2 =(_ref3 = m ['_ omsData'])!= null?_ref3.usualPosition:void 0)!= null?_ref2:m.position),
willSpiderfy:false
});
}
return _results;
})。call(this);
_ref1 = this.markers;
for(i1 = _j = 0,_len1 = _ref1.length; _j <_len1; i1 = ++ _ j){
m1 = _ref1 [i1]; (!((m1.map!= null)&& m1.getVisible())){
continue;
if
}
m1Data = mData [i1];
if(m1Data.willSpiderfy){
continue;
}
_ref2 = this.markers; (i2 = _k = 0,_len2 = _ref2.length; _k <2; i2 = ++ _ k){
m2 = _ref2 [i2];
if(i2 === i1){
continue; $(!2.map!= null)&& m2.getVisible())){
continue;
}
if(!
}
m2Data = mData [i2];
if(i2 continue;
}
if(this.ptDistanceSq(m1Data.pt,m2Data.pt)< pxSq){
m1Data.willSpiderfy = m2Data.willSpiderfy = true;
休息;
}
}
}
_ref3 = this.markers;
_results = [];
for(i = _l = 0,_len3 = _ref3.length; _l <_len3; i = ++ _l){
m = _ref3 [i];
if(mData [i] .willSpiderfy){
_results.push(m);
}
}
return _results;
};

p.makeHighlightListenerFuncs = function(marker){
return {
highlight:(function(_this){
return function(){
return marker ['_omsData']。leg.setOptions({
strokeColor:_this ['legColors'] ['highlight'] [_ this.map.mapTypeId],
zIndex:_this ['highlightedLegZIndex']
$ b})(this),
unhighlight:(function(_this){
return function(){
return marker ['
} _omsData']。leg.setOptions({
strokeColor:_this ['legColors'] ['usual'] [_ this.map.mapTypeId],
zIndex:_this ['usualLegZIndex']
});
};
})(this)
};
};
$ b $ p.spiderfy = function(markerData,nonNearbyMarkers){
var bodyPt,footLl,footPt,footPts,highlightListenerFuncs,leg,marker,md,nearestMarkerDatum,numFeet,spiderfiedMarkers;
if(this ['minZoomLevel']&& this.map.getZoom()< this ['minZoomLevel']){
return false;
}
this.spiderfying = true;
numFeet = markerData.length; (_j = 0,_len1 = markerData.length)
bodyPt = this.ptAverage((function(){
var _j,_len1,_results;
_results = [];
; _j< _len1; _j ++){
md = markerData [_j];
_results.push(md.markerPt);
}
return _results;
} )());
footPts = numFeet> =这['circleSpiralSwitchover']? this.generatePtsSpiral(numFeet,bodyPt).reverse():this.generatePtsCircle(numFeet,bodyPt);
spiderfiedMarkers =(function(){
var _j,_len1,_results;
_results = [];
for(_j = 0,_len1 = footPts.length; _j < _len1; _j ++){
footPt = footPts [_j];
footLl = this.ptToLl(footPt);
nearestMarkerDatum = this.minExtract(markerData,(function(_this){
返回函数(md){
return _this.ptDistanceSq(md.markerPt,footPt);
};
})(this));
marker = nearestMarkerDatum.marker;
leg = new gm.Polyline({
map:this.map,
path:[marker.position,footLl],
strokeColor:this ['legColors'] [''通常'] [this.map.mapTypeId],
strokeWeight:this ['legWeight'],
zIndex:this ['usualLegZIndex']
});
marker ['' _omsData'] = {
usualPosition:marker.position,
leg:leg
};
if(this ['le gColors'] ['highlight'] [this.map.mapTypeId]!== this ['legColors'] ['usual'] [this.map.mapTypeId]){
highlightListenerFuncs = this.makeHighlightListenerFuncs(marker) ;
marker ['_ omsData']。hightlightListeners = {
highlight:ge.addListener(marker,'mouseover',highlightListenerFuncs.highlight),
unhighlight:ge.addListener(marker,'mouseout' ,highlightListenerFuncs.unhighlight)
};
}
marker.setPosition(footLl);
marker.setZIndex(Math.round(this ['spiderfiedZIndex'] + footPt.y));
_results.push(marker);
}
return _results;
})。call(this);
删除this.spiderfying;
this.spiderfied = true;
返回this.trigger('spiderfy',spiderfiedMarkers,nonNearbyMarkers);
};

p ['unspiderfy'] = function(markerNotToMove){
var listeners,marker,nonNearbyMarkers,unspiderfiedMarkers,_j,_len1,_ref1;
if(markerNotToMove == null){
markerNotToMove = null;
}
if(this.spiderfied == null){
return this;
}
this.unspiderfying = true;
unspiderfiedMarkers = [];
nonNearbyMarkers = [];
_ref1 = this.markers; (_j = 0,_len1 = _ref1.length; _j< _len1; _j ++){
marker = _ref1 [_j];
;
if(marker ['_ omsData']!= null){
marker ['_ omsData']。leg.setMap(null);
if(marker!== markerNotToMove){
marker.setPosition(marker ['_ omsData']。usualPosition);
}
marker.setZIndex(null);
listeners = marker ['_ omsData']。hightlightListeners;
if(listeners!= null){
ge.removeListener(listeners.highlight);
ge.removeListener(listeners.unhighlight);
}
delete marker ['_ omsData'];
unspiderfiedMarkers.push(marker);
} else {
nonNearbyMarkers.push(marker);
}
}
删除this.unspiderfying;
删除this.spiderfied;
this.trigger('unspiderfy',unspiderfiedMarkers,nonNearbyMarkers);
返回此;
};

p.ptDistanceSq = function(pt1,pt2){
var dx,dy;
dx = pt1.x - pt2.x;
dy = pt1.y - pt2.y;
return dx * dx + dy * dy;
};

p.ptAverage = function(pts){
var numPts,pt,sumX,sumY,_j,_len1;
sumX = sumY = 0; $ _ b $ for(_j = 0,_len1 = pts.length; _j <_len1; _j ++){
pt = pts [_j];
sumX + = pt.x;
sumY + = pt.y;
}
numPts = pts.length;
返回新的gm.Point(sumX / numPts,sumY / numPts);
};

p.llToPt = function(ll){
return this.projHelper.getProjection()。fromLatLngToDivPixel(ll);
};

p.ptToLl = function(pt){
return this.projHelper.getProjection()。fromDivPixelToLatLng(pt);
};

p.minExtract = function(set,func){
var bestIndex,bestVal,index,item,val,_j,_len1;
for(index = _j = 0,_len1 = set.length; _j< _len1; index = ++ _ j){
item = set [index];
val = func(item); $(b)if((typeof bestIndex ===undefined|| bestIndex === null)|| val< bestVal){
bestVal = val;
bestIndex = index;
}
}
return set.splice(bestIndex,1)[0];
};

p.arrIndexOf = function(arr,obj){
var i,o,_j,_len1;
if(arr.indexOf!= null){
return arr.indexOf(obj);
}
(i = _j = 0,_len1 = arr.length; _j <_len1; i = ++ _ j){
o = arr [i]
if(o === obj){
return i;
}
}
返回-1;
};

_Class.ProjHelper = function(map){
return this.setMap(map);
};

_Class.ProjHelper.prototype = new gm.OverlayView();

_Class.ProjHelper.prototype ['draw'] = function(){};

return _Class;

};

以下是我的代码:

  let omw = require('../../ scripts / overlapping-marker-spidifier.js'); 
this.overlappingMarkerSpidifier = omw()(this.map);

我会认为我现在的东西会延迟脚本的执行直到它被需要,然后手动调用,暴露OverlappingMarkerSpiderfier函数。



有人知道我可以如何解决这个问题吗?

解决方案

好吧,我终于设法实现了这一点。有几个步骤涉及到。

首先,导入并调整重叠标记spidifier脚本



使用修改后的OMS脚本在您的项目中创建一个文件,如下所示。



如果要手动构建项目,请执行以下操作:




  • git clone https:// github.com/jawj/OverlappingMarkerSpiderfier.git

  • cd OverlappingMarkerSpiderfier

  • 打开bower.json并更改d​​evDependency closure-compiler的url至 // dl.google.com/closure-compiler/compiler-20131014.zip

  • 运行 npm运行dist

  • 打开lib / oms.js并修改该文件以导出该函数,如下面的代码所示:


<**>```
/ ** @preserve OverlappingMarkerSpiderfier
https://github.com/jawj/OverlappingMarkerSpiderfier
Copyright(c)2011 - 2013 George MacKerron
根据MIT许可证发布: http://opensource.org/licenses/mit-license
注意:Google Maps API v3必须包含在之前 this code
* /

  module.exports = function(){

var __hasProp = {} .hasOwnProperty,__slice = [] .slice;
var ge,gm,lcH,lcU,mt,p,twoPi,x,_i,_len,_ref;

p = _Class.prototype;

_ref = [_Class,p]; $ _ b $ for(_i = 0,_len = _ref.length; _i <_len; _i ++){
x = _ref [_i];
x ['VERSION'] ='0.3.3';
}

gm = google.maps;

ge = gm.event;

mt = gm.MapTypeId;

twoPi = Math.PI * 2;

p ['keepSpiderfied'] = false;

p ['markersWontHide'] = false;

p ['markersWontMove'] = false;

p ['nearbyDistance'] = 20;

p ['circleSpiralSwitchover'] = 9;

p ['circleFootSeparation'] = 23;

p ['circleStartAngle'] = twoPi / 12;

p ['spiralFootSeparation'] = 26;

p ['spiralLengthStart'] = 11;

p ['spiralLengthFactor'] = 4;

p ['spiderfiedZIndex'] = 1000;

p ['usualLegZIndex'] = 10;

p ['highlightedLegZIndex'] = 20;

p ['event'] ='点击';

p ['minZoomLevel'] = false;

p ['legWeight'] = 1.5;

p ['legColors'] = {
'通常':{},
'突出显示':{}
};

lcU = p ['legColors'] ['usual'];

lcH = p ['legColors'] ['highlight'];

lcU [mt.HYBRID] = lcU [mt.SATELLITE] ='#fff';

lcH [mt.HYBRID] = lcH [mt.SATELLITE] ='#f00';

lcU [mt.TERRAIN] = lcU [mt.ROADMAP] ='#444';

lcH [mt.TERRAIN] = lcH [mt.ROADMAP] ='#f00';

函数_Class(map,opts){
var e,k,v,_j,_len1,_ref1;
this.map = map;
if(opts == null){
opts = {};
}
for(k in opts){
if(!__ hasProp.call(opts,k))continue;
v = opts [k];
this [k] = v;
}
this.projHelper = new this.constructor.ProjHelper(this.map);
this.initMarkerArrays();
this.listeners = {};
_ref1 = ['click','zoom_changed','maptypeid_changed']; $ _ b $ for(_j = 0,_len1 = _ref1.length; _j <_len1; _j ++){
e = _ref1 [_j];
ge.addListener(this.map,e,(function(_this){
return function(){
return _this ['unspiderfy']();
};
})(this));
}
返回此;
}

p.initMarkerArrays = function(){
this.markers = [];
返回this.markerListenerRefs = [];
};

p ['addMarker'] = function(marker){
var listenerRefs;
if(marker ['_ oms']!= null){
return this;
}
marker ['_ oms'] = true;
listenerRefs = [
ge.addListener(marker,this ['event'],(function(_this){
return function(event){
return _this.spiderListener(marker ,event);
};
})(this))
];
if(!this ['markersWontHide']){
listenerRefs.push(ge.addListener(marker,'visible_changed',(function(_this){
return function(){
return _this.markerChangeListener(marker,false);
};
})(this)));

if(!this ['markersWontMove']){
listenerRefs.push(ge.addListener(marker,'position_changed',(function(_this){
return function (){
return _this.markerChangeListener(marker,true);
};
})(this)));
}
this.markerListenerRefs.push(listenerRefs);
this.markers.push(marker);
返回此;
}; $(){

p.markerChangeListener = function(marker,positionChanged){
if((marker ['_ omsData']!= null)&&(positionChanged ||!marker.getVisible() )&&!((this.spiderfying!= null)||(this.unspiderfying!= null))){
return this ['unspiderfy'](positionChanged?marker:null);
}
};

p ['getMarkers'] = function(){
return this.markers.slice(0);
};

p ['removeMarker'] = function(marker){
var i,listenerRef,listenerRefs,_j,_len1;
if(marker ['_ omsData']!= null){
this ['unspiderfy']();
}
i = this.arrIndexOf(this.markers,marker);
if(i <0){
return this;
}
listenerRefs = this.markerListenerRefs.splice(i,1)[0]; $ _ b $ for(_j = 0,_len1 = listenerRefs.length; _j< _len1; _j ++){
listenerRef = listenerRefs [_j];
ge.removeListener(listenerRef);
}
删除标记['_ oms'];
this.markers.splice(i,1);
返回此;
};

p ['clearMarkers'] = function(){
var i,listenerRef,listenerRefs,marker,_j,_k,_len1,_len2,_ref1;
this ['unspiderfy']();
_ref1 = this.markers;
for(i = _j = 0,_len1 = _ref1.length; _j< _len1; i = ++ _ j){
marker = _ref1 [i];
listenerRefs = this.markerListenerRefs [i]; $ _ b $ for(_k = 0,_len2 = listenerRefs.length; _k <_len2; _k ++){
listenerRef = listenerRefs [_k];
ge.removeListener(listenerRef);
}
删除标记['_ oms'];
}
this.initMarkerArrays();
返回此;
};

p ['addListener'] =函数(event,func){
var _base;
((_base = this.listeners)[event]!= null?_base [event]:_base [event] = [])。push(func);
返回此;
};

p ['removeListener'] = function(event,func){
var i;
i = this.arrIndexOf(this.listeners [event],func); (!(i <0)){
this.listeners [event] .splice(i,1);
if(!
}
返回此;
};

p ['clearListeners'] = function(event){
this.listeners [event] = [];
返回此;
};

p.trigger = function(){
var args,event,func,_j,_len1,_ref1,_ref2,_results;
event = arguments [0],args = 2 <= arguments.length? __slice.call(arguments,1):[];
_ref2 =(_ref1 = this.listeners [event])!= null? _ref1:[];
_results = []; (_j = 0,_len1 = _ref2.length; _j< _len1; _j ++){
func = _ref2 [_j];
;
_results.push(func.apply(null,args));
}
return _results;
};

p.generatePtsCircle = function(count,centerPt){
var angle,angleStep,circumference,i,legLength,_j,_results;
circumference = this ['circleFootSeparation'] *(2 + count);
legLength =周长/ twoPi;
angleStep = twoPi / count;
_results = [];
for(i = _j = 0; 0< = count?_j< count:_j> count; i = 0< = count?++ _ j: - _ j){
angle = this ['circleStartAngle'] + i * angleStep;
_results.push(new gm.Point(centerPt.x + legLength * Math.cos(angle),centerPt.y + legLength * Math.sin(angle)));
}
return _results;
};

p.generatePtsSpiral = function(count,centerPt){
var angle,i,legLength,pt,_j,_results;
legLength = this ['spiralLengthStart'];
angle = 0;
_results = [];
for(i = _j = 0; 0< = count?_j< count:_j> count; i = 0< = count?++ _ j: - _ j){
angle + = this ['spiralFootSeparation'] / legLength + i * 0.0005;
pt = new gm.Point(centerPt.x + legLength * Math.cos(angle),centerPt.y + legLength * Math.sin(angle));
legLength + = twoPi * this ['spiralLengthFactor'] / angle;
_results.push(pt);
}
return _results;
};

p.spiderListener = function(marker,event){
var $ this,clear,m,mPt,markerPt,markerSpiderfied,nDist,nearbyMarkerData,nonNearbyMarkers,pxSq,_j,_len1,_ref1 ;
markerSpiderfied = marker ['_ omsData']!= null;
if(!(markerSpiderfied&& this ['keepSpiderfied'])){
if(this ['event'] ==='mouseover'){
$ this = this ;
clear = function(){
return $ this ['unspiderfy']();
};
window.clearTimeout(p.timeout);
p.timeout = setTimeout(clear,3000);
} else {
this ['unspiderfy']();


if(markerSpiderfied || this.map.getStreetView()。getVisible()|| this.map.getMapTypeId()==='GoogleEarthAPI'){
返回this.trigger('click',marker,event);
} else {
nearbyMarkerData = [];
nonNearbyMarkers = [];
nDist = this ['nearbyDistance'];
pxSq = nDist * nDist;
markerPt = this.llToPt(marker.position);
_ref1 = this.markers;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
m = _ref1[_j];
if (!((m.map != null) && m.getVisible())) {
continue;
}
mPt = this.llToPt(m.position);
if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
nearbyMarkerData.push({
marker: m,
markerPt: mPt
});
} else {
nonNearbyMarkers.push(m);
}
}
if (nearbyMarkerData.length === 1) {
return this.trigger(’click’, marker, event);
} else {
return this.spiderfy(nearbyMarkerData, nonNearbyMarkers);
}
}
};

p[’markersNearMarker’] = function(marker, firstOnly) {
var m, mPt, markerPt, markers, nDist, pxSq, _j, _len1, _ref1, _ref2, _ref3;
if (firstOnly == null) {
firstOnly = false;
}
if (this.projHelper.getProjection() == null) {
throw \"Must wait for ’idle’ event on map before calling markersNearMarker\";
}
nDist = this[’nearbyDistance’];
pxSq = nDist * nDist;
markerPt = this.llToPt(marker.position);
markers = [];
_ref1 = this.markers;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
m = _ref1[_j];
if (m === marker || (m.map == null) || !m.getVisible()) {
continue;
}
mPt = this.llToPt((_ref2 = (_ref3 = m[’_omsData’]) != null ? _ref3.usualPosition : void 0) != null ? _ref2 : m.position);
if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
markers.push(m);
if (firstOnly) {
break;
}
}
}
return markers;
};

p[’markersNearAnyOtherMarker’] = function() {
var i, i1, i2, m, m1, m1Data, m2, m2Data, mData, nDist, pxSq, _j, _k, _l, _len1, _len2, _len3, _ref1, _ref2, _ref3, _results;
if (this.projHelper.getProjection() == null) {
throw \"Must wait for ’idle’ event on map before calling markersNearAnyOtherMarker\";
}
nDist = this[’nearbyDistance’];
pxSq = nDist * nDist;
mData = (function() {
var _j, _len1, _ref1, _ref2, _ref3, _results;
_ref1 = this.markers;
_results = [];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
m = _ref1[_j];
_results.push({
pt: this.llToPt((_ref2 = (_ref3 = m[’_omsData’]) != null ? _ref3.usualPosition : void 0) != null ? _ref2 : m.position),
willSpiderfy: false
});
}
return _results;
}).call(this);
_ref1 = this.markers;
for (i1 = _j = 0, _len1 = _ref1.length; _j < _len1; i1 = ++_j) {
m1 = _ref1[i1];
if (!((m1.map != null) && m1.getVisible())) {
continue;
}
m1Data = mData[i1];
if (m1Data.willSpiderfy) {
continue;
}
_ref2 = this.markers;
for (i2 = _k = 0, _len2 = _ref2.length; _k < _len2; i2 = ++_k) {
m2 = _ref2[i2];
if (i2 === i1) {
continue;
}
if (!((m2.map != null) && m2.getVisible())) {
continue;
}
m2Data = mData[i2];
if (i2 < i1 && !m2Data.willSpiderfy) {
continue;
}
if (this.ptDistanceSq(m1Data.pt, m2Data.pt) < pxSq) {
m1Data.willSpiderfy = m2Data.willSpiderfy = true;
break;
}
}
}
_ref3 = this.markers;
_results = [];
for (i = _l = 0, _len3 = _ref3.length; _l < _len3; i = ++_l) {
m = _ref3[i];
if (mData[i].willSpiderfy) {
_results.push(m);
}
}
return _results;
};

p.makeHighlightListenerFuncs = function(marker) {
return {
highlight: (function(_this) {
return function() {
return marker[’_omsData’].leg.setOptions({
strokeColor: _this[’legColors’][’highlighted’][_this.map.mapTypeId],
zIndex: _this[’highlightedLegZIndex’]
});
};
})(this),
unhighlight: (function(_this) {
return function() {
return marker[’_omsData’].leg.setOptions({
strokeColor: _this[’legColors’][’usual’][_this.map.mapTypeId],
zIndex: _this[’usualLegZIndex’]
});
};
})(this)
};
};

p.spiderfy = function(markerData, nonNearbyMarkers) {
var bodyPt, footLl, footPt, footPts, highlightListenerFuncs, leg, marker, md, nearestMarkerDatum, numFeet, spiderfiedMarkers;
if (this[’minZoomLevel’] && this.map.getZoom() < this[’minZoomLevel’]) {
return false;
}
this.spiderfying = true;
numFeet = markerData.length;
bodyPt = this.ptAverage((function() {
var _j, _len1, _results;
_results = [];
for (_j = 0, _len1 = markerData.length; _j < _len1; _j++) {
md = markerData[_j];
_results.push(md.markerPt);
}
return _results;
})());
footPts = numFeet >= this[’circleSpiralSwitchover’] ? this.generatePtsSpiral(numFeet, bodyPt).reverse() : this.generatePtsCircle(numFeet, bodyPt);
spiderfiedMarkers = (function() {
var _j, _len1, _results;
_results = [];
for (_j = 0, _len1 = footPts.length; _j < _len1; _j++) {
footPt = footPts[_j];
footLl = this.ptToLl(footPt);
nearestMarkerDatum = this.minExtract(markerData, (function(_this) {
return function(md) {
return _this.ptDistanceSq(md.markerPt, footPt);
};
})(this));
marker = nearestMarkerDatum.marker;
leg = new gm.Polyline({
map: this.map,
path: [marker.position, footLl],
strokeColor: this[’legColors’][’usual’][this.map.mapTypeId],
strokeWeight: this[’legWeight’],
zIndex: this[’usualLegZIndex’]
});
marker[’_omsData’] = {
usualPosition: marker.position,
leg: leg
};
if (this[’le gColors’][’highlighted’][this.map.mapTypeId] !== this[’legColors’][’usual’][this.map.mapTypeId]) {
highlightListenerFuncs = this.makeHighlightListenerFuncs(marker);
marker[’_omsData’].hightlightListeners = {
highlight: ge.addListener(marker, ’mouseover’, highlightListenerFuncs.highlight),
unhighlight: ge.addListener(marker, ’mouseout’, highlightListenerFuncs.unhighlight)
};
}
marker.setPosition(footLl);
marker.setZIndex(Math.round(this[’spiderfiedZIndex’] + footPt.y));
_results.push(marker);
}
return _results;
}).call(this);
delete this.spiderfying;
this.spiderfied = true;
return this.trigger(’spiderfy’, spiderfiedMarkers, nonNearbyMarkers);
};

p[’unspiderfy’] = function(markerNotToMove) {
var listeners, marker, nonNearbyMarkers, unspiderfiedMarkers, _j, _len1, _ref1;
if (markerNotToMove == null) {
markerNotToMove = null;
}
if (this.spiderfied == null) {
return this;
}
this.unspiderfying = true;
unspiderfiedMarkers = [];
nonNearbyMarkers = [];
_ref1 = this.markers;
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
marker = _ref1[_j];
if (marker[’_omsData’] != null) {
marker[’_omsData’].leg.setMap(null);
if (marker !== markerNotToMove) {
marker.setPosition(marker[’_omsData’].usualPosition);
}
marker.setZIndex(null);
listeners = marker[’_omsData’].hightlightListeners;
if (listeners != null) {
ge.removeListener(listeners.highlight);
ge.removeListener(listeners.unhighlight);
}
delete marker[’_omsData’];
unspiderfiedMarkers.push(marker);
} else {
nonNearbyMarkers.push(marker);
}
}
delete this.unspiderfying;
delete this.spiderfied;
this.trigger(’unspiderfy’, unspiderfiedMarkers, nonNearbyMarkers);
返回此;
};

p.ptDistanceSq = function(pt1, pt2) {
var dx, dy;
dx = pt1.x - pt2.x;
dy = pt1.y - pt2.y;
return dx * dx + dy * dy;
};

p.ptAverage = function(pts) {
var numPts, pt, sumX, sumY, _j, _len1;
sumX = sumY = 0;
for (_j = 0, _len1 = pts.length; _j < _len1; _j++) {
pt = pts[_j];
sumX += pt.x;
sumY += pt.y;
}
numPts = pts.length;
return new gm.Point(sumX / numPts, sumY / numPts);
};

p.llToPt = function(ll) {
return this.projHelper.getProjection().fromLatLngToDivPixel(ll);
};

p.ptToLl = function(pt) {
return this.projHelper.getProjection().fromDivPixelToLatLng(pt);
};

p.minExtract = function(set, func) {
var bestIndex, bestVal, index, item, val, _j, _len1;
for (index = _j = 0, _len1 = set.length; _j < _len1; index = ++_j) {
item = set[index];
val = func(item);
if ((typeof bestIndex === \"undefined\" || bestIndex === null) || val < bestVal) {
bestVal = val;
bestIndex = index;
}
}
return set.splice(bestIndex, 1)[0];
};

p.arrIndexOf = function(arr, obj) {
var i, o, _j, _len1;
if (arr.indexOf != null) {
return arr.indexOf(obj);
}
for (i = _j = 0, _len1 = arr.length; _j < _len1; i = ++_j) {
o = arr[i];
if (o === obj) {
return i;
}
}
return -1;
};

_Class.ProjHelper = function(map) {
return this.setMap(map);
};

_Class.ProjHelper.prototype = new gm.OverlayView();

_Class.ProjHelper.prototype[’draw’] = function() {};

return _Class;

};

```



Import the OMS script into your component that uses sebm-google-map



Add the following property to your component that uses the sebm-google-map component:



let oms = require(’../../scripts/overlapping-marker-spidifier.js’);



Get the native map, marker manager and markers



Create a new directive that will be used to get the native map object, the marker manager, and the markers. It will be nested inside the sebm-google-map component like so (notice get-google-map directive, and make sure your markers are nested within the get-google-map directive):

<my-parent-component> 
<sebm-google-map>
<get-google-map (map)=\"setMap($event)\" (markerManager)=\"setMarkerManager($event)\" (markers)=\"setMarkers($event)\">
<sebm-google-map-marker ... ></sebm-google-map-marker>
</get-google-map>
</sebm-google-map>
</my-parent-component>

Here’s the code for the directive:

import { Directive, Output, EventEmitter, AfterViewInit, ContentChildren, QueryList } from ’@angular/core’; 
import { GoogleMapsAPIWrapper, MarkerManager, SebmGoogleMapMarker } from ’angular2-google-maps/core’;

@Directive({
selector: ’get-google-map’,
})
export class GetGoogleMapDirective implements AfterViewInit {

/**
* Get native map object
*/
private _map: any = null;
@Output(’map’) mapChanged: EventEmitter<any> = new EventEmitter<any>();
set map(val){
this._map = val;
this.mapChanged.emit(val);
}
get map(){
return this._map;
}

/**
* Get marker manager
*/
private _markerManager: any = null;
@Output(’markerManager’) markerManagerChanged: EventEmitter<MarkerManager> = new EventEmitter<MarkerManager>();
set markerManager(val){
this._markerManager = val;
this.markerManagerChanged.emit(val);
}
get markerManager(){
return this._markerManager;
}

/**
* Get sebm markers
*/
private _markers: any = null;
@Output(’markers’) markersChanged: EventEmitter<SebmGoogleMapMarker[]> = new EventEmitter<SebmGoogleMapMarker[]>();
set markers(val){
this._markers = val;
this.markersChanged.emit(val);
}
get markers(){
return this._markers;
}
@ContentChildren(SebmGoogleMapMarker) markerChildren: QueryList<SebmGoogleMapMarker>;

constructor(
private googleMapsWrapper: GoogleMapsAPIWrapper,
private googleMarkerManager: MarkerManager
) { }

ngAfterViewInit() {
// get native map
this.googleMapsWrapper.getNativeMap().then(map => {
this.map = map;
}, error => {
throw error;
})

// get marker manager
this.markerManager = this.googleMarkerManager;

// get markers
this.markerChildren.changes.subscribe(markers => {
this.markers = markers._results;
})
}
}

Three things happen when this directive is inited:




  • It gets a reference to the native map object and outputs it using an event emitter

  • It gets a reference to the marker manager and outputs it using an event emitter

  • It gets references to all SebmGoogleMapMarkers



Make use of the marker manager, markers, and native map object in your parent component



Notice the event bindings on the get-google-map outputs for the markerManager, map and markers. We need to set up functions for these in our parent object to catch these objects when they are outputted:

  /** 
* Sets up google map spidifier
*/
setupSpidifier(){
let getOms = oms();
this.overlappingMarkerSpidifier = getOms.call(getOms.prototype, this.map);
}

/**
* Sets a reference to the google map object created by sebm - uses GetGoogleMapComponent
*/
setMap(map: any){
this.map = map;
this.setupSpidifier();
}

/**
* Gets the google marker manager from get-google-map
*/
setMarkerManager(markerManager: MarkerManager){
this.markerManager = markerManager;
}

/**
* Sets the markers, used by spidifier
*/
setMarkers(markers: SebmGoogleMapMarker[]){
this.markers = markers;
for(let marker of markers){
this.markerManager.getNativeMarker(marker).then(marker => {
this.overlappingMarkerSpidifier.addMarker(marker);
});
}
}

The above code catches the map, marker manager and markers being outputted from our directive. When we get the map, we save it, then call setup spidifier, which initializes the OMS on our sebm-map.



Next, we cache the marker manager, and each time the markers are outputted we add them to the OMS.






That’s it! Apologise if the answer is unclear, wrote it in quite a rush so just comment if I need to clarify anything.


I'm trying to implement OverlappingMarkerSpidifier with SebM Angular 2 Google Maps on angular2 2.0.0.

I've successfully loaded the google maps API with the GoogleMapsAPIWrapper imported from the sebm module. Once it's loaded, I'm executing the OMW script that I downloaded from the repository, to which I added a module.exports statement. However I am getting the following error message:

Uncaught TypeError: this.constructor.ProjHelper is not a constructor

Here is the OMW code:

/** @preserve OverlappingMarkerSpiderfier
https://github.com/jawj/OverlappingMarkerSpiderfier
Copyright (c) 2011 - 2013 George MacKerron
Released under the MIT licence: http://opensource.org/licenses/mit-license
Note: The Google Maps API v3 must be included *before* this code
 */

module.exports = function () {

  var __hasProp = {}.hasOwnProperty, __slice = [].slice;
  var ge, gm, lcH, lcU, mt, p, twoPi, x, _i, _len, _ref;

  p = _Class.prototype;

  _ref = [_Class, p];
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
    x = _ref[_i];
    x['VERSION'] = '0.3.3';
  }

  gm = google.maps;

  ge = gm.event;

  mt = gm.MapTypeId;

  twoPi = Math.PI * 2;

  p['keepSpiderfied'] = false;

  p['markersWontHide'] = false;

  p['markersWontMove'] = false;

  p['nearbyDistance'] = 20;

  p['circleSpiralSwitchover'] = 9;

  p['circleFootSeparation'] = 23;

  p['circleStartAngle'] = twoPi / 12;

  p['spiralFootSeparation'] = 26;

  p['spiralLengthStart'] = 11;

  p['spiralLengthFactor'] = 4;

  p['spiderfiedZIndex'] = 1000;

  p['usualLegZIndex'] = 10;

  p['highlightedLegZIndex'] = 20;

  p['event'] = 'click';

  p['minZoomLevel'] = false;

  p['legWeight'] = 1.5;

  p['legColors'] = {
    'usual': {},
    'highlighted': {}
  };

  lcU = p['legColors']['usual'];

  lcH = p['legColors']['highlighted'];

  lcU[mt.HYBRID] = lcU[mt.SATELLITE] = '#fff';

  lcH[mt.HYBRID] = lcH[mt.SATELLITE] = '#f00';

  lcU[mt.TERRAIN] = lcU[mt.ROADMAP] = '#444';

  lcH[mt.TERRAIN] = lcH[mt.ROADMAP] = '#f00';

  function _Class(map, opts) {
    var e, k, v, _j, _len1, _ref1;
    this.map = map;
    if (opts == null) {
      opts = {};
    }
    for (k in opts) {
      if (!__hasProp.call(opts, k)) continue;
      v = opts[k];
      this[k] = v;
    }
    this.projHelper = new this.constructor.ProjHelper(this.map);
    this.initMarkerArrays();
    this.listeners = {};
    _ref1 = ['click', 'zoom_changed', 'maptypeid_changed'];
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      e = _ref1[_j];
      ge.addListener(this.map, e, (function(_this) {
        return function() {
          return _this['unspiderfy']();
        };
      })(this));
    }
  }

  p.initMarkerArrays = function() {
    this.markers = [];
    return this.markerListenerRefs = [];
  };

  p['addMarker'] = function(marker) {
    var listenerRefs;
    if (marker['_oms'] != null) {
      return this;
    }
    marker['_oms'] = true;
    listenerRefs = [
      ge.addListener(marker, this['event'], (function(_this) {
        return function(event) {
          return _this.spiderListener(marker, event);
        };
      })(this))
    ];
    if (!this['markersWontHide']) {
      listenerRefs.push(ge.addListener(marker, 'visible_changed', (function(_this) {
        return function() {
          return _this.markerChangeListener(marker, false);
        };
      })(this)));
    }
    if (!this['markersWontMove']) {
      listenerRefs.push(ge.addListener(marker, 'position_changed', (function(_this) {
        return function() {
          return _this.markerChangeListener(marker, true);
        };
      })(this)));
    }
    this.markerListenerRefs.push(listenerRefs);
    this.markers.push(marker);
    return this;
  };

  p.markerChangeListener = function(marker, positionChanged) {
    if ((marker['_omsData'] != null) && (positionChanged || !marker.getVisible()) && !((this.spiderfying != null) || (this.unspiderfying != null))) {
      return this['unspiderfy'](positionChanged ? marker : null);
    }
  };

  p['getMarkers'] = function() {
    return this.markers.slice(0);
  };

  p['removeMarker'] = function(marker) {
    var i, listenerRef, listenerRefs, _j, _len1;
    if (marker['_omsData'] != null) {
      this['unspiderfy']();
    }
    i = this.arrIndexOf(this.markers, marker);
    if (i < 0) {
      return this;
    }
    listenerRefs = this.markerListenerRefs.splice(i, 1)[0];
    for (_j = 0, _len1 = listenerRefs.length; _j < _len1; _j++) {
      listenerRef = listenerRefs[_j];
      ge.removeListener(listenerRef);
    }
    delete marker['_oms'];
    this.markers.splice(i, 1);
    return this;
  };

  p['clearMarkers'] = function() {
    var i, listenerRef, listenerRefs, marker, _j, _k, _len1, _len2, _ref1;
    this['unspiderfy']();
    _ref1 = this.markers;
    for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
      marker = _ref1[i];
      listenerRefs = this.markerListenerRefs[i];
      for (_k = 0, _len2 = listenerRefs.length; _k < _len2; _k++) {
        listenerRef = listenerRefs[_k];
        ge.removeListener(listenerRef);
      }
      delete marker['_oms'];
    }
    this.initMarkerArrays();
    return this;
  };

  p['addListener'] = function(event, func) {
    var _base;
    ((_base = this.listeners)[event] != null ? _base[event] : _base[event] = []).push(func);
    return this;
  };

  p['removeListener'] = function(event, func) {
    var i;
    i = this.arrIndexOf(this.listeners[event], func);
    if (!(i < 0)) {
      this.listeners[event].splice(i, 1);
    }
    return this;
  };

  p['clearListeners'] = function(event) {
    this.listeners[event] = [];
    return this;
  };

  p.trigger = function() {
    var args, event, func, _j, _len1, _ref1, _ref2, _results;
    event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    _ref2 = (_ref1 = this.listeners[event]) != null ? _ref1 : [];
    _results = [];
    for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
      func = _ref2[_j];
      _results.push(func.apply(null, args));
    }
    return _results;
  };

  p.generatePtsCircle = function(count, centerPt) {
    var angle, angleStep, circumference, i, legLength, _j, _results;
    circumference = this['circleFootSeparation'] * (2 + count);
    legLength = circumference / twoPi;
    angleStep = twoPi / count;
    _results = [];
    for (i = _j = 0; 0 <= count ? _j < count : _j > count; i = 0 <= count ? ++_j : --_j) {
      angle = this['circleStartAngle'] + i * angleStep;
      _results.push(new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle)));
    }
    return _results;
  };

  p.generatePtsSpiral = function(count, centerPt) {
    var angle, i, legLength, pt, _j, _results;
    legLength = this['spiralLengthStart'];
    angle = 0;
    _results = [];
    for (i = _j = 0; 0 <= count ? _j < count : _j > count; i = 0 <= count ? ++_j : --_j) {
      angle += this['spiralFootSeparation'] / legLength + i * 0.0005;
      pt = new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle));
      legLength += twoPi * this['spiralLengthFactor'] / angle;
      _results.push(pt);
    }
    return _results;
  };

  p.spiderListener = function(marker, event) {
    var $this, clear, m, mPt, markerPt, markerSpiderfied, nDist, nearbyMarkerData, nonNearbyMarkers, pxSq, _j, _len1, _ref1;
    markerSpiderfied = marker['_omsData'] != null;
    if (!(markerSpiderfied && this['keepSpiderfied'])) {
      if (this['event'] === 'mouseover') {
        $this = this;
        clear = function() {
          return $this['unspiderfy']();
        };
        window.clearTimeout(p.timeout);
        p.timeout = setTimeout(clear, 3000);
      } else {
        this['unspiderfy']();
      }
    }
    if (markerSpiderfied || this.map.getStreetView().getVisible() || this.map.getMapTypeId() === 'GoogleEarthAPI') {
      return this.trigger('click', marker, event);
    } else {
      nearbyMarkerData = [];
      nonNearbyMarkers = [];
      nDist = this['nearbyDistance'];
      pxSq = nDist * nDist;
      markerPt = this.llToPt(marker.position);
      _ref1 = this.markers;
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        m = _ref1[_j];
        if (!((m.map != null) && m.getVisible())) {
          continue;
        }
        mPt = this.llToPt(m.position);
        if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
          nearbyMarkerData.push({
            marker: m,
            markerPt: mPt
          });
        } else {
          nonNearbyMarkers.push(m);
        }
      }
      if (nearbyMarkerData.length === 1) {
        return this.trigger('click', marker, event);
      } else {
        return this.spiderfy(nearbyMarkerData, nonNearbyMarkers);
      }
    }
  };

  p['markersNearMarker'] = function(marker, firstOnly) {
    var m, mPt, markerPt, markers, nDist, pxSq, _j, _len1, _ref1, _ref2, _ref3;
    if (firstOnly == null) {
      firstOnly = false;
    }
    if (this.projHelper.getProjection() == null) {
      throw "Must wait for 'idle' event on map before calling markersNearMarker";
    }
    nDist = this['nearbyDistance'];
    pxSq = nDist * nDist;
    markerPt = this.llToPt(marker.position);
    markers = [];
    _ref1 = this.markers;
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      m = _ref1[_j];
      if (m === marker || (m.map == null) || !m.getVisible()) {
        continue;
      }
      mPt = this.llToPt((_ref2 = (_ref3 = m['_omsData']) != null ? _ref3.usualPosition : void 0) != null ? _ref2 : m.position);
      if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
        markers.push(m);
        if (firstOnly) {
          break;
        }
      }
    }
    return markers;
  };

  p['markersNearAnyOtherMarker'] = function() {
    var i, i1, i2, m, m1, m1Data, m2, m2Data, mData, nDist, pxSq, _j, _k, _l, _len1, _len2, _len3, _ref1, _ref2, _ref3, _results;
    if (this.projHelper.getProjection() == null) {
      throw "Must wait for 'idle' event on map before calling markersNearAnyOtherMarker";
    }
    nDist = this['nearbyDistance'];
    pxSq = nDist * nDist;
    mData = (function() {
      var _j, _len1, _ref1, _ref2, _ref3, _results;
      _ref1 = this.markers;
      _results = [];
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        m = _ref1[_j];
        _results.push({
          pt: this.llToPt((_ref2 = (_ref3 = m['_omsData']) != null ? _ref3.usualPosition : void 0) != null ? _ref2 : m.position),
          willSpiderfy: false
        });
      }
      return _results;
    }).call(this);
    _ref1 = this.markers;
    for (i1 = _j = 0, _len1 = _ref1.length; _j < _len1; i1 = ++_j) {
      m1 = _ref1[i1];
      if (!((m1.map != null) && m1.getVisible())) {
        continue;
      }
      m1Data = mData[i1];
      if (m1Data.willSpiderfy) {
        continue;
      }
      _ref2 = this.markers;
      for (i2 = _k = 0, _len2 = _ref2.length; _k < _len2; i2 = ++_k) {
        m2 = _ref2[i2];
        if (i2 === i1) {
          continue;
        }
        if (!((m2.map != null) && m2.getVisible())) {
          continue;
        }
        m2Data = mData[i2];
        if (i2 < i1 && !m2Data.willSpiderfy) {
          continue;
        }
        if (this.ptDistanceSq(m1Data.pt, m2Data.pt) < pxSq) {
          m1Data.willSpiderfy = m2Data.willSpiderfy = true;
          break;
        }
      }
    }
    _ref3 = this.markers;
    _results = [];
    for (i = _l = 0, _len3 = _ref3.length; _l < _len3; i = ++_l) {
      m = _ref3[i];
      if (mData[i].willSpiderfy) {
        _results.push(m);
      }
    }
    return _results;
  };

  p.makeHighlightListenerFuncs = function(marker) {
    return {
      highlight: (function(_this) {
        return function() {
          return marker['_omsData'].leg.setOptions({
            strokeColor: _this['legColors']['highlighted'][_this.map.mapTypeId],
            zIndex: _this['highlightedLegZIndex']
          });
        };
      })(this),
      unhighlight: (function(_this) {
        return function() {
          return marker['_omsData'].leg.setOptions({
            strokeColor: _this['legColors']['usual'][_this.map.mapTypeId],
            zIndex: _this['usualLegZIndex']
          });
        };
      })(this)
    };
  };

  p.spiderfy = function(markerData, nonNearbyMarkers) {
    var bodyPt, footLl, footPt, footPts, highlightListenerFuncs, leg, marker, md, nearestMarkerDatum, numFeet, spiderfiedMarkers;
    if (this['minZoomLevel'] && this.map.getZoom() < this['minZoomLevel']) {
      return false;
    }
    this.spiderfying = true;
    numFeet = markerData.length;
    bodyPt = this.ptAverage((function() {
      var _j, _len1, _results;
      _results = [];
      for (_j = 0, _len1 = markerData.length; _j < _len1; _j++) {
        md = markerData[_j];
        _results.push(md.markerPt);
      }
      return _results;
    })());
    footPts = numFeet >= this['circleSpiralSwitchover'] ? this.generatePtsSpiral(numFeet, bodyPt).reverse() : this.generatePtsCircle(numFeet, bodyPt);
    spiderfiedMarkers = (function() {
      var _j, _len1, _results;
      _results = [];
      for (_j = 0, _len1 = footPts.length; _j < _len1; _j++) {
        footPt = footPts[_j];
        footLl = this.ptToLl(footPt);
        nearestMarkerDatum = this.minExtract(markerData, (function(_this) {
          return function(md) {
            return _this.ptDistanceSq(md.markerPt, footPt);
          };
        })(this));
        marker = nearestMarkerDatum.marker;
        leg = new gm.Polyline({
          map: this.map,
          path: [marker.position, footLl],
          strokeColor: this['legColors']['usual'][this.map.mapTypeId],
          strokeWeight: this['legWeight'],
          zIndex: this['usualLegZIndex']
        });
        marker['_omsData'] = {
          usualPosition: marker.position,
          leg: leg
        };
        if (this['legColors']['highlighted'][this.map.mapTypeId] !== this['legColors']['usual'][this.map.mapTypeId]) {
          highlightListenerFuncs = this.makeHighlightListenerFuncs(marker);
          marker['_omsData'].hightlightListeners = {
            highlight: ge.addListener(marker, 'mouseover', highlightListenerFuncs.highlight),
            unhighlight: ge.addListener(marker, 'mouseout', highlightListenerFuncs.unhighlight)
          };
        }
        marker.setPosition(footLl);
        marker.setZIndex(Math.round(this['spiderfiedZIndex'] + footPt.y));
        _results.push(marker);
      }
      return _results;
    }).call(this);
    delete this.spiderfying;
    this.spiderfied = true;
    return this.trigger('spiderfy', spiderfiedMarkers, nonNearbyMarkers);
  };

  p['unspiderfy'] = function(markerNotToMove) {
    var listeners, marker, nonNearbyMarkers, unspiderfiedMarkers, _j, _len1, _ref1;
    if (markerNotToMove == null) {
      markerNotToMove = null;
    }
    if (this.spiderfied == null) {
      return this;
    }
    this.unspiderfying = true;
    unspiderfiedMarkers = [];
    nonNearbyMarkers = [];
    _ref1 = this.markers;
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      marker = _ref1[_j];
      if (marker['_omsData'] != null) {
        marker['_omsData'].leg.setMap(null);
        if (marker !== markerNotToMove) {
          marker.setPosition(marker['_omsData'].usualPosition);
        }
        marker.setZIndex(null);
        listeners = marker['_omsData'].hightlightListeners;
        if (listeners != null) {
          ge.removeListener(listeners.highlight);
          ge.removeListener(listeners.unhighlight);
        }
        delete marker['_omsData'];
        unspiderfiedMarkers.push(marker);
      } else {
        nonNearbyMarkers.push(marker);
      }
    }
    delete this.unspiderfying;
    delete this.spiderfied;
    this.trigger('unspiderfy', unspiderfiedMarkers, nonNearbyMarkers);
    return this;
  };

  p.ptDistanceSq = function(pt1, pt2) {
    var dx, dy;
    dx = pt1.x - pt2.x;
    dy = pt1.y - pt2.y;
    return dx * dx + dy * dy;
  };

  p.ptAverage = function(pts) {
    var numPts, pt, sumX, sumY, _j, _len1;
    sumX = sumY = 0;
    for (_j = 0, _len1 = pts.length; _j < _len1; _j++) {
      pt = pts[_j];
      sumX += pt.x;
      sumY += pt.y;
    }
    numPts = pts.length;
    return new gm.Point(sumX / numPts, sumY / numPts);
  };

  p.llToPt = function(ll) {
    return this.projHelper.getProjection().fromLatLngToDivPixel(ll);
  };

  p.ptToLl = function(pt) {
    return this.projHelper.getProjection().fromDivPixelToLatLng(pt);
  };

  p.minExtract = function(set, func) {
    var bestIndex, bestVal, index, item, val, _j, _len1;
    for (index = _j = 0, _len1 = set.length; _j < _len1; index = ++_j) {
      item = set[index];
      val = func(item);
      if ((typeof bestIndex === "undefined" || bestIndex === null) || val < bestVal) {
        bestVal = val;
        bestIndex = index;
      }
    }
    return set.splice(bestIndex, 1)[0];
  };

  p.arrIndexOf = function(arr, obj) {
    var i, o, _j, _len1;
    if (arr.indexOf != null) {
      return arr.indexOf(obj);
    }
    for (i = _j = 0, _len1 = arr.length; _j < _len1; i = ++_j) {
      o = arr[i];
      if (o === obj) {
        return i;
      }
    }
    return -1;
  };

  _Class.ProjHelper = function(map) {
    return this.setMap(map);
  };

  _Class.ProjHelper.prototype = new gm.OverlayView();

  _Class.ProjHelper.prototype['draw'] = function() {};

  return _Class;

};

And here's my code:

let omw = require('../../scripts/overlapping-marker-spidifier.js');
this.overlappingMarkerSpidifier = omw()(this.map); 

I would have thought that what I currently have would delay the execution of the script until it is required, then called manually, exposing the OverlappingMarkerSpiderfier function.

Does anybody know how I can solve this?

解决方案

Ok I finally managed to implement this. There are a few steps involved.

First, import and tweak the overlapping marker spidifier script

Create a file within your project with the modified OMS script, bound below.

If you want to build the project manually, do the following:

  • git clone https://github.com/jawj/OverlappingMarkerSpiderfier.git
  • cd OverlappingMarkerSpiderfier
  • Open bower.json and change the url for devDependency closure-compiler to //dl.google.com/closure-compiler/compiler-20131014.zip
  • run npm run dist
  • open lib/oms.js and modify the file to export the function as shown in the code below:

``` /** @preserve OverlappingMarkerSpiderfier https://github.com/jawj/OverlappingMarkerSpiderfier Copyright (c) 2011 - 2013 George MacKerron Released under the MIT licence: http://opensource.org/licenses/mit-license Note: The Google Maps API v3 must be included before this code */

module.exports = function () {

  var __hasProp = {}.hasOwnProperty, __slice = [].slice;
  var ge, gm, lcH, lcU, mt, p, twoPi, x, _i, _len, _ref;

  p = _Class.prototype;

  _ref = [_Class, p];
  for (_i = 0, _len = _ref.length; _i < _len; _i++) {
    x = _ref[_i];
    x['VERSION'] = '0.3.3';
  }

  gm = google.maps;

  ge = gm.event;

  mt = gm.MapTypeId;

  twoPi = Math.PI * 2;

  p['keepSpiderfied'] = false;

  p['markersWontHide'] = false;

  p['markersWontMove'] = false;

  p['nearbyDistance'] = 20;

  p['circleSpiralSwitchover'] = 9;

  p['circleFootSeparation'] = 23;

  p['circleStartAngle'] = twoPi / 12;

  p['spiralFootSeparation'] = 26;

  p['spiralLengthStart'] = 11;

  p['spiralLengthFactor'] = 4;

  p['spiderfiedZIndex'] = 1000;

  p['usualLegZIndex'] = 10;

  p['highlightedLegZIndex'] = 20;

  p['event'] = 'click';

  p['minZoomLevel'] = false;

  p['legWeight'] = 1.5;

  p['legColors'] = {
    'usual': {},
    'highlighted': {}
  };

  lcU = p['legColors']['usual'];

  lcH = p['legColors']['highlighted'];

  lcU[mt.HYBRID] = lcU[mt.SATELLITE] = '#fff';

  lcH[mt.HYBRID] = lcH[mt.SATELLITE] = '#f00';

  lcU[mt.TERRAIN] = lcU[mt.ROADMAP] = '#444';

  lcH[mt.TERRAIN] = lcH[mt.ROADMAP] = '#f00';

  function _Class(map, opts) {
    var e, k, v, _j, _len1, _ref1;
    this.map = map;
    if (opts == null) {
      opts = {};
    }
    for (k in opts) {
      if (!__hasProp.call(opts, k)) continue;
      v = opts[k];
      this[k] = v;
    }
    this.projHelper = new this.constructor.ProjHelper(this.map);
    this.initMarkerArrays();
    this.listeners = {};
    _ref1 = ['click', 'zoom_changed', 'maptypeid_changed'];
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      e = _ref1[_j];
      ge.addListener(this.map, e, (function(_this) {
        return function() {
          return _this['unspiderfy']();
        };
      })(this));
    }
    return this;
  }

  p.initMarkerArrays = function() {
    this.markers = [];
    return this.markerListenerRefs = [];
  };

  p['addMarker'] = function(marker) {
    var listenerRefs;
    if (marker['_oms'] != null) {
      return this;
    }
    marker['_oms'] = true;
    listenerRefs = [
      ge.addListener(marker, this['event'], (function(_this) {
        return function(event) {
          return _this.spiderListener(marker, event);
        };
      })(this))
    ];
    if (!this['markersWontHide']) {
      listenerRefs.push(ge.addListener(marker, 'visible_changed', (function(_this) {
        return function() {
          return _this.markerChangeListener(marker, false);
        };
      })(this)));
    }
    if (!this['markersWontMove']) {
      listenerRefs.push(ge.addListener(marker, 'position_changed', (function(_this) {
        return function() {
          return _this.markerChangeListener(marker, true);
        };
      })(this)));
    }
    this.markerListenerRefs.push(listenerRefs);
    this.markers.push(marker);
    return this;
  };

  p.markerChangeListener = function(marker, positionChanged) {
    if ((marker['_omsData'] != null) && (positionChanged || !marker.getVisible()) && !((this.spiderfying != null) || (this.unspiderfying != null))) {
      return this['unspiderfy'](positionChanged ? marker : null);
    }
  };

  p['getMarkers'] = function() {
    return this.markers.slice(0);
  };

  p['removeMarker'] = function(marker) {
    var i, listenerRef, listenerRefs, _j, _len1;
    if (marker['_omsData'] != null) {
      this['unspiderfy']();
    }
    i = this.arrIndexOf(this.markers, marker);
    if (i < 0) {
      return this;
    }
    listenerRefs = this.markerListenerRefs.splice(i, 1)[0];
    for (_j = 0, _len1 = listenerRefs.length; _j < _len1; _j++) {
      listenerRef = listenerRefs[_j];
      ge.removeListener(listenerRef);
    }
    delete marker['_oms'];
    this.markers.splice(i, 1);
    return this;
  };

  p['clearMarkers'] = function() {
    var i, listenerRef, listenerRefs, marker, _j, _k, _len1, _len2, _ref1;
    this['unspiderfy']();
    _ref1 = this.markers;
    for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
      marker = _ref1[i];
      listenerRefs = this.markerListenerRefs[i];
      for (_k = 0, _len2 = listenerRefs.length; _k < _len2; _k++) {
        listenerRef = listenerRefs[_k];
        ge.removeListener(listenerRef);
      }
      delete marker['_oms'];
    }
    this.initMarkerArrays();
    return this;
  };

  p['addListener'] = function(event, func) {
    var _base;
    ((_base = this.listeners)[event] != null ? _base[event] : _base[event] = []).push(func);
    return this;
  };

  p['removeListener'] = function(event, func) {
    var i;
    i = this.arrIndexOf(this.listeners[event], func);
    if (!(i < 0)) {
      this.listeners[event].splice(i, 1);
    }
    return this;
  };

  p['clearListeners'] = function(event) {
    this.listeners[event] = [];
    return this;
  };

  p.trigger = function() {
    var args, event, func, _j, _len1, _ref1, _ref2, _results;
    event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
    _ref2 = (_ref1 = this.listeners[event]) != null ? _ref1 : [];
    _results = [];
    for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
      func = _ref2[_j];
      _results.push(func.apply(null, args));
    }
    return _results;
  };

  p.generatePtsCircle = function(count, centerPt) {
    var angle, angleStep, circumference, i, legLength, _j, _results;
    circumference = this['circleFootSeparation'] * (2 + count);
    legLength = circumference / twoPi;
    angleStep = twoPi / count;
    _results = [];
    for (i = _j = 0; 0 <= count ? _j < count : _j > count; i = 0 <= count ? ++_j : --_j) {
      angle = this['circleStartAngle'] + i * angleStep;
      _results.push(new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle)));
    }
    return _results;
  };

  p.generatePtsSpiral = function(count, centerPt) {
    var angle, i, legLength, pt, _j, _results;
    legLength = this['spiralLengthStart'];
    angle = 0;
    _results = [];
    for (i = _j = 0; 0 <= count ? _j < count : _j > count; i = 0 <= count ? ++_j : --_j) {
      angle += this['spiralFootSeparation'] / legLength + i * 0.0005;
      pt = new gm.Point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle));
      legLength += twoPi * this['spiralLengthFactor'] / angle;
      _results.push(pt);
    }
    return _results;
  };

  p.spiderListener = function(marker, event) {
    var $this, clear, m, mPt, markerPt, markerSpiderfied, nDist, nearbyMarkerData, nonNearbyMarkers, pxSq, _j, _len1, _ref1;
    markerSpiderfied = marker['_omsData'] != null;
    if (!(markerSpiderfied && this['keepSpiderfied'])) {
      if (this['event'] === 'mouseover') {
        $this = this;
        clear = function() {
          return $this['unspiderfy']();
        };
        window.clearTimeout(p.timeout);
        p.timeout = setTimeout(clear, 3000);
      } else {
        this['unspiderfy']();
      }
    }
    if (markerSpiderfied || this.map.getStreetView().getVisible() || this.map.getMapTypeId() === 'GoogleEarthAPI') {
      return this.trigger('click', marker, event);
    } else {
      nearbyMarkerData = [];
      nonNearbyMarkers = [];
      nDist = this['nearbyDistance'];
      pxSq = nDist * nDist;
      markerPt = this.llToPt(marker.position);
      _ref1 = this.markers;
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        m = _ref1[_j];
        if (!((m.map != null) && m.getVisible())) {
          continue;
        }
        mPt = this.llToPt(m.position);
        if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
          nearbyMarkerData.push({
            marker: m,
            markerPt: mPt
          });
        } else {
          nonNearbyMarkers.push(m);
        }
      }
      if (nearbyMarkerData.length === 1) {
        return this.trigger('click', marker, event);
      } else {
        return this.spiderfy(nearbyMarkerData, nonNearbyMarkers);
      }
    }
  };

  p['markersNearMarker'] = function(marker, firstOnly) {
    var m, mPt, markerPt, markers, nDist, pxSq, _j, _len1, _ref1, _ref2, _ref3;
    if (firstOnly == null) {
      firstOnly = false;
    }
    if (this.projHelper.getProjection() == null) {
      throw "Must wait for 'idle' event on map before calling markersNearMarker";
    }
    nDist = this['nearbyDistance'];
    pxSq = nDist * nDist;
    markerPt = this.llToPt(marker.position);
    markers = [];
    _ref1 = this.markers;
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      m = _ref1[_j];
      if (m === marker || (m.map == null) || !m.getVisible()) {
        continue;
      }
      mPt = this.llToPt((_ref2 = (_ref3 = m['_omsData']) != null ? _ref3.usualPosition : void 0) != null ? _ref2 : m.position);
      if (this.ptDistanceSq(mPt, markerPt) < pxSq) {
        markers.push(m);
        if (firstOnly) {
          break;
        }
      }
    }
    return markers;
  };

  p['markersNearAnyOtherMarker'] = function() {
    var i, i1, i2, m, m1, m1Data, m2, m2Data, mData, nDist, pxSq, _j, _k, _l, _len1, _len2, _len3, _ref1, _ref2, _ref3, _results;
    if (this.projHelper.getProjection() == null) {
      throw "Must wait for 'idle' event on map before calling markersNearAnyOtherMarker";
    }
    nDist = this['nearbyDistance'];
    pxSq = nDist * nDist;
    mData = (function() {
      var _j, _len1, _ref1, _ref2, _ref3, _results;
      _ref1 = this.markers;
      _results = [];
      for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
        m = _ref1[_j];
        _results.push({
          pt: this.llToPt((_ref2 = (_ref3 = m['_omsData']) != null ? _ref3.usualPosition : void 0) != null ? _ref2 : m.position),
          willSpiderfy: false
        });
      }
      return _results;
    }).call(this);
    _ref1 = this.markers;
    for (i1 = _j = 0, _len1 = _ref1.length; _j < _len1; i1 = ++_j) {
      m1 = _ref1[i1];
      if (!((m1.map != null) && m1.getVisible())) {
        continue;
      }
      m1Data = mData[i1];
      if (m1Data.willSpiderfy) {
        continue;
      }
      _ref2 = this.markers;
      for (i2 = _k = 0, _len2 = _ref2.length; _k < _len2; i2 = ++_k) {
        m2 = _ref2[i2];
        if (i2 === i1) {
          continue;
        }
        if (!((m2.map != null) && m2.getVisible())) {
          continue;
        }
        m2Data = mData[i2];
        if (i2 < i1 && !m2Data.willSpiderfy) {
          continue;
        }
        if (this.ptDistanceSq(m1Data.pt, m2Data.pt) < pxSq) {
          m1Data.willSpiderfy = m2Data.willSpiderfy = true;
          break;
        }
      }
    }
    _ref3 = this.markers;
    _results = [];
    for (i = _l = 0, _len3 = _ref3.length; _l < _len3; i = ++_l) {
      m = _ref3[i];
      if (mData[i].willSpiderfy) {
        _results.push(m);
      }
    }
    return _results;
  };

  p.makeHighlightListenerFuncs = function(marker) {
    return {
      highlight: (function(_this) {
        return function() {
          return marker['_omsData'].leg.setOptions({
            strokeColor: _this['legColors']['highlighted'][_this.map.mapTypeId],
            zIndex: _this['highlightedLegZIndex']
          });
        };
      })(this),
      unhighlight: (function(_this) {
        return function() {
          return marker['_omsData'].leg.setOptions({
            strokeColor: _this['legColors']['usual'][_this.map.mapTypeId],
            zIndex: _this['usualLegZIndex']
          });
        };
      })(this)
    };
  };

  p.spiderfy = function(markerData, nonNearbyMarkers) {
    var bodyPt, footLl, footPt, footPts, highlightListenerFuncs, leg, marker, md, nearestMarkerDatum, numFeet, spiderfiedMarkers;
    if (this['minZoomLevel'] && this.map.getZoom() < this['minZoomLevel']) {
      return false;
    }
    this.spiderfying = true;
    numFeet = markerData.length;
    bodyPt = this.ptAverage((function() {
      var _j, _len1, _results;
      _results = [];
      for (_j = 0, _len1 = markerData.length; _j < _len1; _j++) {
        md = markerData[_j];
        _results.push(md.markerPt);
      }
      return _results;
    })());
    footPts = numFeet >= this['circleSpiralSwitchover'] ? this.generatePtsSpiral(numFeet, bodyPt).reverse() : this.generatePtsCircle(numFeet, bodyPt);
    spiderfiedMarkers = (function() {
      var _j, _len1, _results;
      _results = [];
      for (_j = 0, _len1 = footPts.length; _j < _len1; _j++) {
        footPt = footPts[_j];
        footLl = this.ptToLl(footPt);
        nearestMarkerDatum = this.minExtract(markerData, (function(_this) {
          return function(md) {
            return _this.ptDistanceSq(md.markerPt, footPt);
          };
        })(this));
        marker = nearestMarkerDatum.marker;
        leg = new gm.Polyline({
          map: this.map,
          path: [marker.position, footLl],
          strokeColor: this['legColors']['usual'][this.map.mapTypeId],
          strokeWeight: this['legWeight'],
          zIndex: this['usualLegZIndex']
        });
        marker['_omsData'] = {
          usualPosition: marker.position,
          leg: leg
        };
        if (this['legColors']['highlighted'][this.map.mapTypeId] !== this['legColors']['usual'][this.map.mapTypeId]) {
          highlightListenerFuncs = this.makeHighlightListenerFuncs(marker);
          marker['_omsData'].hightlightListeners = {
            highlight: ge.addListener(marker, 'mouseover', highlightListenerFuncs.highlight),
            unhighlight: ge.addListener(marker, 'mouseout', highlightListenerFuncs.unhighlight)
          };
        }
        marker.setPosition(footLl);
        marker.setZIndex(Math.round(this['spiderfiedZIndex'] + footPt.y));
        _results.push(marker);
      }
      return _results;
    }).call(this);
    delete this.spiderfying;
    this.spiderfied = true;
    return this.trigger('spiderfy', spiderfiedMarkers, nonNearbyMarkers);
  };

  p['unspiderfy'] = function(markerNotToMove) {
    var listeners, marker, nonNearbyMarkers, unspiderfiedMarkers, _j, _len1, _ref1;
    if (markerNotToMove == null) {
      markerNotToMove = null;
    }
    if (this.spiderfied == null) {
      return this;
    }
    this.unspiderfying = true;
    unspiderfiedMarkers = [];
    nonNearbyMarkers = [];
    _ref1 = this.markers;
    for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
      marker = _ref1[_j];
      if (marker['_omsData'] != null) {
        marker['_omsData'].leg.setMap(null);
        if (marker !== markerNotToMove) {
          marker.setPosition(marker['_omsData'].usualPosition);
        }
        marker.setZIndex(null);
        listeners = marker['_omsData'].hightlightListeners;
        if (listeners != null) {
          ge.removeListener(listeners.highlight);
          ge.removeListener(listeners.unhighlight);
        }
        delete marker['_omsData'];
        unspiderfiedMarkers.push(marker);
      } else {
        nonNearbyMarkers.push(marker);
      }
    }
    delete this.unspiderfying;
    delete this.spiderfied;
    this.trigger('unspiderfy', unspiderfiedMarkers, nonNearbyMarkers);
    return this;
  };

  p.ptDistanceSq = function(pt1, pt2) {
    var dx, dy;
    dx = pt1.x - pt2.x;
    dy = pt1.y - pt2.y;
    return dx * dx + dy * dy;
  };

  p.ptAverage = function(pts) {
    var numPts, pt, sumX, sumY, _j, _len1;
    sumX = sumY = 0;
    for (_j = 0, _len1 = pts.length; _j < _len1; _j++) {
      pt = pts[_j];
      sumX += pt.x;
      sumY += pt.y;
    }
    numPts = pts.length;
    return new gm.Point(sumX / numPts, sumY / numPts);
  };

  p.llToPt = function(ll) {
    return this.projHelper.getProjection().fromLatLngToDivPixel(ll);
  };

  p.ptToLl = function(pt) {
    return this.projHelper.getProjection().fromDivPixelToLatLng(pt);
  };

  p.minExtract = function(set, func) {
    var bestIndex, bestVal, index, item, val, _j, _len1;
    for (index = _j = 0, _len1 = set.length; _j < _len1; index = ++_j) {
      item = set[index];
      val = func(item);
      if ((typeof bestIndex === "undefined" || bestIndex === null) || val < bestVal) {
        bestVal = val;
        bestIndex = index;
      }
    }
    return set.splice(bestIndex, 1)[0];
  };

  p.arrIndexOf = function(arr, obj) {
    var i, o, _j, _len1;
    if (arr.indexOf != null) {
      return arr.indexOf(obj);
    }
    for (i = _j = 0, _len1 = arr.length; _j < _len1; i = ++_j) {
      o = arr[i];
      if (o === obj) {
        return i;
      }
    }
    return -1;
  };

  _Class.ProjHelper = function(map) {
    return this.setMap(map);
  };

  _Class.ProjHelper.prototype = new gm.OverlayView();

  _Class.ProjHelper.prototype['draw'] = function() {};

  return _Class;

};

```

Import the OMS script into your component that uses sebm-google-map

Add the following property to your component that uses the sebm-google-map component:

let oms = require('../../scripts/overlapping-marker-spidifier.js');

Get the native map, marker manager and markers

Create a new directive that will be used to get the native map object, the marker manager, and the markers. It will be nested inside the sebm-google-map component like so (notice get-google-map directive, and make sure your markers are nested within the get-google-map directive):

<my-parent-component>
    <sebm-google-map>
        <get-google-map (map)="setMap($event)" (markerManager)="setMarkerManager($event)" (markers)="setMarkers($event)">
            <sebm-google-map-marker ... ></sebm-google-map-marker>
        </get-google-map>
    </sebm-google-map>
</my-parent-component>

Here's the code for the directive:

import { Directive, Output, EventEmitter, AfterViewInit, ContentChildren, QueryList } from '@angular/core';
import { GoogleMapsAPIWrapper, MarkerManager, SebmGoogleMapMarker } from 'angular2-google-maps/core';

@Directive({
  selector: 'get-google-map',
})
export class GetGoogleMapDirective implements AfterViewInit {

  /**
   * Get native map object
   */
  private _map: any = null;
  @Output('map') mapChanged: EventEmitter<any> = new EventEmitter<any>();
  set map(val){
    this._map = val;
    this.mapChanged.emit(val);
  }
  get map(){
    return this._map;
  }

  /**
   * Get marker manager
   */
  private _markerManager: any = null;
  @Output('markerManager') markerManagerChanged: EventEmitter<MarkerManager> = new EventEmitter<MarkerManager>();
  set markerManager(val){
    this._markerManager = val;
    this.markerManagerChanged.emit(val);
  }
  get markerManager(){
    return this._markerManager;
  }

  /**
   * Get sebm markers
   */
  private _markers: any = null;
  @Output('markers') markersChanged: EventEmitter<SebmGoogleMapMarker[]> = new EventEmitter<SebmGoogleMapMarker[]>();
  set markers(val){
    this._markers = val;
    this.markersChanged.emit(val);
  }
  get markers(){
    return this._markers;
  }
  @ContentChildren(SebmGoogleMapMarker) markerChildren: QueryList<SebmGoogleMapMarker>;

  constructor(
    private googleMapsWrapper: GoogleMapsAPIWrapper,
    private googleMarkerManager: MarkerManager
  ) { }

  ngAfterViewInit() {
    // get native map
    this.googleMapsWrapper.getNativeMap().then(map => {
      this.map = map;
    }, error => {
      throw error;
    })

    // get marker manager
    this.markerManager = this.googleMarkerManager;

    // get markers
    this.markerChildren.changes.subscribe(markers => {
      this.markers = markers._results;
    })
  }
}

Three things happen when this directive is inited:

  • It gets a reference to the native map object and outputs it using an event emitter
  • It gets a reference to the marker manager and outputs it using an event emitter
  • It gets references to all SebmGoogleMapMarkers

Make use of the marker manager, markers, and native map object in your parent component

Notice the event bindings on the get-google-map outputs for the markerManager, map and markers. We need to set up functions for these in our parent object to catch these objects when they are outputted:

  /**
   * Sets up google map spidifier
   */
  setupSpidifier(){
    let getOms = oms();
    this.overlappingMarkerSpidifier = getOms.call(getOms.prototype, this.map); 
  }

  /**
   * Sets a reference to the google map object created by sebm - uses GetGoogleMapComponent
   */
  setMap(map: any){
    this.map = map;
    this.setupSpidifier();
  }

  /**
   * Gets the google marker manager from get-google-map
   */
  setMarkerManager(markerManager: MarkerManager){
    this.markerManager = markerManager;
  }

  /**
   * Sets the markers, used by spidifier
   */
  setMarkers(markers: SebmGoogleMapMarker[]){
    this.markers = markers;
    for(let marker of markers){
      this.markerManager.getNativeMarker(marker).then(marker => {
        this.overlappingMarkerSpidifier.addMarker(marker);
      });
    }
  }

The above code catches the map, marker manager and markers being outputted from our directive. When we get the map, we save it, then call setup spidifier, which initializes the OMS on our sebm-map.

Next, we cache the marker manager, and each time the markers are outputted we add them to the OMS.


That's it! Apologise if the answer is unclear, wrote it in quite a rush so just comment if I need to clarify anything.

这篇关于使用sebm-angular2-google-map实现OverlappingMarkerSpidifier的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆