forked from bbecquet/Leaflet.MagnifyingGlass
-
Notifications
You must be signed in to change notification settings - Fork 1
/
leaflet.magnifyingglass.js
176 lines (149 loc) · 5.05 KB
/
leaflet.magnifyingglass.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
L.MagnifyingGlass = L.Layer.extend({
includes: L.Mixin.Events,
options: {
radius: 100,
zoomOffset: 3,
layers: [ ],
fixedPosition: false,
latLng: [0, 0],
fixedZoom: -1
},
initialize: function(options) {
L.Util.setOptions(this, options);
this._fixedZoom = (this.options.fixedZoom != -1);
this._mainMap = null;
this._glassMap = null;
},
getMap: function(){
return this._glassMap;
},
_createMiniMap: function(elt) {
return new L.Map(elt, {
layers: this.options.layers,
zoom: this._getZoom(),
maxZoom: this._mainMap.getMaxZoom(),
minZoom: this._mainMap.getMinZoom(),
crs: this._mainMap.options.crs,
fadeAnimation: false,
// disable every controls and interaction means
attributionControl: false,
zoomControl: false,
boxZoom: false,
touchZoom: false,
scrollWheelZoom: false,
doubleClickZoom: false,
dragging: false,
keyboard: false,
});
},
_getZoom: function() {
return (this._fixedZoom) ?
this.options.fixedZoom :
this._mainMap.getZoom() + this.options.zoomOffset;
},
_updateZoom: function() {
this._glassMap.setZoom(this._getZoom());
},
setRadius: function(radius) {
this.options.radius = radius;
if(this._wrapperElt) {
this._wrapperElt.style.width = this.options.radius * 2 + 'px';
this._wrapperElt.style.height = this.options.radius * 2 + 'px';
}
},
setLatLng: function(latLng) {
this.options.latLng = latLng;
this._update(latLng);
},
_updateFromMouse: function(evt) {
this._update(evt.latlng, evt.layerPoint);
},
_updateFixed: function() {
this._update(this.options.latLng);
},
_update: function(latLng, layerPoint) {
// update mini map view, forcing no animation
this._glassMap.setView(latLng, this._getZoom(), {
pan : { animate: false }
});
// update the layer element position on the main map,
// using the one provided or reprojecting it
layerPoint = layerPoint || this._mainMap.latLngToLayerPoint(latLng);
this._wrapperElt.style.left = layerPoint.x - this.options.radius + 'px';
this._wrapperElt.style.top = layerPoint.y - this.options.radius + 'px';
},
/**
As defined by ILayer
*/
onAdd: function(map) {
this._mainMap = map;
// create a wrapper element and a container for the map inside it
this._wrapperElt = L.DomUtil.create('div', 'leaflet-magnifying-glass');
var glassMapElt = L.DomUtil.create('div', '', this._wrapperElt);
// Webkit border-radius clipping workaround (see CSS)
if(L.Browser.webkit)
L.DomUtil.addClass(glassMapElt, 'leaflet-magnifying-glass-webkit');
// build the map
this._glassMap = this._createMiniMap(glassMapElt);
// forward some DOM events as Leaflet events
L.DomEvent.addListener(this._wrapperElt, 'click', this._fireClick, this);
var opts = this.options;
this.setRadius(opts.radius);
this.setLatLng(opts.latLng);
this._glassMap.whenReady(function() {
if(opts.fixedPosition) {
this._mainMap.on('viewreset', this._updateFixed, this);
// for now, hide the elements during zoom transitions
L.DomUtil.addClass(this._wrapperElt, ('leaflet-zoom-hide'));
} else {
this._mainMap.on('mousemove', this._updateFromMouse, this);
if(!this._fixedZoom) {
this._mainMap.on('zoomend', this._updateZoom, this);
}
}
}, this);
// add the magnifying glass as a layer to the top-most pane
map.getPanes().popupPane.appendChild(this._wrapperElt);
// needed after the element has been added, otherwise tile loading is messy
this._glassMap.invalidateSize();
},
_fireClick: function(domMouseEvt) {
this.fire('click', domMouseEvt);
L.DomEvent.stopPropagation(domMouseEvt);
},
/**
As defined by ILayer
*/
onRemove: function(map) {
map.off('viewreset', this._updateFixed, this);
map.off('mousemove', this._updateFromMouse, this);
map.off('zoomend', this._updateZoom, this);
// layers must be explicitely removed before map destruction,
// otherwise they can't be reused if the mg is re-added
for(var i=0, l=this.options.layers.length; i<l; i++) {
this._glassMap.removeLayer(this.options.layers[i]);
}
this._glassMap.remove();
L.DomEvent.removeListener(this._wrapperElt, 'click', this._fireClick);
map.getPanes().popupPane.removeChild(this._wrapperElt);
this._mainMap = null;
},
/**
Shortcut to mimic common layer types' way of adding to the map
*/
addTo: function(map) {
var id = L.stamp(this);
if (map._layers[id]) { return this; }
map._layers[id] = this;
this._zoomAnimated = map._zoomAnimated;
if (this.beforeAdd) {
this.beforeAdd(map);
}
this._mapToAdd = map;
map.whenReady(this._layerAdd, this);
return this;
},
});
L.magnifyingGlass = function (options) {
return new L.MagnifyingGlass(options);
};