consbio / leaflet.htmllegend Goto Github PK
View Code? Open in Web Editor NEWA simple Leaflet plugin for creating legends with HTML elements
License: ISC License
A simple Leaflet plugin for creating legends with HTML elements
License: ISC License
I would like to be able to remove the legend from the control. My use case: I have users who will add raster images to the map from db search results. This could be a large number of images.
It would be very helpful to have an option "allowRemove" which would place an (X) on the "htmlLegend" control for the layer which would allow the user to remove the layer from the "l.control.layers" control. I know I can keep track of the ids and allow the user to remove the layer from somewhere else (like in your example) but this seems much more intuitive.
Currently if the legend entry does not have a label value , the entry is not collapsible. And a missing label key causes "undefined" to be shown on the legend.
Hi,
First of all, thanks for this plugin, it is awesome 👍
Just wondering is there a way to have the legend to collapse by default instead of all being expanded?
Thanks,
Tam
I'm getting in touch to let you know that I've been able to (after a few mistakes) create the legend from a layer (Aquifers, Watersheds, among others).
I made some modifications to .css and .js because my application does not require opacity control.
In the code I did the following:
var htmlLegend11 = L.control.htmllegend({
position: 'bottomleft',
legends: [{
name: 'Aquíferos',
layer: layer_aquiferos_1,
elements: [{
label: '',
html: "
Aluviões | |
Cristalino | |
Formação Açu | |
Formação Barreiras | |
Formação Jandaíra |
I want to thank for making the plugin available.
Good Morning,
I would like to know if you can use a one-layer style to be part of the caption.
EX: I have a layer with the regions division of a particular state, and I would like the caption was the style that I preset.
How can I do this?:
Thanks in advance
Hi,
I added L.Control.HtmlLegend.js and L.Control.HtmlLegend.css to my Default.aspx. Now, when I run I get the following error
JavaScript critical error at line 28, column 10 in http://localhost:63452/L.Control.HtmlLegend.js\n\nSCRIPT1003: Expected ':'
Can you help? thanks
Hi, I've just tried it out in IE 11 and it doesn't work. I found several problems:
I've managed to solve problems number 1 and number 2 (thanks to Babel). So here's the working code (except last point)
`
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arrSymbol.iterator, _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i"return"; } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
L.Control.HtmlLegend = L.Control.extend({
_map: null,
_activeLayers: 0,
_alwaysShow: false,
options: {
position: 'topright',
// array of legend entries - see README for format
legends: [],
// if true, legend entries that are from a simple renderer will use compact presentation
collapseSimple: false,
// if true, will test to see if legend entries look stretched; these are usually in sets of 3 with the middle element having no label
detectStretched: false,
// if true, legends will be collapsed when a new instance is initialized
collapsedOnInit: false,
disableVisibilityControls: false,
updateOpacity: null,
defaultOpacity: 1,
visibleIcon: 'leaflet-html-legend-icon-eye',
hiddenIcon: 'leaflet-html-legend-icon-eye-slash',
toggleIcon: 'leaflet-html-legend-icon-eye'
},
onAdd: function onAdd(map) {
this._map = map;
this._container = L.DomUtil.create('div', 'leaflet-control leaflet-bar leaflet-html-legend');
this._lastId = 0;
this._entries = {};
// Disable events on container
L.DomEvent.disableClickPropagation(this._container);
L.DomEvent.disableScrollPropagation(this._container);
this.render();
return this._container;
},
render: function render() {
var _this = this;
L.DomUtil.empty(this._container);
this.options.legends.forEach(function (legend) {
return _this._renderLegend(legend);
}, this);
this._checkVisibility();
},
addLegend: function addLegend(legend) {
if (this._map) {
this._renderLegend(legend);
return this._lastId;
}
throw Error('Legend control must be added to the map first.');
},
removeLegend: function removeLegend(itemIdx) {
var entry = this._entries[itemIdx];
if (entry) {
if (entry.layer && entry.events) {
Object.entries(entry.events).forEach(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
event = _ref2[0],
handler = _ref2[1];
return entry.layer.off(event, handler);
});
}
L.DomUtil.remove(this._entries[itemIdx].container);
delete this._entries[itemIdx];
}
},
_renderLegend: function _renderLegend(legend) {
var _this2 = this;
if (!legend.elements) {
return;
}
var elements = legend.elements;
var className = 'legend-block';
if (this.options.detectStretched) {
if (elements.length === 3 && elements[0].label !== '' && elements[1].label === '' && elements[2].label !== '') {
className += ' legend-stretched';
}
}
var block = L.DomUtil.create('div', className, this._container);
var entryIdx = ++this._lastId;
this._entries[entryIdx] = { container: block };
if (this.options.collapseSimple && elements.length === 1 && !elements[0].label) {
this._addElement(elements[0].html, legend.name, elements[0].style, block);
this._connectLayer(block, legend, entryIdx);
return block;
}
if (legend.name) {
var header = L.DomUtil.create('h4', null, block);
L.DomUtil.create('div', 'legend-caret', header);
L.DomUtil.create('span', null, header).innerHTML = legend.name;
if (this.options.collapsedOnInit) {
L.DomUtil.addClass(header, 'closed');
}
L.DomEvent.on(header, 'click', function () {
if (L.DomUtil.hasClass(header, 'closed')) {
L.DomUtil.removeClass(header, 'closed');
} else {
L.DomUtil.addClass(header, 'closed');
}
}, this);
}
var elementContainer = L.DomUtil.create('div', 'legend-elements', block);
elements.forEach(function (element) {
_this2._addElement(element.html, element.label, element.style, elementContainer);
}, this);
this._connectLayer(block, legend, entryIdx);
return block;
},
_addElement: function _addElement(html, label, style, container) {
var row = L.DomUtil.create('div', 'legend-row', container);
var symbol = L.DomUtil.create('span', 'symbol', row);
if (style) {
Object.entries(style).forEach(function (_ref3) {
var _ref4 = _slicedToArray(_ref3, 2),
k = _ref4[0],
v = _ref4[1];
symbol.style[k] = v;
});
}
symbol.innerHTML = html;
if (label) {
L.DomUtil.create('label', null, row).innerHTML = label;
}
},
_updateOpacity: function _updateOpacity(layer, opacity) {
if (typeof this.options.updateOpacity === 'function') {
this.options.updateOpacity(layer, opacity);
} else if (typeof layer.setOpacity === 'function') {
layer.setOpacity(opacity);
} else if (typeof layer.setStyle === 'function') {
layer.setStyle({ opacity: opacity });
}
},
_layerAdd: function _layerAdd(container) {
this._activeLayers += 1;
container.style.display = '';
this._checkVisibility();
},
_layerRemove: function _layerRemove(container) {
this._activeLayers -= 1;
container.style.display = 'none';
this._checkVisibility();
},
_connectLayer: function _connectLayer(container, legend, entryIdx) {
var _this3 = this;
var layer = legend.layer;
if (!layer) {
this._alwaysShow = true;
return;
}
if (this._map.hasLayer(layer)) {
this._activeLayers += 1;
} else {
container.style.display = 'none';
}
container.classList.add('layer-control');
if (!this.options.disableVisibilityControls) {
var opacity = layer.opacity || this.options.defaultOpacity || 1;
this._updateOpacity(layer, opacity);
var toggleButton = L.DomUtil.create('i', 'visibility-toggle ' + this.options.toggleIcon, container);
toggleButton.dataset.visibileOpacity = opacity;
L.DomEvent.on(toggleButton, 'click', function (e) {
var button = e.target;
if (L.DomUtil.hasClass(button, 'disabled')) {
L.DomUtil.removeClass(button, 'disabled');
_this3._updateOpacity(layer, button.dataset.visibileOpacity);
} else {
L.DomUtil.addClass(button, 'disabled');
_this3._updateOpacity(layer, 0);
}
});
var opacityController = L.DomUtil.create('span', 'opacity-slider', container);
L.DomUtil.create('span', 'slider-label', opacityController).innerHTML = 'Transparency:';
L.DomUtil.create('i', this.options.visibleIcon, opacityController);
var opacitySlider = L.DomUtil.create('input', null, opacityController);
opacitySlider.type = 'range';
opacitySlider.min = 0;
opacitySlider.max = 1;
opacitySlider.step = 0.1;
opacitySlider.onchange = function (e) {
var newOpacity = 1 - e.target.value || 0;
_this3._updateOpacity(layer, newOpacity);
toggleButton.dataset.visibileOpacity = newOpacity;
L.DomUtil.removeClass(toggleButton, 'disabled');
};
opacitySlider.value = 1 - opacity;
L.DomUtil.create('i', this.options.hiddenIcon, opacityController);
};
var layerAdd = this._layerAdd.bind(this, container);
var layerRemove = this._layerRemove.bind(this, container);
layer.on('add', layerAdd).on('remove', layerRemove);
this._entries[entryIdx].layer = layer;
this._entries[entryIdx].events = {
add: layerAdd,
remove: layerRemove
};
},
_checkVisibility: function _checkVisibility() {
if (this._alwaysShow || this._activeLayers) {
this._container.style.display = '';
} else {
this._container.style.display = 'none';
}
}
});
L.control.htmllegend = function (options) {
return new L.Control.HtmlLegend(options);
};
`
I'll try to figure out what's going on with the slider.
Hope this can help someone else.
Hi, cheers for this very handy plugin!
I try to control the opacity of a GeoJSON layer with the opacity slider. The issue is that my GeoJSON layer is styled with transparent stroke and colored filling. So when using the opacity slider, I want it to control fillOpacity
instead of opacity
. At the moment _updateOpacity
only sets the opacity
attribute.
It's easy to extend HtmlLegend to override _updateOpacity
so that it sets the fillOpacity
attribute.
I just wonder if it might be a common need and if HtmlLegend should allow to specify on which attribute the opacity slider acts.
This looks great! Tried to use it, but npm can't seem to find it :(
https://www.npmjs.com/search?q=leaflet+html+legend
Also, after adding this package directly from github, it seems the package.json is missing a main entry:
"main": "L.Control.HtmlLegend.min.js"
I'm not an npm expert, but this made things work-
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.