Skip to content

Commit 08dca6f

Browse files
committed
Add Leaflet-IconLayers plugins for WorldMap V3
1 parent d42a166 commit 08dca6f

2 files changed

Lines changed: 346 additions & 0 deletions

File tree

leaflet/iconLayers.css

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
.leaflet-iconLayers {
2+
pointer-events: none;
3+
}
4+
5+
.leaflet-iconLayers-layersRow { display: table; pointer-events: auto; }
6+
.leaflet-iconLayers-layerCell { display: table-cell; background-image: url('images/transparent-pixel.png'); /* ie9 fix */ }
7+
8+
.leaflet-iconLayers_topleft .leaflet-iconLayers-layerCell, .leaflet-iconLayers_bottomleft .leaflet-iconLayers-layerCell { padding-right: 5px; }
9+
.leaflet-iconLayers_topright .leaflet-iconLayers-layerCell, .leaflet-iconLayers_bottomright .leaflet-iconLayers-layerCell { padding-left: 5px; }
10+
11+
.leaflet-iconLayers_topleft .leaflet-iconLayers-layerCell, .leaflet-iconLayers_topright .leaflet-iconLayers-layerCell { padding-bottom: 5px; }
12+
.leaflet-iconLayers_bottomleft .leaflet-iconLayers-layerCell, .leaflet-iconLayers_bottomright .leaflet-iconLayers-layerCell { padding-top: 5px; }
13+
14+
.leaflet-iconLayers-layer {
15+
cursor: pointer;
16+
position: relative;
17+
width: 80px;
18+
height: 80px;
19+
background-color: #fff;
20+
background-repeat: no-repeat;
21+
background-size: cover;
22+
text-align: center;
23+
box-sizing: border-box;
24+
box-shadow: 0 0 5px #000;
25+
}
26+
27+
.leaflet-iconLayers-layerTitleContainer {
28+
display: table;
29+
width: 100%;
30+
background: rgba(255,255,255,0.6);
31+
height: 25%;
32+
padding: 0;
33+
border: 0;
34+
position: absolute;
35+
bottom: 0%;
36+
transition: bottom .35s ease;
37+
}
38+
39+
.leaflet-iconLayers-layerCheckIcon {
40+
display: none;
41+
position: absolute;
42+
top: 3px;
43+
right: 3px;
44+
width: 18px;
45+
height: 18px;
46+
background: url('images/check.png');
47+
background-color: #fff;
48+
background-repeat: no-repeat;
49+
background-position: 4px 4px;
50+
border-radius: 10px;
51+
box-sizing: border-box;
52+
border: 1px solid rgba(0,0,0,0.6);
53+
}
54+
55+
.leaflet-iconLayers-layerTitle {
56+
display: table-cell;
57+
vertical-align: middle;
58+
}
59+
60+
.leaflet-iconLayers-layerCell_hidden { display: none; }
61+
.leaflet-iconLayers-layerCell_active .leaflet-iconLayers-layer { cursor: default; }
62+
.leaflet-iconLayers-layerCell_active .leaflet-iconLayers-layerCheckIcon { display: block; }

