npmap.js
Version:
A JavaScript web mapping library, built as a Leaflet plugin, for the National Park Service.
306 lines (265 loc) • 9.66 kB
JavaScript
/* INFO: In leaflet.markercluster, in src/MarkerCluster.js, add "keyboard: false" to line 4. */
/* global L */
;
require('leaflet.markercluster');
var ClusterLayer = L.MarkerClusterGroup.extend({
options: {
showCoverageOnHover: false
},
initialize: function(options) {
var me = this,
interval;
L.Util.setOptions(this, options);
if (options.cluster === true) {
options.cluster = {};
}
options.cluster.iconCreateFunction = new this.createCustomIconFunction(options.cluster.clusterIcon);
L.Util.setOptions(this, options.cluster);
options.clustered = options.cluster.iconCreateFunction('getInfo');
delete options.cluster;
this._currentShownBounds = null;
this._featureGroup = new L.FeatureGroup();
this._featureGroup.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
this._inZoomAnimation = 0;
this._needsClustering = [];
this._needsRemoving = [];
this._nonPointGroup = L.featureGroup();
this._nonPointGroup.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
this._queue = [];
this.L = L.npmap.layer[options.type](options);
interval = setInterval(function() {
if (me.L._loaded) {
clearInterval(interval);
me.addLayer(me.L);
me.fire('ready');
me.readyFired = true;
me._loaded = true;
}
}, 0);
return this;
},
onAdd: function(map) {
this._map = map;
this._addAttribution();
L.MarkerClusterGroup.prototype.onAdd.call(this, map);
},
onRemove: function(map) {
this._removeAttribution();
L.MarkerClusterGroup.prototype.onRemove.call(this, map);
delete this._map;
},
_addAttribution: function() {
var attribution = this.options.attribution;
if (attribution && this._map.attributionControl) {
this._map.attributionControl.addAttribution(attribution);
}
},
_removeAttribution: function() {
var attribution = this.options.attribution;
if (attribution && this._map.attributionControl) {
this._map.attributionControl.removeAttribution(attribution);
}
},
createCustomIconFunction: function(settings) {
var defaultSettings = [{
color: '#7a904f',
fontColor: '#fff',
maxNodes: 9,
name: 'small',
outerRing: 22,
size: 20
},{
color: '#d49900',
fontColor: '#fff',
maxNodes: 99,
name: 'medium',
outerRing: 24,
size: 35
},{
color: '#814705',
fontColor: '#fff',
maxNodes: Infinity,
name: 'large',
outerRing: 24,
size: 50
}];
function addStyles() {
var head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style'),
text = '';
style.type = 'text/css';
text += '.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {';
text += '-webkit-transition: -webkit-transform 0.2s ease-out, opacity 0.2s ease-in;';
text += '-moz-transition: -moz-transform 0.2s ease-out, opacity 0.2s ease-in;';
text += '-o-transition: -o-transform 0.2s ease-out, opacity 0.2s ease-in;';
text += 'transition: transform 0.2s ease-out, opacity 0.2s ease-in;';
text += '}';
for (var i = 0; i < defaultSettings.length; i++) {
var currStyle = createStyle(defaultSettings[i]);
for (var styleType in currStyle) {
text += '.' + 'marker-cluster-custom-' + defaultSettings[i].maxNodes.toString() + ' ' + (styleType === 'main' ? '' : styleType) + ' {' + currStyle[styleType] + '}\n';
}
}
if (style.styleSheet) {
style.styleSheet.cssText = text;
} else {
style.appendChild(document.createTextNode(text));
}
head.appendChild(style);
}
function autoTextColor(rgb) {
if (Object.prototype.toString.call(rgb) !== '[object Array]') {
rgb = hexToArray(rgb);
}
if (rgb) {
var brightness = (((rgb[0] * 299) + (rgb[1] * 587) + (rgb[2]* 144)) / 1000);
if (brightness > 127) {
return '#000';
} else {
return '#fff';
}
} else {
return false;
}
}
function createStyle(style) {
var styles = {
main: {
'background-clip': 'padding-box',
background: supportsRgba('rgba(' + hexToArray(style.color)[0] +', ' + hexToArray(style.color)[1] + ', ' + hexToArray(style.color)[2] + ', 0.4)'),
'border-radius': ((style.size + style.outerRing)*0.5) + 'px'
},
div: {
background: supportsRgba('rgba(' + hexToArray(style.color)[0] +', ' + hexToArray(style.color)[1] + ', ' + hexToArray(style.color)[2] + ', 0.9)'),
'border-radius': (style.size / 2) + 'px',
height: style.size + 'px',
'margin-left': (style.outerRing / 2) + 'px',
'margin-top': (style.outerRing / 2) + 'px',
'text-align': 'center',
width: style.size + 'px'
},
span: {
color: 'rgb(' + hexToArray(style.fontColor)[0] +', ' + hexToArray(style.fontColor)[1] + ', ' + hexToArray(style.fontColor)[2] + ')',
display: 'block',
font: '12px Frutiger, "Frutiger Linotype", Univers, Calibri, "Gill Sans", "Gill Sans MT", "Myriad Pro", Myriad, "DejaVu Sans Condensed", "Liberation Sans", "Nimbus Sans L", Tahoma, Geneva, "Helvetica Neue", Helvetica, Arial, sans-serif',
'line-height': style.size + 'px'
}
};
function cssStyle(fields) {
var returnValue = [];
for (var field in fields) {
returnValue.push(field + ': ' + fields[field] +'; ');
}
return returnValue.join('');
}
function styleLoop(fields, process) {
var returnValue = {};
for (var field in fields) {
returnValue[field] = process(fields[field]);
}
return returnValue;
}
return styleLoop(styles, cssStyle);
}
function customIconCreateFunction(cluster) {
if (cluster === 'getInfo') {
return defaultSettings;
}
var childCount = cluster.getChildCount(),
className, size;
for (var i = 0; i < defaultSettings.length; i++) {
var defaultSetting = defaultSettings[i];
if (childCount <= defaultSetting.maxNodes) {
className = 'marker-cluster-custom-' + defaultSetting.maxNodes.toString();
size = defaultSetting.size + defaultSetting.outerRing;
break;
}
}
return new L.DivIcon({
className: className,
html: '<div><span>' + childCount + '</span></div>',
iconSize: new L.Point(size, size)
});
}
function hexToArray(hexValue) {
var returnValue = false;
if (typeof(hexValue) === 'string') {
hexValue = hexValue.replace('#', '');
if (hexValue.length === 3) {
hexValue = hexValue.replace(/(.)(.)(.)/g, '$1$1$2$2$3$3');
}
if (hexValue.match(/[\da-fA-F]{6}$/)) {
returnValue = [
parseInt(hexValue.substr(0, 2), 16),
parseInt(hexValue.substr(2, 2), 16),
parseInt(hexValue.substr(4, 2), 16)
];
}
}
return returnValue;
}
function supportsRgba(color) {
var returnValue = false,
rgbaTestVal = 'rgba(0,0,0,0.1)',
testDiv = document.createElement('div'),
newColor;
try {
testDiv.style.color = rgbaTestVal;
if (testDiv.style.color.substr(0, 4) === 'rgba') {
returnValue = true;
}
} catch (e) {}
if (color) {
if (returnValue) {
return color;
} else {
newColor = color.replace(/^rgba\(/g, 'rgb(,').replace(')','').split(',');
newColor[1] = Math.floor(parseInt(newColor[1], 10) + (255 * (1 - parseFloat(newColor[4], 10))));
newColor[2] = Math.floor(parseInt(newColor[2], 10) + (255 * (1 - parseFloat(newColor[4], 10))));
newColor[3] = Math.floor(parseInt(newColor[3], 10) + (255 * (1 - parseFloat(newColor[4], 10))));
if (newColor[1] > 255) {newColor[1] = 255;}
if (newColor[2] > 255) {newColor[2] = 255;}
if (newColor[3] > 255) {newColor[3] = 255;}
newColor = newColor.slice(0,4).join(',').replace('(,','(') + ')';
return newColor;
}
} else {
return returnValue;
}
}
function updateDefaults(newSettings) {
for (var j = 0; j < defaultSettings.length; j++) {
if (defaultSettings[j].name && newSettings[defaultSettings[j].name]) {
L.Util.extend(defaultSettings[j], newSettings[defaultSettings[j].name]);
if (!newSettings[defaultSettings[j].name].fontColor && newSettings[defaultSettings[j].name].color) {
defaultSettings[j].fontColor = autoTextColor(hexToArray(newSettings[defaultSettings[j].name].color));
}
}
}
}
if (settings) {
if (typeof settings === 'string') {
updateDefaults({
small: {
color: settings
},
medium: {
color: settings
},
large: {
color: settings
}
});
} else if (Object.prototype.toString.call(settings) === '[object Object]') {
updateDefaults(settings);
} else if (Object.prototype.toString.call(settings) === '[object Array]') {
defaultSettings = settings;
}
}
addStyles();
return customIconCreateFunction;
}
});
module.exports = function(options) {
return new ClusterLayer(options);
};