first commit

This commit is contained in:
2025-07-18 16:20:14 +07:00
commit 98af45c018
16382 changed files with 3148096 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
Copyright (c) 2014 David C.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,27 @@
/* Icons from Font-Awesome | Font Awesome by Dave Gandy - http://fontawesome.io*/
/* Thanks to http://fa2png.io/ for icon png generation */
.leaflet-control-navbar-fwd {
background-image: url("img/arrow-right_000000_14.png");
}
.leaflet-control-navbar-back {
background-image: url("img/arrow-left_000000_14.png");
}
.leaflet-control-navbar-home {
background-image: url("img/home_000000_14.png");
}
.leaflet-control-navbar-fwd-disabled {
background-image: url("img/arrow-right_bbbbbb_14.png");
}
.leaflet-control-navbar-back-disabled {
background-image: url("img/arrow-left_bbbbbb_14.png");
}
.leaflet-control-navbar-home-disabled {
background-image: url("img/home_bbbbbb_14.png");
}

View File

@@ -0,0 +1,4 @@
/*
* Simple navigation control that allows back and forward navigation through map's view history
*/
(function(){L.Control.NavBar=L.Control.extend({options:{position:'topleft',forwardTitle:'Go forward in map view history',backTitle:'Go back in map view history',homeTitle:'Go to home map view'},onAdd:function(map){if(!this.options.center){this.options.center=map.getCenter()}if(!this.options.zoom){this.options.zoom=map.getZoom()}var options=this.options;var controlName='leaflet-control-navbar',container=L.DomUtil.create('div',controlName+' leaflet-bar');this._homeButton=this._createButton(options.homeTitle,controlName+'-home',container,this._goHome);this._fwdButton=this._createButton(options.forwardTitle,controlName+'-fwd',container,this._goFwd);this._backButton=this._createButton(options.backTitle,controlName+'-back',container,this._goBack);this._viewHistory=[{center:this.options.center,zoom:this.options.zoom}];this._curIndx=0;this._updateDisabled();map.once('moveend',function(){this._map.on('moveend',this._updateHistory,this)},this);map.setView(options.center,options.zoom);return container},onRemove:function(map){map.off('moveend',this._updateHistory,this)},_goHome:function(){if(this.options.bbox){try{this._map.fitBounds(this.options.bbox)}catch(err){this._map.setView(this.options.center,this.options.zoom);}}this._map.setView(this.options.center,this.options.zoom)},_goBack:function(){if(this._curIndx!==0){this._map.off('moveend',this._updateHistory,this);this._map.once('moveend',function(){this._map.on('moveend',this._updateHistory,this)},this);this._curIndx-=1;this._updateDisabled();var view=this._viewHistory[this._curIndx];this._map.setView(view.center,view.zoom)}},_goFwd:function(){if(this._curIndx!=this._viewHistory.length-1){this._map.off('moveend',this._updateHistory,this);this._map.once('moveend',function(){this._map.on('moveend',this._updateHistory,this)},this);this._curIndx+=1;this._updateDisabled();var view=this._viewHistory[this._curIndx];this._map.setView(view.center,view.zoom)}},_createButton:function(title,className,container,fn){var link=L.DomUtil.create('a',className,container);link.href='#';link.title=title;L.DomEvent.on(link,'mousedown dblclick',L.DomEvent.stopPropagation).on(link,'click',L.DomEvent.stop).on(link,'click',fn,this).on(link,'click',this._refocusOnMap,this);return link},_updateHistory:function(){var newView={center:this._map.getCenter(),zoom:this._map.getZoom()};var insertIndx=this._curIndx+1;this._viewHistory.splice(insertIndx,this._viewHistory.length-insertIndx,newView);this._curIndx+=1;this._updateDisabled()},_setFwdEnabled:function(enabled){var leafletDisabled='leaflet-disabled';var fwdDisabled='leaflet-control-navbar-fwd-disabled';if(enabled===true){L.DomUtil.removeClass(this._fwdButton,fwdDisabled);L.DomUtil.removeClass(this._fwdButton,leafletDisabled)}else{L.DomUtil.addClass(this._fwdButton,fwdDisabled);L.DomUtil.addClass(this._fwdButton,leafletDisabled)}},_setBackEnabled:function(enabled){var leafletDisabled='leaflet-disabled';var backDisabled='leaflet-control-navbar-back-disabled';if(enabled===true){L.DomUtil.removeClass(this._backButton,backDisabled);L.DomUtil.removeClass(this._backButton,leafletDisabled)}else{L.DomUtil.addClass(this._backButton,backDisabled);L.DomUtil.addClass(this._backButton,leafletDisabled)}},_updateDisabled:function(){if(this._curIndx==(this._viewHistory.length-1)){this._setFwdEnabled(false)}else{this._setFwdEnabled(true)}if(this._curIndx<=0){this._setBackEnabled(false)}else{this._setBackEnabled(true)}}});L.control.navbar=function(options){return new L.Control.NavBar(options)}})();

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

View File

@@ -0,0 +1,7 @@
# 1.0.0 (2019-02-06)
* Switched from base64-encoded images to PouchDB attachments (should perform
much better)

View File

@@ -0,0 +1 @@
if(!HTMLCanvasElement.prototype.toBlob){Object.defineProperty(HTMLCanvasElement.prototype,"toBlob",{value:function(callback,type,quality){var dataURL=this.toDataURL(type,quality).split(",")[1];setTimeout(function(){var binStr=atob(dataURL),len=binStr.length,arr=new Uint8Array(len);for(var i=0;i<len;i+=1){arr[i]=binStr.charCodeAt(i)}callback(new Blob([arr],{type:type||"image/png"}))})}})}L.TileLayer.addInitHook(function(){if(!this.options.useCache){this._db=null;return}this._db=new PouchDB("offline-tiles")});L.TileLayer.prototype.options.useCache=false;L.TileLayer.prototype.options.saveToCache=true;L.TileLayer.prototype.options.useOnlyCache=false;L.TileLayer.prototype.options.cacheFormat="image/png";L.TileLayer.prototype.options.cacheMaxAge=24*3600*1000;L.TileLayer.include({createTile:function(coords,done){var tile=document.createElement("img");tile.onerror=L.bind(this._tileOnError,this,done,tile);if(this.options.crossOrigin){tile.crossOrigin=""}tile.alt="";var tileUrl=this.getTileUrl(coords);if(this.options.useCache){this._db.get(tileUrl,{revs_info:true},this._onCacheLookup(tile,tileUrl,done))}else{tile.onload=L.bind(this._tileOnLoad,this,done,tile);tile.src=tileUrl}return tile},_onCacheLookup:function(tile,tileUrl,done){return function(err,data){if(data){return this._onCacheHit(tile,tileUrl,data,done)}else{return this._onCacheMiss(tile,tileUrl,done)}}.bind(this)},_onCacheHit:function(tile,tileUrl,data,done){this.fire("tilecachehit",{tile:tile,url:tileUrl});this._db.getAttachment(tileUrl,"tile").then(function(blob){var url=URL.createObjectURL(blob);if(Date.now()>data.timestamp+this.options.cacheMaxAge&&!this.options.useOnlyCache){console.log("Tile is too old: ",tileUrl);if(this.options.saveToCache){tile.onload=L.bind(this._saveTile,this,tile,tileUrl,data._revs_info[0].rev,done)}tile.crossOrigin="Anonymous";tile.src=tileUrl;tile.onerror=function(ev){this.src=url}}else{tile.onload=L.bind(this._tileOnLoad,this,done,tile);tile.src=url}}.bind(this))},_onCacheMiss:function(tile,tileUrl,done){this.fire("tilecachemiss",{tile:tile,url:tileUrl});if(this.options.useOnlyCache){tile.onload=L.Util.falseFn;tile.src=L.Util.emptyImageUrl}else{if(this.options.saveToCache){tile.onload=L.bind(this._saveTile,this,tile,tileUrl,undefined,done)}else{tile.onload=L.bind(this._tileOnLoad,this,done,tile)}tile.crossOrigin="Anonymous";tile.src=tileUrl}},_saveTile:function(tile,tileUrl,existingRevision,done){if(!this.options.saveToCache){return}var canvas=document.createElement("canvas");canvas.width=tile.naturalWidth||tile.width;canvas.height=tile.naturalHeight||tile.height;var context=canvas.getContext("2d");context.drawImage(tile,0,0);var format=this.options.cacheFormat;canvas.toBlob(function(blob){this._db.put({_id:tileUrl,_rev:existingRevision,timestamp:Date.now()}).then(function(status){return this._db.putAttachment(tileUrl,"tile",status.rev,blob,format)}.bind(this)).then(function(resp){if(done){done()}}).catch(function(){if(done){done()}})}.bind(this),format)},seed:function(bbox,minZoom,maxZoom){if(!this.options.useCache){return}if(minZoom>maxZoom){return}if(!this._map){return}var queue=[];for(var z=minZoom;z<=maxZoom;z+=1){var northEastPoint=this._map.project(bbox.getNorthEast(),z);var southWestPoint=this._map.project(bbox.getSouthWest(),z);var tileBounds=this._pxBoundsToTileRange(L.bounds([northEastPoint,southWestPoint]));for(var j=tileBounds.min.y;j<=tileBounds.max.y;j+=1){for(var i=tileBounds.min.x;i<=tileBounds.max.x;i+=1){var point=new L.Point(i,j);point.z=z;queue.push(this._getTileUrl(point))}}}var seedData={bbox:bbox,minZoom:minZoom,maxZoom:maxZoom,queueLength:queue.length};this.fire("seedstart",seedData);var tile=this._createTile();tile._layer=this;this._seedOneTile(tile,queue,seedData);return this},_createTile:function(){return document.createElement("img")},_getTileUrl:function(coords){var zoom=coords.z;if(this.options.zoomReverse){zoom=this.options.maxZoom-zoom}zoom+=this.options.zoomOffset;return L.Util.template(this._url,L.extend({r:this.options.detectRetina&&L.Browser.retina&&this.options.maxZoom>0?"@2x":"",s:this._getSubdomain(coords),x:coords.x,y:this.options.tms?this._globalTileRange.max.y-coords.y:coords.y,z:this.options.maxNativeZoom?Math.min(zoom,this.options.maxNativeZoom):zoom},this.options))},_seedOneTile:function(tile,remaining,seedData){if(!remaining.length){this.fire("seedend",seedData);return}this.fire("seedprogress",{bbox:seedData.bbox,minZoom:seedData.minZoom,maxZoom:seedData.maxZoom,queueLength:seedData.queueLength,remainingLength:remaining.length});var url=remaining.shift();this._db.get(url,function(err,data){if(!data){tile.onload=function(ev){this._saveTile(tile,url,null);this._seedOneTile(tile,remaining,seedData)}.bind(this);tile.crossOrigin="Anonymous";tile.src=url}else{this._seedOneTile(tile,remaining,seedData)}}.bind(this))}});

View File

@@ -0,0 +1,82 @@
Allows all Leaflet TileLayers to cache into PouchDB for offline use, in a transparent fashion.
There is a [demo](http://mazemap.github.io/Leaflet.TileLayer.PouchDBCached/demo.html) available, which shows cache hits/misses/seeds in the browser's developer console.
# Dependencies
Tested with Leaflet 1.4.0 and PouchDB 7.0.0.
You probably want to load Leaflet, PouchDB and Leaflet.TileLayer.PouchDB like so:
```html
<script src="https://unpkg.com/leaflet@^1.0.0/dist/leaflet-src.js"></script>
<script src="https://unpkg.com/pouchdb@^5.2.0/dist/pouchdb.js"></script>
<script src="https://unpkg.com/leaflet.tilelayer.pouchdbcached@latest/L.TileLayer.PouchDBCached.js"></script>
```
If you are still using Leaflet 0.7.x, the latest compatible release is [v0.1.0](https://github.com/MazeMap/Leaflet.TileLayer.PouchDBCached/releases/tag/v0.1.0).
# Usage
The plugin modifies the core `L.TileLayer` class, so it should be possible to cache any tile layer.
To use, add the option `useCache` with a value of `true` when instantiating your layer. You probably want to use Leaflet's `crossOrigin` option, like so:
```
var layer = L.tileLayer('https://whatever/{z}/{x}/{y}.png', {
maxZoom: 18,
useCache: true,
crossOrigin: true
});
```
Options available are as follows:
* `useCache`: set to true in order to enable the cache. This option must be set at initialization time.
* `saveToCache`: Whether to save new tiles to the cache or not. Defaults to true.
* `useOnlyCache`: Whether to fetch tiles from the network or not. Defaults to false.
* `cacheMaxAge`: Time, in milliseconds, for any given tile to be considered 'fresh'. Tiles older than this value will be re-requested from the network. Defaults to 24 hours.
New functions available are as follows:
* `seed`: Starts seeding the cache for a given bounding box (a `L.LatLngBounds`), and between the two given zoom levels.
New events available are as follows:
* `tilecachehit`: Fired when a tile has been found in the tile cache. The event includes data as per http://leafletjs.com/reference.html#tile-event
* `tilecachemiss`: Like `tilecachehit`, but is fired when the tile has *not* been found in the cache.
* `tilecacheerror`: Fired when there was an error trying to save a tile in the cache. The event data includes:
* `tile`: A reference to the failed tile
* `error`: The error message, probably related to CORS.
* `seedstart`: Fired when a layer cache has started seeding. The event data includes:
* `bbox`: bounding box for the seed operation, as per the `L.TileLayer.seed()` function call.
* `minZoom` and `maxZoom`: zoom levels the seed operation, as per the `L.TileLayer.seed()` function call.
* `queueLength`: (integer) Total number of tiles to be loaded during the seed operation.
* `seedend`: Fired when a layer cache has finished seeding.
* `seedprogress`: Fired every time a tile is cached during a seed operation
* `remainingLength`: (integer) How many tiles are left in the seed queue. Starts with a value of `queueLength` and drops down to zero.
# Cross-Origin Resource Sharing
Due to the tile images being parsed and stored by the browser (technically, extracting data from a canvas in which a external image has been loaded into), the tiles must come from a tile server which allows CORS (Cross-Origin Resource Sharing) on the tiles. So tiles must have a CORS header allowing them to be loaded in the document where you're using this caching layer.
In other words: if chrome shows a grey map, and displays CORS-related messages in the console, make sure that your tileserver adds this header to all tiles:
`Access-Control-Allow-Origin: *`
# Underlying cache structure
This plugin uses an instance of PouchDB, named `offline-tiles`. PouchDB is a key-value store, so the key is the URL of a tile, and the value is a plain object containing a timestamp and the base64-encoded image.
# License and stuff
Under MIT license.
Heavily inspired by https://github.com/tbicr/OfflineMap

View File

@@ -0,0 +1,2 @@
This work is licensed under a Creative Commons Attribution 3.0 Unported License.
http://creativecommons.org/licenses/by/3.0

View File

@@ -0,0 +1,218 @@
Leaflet.StyledLayerControl
===================
### What is Leaflet.StyledLayerControl?
A [Leaflet](https://github.com/Leaflet/Leaflet) plugin that implements the management and control of layers by organization into categories or groups. The StyledLayerControl class extends the original L.control.layers control.
The plugin uses HTML5 and CSS3 to style the presentation in a modern way.
The initial ideas were based in the plugin: [Leaflet.Groupedlayercontrol](https://github.com/ismyrnow/Leaflet.groupedlayercontrol)
![preview](https://raw.githubusercontent.com/davicustodio/Leaflet.StyledLayerControl/master/examples/StyledLayerControl-example.png)
*Tested with Leaflet 0.7.3*
### Main features
- Organization of the layers into groups or categories. The layers can be an overlay or basemap
- Groups may appear initially expanded or not
- Groups can be opened exclusively
- A layer can be defined as removable
- The main container control behaves responsively, automatically adjusting the vertical resizing the map and the screen
### Live Demos
- [A map using StyledLeafletControl - not exclusive group select](http://davicustodio.github.io/Leaflet.StyledLayerControl/examples/example1.html)
- [A map using StyledLeafletControl with exclusive group select](http://davicustodio.github.io/Leaflet.StyledLayerControl/examples/example2.html)
### How to use?
1 - Create the reference to Leaflet
```javascript
<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script>
```
2 - Insert references to styledLayerControl.css and styledLayerControl.js
```javascript
<link rel="stylesheet" href="../css/styledLayerControl.css" />
<script src="../src/styledLayerControl.js"></script>
```
3 - Define your layers (base maps and overlays)
```javascript
// Google layers
var g_roadmap = new L.Google('ROADMAP');
var g_satellite = new L.Google('SATELLITE');
var g_terrain = new L.Google('TERRAIN');
// OSM layers
var osmUrl='http://{s}.tile.osm.org/{z}/{x}/{y}.png';
var osmAttrib='Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors';
var osm = new L.TileLayer(osmUrl, {attribution: osmAttrib});
// ... more Base Maps
// Sao Paulo Soybeans Plant
var soybeans_sp = new L.LayerGroup();
L.marker([-22, -49.80]).addTo(soybeans_sp),
L.marker([-23, -49.10]).addTo(soybeans_sp),
L.marker([-21, -49.50]).addTo(soybeans_sp);
// Rio de Janeiro Corn Plant
var corn_rj = new L.LayerGroup();
L.marker([-22, -43.20]).addTo(corn_rj),
L.marker([-23, -43.50]).addTo(corn_rj);
// ... more Overlays
```
4 - Create the Leaflet Map Object and add the layer that will be default basemap
```javascript
var map = L.map('map', {
center: [-16, -54],
zoom: 4
});
map.addLayer(g_roadmap);
```
5 - Define structure of groups and layers of basemap
```javascript
var baseMaps = [
{
groupName : "Google Base Maps",
expanded : true,
layers : {
"Satellite" : g_satellite,
"Road Map" : g_roadmap,
"Terreno" : g_terrain
}
}, {
groupName : "OSM Base Maps",
layers : {
"OpenStreetMaps" : osm
}
}, {
groupName : "Bing Base Maps",
layers : {
"Satellite" : bing1,
"Road" : bing2
}
}
];
```
5 - Define structure of groups and layers of overlays
```javascript
var overlays = [
{
groupName : "Sao Paulo",
expanded : true,
layers : {
"Soybeans Plant" : soybeans_sp,
"Corn Plant" : corn_sp
}
}, {
groupName : "Rio de Janeiro",
expanded : true,
layers : {
"Bean Plant" : bean_rj,
"Corn Plant" : corn_rj,
"Rice Plant" : rice_rj
}
}, {
groupName : "Belo Horizonte",
layers : {
"Sugar Cane Plant" : sugar_bh,
"Corn Plant" : corn_bh
}
}
];
```
6 - Declare which layers can be deleted and visible (create the removable property with true in the options StyledLayerControl that can be created in the layer object).
Each layer declared as removable = true will show an icon to delete the user to remove the layer
```javascript
soybeans_sp.StyledLayerControl = {
removable : true,
visible : false
}
// ... more layers
```
7 - Define the options for StyledLayerControl
- container_width - define the main container width - the default is automatic width
- container_maxHeight - define the max height to the main container - the default is automatic depending of map and screen height
- group_maxHeight - define the max height space of group container - the default is 100px
- exclusive - define that the opened group is exclusive
- All the properties are optional
- You can also include all properties available under "Options" of control L.control.layers in the same list
```javascript
var options = {
container_width : "300px",
container_maxHeight : "350px",
group_maxHeight : "80px",
exclusive : false
};
```
8 - Create the StyledLayerControl
```javascript
var control = L.Control.styledLayerControl(baseMaps, overlays, options);
map.addControl(control);
```
### How to add and remove layers and groups dynamically ?
- To add a new base layer dynamically, simply use addBaseLayer and declare that the group layer will belong.
Also note that to add a new group, simply specify a group name that does not exist yet, and a new group will be created.
```javascript
control.addBaseLayer( bing1, "Bing Satellite", {groupName : "Bing Maps", expanded: true} );
control.addBaseLayer( bing2, "Bing Road", {groupName : "Bing Maps"} );
```
- To add a new overlay layer dynamically, simply declare the group that de layer will belong.
```javascript
control.addOverlay( corn_bh, "Corn Plant", {groupName : "Belo Horizonte"} );
```
- To remove a layer dynamically, specify the instance variable of the layer using the method removeLayer. (the method ignore the removable property of layers )
```javascript
control.removeLayer( corn_sp );
```
- To remove a group, specify the name of the group in the removeGroup method.
By doing so all layers belonging to the group will also be excluded
```javascript
control.removeGroup( "Rio de Janeiro");
```
### How to select and unSelect layers dynamically ?
- To force select a layer dynamically, simply use selectLayer function like this :
```javascript
control.selectLayer( corn_sp );
```
- So.. to un-select the layer :
```javascript
control.unSelectLayer( corn_sp );
```
### How to select and unSelect group layers dynamically ?
- To force select all layer of a group, use like this :
```javascript
control.selectGroup( "Rio de Janeiro" );
```
- So.. to un-select the all layer of group :
```javascript
control.unSelectGroup( "Rio de Janeiro" );
```
### License
<a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/88x31.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US">Creative Commons Attribution 3.0 Unported License</a>.

View File

@@ -0,0 +1,146 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
<svg xmlns="http://www.w3.org/2000/svg">
<metadata>
This is a custom SVG webfont generated by Font Squirrel.
Copyright : Copyright c 2010 by Ryoichi Tsunekawa All rights reserved
Designer : Ryoichi Tsunekawa
Foundry : Ryoichi Tsunekawa
</metadata>
<defs>
<font id="BebasNeueRegular" horiz-adv-x="811" >
<font-face units-per-em="2048" ascent="1638" descent="-410" />
<missing-glyph horiz-adv-x="317" />
<glyph unicode=" " horiz-adv-x="317" />
<glyph unicode="&#x09;" horiz-adv-x="317" />
<glyph unicode="&#xa0;" horiz-adv-x="317" />
<glyph unicode="!" horiz-adv-x="389" d="M82 836v598h225v-598l-28 -519h-168zM86 0v217h217v-217h-217z" />
<glyph unicode="&#x22;" horiz-adv-x="665" d="M82 1434h217l-33 -422h-153zM367 1434h217l-33 -422h-154z" />
<glyph unicode="#" horiz-adv-x="839" d="M31 410l16 159h100l39 375h-102l16 160h103l35 330h184l-35 -330h133l35 330h184l-34 -330h104l-16 -160h-105l-39 -375h105l-17 -159h-104l-43 -410h-184l43 410h-134l-43 -410h-184l43 410h-100zM332 569h133l39 375h-133z" />
<glyph unicode="$" d="M70 365v98h213v-113q0 -139 116.5 -139t116.5 139q0 68 -32.5 127.5t-82 99t-105.5 89.5l-106 100q-49 49 -81.5 128t-32.5 175q0 297 237 350v107h185v-107q242 -49 241 -350v-45h-213v59q0 141 -112 141h-1q-112 0 -112 -141q0 -80 45 -146.5t110 -117.5l130 -108 q65 -56 110 -145t45 -201q0 -147 -62.5 -237.5t-180.5 -115.5v-104h-185v104q-244 49 -243 353z" />
<glyph unicode="%" horiz-adv-x="1284" d="M70 743v471q0 111 55 170.5t161.5 59.5t162 -59.5t55.5 -170.5v-471q0 -111 -55.5 -170t-162 -59t-161.5 59t-55 170zM213 733q0 -90 73.5 -90t73.5 90v492q0 90 -73.5 90t-73.5 -90v-492zM287 0l565 1434h133l-565 -1434h-133zM780 219v471q0 111 55.5 170.5t162 59.5 t161.5 -59.5t55 -170.5v-471q0 -111 -55 -170t-161.5 -59t-162 59t-55.5 170zM924 209q0 -90 73.5 -90t73.5 90v491q0 90 -73.5 90t-73.5 -90v-491z" />
<glyph unicode="&#x26;" horiz-adv-x="847" d="M84 311v146q0 231 156 301q-156 66 -156 295v26q0 354 336 355h258v-205h-254q-115 0 -115 -139v-89q0 -82 34 -116.5t101 -34.5h99v160h225v-160h59v-205h-59v-471q0 -117 25 -174h-230q-16 45 -20 113q-59 -129 -209 -129q-250 0 -250 327zM309 330q0 -141 117 -142 q111 0 117 125v332h-86q-78 0 -113 -42t-35 -140v-133z" />
<glyph unicode="'" horiz-adv-x="368" d="M76 1434h217l-33 -422h-154z" />
<glyph unicode="(" horiz-adv-x="514" d="M96 313v807q0 170 73 242t243 72h69v-185h-55q-55 0 -79.5 -27.5t-24.5 -101.5v-807q0 -74 24.5 -101.5t79.5 -27.5h55v-184h-69q-170 0 -243 71.5t-73 241.5z" />
<glyph unicode=")" horiz-adv-x="514" d="M33 0v184h55q55 0 80 28t25 101v807q0 74 -25 101.5t-80 27.5h-55v185h69q170 0 243 -72t73 -242v-807q0 -170 -73 -241.5t-243 -71.5h-69z" />
<glyph unicode="*" d="M4 1075l57 174l306 -153l-54 338h185l-54 -338l306 153l57 -174l-336 -57l240 -240l-148 -108l-157 303l-158 -303l-148 108l240 240z" />
<glyph unicode="+" d="M51 637v160h275v276h159v-276h275v-160h-275v-281h-159v281h-275z" />
<glyph unicode="," horiz-adv-x="380" d="M82 0v217h217v-194l-98 -228h-92l59 205h-86z" />
<glyph unicode="-" horiz-adv-x="552" d="M72 614v205h409v-205h-409z" />
<glyph unicode="." horiz-adv-x="380" d="M82 0v217h217v-217h-217z" />
<glyph unicode="/" horiz-adv-x="780" d="M10 0l565 1434h195l-565 -1434h-195z" />
<glyph unicode="0" d="M63 344v746q0 172 88.5 266t254 94t254 -94t88.5 -266v-746q0 -172 -88.5 -266t-254 -94t-254 94t-88.5 266zM289 330q0 -141 117 -142q116 0 116 142v774q0 141 -116.5 141t-116.5 -141v-774z" />
<glyph unicode="1" d="M221 1094v159q82 0 134.5 28t71.5 60.5t42 92.5h152v-1434h-226v1094h-174z" />
<glyph unicode="2" d="M82 0v176q0 117 46 214t111 170l131 144q66 70 112 166t46 211q0 92 -29.5 128t-86.5 36q-117 0 -117 -141v-154h-213v140q0 174 86 267t250 93t250 -93t86 -267q0 -131 -50.5 -247t-120 -198t-137 -153.5t-109.5 -144.5q-33 -57 -33 -111q0 -16 3 -31h426v-205h-651z " />
<glyph unicode="3" d="M70 344v119h213v-133q0 -141 116 -142q57 0 87 36t30 126v113q0 98 -35 140t-112 42h-76v205h88q68 0 101.5 34.5t33.5 116.5v80q0 92 -29.5 128t-87.5 36q-117 0 -116 -141v-92h-213v78q0 174 86 267t249.5 93t249.5 -93t86 -267v-37q0 -229 -157 -295q158 -70 157 -301 v-113q0 -174 -86 -267t-249.5 -93t-249.5 93t-86 267z" />
<glyph unicode="4" d="M29 260v205l409 969h246v-969h107v-205h-107v-260h-225v260h-430zM236 465h223v530z" />
<glyph unicode="5" d="M72 344v119h213v-133q0 -139 117 -140q116 0 116 140v315q0 141 -116.5 141t-116.5 -141v-43h-213l41 832h594v-205h-392l-18 -342q63 104 197 104q250 0 249 -327v-320q0 -174 -86 -267t-249.5 -93t-249.5 93t-86 267z" />
<glyph unicode="6" d="M68 344v733q0 373 344 373q164 0 250 -93t86 -267v-37h-213v51q0 141 -117 141q-63 0 -94 -39t-31 -137v-262q59 127 209 127q250 0 250 -328v-262q0 -172 -88.5 -266t-254 -94t-253.5 94t-88 266zM293 330q0 -139 117 -140q116 0 116 140v258q0 141 -116.5 141 t-116.5 -141v-258z" />
<glyph unicode="7" d="M68 1229v205h675v-197l-331 -1237h-226l330 1229h-448z" />
<glyph unicode="8" d="M53 1044v46q0 172 91.5 266t261 94t261 -94t91.5 -266v-46q0 -211 -140 -288q139 -78 140 -299v-113q0 -172 -91.5 -266t-261 -94t-261 94t-91.5 266v113q0 221 140 299q-139 76 -140 288zM279 350q0 -162 127 -162q125 0 126 162v133q0 162 -126.5 162t-126.5 -162v-133 zM279 1001q0 -152 126 -152l1 1q126 0 126 151v80q0 164 -126.5 164t-126.5 -164v-80z" />
<glyph unicode="9" d="M59 827v263q0 172 88.5 266t254 94t253.5 -94t88 -266v-734q0 -372 -342 -372h-2q-164 0 -250 93t-86 267v37h213v-51q0 -141 117 -142q63 0 94 39t31 138v262q-59 -127 -209 -127q-250 0 -250 327zM285 846q0 -141 116.5 -141t116.5 141v258q0 139 -116.5 139 t-116.5 -139v-258z" />
<glyph unicode=":" horiz-adv-x="380" d="M82 0v217h217v-217h-217zM82 780v217h217v-217h-217z" />
<glyph unicode=";" horiz-adv-x="380" d="M82 0v217h217v-194l-98 -228h-92l59 205h-86zM82 780v217h217v-217h-217z" />
<glyph unicode="&#x3c;" d="M61 637v160l668 245v-161l-459 -164l459 -164v-162z" />
<glyph unicode="=" d="M72 471v160h667v-160h-667zM72 803v160h667v-160h-667z" />
<glyph unicode="&#x3e;" d="M82 391v162l459 164l-459 164v161l668 -245v-160z" />
<glyph unicode="?" horiz-adv-x="737" d="M41 948v142q0 174 84 267t248 93t248 -93t84 -267q0 -125 -42 -228.5t-91.5 -160t-91.5 -137.5t-42 -167q0 -45 8 -80h-200q-12 37 -13 89q0 104 39 191t84 141.5t84 150.5t39 215q0 141 -112.5 141t-112.5 -141v-156h-213zM236 0v217h217v-217h-217z" />
<glyph unicode="@" horiz-adv-x="1411" d="M49 594q0 193 48 358.5t139.5 291.5t238 199t330.5 73q303 0 436 -164t133 -439q0 -178 -39 -312t-102.5 -204.5t-127.5 -103.5t-130 -33q-168 0 -180 135q-60 -123 -187 -123h-12q-188 5 -188 239q0 36 4 77l22 207q16 152 80 229q61 74 160 74h10q127 -2 168 -127 l12 119h197l-62 -592q-1 -6 -1 -11q0 -40 42 -41q80 0 122 142.5t42 320.5q0 201 -100 316.5t-307 115.5q-270 0 -412.5 -200.5t-142.5 -556.5q0 -254 119.5 -394.5t357.5 -140.5q244 0 424 139l-17 -196q-172 -115 -419 -115q-334 0 -496 191.5t-162 525.5zM610 598 q-2 -16 -2 -30q0 -101 90 -105h6q43 0 71 29q30 32 38 100l21 194q1 11 1 21q0 42 -20 65q-24 29 -70 29h-6q-45 0 -73 -29q-29 -30 -37 -100z" />
<glyph unicode="A" horiz-adv-x="833" d="M23 0l229 1434h330l229 -1434h-227l-39 260h-277l-39 -260h-206zM297 455h217l-108 725z" />
<glyph unicode="B" horiz-adv-x="831" d="M82 0v1434h340q174 0 254 -81t80 -249v-51q0 -221 -146 -289q168 -66 168 -307v-117q0 -166 -87 -253t-255 -87h-354zM307 205h129q59 0 88 31.5t29 109.5v125q0 98 -33.5 136t-111.5 38h-101v-440zM307 850h88q68 0 101.5 35t33.5 116v80q1 148 -114 148h-109v-379z" />
<glyph unicode="C" horiz-adv-x="790" d="M63 344v746q0 174 86.5 267t250 93t249.5 -93t86 -267v-140h-213v154q0 141 -116.5 141t-116.5 -141v-774q1 -140 117 -140q117 0 116 140v205h213v-191q0 -174 -86 -267t-249.5 -93t-250 93t-86.5 267z" />
<glyph unicode="D" horiz-adv-x="835" d="M82 0v1434h356q336 0 336 -355v-725q0 -354 -336 -354h-356zM307 205h127q115 0 115 139v746q0 139 -115 139h-127v-1024z" />
<glyph unicode="E" horiz-adv-x="753" d="M82 0v1434h614v-205h-389v-400h309v-204h-309v-420h389v-205h-614z" />
<glyph unicode="F" horiz-adv-x="704" d="M82 0v1434h596v-205h-371v-432h291v-205h-291v-592h-225z" />
<glyph unicode="G" horiz-adv-x="798" d="M63 344v746q0 174 86.5 267t250 93t249.5 -93t86 -267v-140h-213v154q0 141 -116.5 141t-116.5 -141v-774q0 -139 117 -140q116 0 116 140v264h-102v205h315v-455q0 -174 -86 -267t-249.5 -93t-250 93t-86.5 267z" />
<glyph unicode="H" horiz-adv-x="874" d="M82 0v1434h225v-615h256v615h230v-1434h-230v614h-256v-614h-225z" />
<glyph unicode="I" horiz-adv-x="389" d="M82 0v1434h225v-1434h-225z" />
<glyph unicode="J" horiz-adv-x="524" d="M20 0v205q25 -2 78 -2q129 0 129 137v1094h226v-1078q0 -360 -324 -360q-72 0 -109 4z" />
<glyph unicode="K" horiz-adv-x="847" d="M82 0v1434h225v-625l295 625h225l-313 -639l313 -795h-231l-219 571l-70 -131v-440h-225z" />
<glyph unicode="L" horiz-adv-x="694" d="M82 0v1434h225v-1229h371v-205h-596z" />
<glyph unicode="M" horiz-adv-x="1107" d="M80 0v1434h313l166 -1018l154 1018h313v-1434h-213v1028l-156 -1028h-213l-168 1014v-1014h-196z" />
<glyph unicode="N" horiz-adv-x="874" d="M80 0v1434h282l232 -859v859h201v-1434h-232l-280 1038v-1038h-203z" />
<glyph unicode="O" d="M63 344v746q0 172 88.5 266t254 94t254 -94t88.5 -266v-746q0 -172 -88.5 -266t-254 -94t-254 94t-88.5 266zM289 330q1 -141 117 -142q117 0 116 142v774q0 141 -116.5 141t-116.5 -141v-774z" />
<glyph unicode="P" horiz-adv-x="772" d="M82 0v1434h332q336 0 336 -355v-186q0 -354 -336 -354h-107v-539h-225zM307 743h107q55 0 82.5 31t27.5 105v215q0 74 -27.5 104.5t-82.5 30.5h-107v-486z" />
<glyph unicode="Q" d="M63 1090q0 172 88.5 266t254 94t254 -94t88.5 -266v-746q0 -121 -43 -201q12 -30 60 -30h3h20v-201h-30q-145 0 -195 98q-71 -26 -151 -26h-6q-166 0 -254.5 94t-88.5 266v746zM289 330q0 -141 116 -142h1q116 0 116 142v774q0 141 -116.5 141t-116.5 -141v-774z" />
<glyph unicode="R" horiz-adv-x="823" d="M82 0v1434h340q174 0 254 -81t80 -249v-113q0 -221 -148 -291q150 -63 150 -305v-221v-9q0 -110 24 -165h-229q-20 61 -21 176v225q0 98 -34.5 140.5t-112.5 42.5h-78v-584h-225zM307 788h88q68 0 101.5 35t33.5 117v141q1 148 -114 148h-109v-441z" />
<glyph unicode="S" horiz-adv-x="765" d="M47 344v88h213v-102q0 -140 117 -140h1q116 0 116 140q0 80 -46 150t-110 128l-130 120q-66 63 -110.5 156t-44.5 206q0 174 84 267t248 93t248 -93t84 -267v-46h-213v60q0 141 -112.5 141t-112.5 -141q0 -59 24.5 -112.5t63.5 -96.5t86 -85t93 -88t85 -98.5t63.5 -124 t24.5 -155.5q0 -174 -86 -267t-250 -93t-250 93t-86 267z" />
<glyph unicode="T" horiz-adv-x="729" d="M16 1229v205h697v-205h-236v-1229h-225v1229h-236z" />
<glyph unicode="U" horiz-adv-x="815" d="M72 342v1092h225v-1106q1 -140 117 -140q117 0 116 140v1106h213v-1092q0 -174 -86 -267t-249.5 -93t-249.5 93t-86 267z" />
<glyph unicode="V" horiz-adv-x="823" d="M23 1434h227l172 -1170l172 1170h207l-221 -1434h-336z" />
<glyph unicode="W" horiz-adv-x="1153" d="M31 1434h219l121 -1131l108 1131h217l113 -1139l117 1139h196l-159 -1434h-299l-82 764l-82 -764h-310z" />
<glyph unicode="X" horiz-adv-x="880" d="M31 0l252 737l-236 697h234l170 -529l174 529h209l-236 -697l252 -737h-238l-184 567l-186 -567h-211z" />
<glyph unicode="Y" d="M8 1434h236l172 -654l172 654h215l-285 -959v-475h-225v475z" />
<glyph unicode="Z" horiz-adv-x="757" d="M47 0v201l428 1028h-407v205h639v-201l-428 -1028h428v-205h-660z" />
<glyph unicode="[" horiz-adv-x="514" d="M96 0v1434h373v-185h-147v-1065h147v-184h-373z" />
<glyph unicode="\" horiz-adv-x="780" d="M10 1434h195l565 -1434h-195z" />
<glyph unicode="]" horiz-adv-x="514" d="M45 0v184h148v1065h-148v185h373v-1434h-373z" />
<glyph unicode="^" d="M41 799l285 635h159l285 -635h-180l-184 430l-185 -430h-180z" />
<glyph unicode="_" horiz-adv-x="1024" d="M0 -20h1024v-164h-1024v164z" />
<glyph unicode="`" horiz-adv-x="512" d="M90 1737h232l139 -228h-162z" />
<glyph unicode="a" horiz-adv-x="833" d="M23 0l229 1434h330l229 -1434h-227l-39 260h-277l-39 -260h-206zM297 455h217l-108 725z" />
<glyph unicode="b" horiz-adv-x="831" d="M82 0v1434h340q174 0 254 -81t80 -249v-51q0 -221 -146 -289q168 -66 168 -307v-117q0 -166 -87 -253t-255 -87h-354zM307 205h129q59 0 88 31.5t29 109.5v125q0 98 -33.5 136t-111.5 38h-101v-440zM307 850h88q68 0 101.5 35t33.5 116v80q1 148 -114 148h-109v-379z" />
<glyph unicode="c" horiz-adv-x="790" d="M63 344v746q0 174 86.5 267t250 93t249.5 -93t86 -267v-140h-213v154q0 141 -116.5 141t-116.5 -141v-774q1 -140 117 -140q117 0 116 140v205h213v-191q0 -174 -86 -267t-249.5 -93t-250 93t-86.5 267z" />
<glyph unicode="d" horiz-adv-x="835" d="M82 0v1434h356q336 0 336 -355v-725q0 -354 -336 -354h-356zM307 205h127q115 0 115 139v746q0 139 -115 139h-127v-1024z" />
<glyph unicode="e" horiz-adv-x="753" d="M82 0v1434h614v-205h-389v-400h309v-204h-309v-420h389v-205h-614z" />
<glyph unicode="f" horiz-adv-x="704" d="M82 0v1434h596v-205h-371v-432h291v-205h-291v-592h-225z" />
<glyph unicode="g" horiz-adv-x="798" d="M63 344v746q0 174 86.5 267t250 93t249.5 -93t86 -267v-140h-213v154q0 141 -116.5 141t-116.5 -141v-774q0 -139 117 -140q116 0 116 140v264h-102v205h315v-455q0 -174 -86 -267t-249.5 -93t-250 93t-86.5 267z" />
<glyph unicode="h" horiz-adv-x="874" d="M82 0v1434h225v-615h256v615h230v-1434h-230v614h-256v-614h-225z" />
<glyph unicode="i" horiz-adv-x="389" d="M82 0v1434h225v-1434h-225z" />
<glyph unicode="j" horiz-adv-x="524" d="M20 0v205q25 -2 78 -2q129 0 129 137v1094h226v-1078q0 -360 -324 -360q-72 0 -109 4z" />
<glyph unicode="k" horiz-adv-x="847" d="M82 0v1434h225v-625l295 625h225l-313 -639l313 -795h-231l-219 571l-70 -131v-440h-225z" />
<glyph unicode="l" horiz-adv-x="694" d="M82 0v1434h225v-1229h371v-205h-596z" />
<glyph unicode="m" horiz-adv-x="1107" d="M80 0v1434h313l166 -1018l154 1018h313v-1434h-213v1028l-156 -1028h-213l-168 1014v-1014h-196z" />
<glyph unicode="n" horiz-adv-x="874" d="M80 0v1434h282l232 -859v859h201v-1434h-232l-280 1038v-1038h-203z" />
<glyph unicode="o" d="M63 344v746q0 172 88.5 266t254 94t254 -94t88.5 -266v-746q0 -172 -88.5 -266t-254 -94t-254 94t-88.5 266zM289 330q1 -141 117 -142q117 0 116 142v774q0 141 -116.5 141t-116.5 -141v-774z" />
<glyph unicode="p" horiz-adv-x="772" d="M82 0v1434h332q336 0 336 -355v-186q0 -354 -336 -354h-107v-539h-225zM307 743h107q55 0 82.5 31t27.5 105v215q0 74 -27.5 104.5t-82.5 30.5h-107v-486z" />
<glyph unicode="q" d="M63 1090q0 172 88.5 266t254 94t254 -94t88.5 -266v-746q0 -121 -43 -201q12 -30 60 -30h3h20v-201h-30q-145 0 -195 98q-71 -26 -151 -26h-6q-166 0 -254.5 94t-88.5 266v746zM289 330q0 -141 116 -142h1q116 0 116 142v774q0 141 -116.5 141t-116.5 -141v-774z" />
<glyph unicode="r" horiz-adv-x="823" d="M82 0v1434h340q174 0 254 -81t80 -249v-113q0 -221 -148 -291q150 -63 150 -305v-221v-9q0 -110 24 -165h-229q-20 61 -21 176v225q0 98 -34.5 140.5t-112.5 42.5h-78v-584h-225zM307 788h88q68 0 101.5 35t33.5 117v141q1 148 -114 148h-109v-441z" />
<glyph unicode="s" horiz-adv-x="765" d="M47 344v88h213v-102q0 -140 117 -140h1q116 0 116 140q0 80 -46 150t-110 128l-130 120q-66 63 -110.5 156t-44.5 206q0 174 84 267t248 93t248 -93t84 -267v-46h-213v60q0 141 -112.5 141t-112.5 -141q0 -59 24.5 -112.5t63.5 -96.5t86 -85t93 -88t85 -98.5t63.5 -124 t24.5 -155.5q0 -174 -86 -267t-250 -93t-250 93t-86 267z" />
<glyph unicode="t" horiz-adv-x="729" d="M16 1229v205h697v-205h-236v-1229h-225v1229h-236z" />
<glyph unicode="u" horiz-adv-x="815" d="M72 342v1092h225v-1106q1 -140 117 -140q117 0 116 140v1106h213v-1092q0 -174 -86 -267t-249.5 -93t-249.5 93t-86 267z" />
<glyph unicode="v" horiz-adv-x="823" d="M23 1434h227l172 -1170l172 1170h207l-221 -1434h-336z" />
<glyph unicode="w" horiz-adv-x="1153" d="M31 1434h219l121 -1131l108 1131h217l113 -1139l117 1139h196l-159 -1434h-299l-82 764l-82 -764h-310z" />
<glyph unicode="x" horiz-adv-x="880" d="M31 0l252 737l-236 697h234l170 -529l174 529h209l-236 -697l252 -737h-238l-184 567l-186 -567h-211z" />
<glyph unicode="y" d="M8 1434h236l172 -654l172 654h215l-285 -959v-475h-225v475z" />
<glyph unicode="z" horiz-adv-x="757" d="M47 0v201l428 1028h-407v205h639v-201l-428 -1028h428v-205h-660z" />
<glyph unicode="{" horiz-adv-x="526" d="M23 625v184q63 0 85.5 25.5t26.5 97.5l17 274q8 113 68.5 170.5t158.5 57.5h115v-185h-33q-55 0 -80 -31.5t-29 -113.5l-10 -205q-8 -149 -133 -182q125 -33 133 -182l10 -205q4 -82 29 -114t80 -32h33v-184h-115q-98 0 -158.5 57.5t-68.5 169.5l-17 275 q-4 72 -26.5 97.5t-85.5 25.5z" />
<glyph unicode="|" horiz-adv-x="1024" d="M430 -133v1700h184v-1700h-184z" />
<glyph unicode="}" horiz-adv-x="526" d="M33 1249v185h114q98 0 159 -57.5t69 -170.5l16 -274q4 -72 26.5 -97.5t86.5 -25.5v-184q-63 0 -86 -26t-27 -97l-16 -275q-8 -113 -68.5 -170t-159.5 -57h-114v184h33q55 0 79.5 32t28.5 114l10 205q8 149 133 182q-125 33 -133 182l-10 205q-4 82 -28.5 113.5 t-79.5 31.5h-33z" />
<glyph unicode="~" d="M16 680q70 104 126.5 144t117.5 40q59 0 155.5 -62.5t137.5 -62.5q33 0 58.5 23.5t76.5 93.5l107 -111q-70 -102 -125.5 -139t-118.5 -37q-59 0 -155.5 62.5t-137.5 62.5q-35 0 -60.5 -23t-74.5 -93z" />
<glyph unicode="&#xa2;" d="M74 426v582q0 297 239 350v106h185v-104q248 -49 247 -352v-99h-213v113q0 141 -116.5 141t-116.5 -141v-610q0 -139 117 -140q116 0 116 140v163h213v-149q0 -305 -247 -352v-105h-185v107q-240 49 -239 350z" />
<glyph unicode="&#xa3;" d="M61 0v197q82 0 137.5 62.5t57.5 170.5h-166v174h137q-14 39 -56 123t-65.5 167t-23.5 196q0 174 84 267t248 93t247.5 -93t83.5 -267v-142h-213v156q0 141 -112.5 141t-112.5 -141q0 -113 24.5 -200t62.5 -167t50 -133h248v-174h-233q-14 -145 -115 -225h387v-205h-670z " />
<glyph unicode="&#xa5;" d="M14 1434h236l166 -633l166 633h215l-262 -879h170v-113h-187v-92h187v-112h-187v-238h-225v238h-187v112h187v92h-187v113h168z" />
<glyph unicode="&#xa9;" horiz-adv-x="1507" d="M41 716.5q0 317.5 204 525.5t509 208t508.5 -208t203.5 -525.5t-203.5 -525t-508.5 -207.5t-509 207.5t-204 525zM188 717q0 -256 161 -423t404.5 -167t404.5 167t161 423t-161 423t-404.5 167t-404.5 -167t-161 -423zM514 516v397q0 254 231.5 254t231.5 -254v-73h-148 v86q0 98 -79.5 98t-79.5 -98v-418q0 -96 79.5 -96t79.5 96v123h148v-115q0 -250 -231.5 -250t-231.5 250z" />
<glyph unicode="&#xad;" horiz-adv-x="552" d="M72 614v205h409v-205h-409z" />
<glyph unicode="&#xae;" horiz-adv-x="1507" d="M41 716.5q0 317.5 204 525.5t509 208t508.5 -208t203.5 -525.5t-203.5 -525t-508.5 -207.5t-509 207.5t-204 525zM188 717q0 -256 161 -423t404.5 -167t404.5 167t161 423t-161 423t-404.5 167t-404.5 -167t-161 -423zM528 279v876h238q231 0 231 -229v-19 q0 -156 -106 -202q106 -43 106 -211v-95q1 -79 19 -120h-160q-14 37 -14 122v95q0 70 -24.5 98.5t-80.5 28.5h-53v-344h-156zM684 766h64q94 0 94 104v37q0 105 -84 105h-74v-246z" />
<glyph unicode="&#xb4;" horiz-adv-x="512" d="M55 1509l140 228h221l-209 -228h-152z" />
<glyph unicode="&#x2000;" horiz-adv-x="868" />
<glyph unicode="&#x2001;" horiz-adv-x="1737" />
<glyph unicode="&#x2002;" horiz-adv-x="868" />
<glyph unicode="&#x2003;" horiz-adv-x="1737" />
<glyph unicode="&#x2004;" horiz-adv-x="579" />
<glyph unicode="&#x2005;" horiz-adv-x="434" />
<glyph unicode="&#x2006;" horiz-adv-x="289" />
<glyph unicode="&#x2007;" horiz-adv-x="289" />
<glyph unicode="&#x2008;" horiz-adv-x="217" />
<glyph unicode="&#x2009;" horiz-adv-x="347" />
<glyph unicode="&#x200a;" horiz-adv-x="96" />
<glyph unicode="&#x2010;" horiz-adv-x="552" d="M72 614v205h409v-205h-409z" />
<glyph unicode="&#x2011;" horiz-adv-x="552" d="M72 614v205h409v-205h-409z" />
<glyph unicode="&#x2012;" horiz-adv-x="552" d="M72 614v205h409v-205h-409z" />
<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M0 625v184h1024v-184h-1024z" />
<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M0 625v184h2048v-184h-2048z" />
<glyph unicode="&#x2018;" horiz-adv-x="380" d="M82 1012v194l98 228h92l-59 -205h86v-217h-217z" />
<glyph unicode="&#x2019;" horiz-adv-x="380" d="M82 1217v217h217v-195l-98 -227h-92l59 205h-86z" />
<glyph unicode="&#x201c;" horiz-adv-x="679" d="M82 1012v194l98 228h92l-59 -205h86v-217h-217zM381 1012v194l98 228h92l-59 -205h86v-217h-217z" />
<glyph unicode="&#x201d;" horiz-adv-x="679" d="M82 1217v217h217v-195l-98 -227h-92l59 205h-86zM381 1217v217h217v-195l-98 -227h-92l59 205h-86z" />
<glyph unicode="&#x2022;" d="M121 717q0 119 83 201.5t201.5 82.5t201.5 -82.5t83 -201.5t-83 -202t-201.5 -83t-201.5 83t-83 202z" />
<glyph unicode="&#x2026;" horiz-adv-x="978" d="M82 0v217h217v-217h-217zM381 0v217h217v-217h-217zM680 0v217h217v-217h-217z" />
<glyph unicode="&#x202f;" horiz-adv-x="347" />
<glyph unicode="&#x205f;" horiz-adv-x="434" />
<glyph unicode="&#x20ac;" d="M39 553v113h57v112h-57v113h57v199q0 174 83 267t247 93t247 -93t83 -267v-105h-213v119q0 141 -110.5 141t-110.5 -141v-213h315v-113h-315v-112h315v-113h-315v-223q0 -139 110 -140h1q110 0 110 140v129h213v-115q0 -174 -83 -267t-247 -93t-247 93t-83 267v209h-57z " />
<glyph unicode="&#x2122;" horiz-adv-x="1200" d="M20 1303v131h443v-131h-150v-598h-143v598h-150zM549 705v729h199l106 -512l96 512h199v-729h-135v518l-96 -518h-136l-108 514v-514h-125z" />
<glyph unicode="&#xe000;" horiz-adv-x="1435" d="M0 1435h1435v-1435h-1435v1435z" />
</font>
</defs></svg>

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -0,0 +1,57 @@
____________________________________________________________________________________________________
_____ _ _ __ ____ _ _ __ ______ _ _ ____ _____
/ ) / / / | / ) / /| / | / | / / ) / '
---/----/----/___ /-----/__|----/___ /----/| /-|----/__|--------/--------|---/-----/____/----/__----
/ / / / / | / | / |/ | / | / | / / /
_/____/____/____/_____/____|__/_____|___/__/___|__/____|______/__________|_/_____/_________/____ ___
/
(_ / DHARMA TYPE FREE FONTs
EULA ( the End User License Agreement )
This document is a legal agreement between you the end user, and Dharma Type.
By using or installing Dharma Type font(s), you agree to be bound by the terms of this Agreement.
1. You may use this font for both commercial and non-commercial works at no charge.
2. You may use this font to create images on the website or printed matter on papre, logomark.....up to you.
3. You may not sell this font without permission.
4. You may not redistribute this font without permission.
5. You may not modify, adapt, translate, reverse engineer, decompile, disassemble, or create derivative works based on this font.
6. This font are Copyrighted by Ryoichi Tsunekawa. All rights reserved. You may not claim copyrgiht rights for this font.
7. DISCLAIMER
This font is provided to you free of charge.
Dharma Type give no warranty in relation to this font, and you use this at your own risk.
Dharma Type will not be liable for any damage to your system, any loss or corruption of any data or software,
or any other loss or damage that you may suffer as a result of downloading or using this font, whether it results from our negligence or in any other way.
Here is a list of things you could do, Only if you want to:
* Link http://dharmatype.com/ or credit "Dharma Type"
* Tell me what did you use this font for.
FAQ
Q_ Can I use this for a commercial product?
A_ Yes, You can!
Q_ Can I use this on a web page via css @font-face?
A_ Yes, You can!
Q_ Can I donate $ to you?
A_ Yes, You can! ( Paypal: info@flat-it.com )
Contact_______________________________
info@dharmatype.com
Dharma Type (http://dharmatype.com)
|
|___ Flat it type foundry
|
|___ Prop-a-ganda
|
|___ Holiday Type
______________________________________

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,172 @@
@font-face {
font-family: BebasNeueRegular;
src: url(fonts/BebasNeue-webfont.woff);
}
@font-face {
font-family: Alegreya-Regular;
src: url(fonts/Alegreya-Regular.ttf);
}
@font-face {
font-family: Ubuntu-Medium;
src: url(fonts/Ubuntu-Medium.ttf);
}
@font-face {
font-family: Ubuntu-Regular;
src: url(fonts/Ubuntu-Regular.ttf);
}
.ac-container{
width: auto;
text-align: left;
overflow-y: auto;
overflow-x: hidden;
height: auto;
}
div[id^="leaflet-control-accordion-layers"] > label {
font-family: 'BebasNeueRegular', 'Arial Narrow', Arial, sans-serif;
padding: 5px 20px;
position: relative;
z-index: 20;
display: block;
height: 30px;
cursor: pointer;
color: #777;
text-shadow: 1px 1px 1px rgba(255,255,255,0.8);
line-height: 33px;
font-size: 19px;
background: #ffffff;
background: -moz-linear-gradient(top, #ffffff 1%, #eaeaea 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(1%,#ffffff), color-stop(100%,#eaeaea));
background: -webkit-linear-gradient(top, #ffffff 1%,#eaeaea 100%);
background: -o-linear-gradient(top, #ffffff 1%,#eaeaea 100%);
background: -ms-linear-gradient(top, #ffffff 1%,#eaeaea 100%);
background: linear-gradient(top, #ffffff 1%,#eaeaea 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eaeaea',GradientType=0 );
box-shadow:
0px 0px 0px 1px rgba(155,155,155,0.3),
1px 0px 0px 0px rgba(255,255,255,0.9) inset,
0px 2px 2px rgba(0,0,0,0.1);
box-sizing: content-box;
cursor:pointer;
width: auto;
margin: 0;
}
div[id^="leaflet-control-accordion-layers"] > label:hover {
background: #fff;
}
.ac-container input.menu:checked + label,
.ac-container input.menu:checked + label:hover{
background: #c6e1ec;
color: #3d7489;
text-shadow: 0px 1px 1px rgba(255,255,255, 0.6);
box-shadow:
0px 0px 0px 1px rgba(155,155,155,0.3),
0px 2px 2px rgba(0,0,0,0.1);
}
.ac-container div[id^="leaflet-control-accordion-layers"] > label:hover:after,
.ac-container input.menu:checked + div[id^="leaflet-control-accordion-layers"] > label:hover:after{
content: '';
position: absolute;
width: 24px;
height: 24px;
right: 13px;
top: 7px;
background: transparent url(images/arrow_down.png) no-repeat center center;
}
.ac-container input.menu:checked + div[id^="leaflet-control-accordion-layers"] > label:hover:after{
background-image: url(images/arrow_up.png);
}
.ac-container input.menu{
display: none;
}
.ac-container article{
background: rgba(255, 255, 255, 0.5);
margin-top: -1px;
overflow: hidden;
height: 0px;
padding: 0px;
line-height: 0px;
position: relative;
z-index: 10;
-webkit-transition: height 0.3s ease-in-out, box-shadow 0.6s linear;
-moz-transition: height 0.3s ease-in-out, box-shadow 0.6s linear;
-o-transition: height 0.3s ease-in-out, box-shadow 0.6s linear;
-ms-transition: height 0.3s ease-in-out, box-shadow 0.6s linear;
transition: height 0.3s ease-in-out, box-shadow 0.6s linear;
}
.ac-container input.menu:checked ~ article{
-webkit-transition: height 0.5s ease-in-out, box-shadow 0.1s linear;
-moz-transition: height 0.5s ease-in-out, box-shadow 0.1s linear;
-o-transition: height 0.5s ease-in-out, box-shadow 0.1s linear;
-ms-transition: height 0.5s ease-in-out, box-shadow 0.1s linear;
transition: height 0.5s ease-in-out, box-shadow 0.1s linear;
}
.ac-container input.menu:checked ~ article.ac-large{
height: auto;
max-height : 100px;
padding: 8px 0;
overflow-y: auto;
line-height: 18px;
}
.ac-container article label {
display: inline;
cursor: pointer;
}
.ac-container .group-toggle-container {
text-align: right;
margin-right: 3px;
line-height: 0px;
display: none;
height: 20px;
}
.ac-container input.menu:checked ~ .group-toggle-container {
display: block;
line-height: 1em;
}
.menu-item-radio{
font-family: 'Ubuntu-Regular', Arial, sans-serif;
font-size: 13px;
}
.menu-item-checkbox{
font-family: 'Ubuntu-Regular', Arial, sans-serif;
font-size: 13px;
}
.bt_delete{
position: relative;
float: right;
background-image: url(images/delete.png);
background-color: transparent;
background-repeat: no-repeat;
background-position: 0px 0px;
border: none;
cursor: pointer;
height: 16px;
width: 16px;
vertical-align: middle;
}
.leaflet-control-layers-expanded {
padding: 5px;
}
.leaflet-control-layers:hover {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #e0e3ec url(images/bgnoise_lg.jpg) repeat top left;
border-radius: 5px;
}

View File

@@ -0,0 +1,564 @@
L.Control.StyledLayerControl = L.Control.Layers.extend({
options: {
collapsed: true,
position: 'topright',
autoZIndex: true,
group_togglers: {
show: false,
labelAll: 'All',
labelNone: 'None'
},
groupDeleteLabel: 'Delete the group'
},
initialize: function(baseLayers, groupedOverlays, options) {
var i,
j;
L.Util.setOptions(this, options);
this._layerControlInputs = [];
this._layers = [];
this._lastZIndex = 0;
this._handlingClick = false;
this._groupList = [];
this._domGroups = [];
for (i in baseLayers) {
for (var j in baseLayers[i].layers) {
this._addLayer(baseLayers[i].layers[j], j, baseLayers[i], false);
}
}
for (i in groupedOverlays) {
for (var j in groupedOverlays[i].layers) {
this._addLayer(groupedOverlays[i].layers[j], j, groupedOverlays[i], true);
}
}
},
onAdd: function(map) {
this._initLayout();
this._update();
map
.on('layeradd', this._onLayerChange, this)
.on('layerremove', this._onLayerChange, this)
.on('zoomend', this._onZoomEnd, this);
return this._container;
},
onRemove: function(map) {
map
.off('layeradd', this._onLayerChange)
.off('layerremove', this._onLayerChange);
},
addBaseLayer: function(layer, name, group) {
this._addLayer(layer, name, group, false);
this._update();
return this;
},
addOverlay: function(layer, name, group) {
this._addLayer(layer, name, group, true);
this._update();
return this;
},
removeLayer: function(layer) {
var id = L.Util.stamp(layer);
delete this._layers[id];
this._update();
return this;
},
removeGroup: function(group_Name, del) {
for (group in this._groupList) {
if (this._groupList[group].groupName == group_Name) {
for (layer in this._layers) {
if (this._layers[layer].group && this._layers[layer].group.name == group_Name) {
if (del) {
this._map.removeLayer(this._layers[layer].layer);
}
delete this._layers[layer];
}
}
delete this._groupList[group];
this._update();
break;
}
}
},
removeAllGroups: function(del) {
for (group in this._groupList) {
for (layer in this._layers) {
if (this._layers[layer].group && this._layers[layer].group.removable) {
if (del) {
this._map.removeLayer(this._layers[layer].layer);
}
delete this._layers[layer];
}
}
delete this._groupList[group];
}
this._update();
},
selectLayer: function(layer) {
this._map.addLayer(layer);
this._update();
},
unSelectLayer: function(layer) {
this._map.removeLayer(layer);
this._update();
},
selectGroup: function(group_Name) {
this.changeGroup(group_Name, true)
},
unSelectGroup: function(group_Name) {
this.changeGroup(group_Name, false)
},
changeGroup: function(group_Name, select) {
for (group in this._groupList) {
if (this._groupList[group].groupName == group_Name) {
for (layer in this._layers) {
if (this._layers[layer].group && this._layers[layer].group.name == group_Name) {
if (select) {
this._map.addLayer(this._layers[layer].layer);
} else {
this._map.removeLayer(this._layers[layer].layer);
}
}
}
break;
}
}
this._update();
},
_initLayout: function() {
var className = 'leaflet-control-layers',
container = this._container = L.DomUtil.create('div', className);
//Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
container.setAttribute('aria-haspopup', true);
if (!L.Browser.touch) {
L.DomEvent.disableClickPropagation(container);
L.DomEvent.on(container, 'wheel', L.DomEvent.stopPropagation);
} else {
L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
}
var section = document.createElement('section');
section.className = 'ac-container ' + className + '-list';
var form = this._form = this._section = L.DomUtil.create('form');
section.appendChild(form);
if (this.options.collapsed) {
if (!L.Browser.android) {
L.DomEvent
.on(container, 'mouseover', this._expand, this)
.on(container, 'mouseout', this._collapse, this);
}
var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
link.href = '#';
link.title = 'Layers';
if (L.Browser.touch) {
L.DomEvent
.on(link, 'click', L.DomEvent.stop)
.on(link, 'click', this._expand, this);
} else {
L.DomEvent.on(link, 'focus', this._expand, this);
}
this._map.on('click', this._collapse, this);
// TODO keyboard accessibility
} else {
this._expand();
}
this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);
container.appendChild(section);
// process options of ac-container css class - to options.container_width and options.container_maxHeight
for (var c = 0; c < (containers = container.getElementsByClassName('ac-container')).length; c++) {
if (this.options.container_width) {
containers[c].style.width = this.options.container_width;
}
// set the max-height of control to y value of map object
this._default_maxHeight = this.options.container_maxHeight ? this.options.container_maxHeight : (this._map.getSize().y - 70);
containers[c].style.maxHeight = this._default_maxHeight;
}
window.onresize = this._on_resize_window.bind(this);
},
_on_resize_window: function() {
// listen to resize of screen to reajust de maxHeight of container
for (var c = 0; c < containers.length; c++) {
// input the new value to height
containers[c].style.maxHeight = (window.innerHeight - 90) < this._removePxToInt(this._default_maxHeight) ? (window.innerHeight - 90) + "px" : this._removePxToInt(this._default_maxHeight) + "px";
}
},
// remove the px from a css value and convert to a int
_removePxToInt: function(value) {
if (typeof value === 'string') {
return parseInt(value.replace("px", ""));
}
return value;
},
_addLayer: function(layer, name, group, overlay) {
var id = L.Util.stamp(layer);
this._layers[id] = {
layer: layer,
name: name,
overlay: overlay
};
if (group) {
var groupId = this._groupList.indexOf(group);
// if not find the group search for the name
if (groupId === -1) {
for (g in this._groupList) {
if (this._groupList[g].groupName == group.groupName) {
groupId = g;
break;
}
}
}
if (groupId === -1) {
groupId = this._groupList.push(group) - 1;
}
this._layers[id].group = {
name: group.groupName,
id: groupId,
expanded: group.expanded,
removable: group.removable
};
}
if (this.options.autoZIndex && layer.setZIndex) {
this._lastZIndex++;
layer.setZIndex(this._lastZIndex);
}
},
_update: function() {
if (!this._container) {
return;
}
this._baseLayersList.innerHTML = '';
this._overlaysList.innerHTML = '';
this._domGroups.length = 0;
this._layerControlInputs = [];
var baseLayersPresent = false,
overlaysPresent = false,
i,
obj;
for (i in this._layers) {
obj = this._layers[i];
this._addItem(obj);
overlaysPresent = overlaysPresent || obj.overlay;
baseLayersPresent = baseLayersPresent || !obj.overlay;
}
},
_onLayerChange: function(e) {
var obj = this._layers[L.Util.stamp(e.layer)];
if (!obj) {
return;
}
if (!this._handlingClick) {
this._update();
}
var type = obj.overlay ?
(e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
(e.type === 'layeradd' ? 'baselayerchange' : null);
this._checkIfDisabled();
if (type) {
this._map.fire(type, obj);
}
},
_onZoomEnd: function(e) {
this._checkIfDisabled();
},
_checkIfDisabled: function(layers) {
var currentZoom = this._map.getZoom();
for (layerId in this._layers) {
if (this._layers[layerId].layer.options && (this._layers[layerId].layer.options.minZoom || this._layers[layerId].layer.options.maxZoom)) {
var el = document.getElementById('ac_layer_input_' + this._layers[layerId].layer._leaflet_id);
if (currentZoom < this._layers[layerId].layer.options.minZoom || currentZoom > this._layers[layerId].layer.options.maxZoom) {
el.disabled = 'disabled';
} else {
el.disabled = '';
}
}
}
},
// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
_createRadioElement: function(name, checked) {
var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
if (checked) {
radioHtml += ' checked="checked"';
}
radioHtml += '/>';
var radioFragment = document.createElement('div');
radioFragment.innerHTML = radioHtml;
return radioFragment.firstChild;
},
_addItem: function(obj) {
var label = document.createElement('div'),
input,
checked = this._map.hasLayer(obj.layer),
id = 'ac_layer_input_' + obj.layer._leaflet_id,
container;
if (obj.overlay) {
input = document.createElement('input');
input.type = 'checkbox';
input.className = 'leaflet-control-layers-selector';
input.defaultChecked = checked;
label.className = "menu-item-checkbox";
input.id = id;
} else {
input = this._createRadioElement('leaflet-base-layers', checked);
label.className = "menu-item-radio";
input.id = id;
}
this._layerControlInputs.push(input);
input.layerId = L.Util.stamp(obj.layer);
L.DomEvent.on(input, 'click', this._onInputClick, this);
var name = document.createElement('label');
name.innerHTML = '<label for="' + id + '">' + obj.name + '</label>';
label.appendChild(input);
label.appendChild(name);
if (obj.layer.StyledLayerControl) {
// configure the delete button for layers with attribute removable = true
if (obj.layer.StyledLayerControl.removable) {
var bt_delete = document.createElement("input");
bt_delete.type = "button";
bt_delete.className = "bt_delete";
L.DomEvent.on(bt_delete, 'click', this._onDeleteClick, this);
label.appendChild(bt_delete);
}
// configure the visible attribute to layer
if (obj.layer.StyledLayerControl.visible) {
this._map.addLayer(obj.layer);
}
}
if (obj.overlay) {
container = this._overlaysList;
} else {
container = this._baseLayersList;
}
var groupContainer = this._domGroups[obj.group.id];
if (!groupContainer) {
groupContainer = document.createElement('div');
groupContainer.id = 'leaflet-control-accordion-layers-' + obj.group.id;
// verify if group is expanded
var s_expanded = obj.group.expanded ? ' checked = "true" ' : '';
// verify if type is exclusive
var s_type_exclusive = this.options.exclusive ? ' type="radio" ' : ' type="checkbox" ';
inputElement = '<input id="ac' + obj.group.id + '" name="accordion-1" class="menu" ' + s_expanded + s_type_exclusive + '/>';
inputLabel = '<label for="ac' + obj.group.id + '">' + obj.group.name + '</label>';
article = document.createElement('article');
article.className = 'ac-large';
article.appendChild(label);
// process options of ac-large css class - to options.group_maxHeight property
if (this.options.group_maxHeight) {
article.style.maxHeight = this.options.group_maxHeight;
}
groupContainer.innerHTML = inputElement + inputLabel;
groupContainer.appendChild(article);
// Link to toggle all layers
if (obj.overlay && this.options.group_togglers.show) {
// Toggler container
var togglerContainer = L.DomUtil.create('div', 'group-toggle-container', groupContainer);
// Link All
var linkAll = L.DomUtil.create('a', 'group-toggle-all', togglerContainer);
linkAll.href = '#';
linkAll.title = this.options.group_togglers.labelAll;
linkAll.innerHTML = this.options.group_togglers.labelAll;
linkAll.setAttribute("data-group-name", obj.group.name);
if (L.Browser.touch) {
L.DomEvent
.on(linkAll, 'click', L.DomEvent.stop)
.on(linkAll, 'click', this._onSelectGroup, this);
} else {
L.DomEvent
.on(linkAll, 'click', L.DomEvent.stop)
.on(linkAll, 'focus', this._onSelectGroup, this);
}
// Separator
var separator = L.DomUtil.create('span', 'group-toggle-divider', togglerContainer);
separator.innerHTML = ' / ';
// Link none
var linkNone = L.DomUtil.create('a', 'group-toggle-none', togglerContainer);
linkNone.href = '#';
linkNone.title = this.options.group_togglers.labelNone;
linkNone.innerHTML = this.options.group_togglers.labelNone;
linkNone.setAttribute("data-group-name", obj.group.name);
if (L.Browser.touch) {
L.DomEvent
.on(linkNone, 'click', L.DomEvent.stop)
.on(linkNone, 'click', this._onUnSelectGroup, this);
} else {
L.DomEvent
.on(linkNone, 'click', L.DomEvent.stop)
.on(linkNone, 'focus', this._onUnSelectGroup, this);
}
if (obj.overlay && this.options.group_togglers.show && obj.group.removable) {
// Separator
var separator = L.DomUtil.create('span', 'group-toggle-divider', togglerContainer);
separator.innerHTML = ' / ';
}
if (obj.group.removable) {
// Link delete group
var linkRemove = L.DomUtil.create('a', 'group-toggle-none', togglerContainer);
linkRemove.href = '#';
linkRemove.title = this.options.groupDeleteLabel;
linkRemove.innerHTML = this.options.groupDeleteLabel;
linkRemove.setAttribute("data-group-name", obj.group.name);
if (L.Browser.touch) {
L.DomEvent
.on(linkRemove, 'click', L.DomEvent.stop)
.on(linkRemove, 'click', this._onRemoveGroup, this);
} else {
L.DomEvent
.on(linkRemove, 'click', L.DomEvent.stop)
.on(linkRemove, 'focus', this._onRemoveGroup, this);
}
}
}
container.appendChild(groupContainer);
this._domGroups[obj.group.id] = groupContainer;
} else {
groupContainer.getElementsByTagName('article')[0].appendChild(label);
}
return label;
},
_onDeleteClick: function(obj) {
var node = obj.target.parentElement.childNodes[0];
n_obj = this._layers[node.layerId];
// verify if obj is a basemap and checked to not remove
if (!n_obj.overlay && node.checked) {
return false;
}
if (this._map.hasLayer(n_obj.layer)) {
this._map.removeLayer(n_obj.layer);
}
obj.target.parentNode.remove();
return false;
},
_onSelectGroup: function(e) {
this.selectGroup(e.target.getAttribute("data-group-name"));
},
_onUnSelectGroup: function(e) {
this.unSelectGroup(e.target.getAttribute("data-group-name"));
},
_onRemoveGroup: function(e) {
this.removeGroup(e.target.getAttribute("data-group-name"), true);
},
_expand: function() {
L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
},
_collapse: function() {
this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
}
});
L.Control.styledLayerControl = function(baseLayers, overlays, options) {
return new L.Control.StyledLayerControl(baseLayers, overlays, options);
};

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 608 B

View File

@@ -0,0 +1,80 @@
var blueIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-blue.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var goldIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-gold.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var redIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-red.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var greenIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-green.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var orangeIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-orange.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var yellowIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-yellow.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var violetIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-violet.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var greyIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-grey.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});
var blackIcon = new L.Icon({
iconUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-icon-2x-black.png',
shadowUrl: '../lib/leaflet_plugins/leaflet-colormarkers-1.0.0/img/marker-shadow.png',
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
shadowSize: [41, 41]
});

View File

@@ -0,0 +1,23 @@
Copyright (c) 2012 sa3m (https://github.com/sa3m)
Copyright (c) 2013 Per Liedman
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are
permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list
of conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,126 @@
.leaflet-control-geocoder {
border-radius: 4px;
background: white;
min-width: 26px;
min-height: 26px;
}
.leaflet-touch .leaflet-control-geocoder {
min-width: 30px;
min-height: 30px;
}
.leaflet-control-geocoder a,
.leaflet-control-geocoder .leaflet-control-geocoder-icon {
border-bottom: none;
display: inline-block;
}
.leaflet-control-geocoder .leaflet-control-geocoder-alternatives a {
width: inherit;
height: inherit;
line-height: inherit;
}
.leaflet-control-geocoder a:hover,
.leaflet-control-geocoder .leaflet-control-geocoder-icon:hover {
border-bottom: none;
display: inline-block;
}
.leaflet-control-geocoder-form {
display: none;
vertical-align: middle;
}
.leaflet-control-geocoder-expanded .leaflet-control-geocoder-form {
display: inline-block;
}
.leaflet-control-geocoder-form input {
font-size: 120%;
border: 0;
background-color: transparent;
width: 246px;
}
.leaflet-control-geocoder-icon {
border-radius: 4px;
width: 26px;
height: 26px;
border: none;
background-color: white;
background-image: url(images/geocoder.png);
background-repeat: no-repeat;
background-position: center;
cursor: pointer;
}
.leaflet-touch .leaflet-control-geocoder-icon {
width: 30px;
height: 30px;
}
.leaflet-control-geocoder-throbber .leaflet-control-geocoder-icon {
background-image: url(images/throbber.gif);
}
.leaflet-control-geocoder-form-no-error {
display: none;
}
.leaflet-control-geocoder-form input:focus {
outline: none;
}
.leaflet-control-geocoder-form button {
display: none;
}
.leaflet-control-geocoder-error {
margin-top: 8px;
margin-left: 8px;
display: block;
color: #444;
}
.leaflet-control-geocoder-alternatives {
display: block;
width: 272px;
list-style: none;
padding: 0;
margin: 0;
}
.leaflet-control-geocoder-alternatives-minimized {
display: none;
height: 0;
}
.leaflet-control-geocoder-alternatives li {
white-space: nowrap;
display: block;
overflow: hidden;
padding: 5px 8px;
text-overflow: ellipsis;
border-bottom: 1px solid #ccc;
cursor: pointer;
}
.leaflet-control-geocoder-alternatives li a,
.leaflet-control-geocoder-alternatives li a:hover {
width: inherit;
height: inherit;
line-height: inherit;
background: inherit;
border-radius: inherit;
text-align: left;
}
.leaflet-control-geocoder-alternatives li:last-child {
border-bottom: none;
}
.leaflet-control-geocoder-alternatives li:hover,
.leaflet-control-geocoder-selected {
background-color: #f5f5f5;
}
.leaflet-control-geocoder-address-detail {
}
.leaflet-control-geocoder-address-context {
color: #666;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,363 @@
import L from 'leaflet';
import { Nominatim } from './geocoders/index';
export var Geocoder = L.Control.extend({
options: {
showUniqueResult: true,
showResultIcons: false,
collapsed: true,
expand: 'touch', // options: touch, click, anythingelse
position: 'topright',
placeholder: 'Search...',
errorMessage: 'Nothing found.',
queryMinLength: 1,
suggestMinLength: 3,
suggestTimeout: 250,
defaultMarkGeocode: true
},
includes: L.Evented.prototype || L.Mixin.Events,
initialize: function(options) {
L.Util.setOptions(this, options);
if (!this.options.geocoder) {
this.options.geocoder = new Nominatim();
}
this._requestCount = 0;
},
addThrobberClass: function() {
L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-throbber');
},
removeThrobberClass: function() {
L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-throbber');
},
onAdd: function(map) {
var className = 'leaflet-control-geocoder',
container = L.DomUtil.create('div', className + ' leaflet-bar'),
icon = L.DomUtil.create('button', className + '-icon', container),
form = (this._form = L.DomUtil.create('div', className + '-form', container)),
input;
this._map = map;
this._container = container;
icon.innerHTML = '&nbsp;';
icon.type = 'button';
input = this._input = L.DomUtil.create('input', '', form);
input.type = 'text';
input.placeholder = this.options.placeholder;
L.DomEvent.disableClickPropagation(input);
this._errorElement = L.DomUtil.create('div', className + '-form-no-error', container);
this._errorElement.innerHTML = this.options.errorMessage;
this._alts = L.DomUtil.create(
'ul',
className + '-alternatives leaflet-control-geocoder-alternatives-minimized',
container
);
L.DomEvent.disableClickPropagation(this._alts);
L.DomEvent.addListener(input, 'keydown', this._keydown, this);
if (this.options.geocoder.suggest) {
L.DomEvent.addListener(input, 'input', this._change, this);
}
L.DomEvent.addListener(
input,
'blur',
function() {
if (this.options.collapsed && !this._preventBlurCollapse) {
this._collapse();
}
this._preventBlurCollapse = false;
},
this
);
if (this.options.collapsed) {
if (this.options.expand === 'click') {
L.DomEvent.addListener(
container,
'click',
function(e) {
if (e.button === 0 && e.detail !== 2) {
this._toggle();
}
},
this
);
} else if (L.Browser.touch && this.options.expand === 'touch') {
L.DomEvent.addListener(
container,
'touchstart mousedown',
function(e) {
this._toggle();
e.preventDefault(); // mobile: clicking focuses the icon, so UI expands and immediately collapses
e.stopPropagation();
},
this
);
} else {
L.DomEvent.addListener(container, 'mouseover', this._expand, this);
L.DomEvent.addListener(container, 'mouseout', this._collapse, this);
this._map.on('movestart', this._collapse, this);
}
} else {
this._expand();
if (L.Browser.touch) {
L.DomEvent.addListener(
container,
'touchstart',
function() {
this._geocode();
},
this
);
} else {
L.DomEvent.addListener(
container,
'click',
function() {
this._geocode();
},
this
);
}
}
if (this.options.defaultMarkGeocode) {
this.on('markgeocode', this.markGeocode, this);
}
this.on('startgeocode', this.addThrobberClass, this);
this.on('finishgeocode', this.removeThrobberClass, this);
this.on('startsuggest', this.addThrobberClass, this);
this.on('finishsuggest', this.removeThrobberClass, this);
L.DomEvent.disableClickPropagation(container);
return container;
},
_geocodeResult: function(results, suggest) {
if (!suggest && this.options.showUniqueResult && results.length === 1) {
this._geocodeResultSelected(results[0]);
} else if (results.length > 0) {
this._alts.innerHTML = '';
this._results = results;
L.DomUtil.removeClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized');
L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-options-open');
for (var i = 0; i < results.length; i++) {
this._alts.appendChild(this._createAlt(results[i], i));
}
} else {
L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-options-error');
L.DomUtil.addClass(this._errorElement, 'leaflet-control-geocoder-error');
}
},
markGeocode: function(result) {
result = result.geocode || result;
this._map.fitBounds(result.bbox);
if (this._geocodeMarker) {
this._map.removeLayer(this._geocodeMarker);
}
this._geocodeMarker = new L.Marker(result.center)
.bindPopup(result.html || result.name)
.addTo(this._map)
.openPopup();
return this;
},
_geocode: function(suggest) {
var value = this._input.value;
if (!suggest && value.length < this.options.queryMinLength) {
return;
}
var requestCount = ++this._requestCount,
mode = suggest ? 'suggest' : 'geocode',
eventData = { input: value };
this._lastGeocode = value;
if (!suggest) {
this._clearResults();
}
this.fire('start' + mode, eventData);
this.options.geocoder[mode](
value,
function(results) {
if (requestCount === this._requestCount) {
eventData.results = results;
this.fire('finish' + mode, eventData);
this._geocodeResult(results, suggest);
}
},
this
);
},
_geocodeResultSelected: function(result) {
this.fire('markgeocode', { geocode: result });
},
_toggle: function() {
if (L.DomUtil.hasClass(this._container, 'leaflet-control-geocoder-expanded')) {
this._collapse();
} else {
this._expand();
}
},
_expand: function() {
L.DomUtil.addClass(this._container, 'leaflet-control-geocoder-expanded');
this._input.select();
this.fire('expand');
},
_collapse: function() {
L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-expanded');
L.DomUtil.addClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized');
L.DomUtil.removeClass(this._errorElement, 'leaflet-control-geocoder-error');
L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-options-open');
L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-options-error');
this._input.blur(); // mobile: keyboard shouldn't stay expanded
this.fire('collapse');
},
_clearResults: function() {
L.DomUtil.addClass(this._alts, 'leaflet-control-geocoder-alternatives-minimized');
this._selection = null;
L.DomUtil.removeClass(this._errorElement, 'leaflet-control-geocoder-error');
L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-options-open');
L.DomUtil.removeClass(this._container, 'leaflet-control-geocoder-options-error');
},
_createAlt: function(result, index) {
var li = L.DomUtil.create('li', ''),
a = L.DomUtil.create('a', '', li),
icon = this.options.showResultIcons && result.icon ? L.DomUtil.create('img', '', a) : null,
text = result.html ? undefined : document.createTextNode(result.name),
mouseDownHandler = function mouseDownHandler(e) {
// In some browsers, a click will fire on the map if the control is
// collapsed directly after mousedown. To work around this, we
// wait until the click is completed, and _then_ collapse the
// control. Messy, but this is the workaround I could come up with
// for #142.
this._preventBlurCollapse = true;
L.DomEvent.stop(e);
this._geocodeResultSelected(result);
L.DomEvent.on(
li,
'click',
function() {
if (this.options.collapsed) {
this._collapse();
} else {
this._clearResults();
}
},
this
);
};
if (icon) {
icon.src = result.icon;
}
li.setAttribute('data-result-index', index);
if (result.html) {
a.innerHTML = a.innerHTML + result.html;
} else {
a.appendChild(text);
}
// Use mousedown and not click, since click will fire _after_ blur,
// causing the control to have collapsed and removed the items
// before the click can fire.
L.DomEvent.addListener(li, 'mousedown touchstart', mouseDownHandler, this);
return li;
},
_keydown: function(e) {
var _this = this,
select = function select(dir) {
if (_this._selection) {
L.DomUtil.removeClass(_this._selection, 'leaflet-control-geocoder-selected');
_this._selection = _this._selection[dir > 0 ? 'nextSibling' : 'previousSibling'];
}
if (!_this._selection) {
_this._selection = _this._alts[dir > 0 ? 'firstChild' : 'lastChild'];
}
if (_this._selection) {
L.DomUtil.addClass(_this._selection, 'leaflet-control-geocoder-selected');
}
};
switch (e.keyCode) {
// Escape
case 27:
if (this.options.collapsed) {
this._collapse();
} else {
this._clearResults();
}
break;
// Up
case 38:
select(-1);
break;
// Up
case 40:
select(1);
break;
// Enter
case 13:
if (this._selection) {
var index = parseInt(this._selection.getAttribute('data-result-index'), 10);
this._geocodeResultSelected(this._results[index]);
this._clearResults();
} else {
this._geocode();
}
break;
default:
return;
}
L.DomEvent.preventDefault(e);
},
_change: function() {
var v = this._input.value;
if (v !== this._lastGeocode) {
clearTimeout(this._suggestTimeout);
if (v.length >= this.options.suggestMinLength) {
this._suggestTimeout = setTimeout(
L.bind(function() {
this._geocode(true);
}, this),
this.options.suggestTimeout
);
} else {
this._clearResults();
}
}
}
});
export function geocoder(options) {
return new Geocoder(options);
}

View File

@@ -0,0 +1,88 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var ArcGis = L.Class.extend({
options: {
service_url: 'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer'
},
initialize: function(accessToken, options) {
L.setOptions(this, options);
this._accessToken = accessToken;
},
geocode: function(query, cb, context) {
var params = {
SingleLine: query,
outFields: 'Addr_Type',
forStorage: false,
maxLocations: 10,
f: 'json'
};
if (this._key && this._key.length) {
params.token = this._key;
}
getJSON(
this.options.service_url + '/findAddressCandidates',
L.extend(params, this.options.geocodingQueryParams),
function(data) {
var results = [],
loc,
latLng,
latLngBounds;
if (data.candidates && data.candidates.length) {
for (var i = 0; i <= data.candidates.length - 1; i++) {
loc = data.candidates[i];
latLng = L.latLng(loc.location.y, loc.location.x);
latLngBounds = L.latLngBounds(
L.latLng(loc.extent.ymax, loc.extent.xmax),
L.latLng(loc.extent.ymin, loc.extent.xmin)
);
results[i] = {
name: loc.address,
bbox: latLngBounds,
center: latLng
};
}
}
cb.call(context, results);
}
);
},
suggest: function(query, cb, context) {
return this.geocode(query, cb, context);
},
reverse: function(location, scale, cb, context) {
var params = {
location: encodeURIComponent(location.lng) + ',' + encodeURIComponent(location.lat),
distance: 100,
f: 'json'
};
getJSON(this.options.service_url + '/reverseGeocode', params, function(data) {
var result = [],
loc;
if (data && !data.error) {
loc = L.latLng(data.location.y, data.location.x);
result.push({
name: data.address.Match_addr,
center: loc,
bounds: L.latLngBounds(loc, loc)
});
}
cb.call(context, result);
});
}
});
export function arcgis(accessToken, options) {
return new ArcGis(accessToken, options);
}

View File

@@ -0,0 +1,63 @@
import L from 'leaflet';
import { jsonp } from '../util';
export var Bing = L.Class.extend({
initialize: function(key) {
this.key = key;
},
geocode: function(query, cb, context) {
jsonp(
'https://dev.virtualearth.net/REST/v1/Locations',
{
query: query,
key: this.key
},
function(data) {
var results = [];
if (data.resourceSets.length > 0) {
for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) {
var resource = data.resourceSets[0].resources[i],
bbox = resource.bbox;
results[i] = {
name: resource.name,
bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]),
center: L.latLng(resource.point.coordinates)
};
}
}
cb.call(context, results);
},
this,
'jsonp'
);
},
reverse: function(location, scale, cb, context) {
jsonp(
'//dev.virtualearth.net/REST/v1/Locations/' + location.lat + ',' + location.lng,
{
key: this.key
},
function(data) {
var results = [];
for (var i = data.resourceSets[0].resources.length - 1; i >= 0; i--) {
var resource = data.resourceSets[0].resources[i],
bbox = resource.bbox;
results[i] = {
name: resource.name,
bbox: L.latLngBounds([bbox[0], bbox[1]], [bbox[2], bbox[3]]),
center: L.latLng(resource.point.coordinates)
};
}
cb.call(context, results);
},
this,
'jsonp'
);
}
});
export function bing(key) {
return new Bing(key);
}

View File

@@ -0,0 +1,93 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var Google = L.Class.extend({
options: {
serviceUrl: 'https://maps.googleapis.com/maps/api/geocode/json',
geocodingQueryParams: {},
reverseQueryParams: {}
},
initialize: function(key, options) {
this._key = key;
L.setOptions(this, options);
// Backwards compatibility
this.options.serviceUrl = this.options.service_url || this.options.serviceUrl;
},
geocode: function(query, cb, context) {
var params = {
address: query
};
if (this._key && this._key.length) {
params.key = this._key;
}
params = L.Util.extend(params, this.options.geocodingQueryParams);
getJSON(this.options.serviceUrl, params, function(data) {
var results = [],
loc,
latLng,
latLngBounds;
if (data.results && data.results.length) {
for (var i = 0; i <= data.results.length - 1; i++) {
loc = data.results[i];
latLng = L.latLng(loc.geometry.location);
latLngBounds = L.latLngBounds(
L.latLng(loc.geometry.viewport.northeast),
L.latLng(loc.geometry.viewport.southwest)
);
results[i] = {
name: loc.formatted_address,
bbox: latLngBounds,
center: latLng,
properties: loc.address_components
};
}
}
cb.call(context, results);
});
},
reverse: function(location, scale, cb, context) {
var params = {
latlng: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng)
};
params = L.Util.extend(params, this.options.reverseQueryParams);
if (this._key && this._key.length) {
params.key = this._key;
}
getJSON(this.options.serviceUrl, params, function(data) {
var results = [],
loc,
latLng,
latLngBounds;
if (data.results && data.results.length) {
for (var i = 0; i <= data.results.length - 1; i++) {
loc = data.results[i];
latLng = L.latLng(loc.geometry.location);
latLngBounds = L.latLngBounds(
L.latLng(loc.geometry.viewport.northeast),
L.latLng(loc.geometry.viewport.southwest)
);
results[i] = {
name: loc.formatted_address,
bbox: latLngBounds,
center: latLng,
properties: loc.address_components
};
}
}
cb.call(context, results);
});
}
});
export function google(key, options) {
return new Google(key, options);
}

View File

@@ -0,0 +1,70 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var HERE = L.Class.extend({
options: {
geocodeUrl: 'https://geocoder.api.here.com/6.2/geocode.json',
reverseGeocodeUrl: 'https://reverse.geocoder.api.here.com/6.2/reversegeocode.json',
app_id: '<insert your app_id here>',
app_code: '<insert your app_code here>',
geocodingQueryParams: {},
reverseQueryParams: {},
reverseGeocodeProxRadius: null
},
initialize: function(options) {
L.setOptions(this, options);
},
geocode: function(query, cb, context) {
var params = {
searchtext: query,
gen: 9,
app_id: this.options.app_id,
app_code: this.options.app_code,
jsonattributes: 1
};
params = L.Util.extend(params, this.options.geocodingQueryParams);
this.getJSON(this.options.geocodeUrl, params, cb, context);
},
reverse: function(location, scale, cb, context) {
var _proxRadius = this.options.reverseGeocodeProxRadius
? this.options.reverseGeocodeProxRadius
: null;
var proxRadius = _proxRadius ? ',' + encodeURIComponent(_proxRadius) : '';
var params = {
prox: encodeURIComponent(location.lat) + ',' + encodeURIComponent(location.lng) + proxRadius,
mode: 'retrieveAddresses',
app_id: this.options.app_id,
app_code: this.options.app_code,
gen: 9,
jsonattributes: 1
};
params = L.Util.extend(params, this.options.reverseQueryParams);
this.getJSON(this.options.reverseGeocodeUrl, params, cb, context);
},
getJSON: function(url, params, cb, context) {
getJSON(url, params, function(data) {
var results = [],
loc,
latLng,
latLngBounds;
if (data.response.view && data.response.view.length) {
for (var i = 0; i <= data.response.view[0].result.length - 1; i++) {
loc = data.response.view[0].result[i].location;
latLng = L.latLng(loc.displayPosition.latitude, loc.displayPosition.longitude);
latLngBounds = L.latLngBounds(
L.latLng(loc.mapView.topLeft.latitude, loc.mapView.topLeft.longitude),
L.latLng(loc.mapView.bottomRight.latitude, loc.mapView.bottomRight.longitude)
);
results[i] = {
name: loc.address.label,
bbox: latLngBounds,
center: latLng
};
}
}
cb.call(context, results);
});
}
});
export function here(options) {
return new HERE(options);
}

View File

@@ -0,0 +1,14 @@
export * from './arcgis';
export * from './bing';
export * from './google';
export * from './here';
export * from './latlng';
export * from './mapbox';
export * from './mapquest';
export * from './neutrino';
export * from './nominatim';
export * from './open-location-code';
export * from './opencage';
export * from './pelias';
export * from './photon';
export * from './what3words';

View File

@@ -0,0 +1,98 @@
import L from 'leaflet';
export var LatLng = L.Class.extend({
options: {
// the next geocoder to use
next: undefined,
sizeInMeters: 10000
},
initialize: function(options) {
L.Util.setOptions(this, options);
},
geocode: function(query, cb, context) {
var match;
var center;
// regex from https://github.com/openstreetmap/openstreetmap-website/blob/master/app/controllers/geocoder_controller.rb
if ((match = query.match(/^([NS])\s*(\d{1,3}(?:\.\d*)?)\W*([EW])\s*(\d{1,3}(?:\.\d*)?)$/))) {
// [NSEW] decimal degrees
center = L.latLng(
(/N/i.test(match[1]) ? 1 : -1) * parseFloat(match[2]),
(/E/i.test(match[3]) ? 1 : -1) * parseFloat(match[4])
);
} else if (
(match = query.match(/^(\d{1,3}(?:\.\d*)?)\s*([NS])\W*(\d{1,3}(?:\.\d*)?)\s*([EW])$/))
) {
// decimal degrees [NSEW]
center = L.latLng(
(/N/i.test(match[2]) ? 1 : -1) * parseFloat(match[1]),
(/E/i.test(match[4]) ? 1 : -1) * parseFloat(match[3])
);
} else if (
(match = query.match(
/^([NS])\s*(\d{1,3})°?\s*(\d{1,3}(?:\.\d*)?)?[']?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,3}(?:\.\d*)?)?[']?$/
))
) {
// [NSEW] degrees, decimal minutes
center = L.latLng(
(/N/i.test(match[1]) ? 1 : -1) * (parseFloat(match[2]) + parseFloat(match[3] / 60)),
(/E/i.test(match[4]) ? 1 : -1) * (parseFloat(match[5]) + parseFloat(match[6] / 60))
);
} else if (
(match = query.match(
/^(\d{1,3})°?\s*(\d{1,3}(?:\.\d*)?)?[']?\s*([NS])\W*(\d{1,3})°?\s*(\d{1,3}(?:\.\d*)?)?[']?\s*([EW])$/
))
) {
// degrees, decimal minutes [NSEW]
center = L.latLng(
(/N/i.test(match[3]) ? 1 : -1) * (parseFloat(match[1]) + parseFloat(match[2] / 60)),
(/E/i.test(match[6]) ? 1 : -1) * (parseFloat(match[4]) + parseFloat(match[5] / 60))
);
} else if (
(match = query.match(
/^([NS])\s*(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(?:\.\d*)?)?["″]?\W*([EW])\s*(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(?:\.\d*)?)?["″]?$/
))
) {
// [NSEW] degrees, minutes, decimal seconds
center = L.latLng(
(/N/i.test(match[1]) ? 1 : -1) *
(parseFloat(match[2]) + parseFloat(match[3] / 60 + parseFloat(match[4] / 3600))),
(/E/i.test(match[5]) ? 1 : -1) *
(parseFloat(match[6]) + parseFloat(match[7] / 60) + parseFloat(match[8] / 3600))
);
} else if (
(match = query.match(
/^(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(?:\.\d*)?)?["″]\s*([NS])\W*(\d{1,3})°?\s*(\d{1,2})[']?\s*(\d{1,3}(?:\.\d*)?)?["″]?\s*([EW])$/
))
) {
// degrees, minutes, decimal seconds [NSEW]
center = L.latLng(
(/N/i.test(match[4]) ? 1 : -1) *
(parseFloat(match[1]) + parseFloat(match[2] / 60 + parseFloat(match[3] / 3600))),
(/E/i.test(match[8]) ? 1 : -1) *
(parseFloat(match[5]) + parseFloat(match[6] / 60) + parseFloat(match[7] / 3600))
);
} else if (
(match = query.match(/^\s*([+-]?\d+(?:\.\d*)?)\s*[\s,]\s*([+-]?\d+(?:\.\d*)?)\s*$/))
) {
center = L.latLng(parseFloat(match[1]), parseFloat(match[2]));
}
if (center) {
var results = [
{
name: query,
center: center,
bbox: center.toBounds(this.options.sizeInMeters)
}
];
cb.call(context, results);
} else if (this.options.next) {
this.options.next.geocode(query, cb, context);
}
}
});
export function latLng(options) {
return new LatLng(options);
}

View File

@@ -0,0 +1,112 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var Mapbox = L.Class.extend({
options: {
serviceUrl: 'https://api.mapbox.com/geocoding/v5/mapbox.places/',
geocodingQueryParams: {},
reverseQueryParams: {}
},
initialize: function(accessToken, options) {
L.setOptions(this, options);
this.options.geocodingQueryParams.access_token = accessToken;
this.options.reverseQueryParams.access_token = accessToken;
},
geocode: function(query, cb, context) {
var params = this.options.geocodingQueryParams;
if (
params.proximity !== undefined &&
params.proximity.lat !== undefined &&
params.proximity.lng !== undefined
) {
params.proximity = params.proximity.lng + ',' + params.proximity.lat;
}
getJSON(this.options.serviceUrl + encodeURIComponent(query) + '.json', params, function(data) {
var results = [],
loc,
latLng,
latLngBounds;
if (data.features && data.features.length) {
for (var i = 0; i <= data.features.length - 1; i++) {
loc = data.features[i];
latLng = L.latLng(loc.center.reverse());
if (loc.bbox) {
latLngBounds = L.latLngBounds(
L.latLng(loc.bbox.slice(0, 2).reverse()),
L.latLng(loc.bbox.slice(2, 4).reverse())
);
} else {
latLngBounds = L.latLngBounds(latLng, latLng);
}
var properties = {
text: loc.text,
address: loc.address
};
for (var j = 0; j < (loc.context || []).length; j++) {
var id = loc.context[j].id.split('.')[0];
properties[id] = loc.context[j].text;
}
results[i] = {
name: loc.place_name,
bbox: latLngBounds,
center: latLng,
properties: properties
};
}
}
cb.call(context, results);
});
},
suggest: function(query, cb, context) {
return this.geocode(query, cb, context);
},
reverse: function(location, scale, cb, context) {
getJSON(
this.options.serviceUrl +
encodeURIComponent(location.lng) +
',' +
encodeURIComponent(location.lat) +
'.json',
this.options.reverseQueryParams,
function(data) {
var results = [],
loc,
latLng,
latLngBounds;
if (data.features && data.features.length) {
for (var i = 0; i <= data.features.length - 1; i++) {
loc = data.features[i];
latLng = L.latLng(loc.center.reverse());
if (loc.bbox) {
latLngBounds = L.latLngBounds(
L.latLng(loc.bbox.slice(0, 2).reverse()),
L.latLng(loc.bbox.slice(2, 4).reverse())
);
} else {
latLngBounds = L.latLngBounds(latLng, latLng);
}
results[i] = {
name: loc.place_name,
bbox: latLngBounds,
center: latLng
};
}
}
cb.call(context, results);
}
);
}
});
export function mapbox(accessToken, options) {
return new Mapbox(accessToken, options);
}

View File

@@ -0,0 +1,91 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var MapQuest = L.Class.extend({
options: {
serviceUrl: 'https://www.mapquestapi.com/geocoding/v1'
},
initialize: function(key, options) {
// MapQuest seems to provide URI encoded API keys,
// so to avoid encoding them twice, we decode them here
this._key = decodeURIComponent(key);
L.Util.setOptions(this, options);
},
_formatName: function() {
var r = [],
i;
for (i = 0; i < arguments.length; i++) {
if (arguments[i]) {
r.push(arguments[i]);
}
}
return r.join(', ');
},
geocode: function(query, cb, context) {
getJSON(
this.options.serviceUrl + '/address',
{
key: this._key,
location: query,
limit: 5,
outFormat: 'json'
},
L.bind(function(data) {
var results = [],
loc,
latLng;
if (data.results && data.results[0].locations) {
for (var i = data.results[0].locations.length - 1; i >= 0; i--) {
loc = data.results[0].locations[i];
latLng = L.latLng(loc.latLng);
results[i] = {
name: this._formatName(loc.street, loc.adminArea4, loc.adminArea3, loc.adminArea1),
bbox: L.latLngBounds(latLng, latLng),
center: latLng
};
}
}
cb.call(context, results);
}, this)
);
},
reverse: function(location, scale, cb, context) {
getJSON(
this.options.serviceUrl + '/reverse',
{
key: this._key,
location: location.lat + ',' + location.lng,
outputFormat: 'json'
},
L.bind(function(data) {
var results = [],
loc,
latLng;
if (data.results && data.results[0].locations) {
for (var i = data.results[0].locations.length - 1; i >= 0; i--) {
loc = data.results[0].locations[i];
latLng = L.latLng(loc.latLng);
results[i] = {
name: this._formatName(loc.street, loc.adminArea4, loc.adminArea3, loc.adminArea1),
bbox: L.latLngBounds(latLng, latLng),
center: latLng
};
}
}
cb.call(context, results);
}, this)
);
}
});
export function mapQuest(key, options) {
return new MapQuest(key, options);
}

View File

@@ -0,0 +1,80 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var Neutrino = L.Class.extend({
options: {
userId: '<insert your userId here>',
apiKey: '<insert your apiKey here>',
serviceUrl: 'https://neutrinoapi.com/'
},
initialize: function(options) {
L.Util.setOptions(this, options);
},
// https://www.neutrinoapi.com/api/geocode-address/
geocode: function(query, cb, context) {
getJSON(
this.options.serviceUrl + 'geocode-address',
{
apiKey: this.options.apiKey,
userId: this.options.userId,
//get three words and make a dot based string
address: query.split(/\s+/).join('.')
},
function(data) {
var results = [],
latLng,
latLngBounds;
if (data.locations) {
data.geometry = data.locations[0];
latLng = L.latLng(data.geometry['latitude'], data.geometry['longitude']);
latLngBounds = L.latLngBounds(latLng, latLng);
results[0] = {
name: data.geometry.address,
bbox: latLngBounds,
center: latLng
};
}
cb.call(context, results);
}
);
},
suggest: function(query, cb, context) {
return this.geocode(query, cb, context);
},
// https://www.neutrinoapi.com/api/geocode-reverse/
reverse: function(location, scale, cb, context) {
getJSON(
this.options.serviceUrl + 'geocode-reverse',
{
apiKey: this.options.apiKey,
userId: this.options.userId,
latitude: location.lat,
longitude: location.lng
},
function(data) {
var results = [],
latLng,
latLngBounds;
if (data.status.status == 200 && data.found) {
latLng = L.latLng(location.lat, location.lng);
latLngBounds = L.latLngBounds(latLng, latLng);
results[0] = {
name: data.address,
bbox: latLngBounds,
center: latLng
};
}
cb.call(context, results);
}
);
}
});
export function neutrino(accessToken) {
return new Neutrino(accessToken);
}

View File

@@ -0,0 +1,107 @@
import L from 'leaflet';
import { template, getJSON } from '../util';
export var Nominatim = L.Class.extend({
options: {
serviceUrl: 'https://nominatim.openstreetmap.org/',
geocodingQueryParams: {},
reverseQueryParams: {},
htmlTemplate: function(r) {
var a = r.address,
parts = [];
if (a.road || a.building) {
parts.push('{building} {road} {house_number}');
}
if (a.city || a.town || a.village || a.hamlet) {
parts.push(
'<span class="' +
(parts.length > 0 ? 'leaflet-control-geocoder-address-detail' : '') +
'">{postcode} {city} {town} {village} {hamlet}</span>'
);
}
if (a.state || a.country) {
parts.push(
'<span class="' +
(parts.length > 0 ? 'leaflet-control-geocoder-address-context' : '') +
'">{state} {country}</span>'
);
}
return template(parts.join('<br/>'), a, true);
}
},
initialize: function(options) {
L.Util.setOptions(this, options);
},
geocode: function(query, cb, context) {
getJSON(
this.options.serviceUrl + 'search',
L.extend(
{
q: query,
limit: 5,
format: 'json',
addressdetails: 1
},
this.options.geocodingQueryParams
),
L.bind(function(data) {
var results = [];
for (var i = data.length - 1; i >= 0; i--) {
var bbox = data[i].boundingbox;
for (var j = 0; j < 4; j++) bbox[j] = parseFloat(bbox[j]);
results[i] = {
icon: data[i].icon,
name: data[i].display_name,
html: this.options.htmlTemplate ? this.options.htmlTemplate(data[i]) : undefined,
bbox: L.latLngBounds([bbox[0], bbox[2]], [bbox[1], bbox[3]]),
center: L.latLng(data[i].lat, data[i].lon),
properties: data[i]
};
}
cb.call(context, results);
}, this)
);
},
reverse: function(location, scale, cb, context) {
getJSON(
this.options.serviceUrl + 'reverse',
L.extend(
{
lat: location.lat,
lon: location.lng,
zoom: Math.round(Math.log(scale / 256) / Math.log(2)),
addressdetails: 1,
format: 'json'
},
this.options.reverseQueryParams
),
L.bind(function(data) {
var result = [],
loc;
if (data && data.lat && data.lon) {
loc = L.latLng(data.lat, data.lon);
result.push({
name: data.display_name,
html: this.options.htmlTemplate ? this.options.htmlTemplate(data) : undefined,
center: loc,
bounds: L.latLngBounds(loc, loc),
properties: data
});
}
cb.call(context, result);
}, this)
);
}
});
export function nominatim(options) {
return new Nominatim(options);
}

View File

@@ -0,0 +1,55 @@
import L from 'leaflet';
export var OpenLocationCode = L.Class.extend({
options: {
OpenLocationCode: undefined,
codeLength: undefined
},
initialize: function(options) {
L.setOptions(this, options);
},
geocode: function(query, cb, context) {
try {
var decoded = this.options.OpenLocationCode.decode(query);
var result = {
name: query,
center: L.latLng(decoded.latitudeCenter, decoded.longitudeCenter),
bbox: L.latLngBounds(
L.latLng(decoded.latitudeLo, decoded.longitudeLo),
L.latLng(decoded.latitudeHi, decoded.longitudeHi)
)
};
cb.call(context, [result]);
} catch (e) {
console.warn(e); // eslint-disable-line no-console
cb.call(context, []);
}
},
reverse: function(location, scale, cb, context) {
try {
var code = this.options.OpenLocationCode.encode(
location.lat,
location.lng,
this.options.codeLength
);
var result = {
name: code,
center: L.latLng(location.lat, location.lng),
bbox: L.latLngBounds(
L.latLng(location.lat, location.lng),
L.latLng(location.lat, location.lng)
)
};
cb.call(context, [result]);
} catch (e) {
console.warn(e); // eslint-disable-line no-console
cb.call(context, []);
}
}
});
export function openLocationCode(options) {
return new OpenLocationCode(options);
}

View File

@@ -0,0 +1,92 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var OpenCage = L.Class.extend({
options: {
serviceUrl: 'https://api.opencagedata.com/geocode/v1/json'
},
initialize: function(apiKey) {
this._accessToken = apiKey;
},
geocode: function(query, cb, context) {
getJSON(
this.options.serviceUrl,
{
key: this._accessToken,
q: query
},
function(data) {
var results = [],
latLng,
latLngBounds,
loc;
if (data.results && data.results.length) {
for (var i = 0; i < data.results.length; i++) {
loc = data.results[i];
latLng = L.latLng(loc.geometry);
if (loc.annotations && loc.annotations.bounds) {
latLngBounds = L.latLngBounds(
L.latLng(loc.annotations.bounds.northeast),
L.latLng(loc.annotations.bounds.southwest)
);
} else {
latLngBounds = L.latLngBounds(latLng, latLng);
}
results.push({
name: loc.formatted,
bbox: latLngBounds,
center: latLng
});
}
}
cb.call(context, results);
}
);
},
suggest: function(query, cb, context) {
return this.geocode(query, cb, context);
},
reverse: function(location, scale, cb, context) {
getJSON(
this.options.serviceUrl,
{
key: this._accessToken,
q: [location.lat, location.lng].join(',')
},
function(data) {
var results = [],
latLng,
latLngBounds,
loc;
if (data.results && data.results.length) {
for (var i = 0; i < data.results.length; i++) {
loc = data.results[i];
latLng = L.latLng(loc.geometry);
if (loc.annotations && loc.annotations.bounds) {
latLngBounds = L.latLngBounds(
L.latLng(loc.annotations.bounds.northeast),
L.latLng(loc.annotations.bounds.southwest)
);
} else {
latLngBounds = L.latLngBounds(latLng, latLng);
}
results.push({
name: loc.formatted,
bbox: latLngBounds,
center: latLng
});
}
}
cb.call(context, results);
}
);
}
});
export function opencage(apiKey) {
return new OpenCage(apiKey);
}

View File

@@ -0,0 +1,124 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var Pelias = L.Class.extend({
options: {
serviceUrl: 'https://api.geocode.earth/v1',
geocodingQueryParams: {},
reverseQueryParams: {}
},
initialize: function(apiKey, options) {
L.Util.setOptions(this, options);
this._apiKey = apiKey;
this._lastSuggest = 0;
},
geocode: function(query, cb, context) {
var _this = this;
getJSON(
this.options.serviceUrl + '/search',
L.extend(
{
api_key: this._apiKey,
text: query
},
this.options.geocodingQueryParams
),
function(data) {
cb.call(context, _this._parseResults(data, 'bbox'));
}
);
},
suggest: function(query, cb, context) {
var _this = this;
getJSON(
this.options.serviceUrl + '/autocomplete',
L.extend(
{
api_key: this._apiKey,
text: query
},
this.options.geocodingQueryParams
),
L.bind(function(data) {
if (data.geocoding.timestamp > this._lastSuggest) {
this._lastSuggest = data.geocoding.timestamp;
cb.call(context, _this._parseResults(data, 'bbox'));
}
}, this)
);
},
reverse: function(location, scale, cb, context) {
var _this = this;
getJSON(
this.options.serviceUrl + '/reverse',
L.extend(
{
api_key: this._apiKey,
'point.lat': location.lat,
'point.lon': location.lng
},
this.options.reverseQueryParams
),
function(data) {
cb.call(context, _this._parseResults(data, 'bounds'));
}
);
},
_parseResults: function(data, bboxname) {
var results = [];
L.geoJson(data, {
pointToLayer: function(feature, latlng) {
return L.circleMarker(latlng);
},
onEachFeature: function(feature, layer) {
var result = {},
bbox,
center;
if (layer.getBounds) {
bbox = layer.getBounds();
center = bbox.getCenter();
} else if (layer.feature.bbox) {
center = layer.getLatLng();
bbox = L.latLngBounds(
L.GeoJSON.coordsToLatLng(layer.feature.bbox.slice(0, 2)),
L.GeoJSON.coordsToLatLng(layer.feature.bbox.slice(2, 4))
);
} else {
center = layer.getLatLng();
bbox = L.latLngBounds(center, center);
}
result.name = layer.feature.properties.label;
result.center = center;
result[bboxname] = bbox;
result.properties = layer.feature.properties;
results.push(result);
}
});
return results;
}
});
export function pelias(apiKey, options) {
return new Pelias(apiKey, options);
}
export var GeocodeEarth = Pelias;
export var geocodeEarth = pelias;
export var Mapzen = Pelias; // r.i.p.
export var mapzen = pelias;
export var Openrouteservice = Mapzen.extend({
options: {
serviceUrl: 'https://api.openrouteservice.org/geocode'
}
});
export function openrouteservice(apiKey, options) {
return new Openrouteservice(apiKey, options);
}

View File

@@ -0,0 +1,103 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var Photon = L.Class.extend({
options: {
serviceUrl: 'https://photon.komoot.de/api/',
reverseUrl: 'https://photon.komoot.de/reverse/',
nameProperties: ['name', 'street', 'suburb', 'hamlet', 'town', 'city', 'state', 'country']
},
initialize: function(options) {
L.setOptions(this, options);
},
geocode: function(query, cb, context) {
var params = L.extend(
{
q: query
},
this.options.geocodingQueryParams
);
getJSON(
this.options.serviceUrl,
params,
L.bind(function(data) {
cb.call(context, this._decodeFeatures(data));
}, this)
);
},
suggest: function(query, cb, context) {
return this.geocode(query, cb, context);
},
reverse: function(latLng, scale, cb, context) {
var params = L.extend(
{
lat: latLng.lat,
lon: latLng.lng
},
this.options.reverseQueryParams
);
getJSON(
this.options.reverseUrl,
params,
L.bind(function(data) {
cb.call(context, this._decodeFeatures(data));
}, this)
);
},
_decodeFeatures: function(data) {
var results = [],
i,
f,
c,
latLng,
extent,
bbox;
if (data && data.features) {
for (i = 0; i < data.features.length; i++) {
f = data.features[i];
c = f.geometry.coordinates;
latLng = L.latLng(c[1], c[0]);
extent = f.properties.extent;
if (extent) {
bbox = L.latLngBounds([extent[1], extent[0]], [extent[3], extent[2]]);
} else {
bbox = L.latLngBounds(latLng, latLng);
}
results.push({
name: this._decodeFeatureName(f),
html: this.options.htmlTemplate ? this.options.htmlTemplate(f) : undefined,
center: latLng,
bbox: bbox,
properties: f.properties
});
}
}
return results;
},
_decodeFeatureName: function(f) {
return (this.options.nameProperties || [])
.map(function(p) {
return f.properties[p];
})
.filter(function(v) {
return !!v;
})
.join(', ');
}
});
export function photon(options) {
return new Photon(options);
}

View File

@@ -0,0 +1,72 @@
import L from 'leaflet';
import { getJSON } from '../util';
export var What3Words = L.Class.extend({
options: {
serviceUrl: 'https://api.what3words.com/v2/'
},
initialize: function(accessToken) {
this._accessToken = accessToken;
},
geocode: function(query, cb, context) {
//get three words and make a dot based string
getJSON(
this.options.serviceUrl + 'forward',
{
key: this._accessToken,
addr: query.split(/\s+/).join('.')
},
function(data) {
var results = [],
latLng,
latLngBounds;
if (data.geometry) {
latLng = L.latLng(data.geometry['lat'], data.geometry['lng']);
latLngBounds = L.latLngBounds(latLng, latLng);
results[0] = {
name: data.words,
bbox: latLngBounds,
center: latLng
};
}
cb.call(context, results);
}
);
},
suggest: function(query, cb, context) {
return this.geocode(query, cb, context);
},
reverse: function(location, scale, cb, context) {
getJSON(
this.options.serviceUrl + 'reverse',
{
key: this._accessToken,
coords: [location.lat, location.lng].join(',')
},
function(data) {
var results = [],
latLng,
latLngBounds;
if (data.status.status == 200) {
latLng = L.latLng(data.geometry['lat'], data.geometry['lng']);
latLngBounds = L.latLngBounds(latLng, latLng);
results[0] = {
name: data.words,
bbox: latLngBounds,
center: latLng
};
}
cb.call(context, results);
}
);
}
});
export function what3words(accessToken) {
return new What3Words(accessToken);
}

View File

@@ -0,0 +1,11 @@
import L from 'leaflet';
import { Geocoder, geocoder } from './control';
import * as geocoders from './geocoders/index';
L.Util.extend(Geocoder, geocoders);
export default Geocoder;
L.Util.extend(L.Control, {
Geocoder: Geocoder,
geocoder: geocoder
});

View File

@@ -0,0 +1,104 @@
import L from 'leaflet';
var lastCallbackId = 0;
// Adapted from handlebars.js
// https://github.com/wycats/handlebars.js/
var badChars = /[&<>"'`]/g;
var possible = /[&<>"'`]/;
var escape = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;',
'`': '&#x60;'
};
function escapeChar(chr) {
return escape[chr];
}
export function htmlEscape(string) {
if (string == null) {
return '';
} else if (!string) {
return string + '';
}
// Force a string conversion as this will be done by the append regardless and
// the regex test will do this transparently behind the scenes, causing issues if
// an object's to string has escaped characters in it.
string = '' + string;
if (!possible.test(string)) {
return string;
}
return string.replace(badChars, escapeChar);
}
export function jsonp(url, params, callback, context, jsonpParam) {
var callbackId = '_l_geocoder_' + lastCallbackId++;
params[jsonpParam || 'callback'] = callbackId;
window[callbackId] = L.Util.bind(callback, context);
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url + getParamString(params);
script.id = callbackId;
document.getElementsByTagName('head')[0].appendChild(script);
}
export function getJSON(url, params, callback) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState !== 4) {
return;
}
var message;
if (xmlHttp.status !== 200 && xmlHttp.status !== 304) {
message = '';
} else if (typeof xmlHttp.response === 'string') {
// IE doesn't parse JSON responses even with responseType: 'json'.
try {
message = JSON.parse(xmlHttp.response);
} catch (e) {
// Not a JSON response
message = xmlHttp.response;
}
} else {
message = xmlHttp.response;
}
callback(message);
};
xmlHttp.open('GET', url + getParamString(params), true);
xmlHttp.responseType = 'json';
xmlHttp.setRequestHeader('Accept', 'application/json');
xmlHttp.send(null);
}
export function template(str, data) {
return str.replace(/\{ *([\w_]+) *\}/g, function(str, key) {
var value = data[key];
if (value === undefined) {
value = '';
} else if (typeof value === 'function') {
value = value(data);
}
return htmlEscape(value);
});
}
export function getParamString(obj, existingUrl, uppercase) {
var params = [];
for (var i in obj) {
var key = encodeURIComponent(uppercase ? i.toUpperCase() : i);
var value = obj[i];
if (!L.Util.isArray(value)) {
params.push(key + '=' + encodeURIComponent(value));
} else {
for (var j = 0; j < value.length; j++) {
params.push(key + '=' + encodeURIComponent(value[j]));
}
}
}
return (!existingUrl || existingUrl.indexOf('?') === -1 ? '?' : '&') + params.join('&');
}

View File

@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Rowan Winsemius
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,20 @@
Copyright 2012 David Leaver
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -0,0 +1,60 @@
.marker-cluster-small {
background-color: rgba(181, 226, 140, 0.6);
}
.marker-cluster-small div {
background-color: rgba(110, 204, 57, 0.6);
}
.marker-cluster-medium {
background-color: rgba(241, 211, 87, 0.6);
}
.marker-cluster-medium div {
background-color: rgba(240, 194, 12, 0.6);
}
.marker-cluster-large {
background-color: rgba(253, 156, 115, 0.6);
}
.marker-cluster-large div {
background-color: rgba(241, 128, 23, 0.6);
}
/* IE 6-8 fallback colors */
.leaflet-oldie .marker-cluster-small {
background-color: rgb(181, 226, 140);
}
.leaflet-oldie .marker-cluster-small div {
background-color: rgb(110, 204, 57);
}
.leaflet-oldie .marker-cluster-medium {
background-color: rgb(241, 211, 87);
}
.leaflet-oldie .marker-cluster-medium div {
background-color: rgb(240, 194, 12);
}
.leaflet-oldie .marker-cluster-large {
background-color: rgb(253, 156, 115);
}
.leaflet-oldie .marker-cluster-large div {
background-color: rgb(241, 128, 23);
}
.marker-cluster {
background-clip: padding-box;
border-radius: 20px;
}
.marker-cluster div {
width: 30px;
height: 30px;
margin-left: 5px;
margin-top: 5px;
text-align: center;
border-radius: 15px;
font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif;
}
.marker-cluster span {
line-height: 30px;
}

View File

@@ -0,0 +1,14 @@
.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
-webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
-moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
-o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
transition: transform 0.3s ease-out, opacity 0.3s ease-in;
}
.leaflet-cluster-spider-leg {
/* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */
-webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in;
-moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in;
-o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in;
transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,58 @@
Copyright (c) 2014, Mapbox
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of the {organization} nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
TopoJSON
Copyright (c) 2012, Michael Bostock
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name Michael Bostock may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,184 @@
# leaflet-omnivore
![](https://farm8.staticflickr.com/7373/12376158164_e335b4e61d_b.jpg)
[Leaflet](http://leafletjs.com/) supports the [GeoJSON](http://geojson.org/) format
by default. What if you have something else? That's where omnivore comes in.
It currently supports:
* [CSV](http://en.wikipedia.org/wiki/Comma-separated_values) (via [csv2geojson](https://github.com/mapbox/csv2geojson))
* GPX (via [toGeoJSON](https://github.com/mapbox/togeojson))
* [KML](http://developers.google.com/kml/documentation/) (via [toGeoJSON](https://github.com/mapbox/togeojson))
* [WKT](http://en.wikipedia.org/wiki/Well-known_text) (via [wellknown](https://github.com/mapbox/wellknown))
* [TopoJSON](https://github.com/mbostock/topojson)
* [Encoded Polylines](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) via [polyline](https://github.com/mapbox/polyline)
Omnivore also includes an AJAX library, [corslite](https://github.com/mapbox/corslite),
so you can specify what you want to add to the map with just a URL.
## Installation
use it easily with the [Mapbox Plugins CDN](http://mapbox.com/mapbox.js/plugins/#leaflet-omnivore):
```html
<script src='//api.tiles.mapbox.com/mapbox.js/plugins/leaflet-omnivore/v0.3.1/leaflet-omnivore.min.js'></script>
```
Or download `leaflet-omnivore.min.js` from this repository.
## example
Live examples:
* [WKT](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-wkt/)
* [TopoJSON](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-topojson/)
* [Tooltips](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-kml-tooltip/)
* [KML](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-kml/)
* [GPX](https://www.mapbox.com/mapbox.js/example/v1.0.0/omnivore-gpx/)
* [Icons](https://www.mapbox.com/mapbox.js/example/v1.0.0/markers-from-csv-custom-style/)
* [CSV](https://www.mapbox.com/mapbox.js/example/v1.0.0/markers-from-csv/)
```js
var map = L.mapbox.map('map', 'mapbox.streets')
.setView([38, -102.0], 5);
omnivore.csv('a.csv').addTo(map);
omnivore.gpx('a.gpx').addTo(map);
omnivore.kml('a.kml').addTo(map);
omnivore.wkt('a.wkt').addTo(map);
omnivore.topojson('a.topojson').addTo(map);
omnivore.geojson('a.geojson').addTo(map);
omnivore.polyline('a.txt').addTo(map);
```
## API
Arguments with `?` are optional. **parser_options** consists of options
sent to the parser library, _not_ to the layer: if you want to provide options
to the layer, see the example in the Custom Layers section.
By default, the library will construct a `L.geoJson()` layer internally and
call `.addData(geojson)` on it in order to load it full of GeoJSON. If you want
to use a different kind of layer, like a `L.mapbox.featureLayer()`, you can,
by passing it as `customLayer`, as long as it supports events and `addData()`.
You can also use this API to pass custom options to a `L.geoJson()` instance.:
* `.csv(url, parser_options?, customLayer?)`: Load & parse CSV, and return layer. Options are the same as [csv2geojson](https://github.com/mapbox/csv2geojson#api): `latfield, lonfield, delimiter`
* `.csv.parse(csvString, parser_options?)`: Parse CSV, and return layer.
* `.kml(url)`: Load & parse KML, and return layer.
* `.kml.parse(kmlString | gpxDom)`: Parse KML from a string of XML or XML DOM, and return layer.
* `.gpx(url, parser_options?, customLayer?)`: Load & parse GPX, and return layer.
* `.gpx.parse(gpxString | gpxDom)`: Parse GPX from a string of XML or XML DOM, and return layer.
* `.geojson(url, parser_options?, customLayer?)`: Load GeoJSON file at URL, parse GeoJSON, and return layer.
* `.wkt(url, parser_options?, customLayer?)`: Load & parse WKT, and return layer.
* `.wkt.parse(wktString)`: Parse WKT, and return layer.
* `.topojson(url, parser_options?, customLayer?)`: Load & parse TopoJSON, and return layer.
* `.topojson.parse(topojson)`: Parse TopoJSON (given as a string or object), and return layer.
* `.polyline(url, parser_options?, customLayer?)`: Load & parse polyline, and return layer.
* `.polyline.parse(txt, options, layer)`: Parse polyline (given as a string or object), and return layer.
Valid options:
#### polyline
* `precision` will change how the polyline is interpreted. By default, the value
is 5. This is the [factor in the algorithm](https://developers.google.com/maps/documentation/utilities/polylinealgorithm),
by default 1e5, which is adjustable.
### Custom Layers
Passing custom options:
```js
var customLayer = L.geoJson(null, {
filter: function() {
// my custom filter function
return true;
}
});
var myLayer = omnivore.csv('foo', null, customLayer);
```
Adding custom styles to a GeoJSON layer:
```js
var customLayer = L.geoJson(null, {
// http://leafletjs.com/reference.html#geojson-style
style: function(feature) {
return { color: '#f00' };
}
});
// this can be any kind of omnivore layer
var runLayer = omnivore.kml('line.kml', null, customLayer)
```
Using a `L.mapbox.featureLayer`:
```js
var layer = omnivore.gpx('a.gpx', null, L.mapbox.featureLayer());
```
### Async & Events
Each function returns an `L.geoJson` object. Functions that load from URLs
are **asynchronous**, so they will **not** immediately expose accurate `.setGeoJSON()` functions.
For this reason, we fire events:
* `ready`: fired when all data is loaded into the layer
* `error`: fired if data can't be loaded or parsed
```js
var layer = omnivore.gpx('a.gpx')
.on('ready', function() {
// when this is fired, the layer
// is done being initialized
})
.on('error', function() {
// fired if the layer can't be loaded over AJAX
// or can't be parsed
})
.addTo(map);
```
`ready` does **not** fire if you don't use an asynchronous form of the function
like `.topojson.parse()`: because you don't need an event. Just run your code
after the call.
## Development
This is a [browserify](http://browserify.org/) project:
```sh
git clone git@github.com:mapbox/leaflet-omnivore.git
cd leaflet-omnivore
# to run tests
npm install
# to build leaflet-omnivore.js
npm run prepublish
```
`leaflet-omnivore.js` and `leaflet-omnivore.min.js` are **built files** generated
from `index.js` by `browserify`. If you find an issue, it either needs to be
fixed in `index.js`, or in one of the libraries leaflet-omnivore uses
to parse formats.
## FAQ
* **What if I just want one format?** Lucky for you, each format is specified
in a different module, so you can just use [TopoJSON](https://github.com/mbostock/topojson),
[csv2geojson](https://github.com/mapbox/csv2geojson), [wellknown](https://github.com/mapbox/wellknown), or
[toGeoJSON](https://github.com/mapbox/togeojson)
individually.
* **My AJAX request is failing for a cross-domain request**. Read up on the [Same Origin Restriction](http://en.wikipedia.org/wiki/Same-origin_policy).
By default, we use corslite, so cross-domain requests will try to use [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
if your server and browser supports it, but if one of them doesn't, there's no
way on the internet to support your request.
* **Why isn't JSONP supported?** [Here's why](https://gist.github.com/tmcw/6244497).

View File

@@ -0,0 +1 @@
var xhr=require('corslite'),csv2geojson=require('csv2geojson'),wellknown=require('wellknown'),polyline=require('polyline'),topojson=require('topojson'),toGeoJSON=require('togeojson');module.exports.polyline=polylineLoad;module.exports.polyline.parse=polylineParse;module.exports.geojson=geojsonLoad;module.exports.topojson=topojsonLoad;module.exports.topojson.parse=topojsonParse;module.exports.csv=csvLoad;module.exports.csv.parse=csvParse;module.exports.gpx=gpxLoad;module.exports.gpx.parse=gpxParse;module.exports.kml=kmlLoad;module.exports.kml.parse=kmlParse;module.exports.wkt=wktLoad;module.exports.wkt.parse=wktParse;function addData(l,d){if('setGeoJSON'in l){l.setGeoJSON(d)}else if('addData'in l){l.addData(d)}}function geojsonLoad(url,options,customLayer){var layer=customLayer||L.geoJson();xhr(url,function(err,response){if(err){return layer.fire('error',{error:err})}addData(layer,JSON.parse(response.responseText));layer.fire('ready')});return layer}function topojsonLoad(url,options,customLayer){var layer=customLayer||L.geoJson();xhr(url,onload);function onload(err,response){if(err){return layer.fire('error',{error:err})}topojsonParse(response.responseText,options,layer);layer.fire('ready')}return layer}function csvLoad(url,options,customLayer){var layer=customLayer||L.geoJson();xhr(url,onload);function onload(err,response){var error;if(err){return layer.fire('error',{error:err})}function avoidReady(){error=true}layer.on('error',avoidReady);csvParse(response.responseText,options,layer);layer.off('error',avoidReady);if(!error){layer.fire('ready')}}return layer}function gpxLoad(url,options,customLayer){var layer=customLayer||L.geoJson();xhr(url,onload);function onload(err,response){var error;if(err){return layer.fire('error',{error:err})}function avoidReady(){error=true}layer.on('error',avoidReady);gpxParse(response.responseXML||response.responseText,options,layer);layer.off('error',avoidReady);if(!error){layer.fire('ready')}}return layer}function kmlLoad(url,options,customLayer){var layer=customLayer||L.geoJson();xhr(url,onload);function onload(err,response){var error;if(err){return layer.fire('error',{error:err})}function avoidReady(){error=true}layer.on('error',avoidReady);kmlParse(response.responseXML||response.responseText,options,layer);layer.off('error',avoidReady);if(!error){layer.fire('ready')}}return layer}function wktLoad(url,options,customLayer){var layer=customLayer||L.geoJson();xhr(url,onload);function onload(err,response){if(err){return layer.fire('error',{error:err})}wktParse(response.responseText,options,layer);layer.fire('ready')}return layer}function polylineLoad(url,options,customLayer){var layer=customLayer||L.geoJson();xhr(url,onload);function onload(err,response){if(err){return layer.fire('error',{error:err})}polylineParse(response.responseText,options,layer);layer.fire('ready')}return layer}function topojsonParse(data,options,layer){var o=typeof data==='string'?JSON.parse(data):data;layer=layer||L.geoJson();for(var i in o.objects){var ft=topojson.feature(o,o.objects[i]);if(ft.features){addData(layer,ft.features)}else{addData(layer,ft)}}return layer}function csvParse(csv,options,layer){layer=layer||L.geoJson();options=options||{};csv2geojson.csv2geojson(csv,options,onparse);function onparse(err,geojson){if(err){return layer.fire('error',{error:err})}addData(layer,geojson)}return layer}function gpxParse(gpx,options,layer){var xml=parseXML(gpx);if(!xml){return layer.fire('error',{error:'Could not parse GPX'})}layer=layer||L.geoJson();var geojson=toGeoJSON.gpx(xml);addData(layer,geojson);return layer}function kmlParse(gpx,options,layer){var xml=parseXML(gpx);if(!xml){return layer.fire('error',{error:'Could not parse KML'})}layer=layer||L.geoJson();var geojson=toGeoJSON.kml(xml);addData(layer,geojson);return layer}function polylineParse(txt,options,layer){layer=layer||L.geoJson();options=options||{};var coords=polyline.decode(txt,options.precision);var geojson={type:'LineString',coordinates:[]};for(var i=0;i<coords.length;i+=1){geojson.coordinates[i]=[coords[i][1],coords[i][0]]}addData(layer,geojson);return layer}function wktParse(wkt,options,layer){layer=layer||L.geoJson();var geojson=wellknown(wkt);addData(layer,geojson);return layer}function parseXML(str){if(typeof str==='string'){return(new DOMParser()).parseFromString(str,'text/xml')}else{return str}}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,9 @@
Copyright (c) 2013 Leaflet Providers contributors
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
_THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE._

View File

@@ -0,0 +1,136 @@
# leaflet-shades
Leaflet plugin for creating gray overlay in unselected areas.
This plugin adds onto Leaflet.Editable which makes geometries editable in Leaflet (https://github.com/Leaflet/Leaflet.Editable)
Leaflet shades specifically expands on the Rectangle Editor of Leaflet.Editable.
Originally, Leaflet.Editable's geometries have a blue overlay within the geometry.
Using Leaflet shades, the area inside the geometry now has a transparent overlay while the unselected regions have a gray overlay. This is so that the selected region can be seen while the unselected regions are slightly hidden.
# Requirements
Leaflet, Leaflet.Editable, and Leaflet.Path.Drag are all embedded in the Leaflet Shades plugin. Leaflet is required before adding Leaflet Shades.
Leaflet Shades supports Leaflet v1.2.0, Leaflet.Editable v.1.1.0, and Leaflet.Path.Drag 0.0.6.
Leaflet.Editable syntax is also required to start drawing the rectangle or enable editing on an already existing rectangle as seen in the "Basic Usage" instructions step 4.
# Basic Usage:
<b> Step 1: </b> Clone the Leaflet Shades repository by doing:
```
git clone git@github.com:mkong0216/leaflet-shades.git
```
<b> Step 2: </b> In HTML, import the required Leaflet Javascript and CSS files along with the Javascript and CSS files for the leaflet-shades plugin.
```html
<!-- Load Leaflet and Leaflet-Shades stylesheets -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css" />
<link rel="stylesheet" href="./src/css/leaflet-shades.css" />
<!-- Load Javascript files for Leaflet and Leaflet-Shades -->
<script src="https://unpkg.com/leaflet@1.2.0/dist/leaflet.js"></script>
<script src="./dist/leaflet-shades.js"></script>
```
<b> Step 3: </b> In Javascript, initialize your Leaflet Map and enable editable in your initialization
```javascript
var map = L.map('map', {editable: true});
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
map.setView([0,0], 5);
```
<b> Step 4: </b> In Javascript, start drawing your rectangle using Leaflet.Editable's `startRectangle()` or allow an already existing rectangle to be edited by using `enableEdit()`
```javascript
// Start drawing rectangle
map.editTools.startRectangle();
// Enable edit on already existing rectangle
const rect = L.rectangle([[54.559322, -5.767822], [56.1210604, -3.021240]]).addTo(map);
rect.enableEdit();
```
<b> Step 5a: </b> In Javascript, create your shades and add it onto your map
```javascript
var shades = new L.LeafletShades();
// or you can do
// var shades = L.leafletShades();
shades.addTo(map);
```
<b> Step 5b: </b> If you want to add shades to an already existing rectangle on the map, pass the bounds of the rectangle to the Leaflet Shades constructor as an object before adding it to the map
```javascript
// rect was previously created in step 4
var shades = new L.LeafletShades({bounds: rect.getBounds()});
shades.addTo(map);
```
Now you're done! Go to: https://mkong0216.github.io/leaflet-shades/examples to see the finished product. Alternatively, click <a href='https://mkong0216.github.io/leaflet-shades/examples/bounds'> here </a> to see how Leaflet Shades works with an already defined rectangle using step 5b.
<b> Sidenote: </b> In Javascript, you can remove your shades from the map by doing:
```javascript
map.removeLayer(shades);
```
# Leaflet Shades as Module
You can also install Leaflet Shades as a module by doing: <br/>
```
npm install leaflet-shades
```
And then import it into your module system. For example, with Browserify:
```javascript
// Require Leaflet first
var L = require('leaflet');
// You can store a reference to the leaflet shades constructor in require
var shades = require('leaflet-shades');
// Now you can do steps 3 to 5 from "Basic Usage" instructions above
```
# API Documentation:
Leaflet-Shades only has one public method which is the `setDimensions(element, dimensions)` method.
This method takes an element and an object containing the desired dimensions for this element.
For example, if you wanted to manually set the dimensions for the left side of the selected region you can do this:
```javascript
// Defining the width and height of the shade along with the top and left position of the shade
var dimensions = {
width: 500,
height: 500,
top: 10,
left: 10
}
// Element passed into this method can be either
// shades._leftShade, shades._rightShade, shades._topShade, or shades._bottomShade
shades.setDimensions(shades._leftShade, dimensions);
```
This will change the left shade to become 500px by 500px at position 10px from the top and 10px to the left.
# Events
Leaflet Shades listens to events fired by Leaflet.Editable (http://leaflet.github.io/Leaflet.Editable/doc/api.html) and Leaflet.
When the Leaflet.Editable geometry is resized or dragged, firing the events `editable:vertex:dragend` and `editable:dragend`, respectively, Leaflet Shades updates the shades' dimensions. When the Leaflet map is zoomed in/out or panned, firing the event `moveend`, Leaflet Shades updates the shades' dimensions as well.
Leaflet Shades provides the event:
`shades:bounds-changed` which fires whenever shades' dimensions are updated and allow users to access the new values for the bounds of the selected region through `event.bounds`
To use the `shades:bounds-changed` event to access the values of the region's bounds, you can do:
```javascript
shades.on('shades:bounds-changed', function(event) {
var bounds = event.bounds
});
```
All events, including events from Leaflet and Leaflet Editable that Leaflet Shades listens to, can be seen in this <a href='https://mkong0216.github.io/leaflet-shades/examples/events'> demo </a>

Some files were not shown because too many files have changed in this diff Show More