leaflet/iconLayers.js

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
+ function() {
2+
function each(o, cb) {
3+
for (var p in o) {
4+
if (o.hasOwnProperty(p)) {
5+
cb(o[p], p, o);
6+
}
7+
}
8+
}
9+
10+
function find(ar, cb) {
11+
if (ar.length) {
12+
for (var i = 0; i < ar.length; i++) {
13+
if (cb(ar[i])) {
14+
return ar[i];
15+
}
16+
}
17+
} else {
18+
for (var p in ar) {
19+
if (ar.hasOwnProperty(p) && cb(ar[p])) {
20+
return ar[p];
21+
}
22+
}
23+
}
24+
}
25+
26+
function first(o) {
27+
for (var p in o) {
28+
if (o.hasOwnProperty(p)) {
29+
return o[p];
30+
}
31+
}
32+
}
33+
34+
function length(o) {
35+
var length = 0;
36+
for (var p in o) {
37+
if (o.hasOwnProperty(p)) {
38+
length++;
39+
}
40+
}
41+
return length;
42+
}
43+
44+
function prepend(parent, el) {
45+
if (parent.children.length) {
46+
parent.insertBefore(el, parent.children[0]);
47+
} else {
48+
parent.appendChild(el);
49+
}
50+
}
51+
52+
L.Control.IconLayers = L.Control.extend({
53+
includes: L.Mixin.Events,
54+
_getActiveLayer: function() {
55+
if (this._activeLayerId) {
56+
return this._layers[this._activeLayerId];
57+
} else if (length(this._layers)) {
58+
return first(this._layers);
59+
} else {
60+
return null;
61+
}
62+
},
63+
_getPreviousLayer: function() {
64+
var activeLayer = this._getActiveLayer();
65+
if (!activeLayer) {
66+
return null;
67+
} else if (this._previousLayerId) {
68+
return this._layers[this._previousLayerId];
69+
} else {
70+
return find(this._layers, function(l) {
71+
return l.id !== activeLayer.id;
72+
}.bind(this)) || null;
73+
}
74+
},
75+
_getInactiveLayers: function() {
76+
var ar = [];
77+
var activeLayerId = this._getActiveLayer() ? this._getActiveLayer().id : null;
78+
var previousLayerId = this._getPreviousLayer() ? this._getPreviousLayer().id : null;
79+
each(this._layers, function(l) {
80+
if ((l.id !== activeLayerId) && (l.id !== previousLayerId)) {
81+
ar.push(l);
82+
}
83+
});
84+
return ar;
85+
},
86+
_arrangeLayers: function() {
87+
var behaviors = {};
88+
89+
behaviors['previous'] = function() {
90+
var layers = this._getInactiveLayers();
91+
this._getActiveLayer() && layers.unshift(this._getActiveLayer());
92+
this._getPreviousLayer() && layers.unshift(this._getPreviousLayer());
93+
return layers;
94+
};
95+
96+
return behaviors[this.options.behavior].apply(this, arguments);
97+
},
98+
_getLayerCellByLayerId: function(id) {
99+
var els = this._container.getElementsByClassName('leaflet-iconLayers-layerCell');
100+
for (var i = 0; i < els.length; i++) {
101+
if (els[i].getAttribute('data-layerid') == id) {
102+
return els[i];
103+
}
104+
}
105+
},
106+
_createLayerElement: function(layerObj) {
107+
var el = L.DomUtil.create('div', 'leaflet-iconLayers-layer');
108+
if (layerObj.title) {
109+
var titleContainerEl = L.DomUtil.create('div', 'leaflet-iconLayers-layerTitleContainer');
110+
var titleEl = L.DomUtil.create('div', 'leaflet-iconLayers-layerTitle');
111+
var checkIconEl = L.DomUtil.create('div', 'leaflet-iconLayers-layerCheckIcon');
112+
titleEl.innerHTML = layerObj.title;
113+
titleContainerEl.appendChild(titleEl);
114+
el.appendChild(titleContainerEl);
115+
el.appendChild(checkIconEl);
116+
}
117+
if (layerObj.icon) {
118+
el.setAttribute('style', "background-image: url('" + layerObj.icon + "')");
119+
}
120+
return el;
121+
},
122+
_createLayerElements: function() {
123+
var currentRow, layerCell;
124+
var layers = this._arrangeLayers();
125+
var activeLayerId = this._getActiveLayer() && this._getActiveLayer().id;
126+
127+
for (var i = 0; i < layers.length; i++) {
128+
if (i % this.options.maxLayersInRow === 0) {
129+
currentRow = L.DomUtil.create('div', 'leaflet-iconLayers-layersRow');
130+
if (this.options.position.indexOf('bottom') === -1) {
131+
this._container.appendChild(currentRow);
132+
} else {
133+
prepend(this._container, currentRow);
134+
}
135+
}
136+
layerCell = L.DomUtil.create('div', 'leaflet-iconLayers-layerCell');
137+
layerCell.setAttribute('data-layerid', layers[i].id);
138+
if (i !== 0) {
139+
L.DomUtil.addClass(layerCell, 'leaflet-iconLayers-layerCell_hidden');
140+
}
141+
if (layers[i].id === activeLayerId) {
142+
L.DomUtil.addClass(layerCell, 'leaflet-iconLayers-layerCell_active');
143+
}
144+
if (this._expandDirection === 'left') {
145+
L.DomUtil.addClass(layerCell, 'leaflet-iconLayers-layerCell_expandLeft');
146+
} else {
147+
L.DomUtil.addClass(layerCell, 'leaflet-iconLayers-layerCell_expandRight');
148+
}
149+
layerCell.appendChild(this._createLayerElement(layers[i]));
150+
151+
if (this.options.position.indexOf('right') === -1) {
152+
currentRow.appendChild(layerCell);
153+
} else {
154+
prepend(currentRow, layerCell);
155+
}
156+
}
157+
},
158+
_onLayerClick: function(e) {
159+
e.stopPropagation();
160+
var layerId = e.currentTarget.getAttribute('data-layerid');
161+
var layer = this._layers[layerId];
162+
this.setActiveLayer(layer.layer);
163+
this.expand();
164+
},
165+
_attachEvents: function() {
166+
each(this._layers, function(l) {
167+
var e = this._getLayerCellByLayerId(l.id);
168+
if (e) {
169+
e.addEventListener('click', this._onLayerClick.bind(this));
170+
}
171+
}.bind(this));
172+
var layersRowCollection = this._container.getElementsByClassName('leaflet-iconLayers-layersRow');
173+
for (var i = 0; i < layersRowCollection.length; i++) {
174+
var el = layersRowCollection[i];
175+
el.addEventListener('mouseenter', function(e) {
176+
e.stopPropagation();
177+
this.expand();
178+
}.bind(this));
179+
el.addEventListener('mouseleave', function(e) {
180+
e.stopPropagation();
181+
this.collapse();
182+
}.bind(this));
183+
el.addEventListener('mousemove', function(e) {
184+
e.stopPropagation();
185+
});
186+
}
187+
},
188+
_render: function() {
189+
this._container.innerHTML = '';
190+
this._createLayerElements();
191+
this._attachEvents();
192+
},
193+
_switchMapLayers: function() {
194+
if (!this._map) {
195+
return;
196+
}
197+
var activeLayer = this._getActiveLayer();
198+
var previousLayer = this._getPreviousLayer();
199+
if (previousLayer) {
200+
this._map.removeLayer(previousLayer.layer);
201+
} else {
202+
each(this._layers, function(layerObject) {
203+
var layer = layerObject.layer;
204+
this._map.removeLayer(layer);
205+
}.bind(this));
206+
}
207+
if (activeLayer) {
208+
this._map.addLayer(activeLayer.layer);
209+
}
210+
},
211+
options: {
212+
position: 'bottomleft', // one of expanding directions depends on this
213+
behavior: 'previous', // may be 'previous', 'expanded' or 'first'
214+
expand: 'horizontal', // or 'vertical'
215+
autoZIndex: true, // from L.Control.Layers
216+
maxLayersInRow: 5,
217+
manageLayers: true
218+
},
219+
initialize: function(layers, options) {
220+
if (!L.Util.isArray(arguments[0])) {
221+
// first argument is options
222+
options = layers;
223+
layers = [];
224+
}
225+
L.setOptions(this, options);
226+
this._expandDirection = (this.options.position.indexOf('left') != -1) ? 'right' : 'left';
227+
if (this.options.manageLayers) {
228+
this.on('activelayerchange', this._switchMapLayers, this);
229+
}
230+
this.setLayers(layers);
231+
},
232+
onAdd: function(map) {
233+
this._container = L.DomUtil.create('div', 'leaflet-iconLayers');
234+
L.DomUtil.addClass(this._container, 'leaflet-iconLayers_' + this.options.position);
235+
this._render();
236+
map.on('click', this.collapse, this);
237+
if (this.options.manageLayers) {
238+
this._switchMapLayers();
239+
}
240+
return this._container;
241+
},
242+
onRemove: function(map) {
243+
map.off('click', this.collapse, this);
244+
},
245+
setLayers: function(layers) {
246+
this._layers = {};
247+
layers.map(function(layer) {
248+
var id = L.stamp(layer.layer)
249+
this._layers[id] = L.extend(layer, {
250+
id: id
251+
});
252+
}.bind(this));
253+
this._container && this._render();
254+
},
255+
setActiveLayer: function(layer) {
256+
var l = layer && this._layers[L.stamp(layer)];
257+
if (!l || l.id === this._activeLayerId) {
258+
return;
259+
}
260+
this._previousLayerId = this._activeLayerId;
261+
this._activeLayerId = l.id;
262+
this._container && this._render();
263+
this.fire('activelayerchange', {
264+
layer: layer
265+
});
266+
},
267+
expand: function() {
268+
this._arrangeLayers().slice(1).map(function(l) {
269+
var el = this._getLayerCellByLayerId(l.id);
270+
L.DomUtil.removeClass(el, 'leaflet-iconLayers-layerCell_hidden');
271+
}.bind(this));
272+
},
273+
collapse: function() {
274+
this._arrangeLayers().slice(1).map(function(l) {
275+
var el = this._getLayerCellByLayerId(l.id);
276+
L.DomUtil.addClass(el, 'leaflet-iconLayers-layerCell_hidden');
277+
}.bind(this));
278+
}
279+
});
280+
}();
281+
282+
L.control.iconLayers = function(layers, options) {
283+
return new L.Control.IconLayers(layers, options);
284+
};

0 commit comments

Comments
 (0)