Built with blockbuilder.org
Instantly share code, notes, and snippets.
-
Star
(0)
0
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save renauld94/70697d1b6b56c16c4bc15559700a645b to your computer and use it in GitHub Desktop.
L.FunctionButtons
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
license: mit |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.leaflet-bar button, | |
.leaflet-bar button:hover { | |
background-color: #fff; | |
border: none; | |
border-bottom: 1px solid #ccc; | |
width: 26px; | |
height: 26px; | |
line-height: 26px; | |
display: block; | |
text-align: center; | |
text-decoration: none; | |
color: black; | |
} | |
.leaflet-bar button { | |
background-position: 50% 50%; | |
background-repeat: no-repeat; | |
overflow: hidden; | |
display: block; | |
} | |
.leaflet-bar button:hover { | |
background-color: #f4f4f4; | |
} | |
.leaflet-bar button:first-of-type { | |
border-top-left-radius: 4px; | |
border-top-right-radius: 4px; | |
} | |
.leaflet-bar button:last-of-type { | |
border-bottom-left-radius: 4px; | |
border-bottom-right-radius: 4px; | |
border-bottom: none; | |
} | |
.leaflet-bar.disabled, | |
.leaflet-bar button.disabled { | |
cursor: default; | |
pointer-events: none; | |
opacity: .4; | |
} | |
.easy-button-button .button-state{ | |
display: block; | |
width: 100%; | |
height: 100%; | |
position: relative; | |
} | |
.leaflet-touch .leaflet-bar button { | |
width: 30px; | |
height: 30px; | |
line-height: 30px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as L from 'leaflet' | |
import {ControlPosition} from 'leaflet'; | |
declare module 'leaflet' { | |
/** | |
* Creates a bar that holds a group of EasyButtons | |
* @param buttons array of EasyButtons that will be grouped together in the EasyBar | |
* @param options | |
*/ | |
function easyBar(buttons: Control.EasyButton[], options?: EasyBarOptions): Control.EasyBar; | |
/** | |
* Creates a easyButton | |
* @param icon e.g. fa-globe | |
* @param onClick the button click handler | |
* @param title title on the button | |
* @param id an id to tag the button with | |
* @example | |
* var helloPopup = L.popup().setContent('Hello World!'); | |
* | |
* L.easyButton('fa-globe', function(btn, map){ | |
* helloPopup.setLatLng(map.getCenter()).openOn(map); | |
* }).addTo( YOUR_LEAFLET_MAP ); | |
*/ | |
function easyButton(icon: string, | |
onClick: (btn: Control.EasyButton, map: L.Map) => void, | |
title?: string, | |
id?: string): Control.EasyButton; | |
/** | |
* Creates a easyButton | |
* @param options the options object | |
* @example | |
* | |
* | |
* L.easyButton({ | |
* position: 'topleft', | |
* leafletClasses: true, | |
* states: [ | |
* { | |
* stateName: 'center', | |
* onClick: function(btn, map){}, | |
* title: 'Get Center', | |
* icon: 'fa-globe' | |
* } | |
* ] | |
* }).addTo( YOUR_LEAFLET_MAP ); | |
*/ | |
function easyButton(options: EasyButtonOptions): Control.EasyButton; | |
interface EasyBarOptions { | |
position?: ControlPosition | |
id?: string | |
leafletClasses?: boolean | |
} | |
interface EasyButtonOptions { | |
position?: ControlPosition | |
id?: string | |
type?: 'replace' | 'animate' | |
states?: EasyButtonState[] | |
leafletClasses?: boolean | |
tagName?: string | |
} | |
interface EasyButtonState { | |
stateName: string | |
onClick: (btn: L.Control.EasyButton, map: L.Map) => void | |
title: string | |
icon: string | |
} | |
namespace Control { | |
class EasyButton extends L.Control { | |
constructor(options?: EasyButtonOptions) | |
state(stateName: string): EasyButton | |
enable(): void | |
disable(): void | |
} | |
class EasyBar extends L.Control { | |
constructor(options?: EasyBarOptions) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* A leaflet button with icon or text and click listener. | |
*/ | |
L.FunctionButtons = L.Control.extend({ | |
includes: L.Mixin.Events, | |
initialize: function( buttons, options ) { | |
if( !('push' in buttons && 'splice' in buttons) ) | |
buttons = [buttons]; | |
this._buttons = buttons; | |
if( !options && buttons.length > 0 && 'position' in buttons[0] ) | |
options = { position: buttons[0].position }; | |
L.Control.prototype.initialize.call(this, options); | |
}, | |
onAdd: function( map ) { | |
this._map = map; | |
this._links = []; | |
var container = L.DomUtil.create('div', 'leaflet-bar'); | |
for( var i = 0; i < this._buttons.length; i++ ) { | |
var button = this._buttons[i], | |
link = L.DomUtil.create('a', '', container); | |
link._buttonIndex = i; // todo: remove? | |
link.href = button.href || '#'; | |
if( button.href ) | |
link.target = 'funcbtn'; | |
link.style.padding = '0 4px'; | |
link.style.width = 'auto'; | |
link.style.minWidth = '20px'; | |
if( button.bgColor ) | |
link.style.backgroundColor = button.bgColor; | |
if( button.title ) | |
link.title = button.title; | |
button.link = link; | |
this._updateContent(i); | |
var stop = L.DomEvent.stopPropagation; | |
L.DomEvent | |
.on(link, 'click', stop) | |
.on(link, 'mousedown', stop) | |
.on(link, 'dblclick', stop); | |
if( !button.href ) | |
L.DomEvent | |
.on(link, 'click', L.DomEvent.preventDefault) | |
.on(link, 'click', this.clicked, this); | |
} | |
return container; | |
}, | |
_updateContent: function( n ) { | |
if( n >= this._buttons.length ) | |
return; | |
var button = this._buttons[n], | |
link = button.link, | |
content = button.content; | |
if( !link ) | |
return; | |
if( content === undefined || content === false || content === null || content === '' ) | |
link.innerHTML = button.alt || ' '; | |
else if( typeof content === 'string' ) { | |
var ext = content.length < 4 ? '' : content.substring(content.length - 4), | |
isData = content.substring(0, 11) === 'data:image/'; | |
if( ext === '.png' || ext === '.gif' || ext === '.jpg' || isData ) { | |
link.style.width = '' + (button.imageSize || 26) + 'px'; | |
link.style.height = '' + (button.imageSize || 26) + 'px'; | |
link.style.padding = '0'; | |
link.style.backgroundImage = 'url(' + content + ')'; | |
link.style.backgroundRepeat = 'no-repeat'; | |
link.style.backgroundPosition = button.bgPos ? (-button.bgPos[0]) + 'px ' + (-button.bgPos[1]) + 'px' : '0px 0px'; | |
} else | |
link.innerHTML = content; | |
} else { | |
while( link.firstChild ) | |
link.removeChild(link.firstChild); | |
link.appendChild(content); | |
} | |
}, | |
setContent: function( n, content ) { | |
if( content === undefined ) { | |
content = n; | |
n = 0; | |
} | |
if( n < this._buttons.length ) { | |
this._buttons[n].content = content; | |
this._updateContent(n); | |
} | |
}, | |
setTitle: function( n, title ) { | |
if( title === undefined ) { | |
title = n; | |
n = 0; | |
} | |
if( n < this._buttons.length ) { | |
var button = this._buttons[n]; | |
button.title = title; | |
if( button.link ) | |
button.link.title = title; | |
} | |
}, | |
setBgPos: function( n, bgPos ) { | |
if( bgPos === undefined ) { | |
bgPos = n; | |
n = 0; | |
} | |
if( n < this._buttons.length ) { | |
var button = this._buttons[n]; | |
button.bgPos = bgPos; | |
if( button.link ) | |
button.link.style.backgroundPosition = bgPos ? (-bgPos[0]) + 'px ' + (-bgPos[1]) + 'px' : '0px 0px'; | |
} | |
}, | |
setHref: function( n, href ) { | |
if( href === undefined ) { | |
href = n; | |
n = 0; | |
} | |
if( n < this._buttons.length ) { | |
var button = this._buttons[n]; | |
button.href = href; | |
if( button.link ) | |
button.link.href = href; | |
} | |
}, | |
clicked: function(e) { | |
var link = (window.event && window.event.srcElement) || e.target || e.srcElement; | |
while( link && 'tagName' in link && link.tagName !== 'A' && !('_buttonIndex' in link ) ) | |
link = link.parentNode; | |
if( '_buttonIndex' in link ) { | |
var button = this._buttons[link._buttonIndex]; | |
if( button ) { | |
if( 'callback' in button ) | |
button.callback.call(button.context); | |
this.fire('clicked', { idx: link._buttonIndex }); | |
} | |
} | |
} | |
}); | |
L.functionButtons = function( buttons, options ) { | |
return new L.FunctionButtons(buttons, options); | |
}; | |
/* | |
* Helper method from the old class. It is not recommended to use it, please use L.functionButtons(). | |
*/ | |
L.functionButton = function( content, button, options ) { | |
if( button ) | |
button.content = content; | |
else | |
button = { content: content }; | |
return L.functionButtons([button], options); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>GeoJSON with Leaflet + D3 using L.D3SvgOverlay</title> | |
<style type="text/css"> | |
html { height: 100% } | |
body { height: 100%; margin: 0; padding: 0 } | |
#map-canvas { height: 100% } | |
</style> | |
<link href='https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.css' | |
rel='stylesheet' type='text/css'/> | |
<meta http-equiv="X-UA-Compatible" content="IE=Edge"> | |
</head> | |
<body> | |
<div id="map-canvas"></div> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.7/leaflet.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.9/d3.min.js"></script> | |
<script src="L.D3SvgOverlay.min.js"></script> | |
<script src="leaflet/label.js"></script> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet-easybutton@2/src/easy-button.css"> | |
<script src="https://cdn.jsdelivr.net/npm/leaflet-easybutton@2/src/easy-button.js"></script> | |
<script> | |
//change for open streetmaps or multiselection #an attribution is obligatory as per the copyright notice | |
var map = L.map("map-canvas", {center: [10.762622, 106.660172], zoom: 11}); | |
var tiles = L.tileLayer('http://server.arcgisonline.com/ArcGIS/rest/services/World_Topo_Map/MapServer/tile/{z}/{y}/{x}', { | |
attribution: 'Sanisphere©' | |
}); | |
tiles.addTo(map); | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function(){ | |
// This is for grouping buttons into a bar | |
// takes an array of `L.easyButton`s and | |
// then the usual `.addTo(map)` | |
L.Control.EasyBar = L.Control.extend({ | |
options: { | |
position: 'topleft', // part of leaflet's defaults | |
id: null, // an id to tag the Bar with | |
leafletClasses: true // use leaflet classes? | |
}, | |
initialize: function(buttons, options){ | |
if(options){ | |
L.Util.setOptions( this, options ); | |
} | |
this._buildContainer(); | |
this._buttons = []; | |
for(var i = 0; i < buttons.length; i++){ | |
buttons[i]._bar = this; | |
buttons[i]._container = buttons[i].button; | |
this._buttons.push(buttons[i]); | |
this.container.appendChild(buttons[i].button); | |
} | |
}, | |
_buildContainer: function(){ | |
this._container = this.container = L.DomUtil.create('div', ''); | |
this.options.leafletClasses && L.DomUtil.addClass(this.container, 'leaflet-bar easy-button-container leaflet-control'); | |
this.options.id && (this.container.id = this.options.id); | |
}, | |
enable: function(){ | |
L.DomUtil.addClass(this.container, 'enabled'); | |
L.DomUtil.removeClass(this.container, 'disabled'); | |
this.container.setAttribute('aria-hidden', 'false'); | |
return this; | |
}, | |
disable: function(){ | |
L.DomUtil.addClass(this.container, 'disabled'); | |
L.DomUtil.removeClass(this.container, 'enabled'); | |
this.container.setAttribute('aria-hidden', 'true'); | |
return this; | |
}, | |
onAdd: function () { | |
return this.container; | |
}, | |
addTo: function (map) { | |
this._map = map; | |
for(var i = 0; i < this._buttons.length; i++){ | |
this._buttons[i]._map = map; | |
} | |
var container = this._container = this.onAdd(map), | |
pos = this.getPosition(), | |
corner = map._controlCorners[pos]; | |
L.DomUtil.addClass(container, 'leaflet-control'); | |
if (pos.indexOf('bottom') !== -1) { | |
corner.insertBefore(container, corner.firstChild); | |
} else { | |
corner.appendChild(container); | |
} | |
return this; | |
} | |
}); | |
L.easyBar = function(){ | |
var args = [L.Control.EasyBar]; | |
for(var i = 0; i < arguments.length; i++){ | |
args.push( arguments[i] ); | |
} | |
return new (Function.prototype.bind.apply(L.Control.EasyBar, args)); | |
}; | |
// L.EasyButton is the actual buttons | |
// can be called without being grouped into a bar | |
L.Control.EasyButton = L.Control.extend({ | |
options: { | |
position: 'topleft', // part of leaflet's defaults | |
id: null, // an id to tag the button with | |
type: 'replace', // [(replace|animate)] | |
// replace swaps out elements | |
// animate changes classes with all elements inserted | |
states: [], // state names look like this | |
// { | |
// stateName: 'untracked', | |
// onClick: function(){ handle_nav_manually(); }; | |
// title: 'click to make inactive', | |
// icon: 'fa-circle', // wrapped with <a> | |
// } | |
leafletClasses: true, // use leaflet styles for the button | |
tagName: 'button', | |
}, | |
initialize: function(icon, onClick, title, id){ | |
// clear the states manually | |
this.options.states = []; | |
// add id to options | |
if(id != null){ | |
this.options.id = id; | |
} | |
// storage between state functions | |
this.storage = {}; | |
// is the last item an object? | |
if( typeof arguments[arguments.length-1] === 'object' ){ | |
// if so, it should be the options | |
L.Util.setOptions( this, arguments[arguments.length-1] ); | |
} | |
// if there aren't any states in options | |
// use the early params | |
if( this.options.states.length === 0 && | |
typeof icon === 'string' && | |
typeof onClick === 'function'){ | |
// turn the options object into a state | |
this.options.states.push({ | |
icon: icon, | |
onClick: onClick, | |
title: typeof title === 'string' ? title : '' | |
}); | |
} | |
// curate and move user's states into | |
// the _states for internal use | |
this._states = []; | |
for(var i = 0; i < this.options.states.length; i++){ | |
this._states.push( new State(this.options.states[i], this) ); | |
} | |
this._buildButton(); | |
this._activateState(this._states[0]); | |
}, | |
_buildButton: function(){ | |
this.button = L.DomUtil.create(this.options.tagName, ''); | |
if (this.options.tagName === 'button') { | |
this.button.setAttribute('type', 'button'); | |
} | |
if (this.options.id ){ | |
this.button.id = this.options.id; | |
} | |
if (this.options.leafletClasses){ | |
L.DomUtil.addClass(this.button, 'easy-button-button leaflet-bar-part leaflet-interactive'); | |
} | |
// don't let double clicks and mousedown get to the map | |
L.DomEvent.addListener(this.button, 'dblclick', L.DomEvent.stop); | |
L.DomEvent.addListener(this.button, 'mousedown', L.DomEvent.stop); | |
L.DomEvent.addListener(this.button, 'mouseup', L.DomEvent.stop); | |
// take care of normal clicks | |
L.DomEvent.addListener(this.button,'click', function(e){ | |
L.DomEvent.stop(e); | |
this._currentState.onClick(this, this._map ? this._map : null ); | |
this._map && this._map.getContainer().focus(); | |
}, this); | |
// prep the contents of the control | |
if(this.options.type == 'replace'){ | |
this.button.appendChild(this._currentState.icon); | |
} else { | |
for(var i=0;i<this._states.length;i++){ | |
this.button.appendChild(this._states[i].icon); | |
} | |
} | |
}, | |
_currentState: { | |
// placeholder content | |
stateName: 'unnamed', | |
icon: (function(){ return document.createElement('span'); })() | |
}, | |
_states: null, // populated on init | |
state: function(newState){ | |
// activate by name | |
if(typeof newState == 'string'){ | |
this._activateStateNamed(newState); | |
// activate by index | |
} else if (typeof newState == 'number'){ | |
this._activateState(this._states[newState]); | |
} | |
return this; | |
}, | |
_activateStateNamed: function(stateName){ | |
for(var i = 0; i < this._states.length; i++){ | |
if( this._states[i].stateName == stateName ){ | |
this._activateState( this._states[i] ); | |
} | |
} | |
}, | |
_activateState: function(newState){ | |
if( newState === this._currentState ){ | |
// don't touch the dom if it'll just be the same after | |
return; | |
} else { | |
// swap out elements... if you're into that kind of thing | |
if( this.options.type == 'replace' ){ | |
this.button.appendChild(newState.icon); | |
this.button.removeChild(this._currentState.icon); | |
} | |
if( newState.title ){ | |
this.button.title = newState.title; | |
} else { | |
this.button.removeAttribute('title'); | |
} | |
// update classes for animations | |
for(var i=0;i<this._states.length;i++){ | |
L.DomUtil.removeClass(this._states[i].icon, this._currentState.stateName + '-active'); | |
L.DomUtil.addClass(this._states[i].icon, newState.stateName + '-active'); | |
} | |
// update classes for animations | |
L.DomUtil.removeClass(this.button, this._currentState.stateName + '-active'); | |
L.DomUtil.addClass(this.button, newState.stateName + '-active'); | |
// update the record | |
this._currentState = newState; | |
} | |
}, | |
enable: function(){ | |
L.DomUtil.addClass(this.button, 'enabled'); | |
L.DomUtil.removeClass(this.button, 'disabled'); | |
this.button.setAttribute('aria-hidden', 'false'); | |
return this; | |
}, | |
disable: function(){ | |
L.DomUtil.addClass(this.button, 'disabled'); | |
L.DomUtil.removeClass(this.button, 'enabled'); | |
this.button.setAttribute('aria-hidden', 'true'); | |
return this; | |
}, | |
onAdd: function(map){ | |
var bar = L.easyBar([this], { | |
position: this.options.position, | |
leafletClasses: this.options.leafletClasses | |
}); | |
this._anonymousBar = bar; | |
this._container = bar.container; | |
return this._anonymousBar.container; | |
}, | |
removeFrom: function (map) { | |
if (this._map === map) | |
this.remove(); | |
return this; | |
}, | |
}); | |
L.easyButton = function(/* args will pass automatically */){ | |
var args = Array.prototype.concat.apply([L.Control.EasyButton],arguments); | |
return new (Function.prototype.bind.apply(L.Control.EasyButton, args)); | |
}; | |
/************************* | |
* | |
* util functions | |
* | |
*************************/ | |
// constructor for states so only curated | |
// states end up getting called | |
function State(template, easyButton){ | |
this.title = template.title; | |
this.stateName = template.stateName ? template.stateName : 'unnamed-state'; | |
// build the wrapper | |
this.icon = L.DomUtil.create('span', ''); | |
L.DomUtil.addClass(this.icon, 'button-state state-' + this.stateName.replace(/(^\s*|\s*$)/g,'')); | |
this.icon.innerHTML = buildIcon(template.icon); | |
this.onClick = L.Util.bind(template.onClick?template.onClick:function(){}, easyButton); | |
} | |
function buildIcon(ambiguousIconString) { | |
var tmpIcon; | |
// does this look like html? (i.e. not a class) | |
if( ambiguousIconString.match(/[&;=<>"']/) ){ | |
// if so, the user should have put in html | |
// so move forward as such | |
tmpIcon = ambiguousIconString; | |
// then it wasn't html, so | |
// it's a class list, figure out what kind | |
} else { | |
ambiguousIconString = ambiguousIconString.replace(/(^\s*|\s*$)/g,''); | |
tmpIcon = L.DomUtil.create('span', ''); | |
if( ambiguousIconString.indexOf('fa-') === 0 ){ | |
L.DomUtil.addClass(tmpIcon, 'fa ' + ambiguousIconString) | |
} else if ( ambiguousIconString.indexOf('glyphicon-') === 0 ) { | |
L.DomUtil.addClass(tmpIcon, 'glyphicon ' + ambiguousIconString) | |
} else { | |
L.DomUtil.addClass(tmpIcon, /*rollwithit*/ ambiguousIconString) | |
} | |
// make this a string so that it's easy to set innerHTML below | |
tmpIcon = tmpIcon.outerHTML; | |
} | |
return tmpIcon; | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment