├── .gitignore
├── config.json
├── data
└── statquart.geojson
├── db
├── db_init.js
└── db_update.js
├── docs
├── docs.css
├── docs.js
├── documentation.html
├── index.html
├── launch.html
├── leaflet-plugins.js
├── libs.js
├── map.html
└── script.js
├── index.js
├── package.json
└── readme.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | data/baumkataster.json
3 | data/veloweg.json
4 | *.db
5 | *.db-journal
--------------------------------------------------------------------------------
/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "host": "https://where2demo.herokuapp.com",
3 | "docs": {
4 | "description": "Where2 turns static GeoJSON files into queryable APIs. This Demo allows you to query selected GeoJSON-files from Open Data Zürich . Look here to find out more on how to set up your own Where2-API with your datasets.",
5 | "title": "Where2 Demo",
6 | "map_center": [47.3695, 8.5426],
7 | "map_zoom": 13
8 | },
9 | "data": [{
10 | "name": "KunstImStadtraum",
11 | "url": "https://data.stadt-zuerich.ch/dataset/kunst_im_stadtraum/resource/3e42de5e-b098-4b61-a965-b32f3439b4b7/download/kis.json",
12 | "schedule": "3 0 1 * *"
13 | },{
14 | "name": "baumkataster",
15 | "url": "https://data.stadt-zuerich.ch/dataset/baumkataster/resource/c7e85cfe-7899-4aa4-9a59-3b0c7b6a4937/download/baumkataster.json",
16 | "schedule": "3 10 1 * *",
17 | "schema": {
18 | "Baumname_D": "TEXT",
19 | "Baumname_LAT": "TEXT",
20 | "Strasse": "TEXT",
21 | "Baumnummer": "TEXT",
22 | "Baumart_LAT": "TEXT",
23 | "Pflanzjahr": "INT",
24 | "Baumgattung": "TEXT"
25 | }
26 | }, {
27 | "name": "velo",
28 | "url": "https://data.stadt-zuerich.ch/dataset/veloweg/resource/5f6c2689-824c-4c11-972f-bb5736b342be/download/veloweg.json",
29 | "schedule": "3 20 1 * *"
30 | }, {
31 | "name": "statquart",
32 | "path": "statquart.geojson"
33 | }],
34 | "server_port": "33333",
35 | "data_dir": "data/",
36 | "db_name": "db.db"
37 | }
38 |
--------------------------------------------------------------------------------
/db/db_init.js:
--------------------------------------------------------------------------------
1 | var sqlite = require('spatialite')
2 | var fs = require("fs")
3 |
4 | var config = require('./../config.json')
5 |
6 | fs.unlink(config.db_name, function(){
7 | var db = new sqlite.Database(config.db_name)
8 |
9 | db.spatialite(function(err) {
10 | db.run("SELECT InitSpatialMetaData()", function() {
11 | process.send("done")
12 | })
13 | })
14 | })
--------------------------------------------------------------------------------
/db/db_update.js:
--------------------------------------------------------------------------------
1 | var sqlite = require('spatialite'),
2 | request = require('request'),
3 | fs = require('fs')
4 |
5 | var opt = JSON.parse(process.argv[2])
6 |
7 | var db = new sqlite.Database(opt.db_name)
8 |
9 | if (opt.dataset.url) {
10 | request(opt.dataset.url, (err, resp, data) => {
11 | if (err) throw err
12 | initTable(JSON.parse(data))
13 | })
14 | } else {
15 | fs.readFile(opt.data_dir + opt.dataset.path, opt.dataset.encoding || 'utf8', (err, data) => {
16 | if (err) throw err
17 | initTable(JSON.parse(data))
18 | })
19 | }
20 |
21 | function initTable(data) {
22 | var schema = {}
23 | if (opt.dataset.schema) {
24 | Object.keys(opt.dataset.schema).forEach(key => {
25 | schema[key] = {type: opt.dataset.schema[key], example: data.features[0].properties[key]}
26 | })
27 | } else {
28 | Object.keys(data.features[0].properties).forEach(key => {
29 | switch (typeof data.features[0].properties[key]) {
30 | case "string":
31 | schema[key] = {type: "TEXT", example: data.features[0].properties[key]}
32 | break
33 | case "number":
34 | schema[key] = {type: "FLOAT", example: data.features[0].properties[key]}
35 | break
36 | case "boolean":
37 | schema[key] = {type: "BOOL", example: data.features[0].properties[key]}
38 | break
39 | }
40 | })
41 | }
42 |
43 | db.serialize(err => {
44 | db.run("begin transaction")
45 | if (err) throw err
46 | db.spatialite(err => {
47 | if (err) throw err
48 | db.run("SELECT " + (opt.update ? "DisableSpatialIndex('" + opt.dataset.name + "', '_where_geom')" : "''"), err => {
49 | if (err) throw err
50 | db.run("DROP TABLE IF EXISTS idx_" + opt.dataset.name + "__where_geom", err => {
51 | if (err) throw err
52 | db.run("SELECT " + (opt.update ? "DiscardGeometryColumn('" + opt.dataset.name + "', '_where_geom')" : "''"), err => {
53 | if (err) throw err
54 | db.run("DROP TABLE IF EXISTS " + opt.dataset.name, err => {
55 | if (err) throw err
56 | db.run("CREATE TABLE " + opt.dataset.name + "('ROWID' INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " + Object.keys(schema).map(k => "'" + k + "' " + schema[k].type).join(", ") + ", '_where_wkt' TEXT)", err => {
57 | if (err) throw err
58 | db.run("SELECT AddGeometryColumn('" + opt.dataset.name + "', '_where_geom', 4326, 'GEOMETRY', 'XY')", err => {
59 | if (err) throw err
60 | var prep = db.prepare("INSERT INTO " + opt.dataset.name + " ('" + Object.keys(schema).join("', '") + "', _where_wkt) VALUES (" + Object.keys(schema).map(() => "?").join(", ") + ",?)")
61 | data.features.forEach(feature => {
62 | var values = Object.keys(schema).map(k => feature.properties[k])
63 | values.push(geoJsonToWkt(feature.geometry))
64 | prep.bind(values)
65 | prep.run(err => {
66 | if (err) throw err
67 | })
68 | })
69 | prep.finalize((err) => {
70 | if (err) throw err
71 | })
72 | })
73 | })
74 | })
75 | })
76 | })
77 | })
78 | })
79 | db.run("commit", err => {
80 | if (err) throw err
81 | db.spatialite(err => {
82 | if (err) throw err
83 | db.run("UPDATE " + opt.dataset.name + " SET '_where_geom' = GeomFromText(" + opt.dataset.name + "._where_wkt, 4326)", err => {
84 | if (err) throw err
85 | db.run("SELECT CreateSpatialIndex('" + opt.dataset.name + "', '_where_geom')", err => {
86 | if (err) throw err
87 | process.send({
88 | status: "success",
89 | dataset: opt.dataset.name,
90 | schema: schema
91 | })
92 | })
93 | })
94 | })
95 | })
96 | })
97 | }
98 |
99 | function geoJsonToWkt(geojson) {
100 | if (geojson.type == "Point")
101 | return "POINT(" + geojson.coordinates[0] + " " + geojson.coordinates[1] + ")"
102 | if (geojson.type == "LineString")
103 | return "LINESTRING(" + geojson.coordinates.map(d => d[0] + " " + d[1]).join(", ") + ")"
104 | if (geojson.type == "Polygon")
105 | return "POLYGON((" + geojson.coordinates.map(d => d.map(e => e[0] + " " + e[1]).join(", ")).join("), (") + "))"
106 | return "NULL"
107 | }
--------------------------------------------------------------------------------
/docs/docs.css:
--------------------------------------------------------------------------------
1 | /*leaflet*/
2 | .leaflet-image-layer,.leaflet-layer,.leaflet-map-pane,.leaflet-marker-icon,.leaflet-marker-pane,.leaflet-marker-shadow,.leaflet-overlay-pane,.leaflet-overlay-pane svg,.leaflet-popup-pane,.leaflet-shadow-pane,.leaflet-tile,.leaflet-tile-container,.leaflet-tile-pane,.leaflet-zoom-box{position:absolute;left:0;top:0}.leaflet-marker-icon,.leaflet-marker-shadow,.leaflet-tile{-webkit-user-select:none;-moz-user-select:none;user-select:none;-webkit-user-drag:none}.leaflet-marker-icon,.leaflet-marker-shadow{display:block}.leaflet-container img{max-width:none!important}.leaflet-container img.leaflet-image-layer{max-width:15000px!important}.leaflet-tile{filter:inherit;visibility:hidden}.leaflet-tile-loaded{visibility:inherit}.leaflet-zoom-box{width:0;height:0}.leaflet-overlay-pane svg{-moz-user-select:none}.leaflet-tile-pane{z-index:2}.leaflet-objects-pane{z-index:3}.leaflet-overlay-pane{z-index:4}.leaflet-shadow-pane{z-index:5}.leaflet-marker-pane{z-index:6}.leaflet-popup-pane{z-index:7}.leaflet-vml-shape{width:1px;height:1px}.lvml{behavior:url(#default#VML);display:inline-block;position:absolute}.leaflet-control{position:relative;z-index:7;pointer-events:auto;float:left;clear:both}.leaflet-bottom,.leaflet-top{position:absolute;z-index:1000;pointer-events:none}.leaflet-top{top:0}.leaflet-right{right:0}.leaflet-bottom{bottom:0}.leaflet-left{left:0}.leaflet-right .leaflet-control{float:right;margin-right:10px}.leaflet-top .leaflet-control{margin-top:10px}.leaflet-bottom .leaflet-control{margin-bottom:10px}.leaflet-left .leaflet-control{margin-left:10px}.leaflet-fade-anim .leaflet-popup,.leaflet-fade-anim .leaflet-tile{opacity:0;-webkit-transition:opacity .2s linear;-moz-transition:opacity .2s linear;-o-transition:opacity .2s linear;transition:opacity .2s linear}.leaflet-fade-anim .leaflet-map-pane .leaflet-popup,.leaflet-fade-anim .leaflet-tile-loaded{opacity:1}.leaflet-zoom-anim .leaflet-zoom-animated{-webkit-transition:-webkit-transform .25s cubic-bezier(0,0,.25,1);-moz-transition:-moz-transform .25s cubic-bezier(0,0,.25,1);-o-transition:-o-transform .25s cubic-bezier(0,0,.25,1);transition:transform .25s cubic-bezier(0,0,.25,1)}.leaflet-pan-anim .leaflet-tile,.leaflet-touching .leaflet-zoom-animated,.leaflet-zoom-anim .leaflet-tile{-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.leaflet-zoom-anim .leaflet-zoom-hide{visibility:hidden}.leaflet-clickable{cursor:pointer}.leaflet-container{overflow:hidden;-ms-touch-action:none;touch-action:none;cursor:-webkit-grab;cursor:-moz-grab;background:#ddd;outline:0;font:12px/1.5 "Helvetica Neue",Arial,Helvetica,sans-serif}.leaflet-control,.leaflet-popup-pane{cursor:auto}.leaflet-dragging .leaflet-clickable,.leaflet-dragging .leaflet-container{cursor:move;cursor:-webkit-grabbing;cursor:-moz-grabbing}.leaflet-container a{color:#0078A8}.leaflet-container a.leaflet-active{outline:orange solid 2px}.leaflet-zoom-box{border:2px dotted #38f;background:rgba(255,255,255,.5)}.leaflet-bar{box-shadow:0 1px 5px rgba(0,0,0,.65);border-radius:4px}.leaflet-bar a,.leaflet-bar a:hover{background-color:#fff;border-bottom:1px solid #ccc;width:26px;height:26px;line-height:26px;display:block;text-align:center;text-decoration:none;color:#000}.leaflet-bar a,.leaflet-control-layers-toggle{background-position:50% 50%;background-repeat:no-repeat;display:block}.leaflet-bar a:hover{background-color:#f4f4f4}.leaflet-bar a:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.leaflet-bar a:last-child{border-bottom-left-radius:4px;border-bottom-right-radius:4px;border-bottom:none}.leaflet-bar a.leaflet-disabled{cursor:default;background-color:#f4f4f4;color:#bbb}.leaflet-touch .leaflet-bar a{width:30px;height:30px;line-height:30px}.leaflet-control-zoom-in,.leaflet-control-zoom-out{font:700 18px 'Lucida Console',Monaco,monospace;text-indent:1px}.leaflet-control-zoom-out{font-size:20px}.leaflet-touch .leaflet-control-zoom-in{font-size:22px}.leaflet-touch .leaflet-control-zoom-out{font-size:24px}.leaflet-control-layers{box-shadow:0 1px 5px rgba(0,0,0,.4);background:#fff;border-radius:5px}.leaflet-control-layers-toggle{background-image:url('data:image/png;base64,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');width:36px;height:36px}.leaflet-retina .leaflet-control-layers-toggle{background-image:url('data:image/png;base64,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');background-size:26px 26px}.leaflet-touch .leaflet-control-layers-toggle{width:44px;height:44px}.leaflet-control-layers .leaflet-control-layers-list,.leaflet-control-layers-expanded .leaflet-control-layers-toggle{display:none}.leaflet-control-layers-expanded .leaflet-control-layers-list{display:block;position:relative}.leaflet-control-layers-expanded{padding:6px 10px 6px 6px;color:#333;background:#fff}.leaflet-control-layers-selector{margin-top:2px;position:relative;top:1px}.leaflet-control-layers label{display:block}.leaflet-control-layers-separator{height:0;border-top:1px solid #ddd;margin:5px -10px 5px -6px}.leaflet-container .leaflet-control-attribution{background:#fff;background:rgba(255,255,255,.7);margin:0}.leaflet-control-attribution,.leaflet-control-scale-line{padding:0 5px;color:#333}.leaflet-control-attribution a{text-decoration:none}.leaflet-control-attribution a:hover{text-decoration:underline}.leaflet-container .leaflet-control-attribution,.leaflet-container .leaflet-control-scale{font-size:11px}.leaflet-left .leaflet-control-scale{margin-left:5px}.leaflet-bottom .leaflet-control-scale{margin-bottom:5px}.leaflet-control-scale-line{border:2px solid #777;border-top:none;line-height:1.1;padding:2px 5px 1px;font-size:11px;white-space:nowrap;overflow:hidden;-moz-box-sizing:content-box;box-sizing:content-box;background:#fff;background:rgba(255,255,255,.5)}.leaflet-control-scale-line:not(:first-child){border-top:2px solid #777;border-bottom:none;margin-top:-2px}.leaflet-control-scale-line:not(:first-child):not(:last-child){border-bottom:2px solid #777}.leaflet-touch .leaflet-bar,.leaflet-touch .leaflet-control-attribution,.leaflet-touch .leaflet-control-layers{box-shadow:none}.leaflet-touch .leaflet-bar,.leaflet-touch .leaflet-control-layers{border:2px solid rgba(0,0,0,.2);background-clip:padding-box}.leaflet-popup{position:absolute;text-align:center}.leaflet-popup-content-wrapper{padding:1px;text-align:left;border-radius:12px}.leaflet-popup-content{margin:13px 19px;line-height:1.4}.leaflet-popup-content p{margin:18px 0}.leaflet-popup-tip-container{margin:0 auto;width:40px;height:20px;position:relative;overflow:hidden}.leaflet-popup-tip{width:17px;height:17px;padding:1px;margin:-10px auto 0;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-ms-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}.leaflet-popup-content-wrapper,.leaflet-popup-tip{background:#fff;box-shadow:0 3px 14px rgba(0,0,0,.4)}.leaflet-container a.leaflet-popup-close-button{position:absolute;top:0;right:0;padding:4px 4px 0 0;text-align:center;width:18px;height:14px;font:16px/14px Tahoma,Verdana,sans-serif;color:#c3c3c3;text-decoration:none;font-weight:700;background:0 0}.leaflet-container a.leaflet-popup-close-button:hover{color:#999}.leaflet-popup-scrolled{overflow:auto;border-bottom:1px solid #ddd;border-top:1px solid #ddd}.leaflet-oldie .leaflet-popup-content-wrapper{zoom:1}.leaflet-oldie .leaflet-popup-tip{width:24px;margin:0 auto;-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";filter:progid:DXImageTransform.Microsoft.Matrix(M11=.70710678, M12=.70710678, M21=-.70710678, M22=.70710678)}.leaflet-oldie .leaflet-popup-tip-container{margin-top:-1px}.leaflet-oldie .leaflet-control-layers,.leaflet-oldie .leaflet-control-zoom,.leaflet-oldie .leaflet-popup-content-wrapper,.leaflet-oldie .leaflet-popup-tip{border:1px solid #999}.leaflet-div-icon{background:#fff;border:1px solid #666}
3 | /*leaflet draw*/
4 | .leaflet-draw-section{position:relative}.leaflet-draw-toolbar{margin-top:12px}.leaflet-draw-actions-bottom,.leaflet-draw-toolbar-top{margin-top:0}.leaflet-draw-toolbar-notop a:first-child{border-top-right-radius:0}.leaflet-draw-toolbar-nobottom a:last-child{border-bottom-right-radius:0}.leaflet-draw-toolbar a{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQ4AAAAeCAYAAADdEPCKAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA8JJREFUeNrsms912kAQxgWPu0kFkApiVxA4wDVQQVAFQAU2FYArMKnAnNEBpYIoHcgVWK7AmXFGyUYWSIIdIZTv956eFu0+Dfvv0+zsOg4AAAAAAAAAAAAAAAAAAAAAAAAAAKgCDTQBqDrD4bBNt9l2u71TeDe/8zbxeKFhqwie503oFgwGg8Dye1PrS3YK1bdlsQNe4zQ1ekOpg6d0baRjw5pPli7dRnS15VHEddeut0xSttuVR6HYjZRtXiefk01f8nacT+kOPXMV/sIfoZBxVoYwXBt9GxPSBA5FNB64zyndty0eplCIkJzH45DOfabrA99tCwe9P25Ik7WmgJhCeAglkZzRbbkne042V0p15sH8aIiGY4jHmOwGCoLB9nop2dy/c0lzW/AYcOk/rJW8jExRsehJLFNEg4W5L/dYLLndWTiiE20Wqm8e76NhqfN35hfD5mTaIxrqAnIu4cgQDTXxkH78IaLBA/VesqYykLl9b2x6HmRzJ6IRyhXDArWQceXIhLpmD+SSvUiawD2jTsm6zGUO8Vh3pQ3CU0VDi5ZF0eCK9i0PrCzRcORLNKlDvEaWJ8scRZdU1vayxVye9GPvgu0YgjISobbFm2iQrY8ZH6MeldmUENtQ9TYMz8olQVineCLxWJ9S/k0JsY2jvI2ThKMiolE3RgXL2vQ6PhleVGCmqS/in12FOm8yRMNNeCNW1/pn6ufNAdF4m0scA9GIbdh6UbOKoiEUEY2gJsLRVip7TKzjXZq4UjD3kiEageHe1wJz+ZEmGuJ1jqpch2ZFRcMp6BJHNRlTnTPafjLSO3blxZ3f7SmjwcwUDQmEjjRFsgL8IxoiKpOq/+lmRUUjdqvyvvt7TQbRzzOK5TrhzdzK1T5SzE/Byu7JBWGKxkXQqqho8No6JJv3Tr5tpLp4HBsnX3D03TrZQntH1N6LA+290Oxv+Q/s4dz9R4LBy5aLDOo3c4oGb00+lyUaBqucolCLGIfsksxzFJ0rnV/h9k57b+jYDcSafMmTLztOtcDzvFGOvE6V69AqMKgbIiBliUb8FczyOiJHL+p+DvFYyS5G6QfApL3H4lmaJ1bHSn3u09WT8xxpy83P8rHya3JS2Jex/EACwXV7SeRfGfGNb3VZqrzGg6vkicRBuq/O761AX0TiSdKB1v/ROBFaUDx4KVL6kXPZfuXI/qM8sn5i1GDs/D052jsw2cZK9jPPNVhelvgkGK58FGYHPoR8zsO/9PoCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKggvwQYACihxUu99ixmAAAAAElFTkSuQmCC');background-repeat:no-repeat}.leaflet-retina .leaflet-draw-toolbar a{background-image:url('data:image/png;base64,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');background-size:270px 30px}.leaflet-draw a{display:block;text-align:center;text-decoration:none}.leaflet-draw-actions{display:none;list-style:none;margin:0;padding:0;position:absolute;left:26px;top:0;white-space:nowrap}.leaflet-touch .leaflet-draw-actions{left:32px}.leaflet-right .leaflet-draw-actions{right:26px;left:auto}.leaflet-touch .leaflet-right .leaflet-draw-actions{right:32px;left:auto}.leaflet-draw-actions li{display:inline-block}.leaflet-draw-actions li:first-child a{border-left:none}.leaflet-draw-actions li:last-child a{-webkit-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.leaflet-right .leaflet-draw-actions li:last-child a{-webkit-border-radius:0;border-radius:0}.leaflet-right .leaflet-draw-actions li:first-child a{-webkit-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.leaflet-draw-actions a{background-color:#919187;border-left:1px solid #AAA;color:#FFF;font:11px/19px "Helvetica Neue",Arial,Helvetica,sans-serif;line-height:28px;text-decoration:none;padding-left:10px;padding-right:10px;height:28px}.leaflet-touch .leaflet-draw-actions a{font-size:12px;line-height:30px;height:30px}.leaflet-draw-actions-top{margin-top:1px}.leaflet-draw-actions-bottom a,.leaflet-draw-actions-top a{height:27px;line-height:27px}.leaflet-draw-actions a:hover{background-color:#A0A098}.leaflet-draw-actions-top.leaflet-draw-actions-bottom a{height:26px;line-height:26px}.leaflet-draw-toolbar .leaflet-draw-draw-polyline{background-position:-2px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polyline{background-position:0 -1px}.leaflet-draw-toolbar .leaflet-draw-draw-polygon{background-position:-31px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-polygon{background-position:-29px -1px}.leaflet-draw-toolbar .leaflet-draw-draw-rectangle{background-position:-62px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-rectangle{background-position:-60px -1px}.leaflet-draw-toolbar .leaflet-draw-draw-circle{background-position:-92px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-circle{background-position:-90px -1px}.leaflet-draw-toolbar .leaflet-draw-draw-marker{background-position:-122px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-draw-marker{background-position:-120px -1px}.leaflet-draw-toolbar .leaflet-draw-edit-edit{background-position:-152px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit{background-position:-150px -1px}.leaflet-draw-toolbar .leaflet-draw-edit-remove{background-position:-182px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove{background-position:-180px -1px}.leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled{background-position:-212px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-edit.leaflet-disabled{background-position:-210px -1px}.leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled{background-position:-242px -2px}.leaflet-touch .leaflet-draw-toolbar .leaflet-draw-edit-remove.leaflet-disabled{background-position:-240px -2px}.leaflet-mouse-marker{background-color:#fff;cursor:crosshair}.leaflet-draw-tooltip{background:#363636;background:rgba(0,0,0,.5);border:1px solid transparent;-webkit-border-radius:4px;border-radius:4px;color:#fff;font:12px/18px "Helvetica Neue",Arial,Helvetica,sans-serif;margin-left:20px;margin-top:-21px;padding:4px 8px;position:absolute;visibility:hidden;white-space:nowrap;z-index:6}.leaflet-draw-tooltip:before{border-right:6px solid #000;border-right-color:rgba(0,0,0,.5);border-top:6px solid transparent;border-bottom:6px solid transparent;content:"";position:absolute;top:7px;left:-7px}.leaflet-error-draw-tooltip{background-color:#F2DEDE;border:1px solid #E6B6BD;color:#B94A48}.leaflet-error-draw-tooltip:before{border-right-color:#E6B6BD}.leaflet-draw-tooltip-single{margin-top:-12px}.leaflet-draw-tooltip-subtext{color:#f8d5e4}.leaflet-draw-guide-dash{font-size:1%;opacity:.6;position:absolute;width:5px;height:5px}.leaflet-edit-marker-selected{background:rgba(254,87,161,.1);border:4px dashed rgba(254,87,161,.6);-webkit-border-radius:4px;border-radius:4px;box-sizing:content-box}.leaflet-edit-move{cursor:move}.leaflet-edit-resize{cursor:pointer}.leaflet-oldie .leaflet-draw-toolbar{border:1px solid #999}
5 | /*leaflet fullscreen*/
6 | .leaflet-container.leaflet-fullscreen-on,.leaflet-pseudo-fullscreen{width:100%!important;height:100%!important}.leaflet-control-fullscreen a{background:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABoAAAA0CAYAAACU7CiIAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAACoSURBVFiF7ZZhDoAgCIWxdbF3suxkHM3+1FaOmNqyIr6fiHuJTyKklKgHQxcVF7rCKAUBiA5h5tCSR/T0iTakL9PWz05IZNEM3YSCt6BvCgFI2ps4Q9v3k9Ldgdrr8nrX9LYc7wwu5EIu9KCQT6rq+r8mVbV0ewBEIpqy8MzMsWR/8f+oxmES9u7olZPqLKQeYtqkWuy61V2xND/H3h35pNqMPTPYE1oAnZZStKN8jj8AAAAASUVORK5CYII=') no-repeat #fff;background-size:26px 52px}.leaflet-touch .leaflet-control-fullscreen a{background-position:2px 2px}.leaflet-fullscreen-on .leaflet-control-fullscreen a{background-position:0 -26px}.leaflet-touch.leaflet-fullscreen-on .leaflet-control-fullscreen a{background-position:2px -24px}.leaflet-container:-webkit-full-screen{width:100%!important;height:100%!important}.leaflet-pseudo-fullscreen{position:fixed!important;top:0!important;left:0!important;z-index:99999}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:192dpi){.leaflet-control-fullscreen a{background-image:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAABoCAYAAAC+NNNnAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAbrwAAG68BXhqRHAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAEhSURBVHic7dpBDoIwFADRj/FiPRlwsh4NN5CoiVKg1Ukzb43ApKK1dliWJXpy+/cN1GYQnUF0BtEZRHcvPTCldGhKkXMefnm+TXcjZBBd8TP0rvQ9ffb1R5+xTXcjZBCdQXQG0Q2u+sAZRGcQnUF0p9cUrv4eanW97kbIIDqD6AyiO70ut7du1mrdbU93I2QQnWsKdAbRGURnEJ1BdAbRGURnEJ1BdAbRueeUziA695zSGURnEN3pT7lvUkpTRIw7h80556n2tauPUGFMRMS4HltV9f+HWs3RSnX3DBlEZxCdQXQt9pzOUfbFuh179Xovqo/QOp35eKNPmkx9mszl1hudWpx7T3fPkEF0BtG555TOIDr3nNIZRGcQnUF0BtE9AF5WX48h7QeZAAAAAElFTkSuQmCC')}}
7 | /*custom*/
8 | body{
9 | font-family: "Source Code Pro";
10 | font-size: 18px;
11 | color: #000;
12 | margin: 0px;
13 | }
14 | h1{
15 | font-size: 18px;
16 | font-weight: 700;
17 | margin: 0px;
18 | }
19 | a{
20 | color: #2661FF;
21 | }
22 | pre{
23 | background: #f6f6f6;
24 | padding: 4px;
25 | color: #555;
26 | border-radius: 4px;
27 | tab-size: 2;
28 | }
29 | code{
30 | color: #999;
31 | }
32 | header, footer, #content{
33 | position: relative;
34 | width: 720px;
35 | left: 50%;
36 | margin-left: -460px;
37 | padding: 4px 100px;
38 | }
39 | header{
40 | font-weight: 700;
41 | padding: 35px 100px 0px;
42 | height: 40px;
43 | background: #2661FF;
44 | color: #fff;
45 | }
46 | footer{
47 | bottom: 0px;
48 | background: #2661FF;
49 | color: #fff;
50 | }
51 | #content{
52 | padding-top: 14px;
53 | }
54 | .selection .selected{
55 | font-weight: 700;
56 | }
57 | .blue{
58 | color: #2661FF;
59 | cursor: pointer;
60 | }
61 | table, th, td {
62 | border: 1px solid black;
63 | border-collapse: collapse;
64 | padding: 0px 8px;
65 | }
66 | .cb{
67 | margin-left: -25px
68 | }
69 | #container-query div{
70 | display: inline-table;
71 | }
72 | #container-properties{
73 | display: inline-table;
74 | }
75 | #container-query div input{
76 | width: 150px
77 | }
78 | select{
79 | margin-right: 4px;
80 | }
81 | label {
82 | white-space: nowrap;
83 | }
84 | #map1, #map2{
85 | margin-top: 4px;
86 | width: 100%;
87 | height: 400px;
88 | }
89 | input.in-spatial, #request, #query-builder, #documentation{
90 | display: none;
91 | }
92 | #req_URL, #map_URL{
93 | word-wrap: break-word;
94 | }
95 | #res_body{
96 | overflow: auto;
97 | max-height: 400px;
98 | white-space: pre;
99 | }
100 |
--------------------------------------------------------------------------------
/docs/docs.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs")
2 |
3 | module.exports.docs = function(config, files, url) {
4 | return docs(config, files, url)
5 | }
6 |
7 | module.exports.launch = function() {
8 | return launch ? launch : ""
9 | }
10 |
11 | module.exports.map = function(q, url) {
12 | return map(q, url)
13 | }
14 |
15 | var html = "",
16 | documentation = "",
17 | css = "",
18 | libs = "",
19 | script = "",
20 | mapHtml = ""
21 |
22 | fs.readFile("./docs/index.html", 'utf8', (err, f) => {
23 | if (err) throw err
24 | html = f
25 | })
26 |
27 | fs.readFile("./docs/launch.html", 'utf8', (err, f) => {
28 | if (err) throw err
29 | launch = f
30 | })
31 |
32 | fs.readFile("./docs/documentation.html", 'utf8', (err, f) => {
33 | if (err) throw err
34 | documentation = f
35 | })
36 |
37 | fs.readFile("./docs/docs.css", 'utf8', (err, f) => {
38 | if (err) throw err
39 | css = f
40 | })
41 |
42 | fs.readFile("./docs/libs.js", 'utf8', (err, f) => {
43 | if (err) throw err
44 | libs = f
45 | })
46 |
47 | fs.readFile("./docs/script.js", 'utf8', (err, f) => {
48 | if (err) throw err
49 | script = f
50 | })
51 |
52 | fs.readFile("./docs/map.html", 'utf8', (err, f) => {
53 | if (err) throw err
54 | mapHtml = f
55 | })
56 |
57 | function docs(s, snippets, url) {
58 | var availableDatasets = Object.keys(s).map(d => {
59 | return d + ' properties ' +
60 | "
Property Type Example " +
61 | Object.keys(s[d]).map(p => "" + p + " " + s[d][p].type + " " + s[d][p].example + " ").join("") + "
"
62 | }).join(" ")
63 | var optDatasets = Object.keys(s).map(d => "" + d + " ").join("")
64 |
65 | return html
66 | .replace("{{script}}", "")
67 | .replace("{{documentation}}", documentation)
68 | .replace("{{css}}", css)
69 | .replace("{{libs}}", libs)
70 | .replace(/{{url}}/g, url)
71 | }
72 |
73 | function map(q, url) {
74 | return mapHtml.replace("{{variables}}", "var q = "+ JSON.stringify(q)+", url = '"+ url+"'").replace("{{libs}}", libs).replace("{{css}}", css)
75 | }
76 |
--------------------------------------------------------------------------------
/docs/documentation.html:
--------------------------------------------------------------------------------
1 |
2 | Overview
3 |
4 | This API allows you to perform spatial and property-based queries on spatial data and returns GeoJSON .
5 |
6 | All API requests are performed by sending your query as JSON to {{url}}/q
. Requests can be performed using either GET
or POST
. Using POST
allows you to send the JSON as request body, while POST
requires you to URI encode the JSON and append it to {{url}}/q/
.
7 |
8 |
9 | JSON structure
10 | {
11 | "dataset ": …,
12 | "query ": …,
13 | "spatial ": …,
14 | "properties ": …,
15 | "distance ": …,
16 | "sort ": …,
17 | "limit ": …,
18 | "offset ": …,
19 | }
20 |
21 | dataset : String (required)
22 | Name of the dataset you want to perform the query on. If you do not pass any other arguments a JSON-file representing the full dataset will be returned.
23 |
24 | example:
25 | dataset: "addresses"
26 |
27 | query : Object
28 | Property-based query: Object containing property (prop
, String), operator (op
, String), value (val
, String / Number) and optionally case-sensitivity (c
, Boolean, default is false
).
29 |
30 | available operators:
31 |
32 | Operator Description
33 | = Equal
34 | != Not equal
35 | < Less than
36 | > More than
37 | <= Less than or equal
38 | >= More than or equal
39 | $ contains
40 | !$ Does not contain
41 | $= starts with
42 | !$= Does not start with
43 | =$ ends with
44 | !=$ Does not end with
45 |
46 |
47 | Use Arrays to query multiple relations using and
or or
.
48 |
49 | example:
50 | query: {
51 | "and": [{
52 | "prop": "age",
53 | "op": "<=",
54 | "val": "25"
55 | }, {
56 | "or": [{
57 | "prop": "name",
58 | "op": "=",
59 | "val": "Jane Doe"
60 | }, {
61 | "prop": "name",
62 | "op": "=",
63 | "val": "John Doe"
64 | }]
65 | }]
66 | }
67 |
68 |
69 | spatial : Object
70 | Spatial query: Object containing spatial relation (relation
, String), geometry (geometry
, String (WKT) or Object (GeoJSON-Feature), supported feature types: Point, LineString, Polygon) and distance (distance
, Number, only for relation "DistWithin"
).
71 | available relations:
72 |
73 | Relation Description
74 | Equals TRUE if queried geometry (g1) and supplied geometry (g2) are equal
75 | Disjoint TRUE if the intersection of g1 and g2 is the empty set
76 | Touches TRUE if the only Points in common between g1 and g2 lie in the union of the boundaries of g1 and g2
77 | Within TRUE if g1 is completely contained in g2
78 | Overlaps TRUE if the intersection of g1 and g2 results in a value of the same dimension as g1 and g2 that is different from both g1 and g2
79 | Crosses TRUE if the intersection of g1 and g2 results in a value whose dimension is less than the maximum dimension of g1 and g2 and the intersection value includes Points interior to both g1 and g2, and the intersection value is not equal to either g1 or g2
80 | Intersects TRUE if the intersection of g1 and g2 is not empty
81 | Contains TRUE if g2 is completely contained in g1
82 | DistWithin TRUE if g2 is within supplied distance of g1
83 |
84 |
85 | example:
86 | spatial: {
87 | "relation": "within",
88 | "geometry": {
89 | "type": "Polygon",
90 | "coordinates": [
91 | [
92 | [8.522214889526367, 47.39189986655709],
93 | [8.522214889526367, 47.41112933122305],
94 | [8.545131683349610, 47.41112933122305],
95 | [8.522214889526367, 47.39189986655709]
96 | ]
97 | ]
98 | }
99 | }
100 |
101 |
102 | properties : Array
103 | Specify which properties will be returned. This may be used to reduce the size of the response. If not specified all properties will be returned.
104 | example:
105 | properties: ["city", "district", "street"]
106 |
107 |
108 | distance : String (WKT) or Object (GeoJSON Feature)
109 | Calculates distance to specified geometry and returns it as property where_distance
. This allows you to sort the result according to distance. For performance reasons it is recommended to only use this on small datasets or subsets.
110 |
111 | example:
112 | distance: "POINT (13.467375 52.483492)"
113 |
114 |
115 | sort : Object
116 | Sorts results by specified property (by
, String, property name) in ascending or descending order (desc
, Boolean, default is false
).
117 |
118 | example:
119 | sort: {
120 | by: "city",
121 | desc: true
122 | }
123 |
124 |
125 | limit : Number
126 | Sets maximum number of returned features
127 | example:
128 | limit: 50
129 |
130 |
131 | offset : Number
132 | Sets offset for returned features
133 | example:
134 | offset: 50
135 |
136 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
14 | {{script}}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | Datasets | Documentation | Query-Builder
24 |
25 |
26 |
27 |
{{documentation}}
28 |
29 | dataset:
30 |
31 |
39 |
40 |
spatial:
41 |
42 | Equals
43 | Disjoint
44 | Touches
45 | Within
46 | Overlaps
47 | Crosses
48 | Intersects
49 | Contains
50 | DistWithin
51 |
52 |
53 |
54 |
properties:
55 |
56 |
sort: descending
57 |
58 |
limit:
59 |
60 |
offset:
61 |
62 |
send
63 |
64 |
65 |
66 |
67 | Request URL:
68 |
69 | Map URL:
70 |
71 | Request Body:
72 |
73 | Response:
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/docs/launch.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | where2 starting...
6 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/docs/leaflet-plugins.js:
--------------------------------------------------------------------------------
1 | /*
2 | Leaflet.draw, a plugin that adds drawing and editing tools to Leaflet powered maps.
3 | (c) 2012-2013, Jacob Toye, Smartrak
4 |
5 | https://github.com/Leaflet/Leaflet.draw
6 | http://leafletjs.com
7 | https://github.com/jacobtoye
8 | */
9 | !function(t,e){L.drawVersion="0.2.3",L.drawLocal={draw:{toolbar:{actions:{title:"Cancel drawing",text:"Cancel"},undo:{title:"Delete last point drawn",text:"Delete last point"},buttons:{polyline:"Draw a polyline",polygon:"Draw a polygon",rectangle:"Draw a rectangle",circle:"Draw a circle",marker:"Draw a marker"}},handlers:{circle:{tooltip:{start:"Click and drag to draw circle."}},marker:{tooltip:{start:"Click map to place marker."}},polygon:{tooltip:{start:"Click to start drawing shape.",cont:"Click to continue drawing shape.",end:"Click first point to close this shape."}},polyline:{error:"Error: shape edges cannot cross!",tooltip:{start:"Click to start drawing line.",cont:"Click to continue drawing line.",end:"Click last point to finish line."}},rectangle:{tooltip:{start:"Click and drag to draw rectangle."}},simpleshape:{tooltip:{end:"Release mouse to finish drawing."}}}},edit:{toolbar:{actions:{save:{title:"Save changes.",text:"Save"},cancel:{title:"Cancel editing, discards all changes.",text:"Cancel"}},buttons:{edit:"Edit layers.",editDisabled:"No layers to edit.",remove:"Delete layers.",removeDisabled:"No layers to delete."}},handlers:{edit:{tooltip:{text:"Drag handles, or marker to edit feature.",subtext:"Click cancel to undo changes."}},remove:{tooltip:{text:"Click on a feature to remove"}}}}},L.Draw={},L.Draw.Feature=L.Handler.extend({includes:L.Mixin.Events,initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.setOptions(this,e)},enable:function(){this._enabled||(this.fire("enabled",{handler:this.type}),this._map.fire("draw:drawstart",{layerType:this.type}),L.Handler.prototype.enable.call(this))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._map.fire("draw:drawstop",{layerType:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(L.DomUtil.disableTextSelection(),t.getContainer().focus(),this._tooltip=new L.Tooltip(this._map),L.DomEvent.on(this._container,"keyup",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.off(this._container,"keyup",this._cancelDrawing,this))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire("draw:created",{layer:t,layerType:this.type})},_cancelDrawing:function(t){27===t.keyCode&&this.disable()}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:"polyline"},Poly:L.Polyline,options:{allowIntersection:!0,repeatMode:!1,drawError:{color:"#b00b00",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"}),guidelineDistance:20,maxGuideLineLength:4e3,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!1,clickable:!0},metric:!0,showLength:!0,zIndexOffset:2e3},initialize:function(t,e){this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error,e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("mousedown",this._onMouseDown,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this).on("mouseup",this._onMouseUp,this).on("zoomend",this._onZoomEnd,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._clearHideErrorTimeout(),this._cleanUpShape(),this._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers,this._map.removeLayer(this._poly),delete this._poly,this._mouseMarker.off("mousedown",this._onMouseDown,this).off("mouseup",this._onMouseUp,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._clearGuides(),this._map.off("mousemove",this._onMouseMove,this).off("zoomend",this._onZoomEnd,this)},deleteLastVertex:function(){if(!(this._markers.length<=1)){var t=this._markers.pop(),e=this._poly,i=this._poly.spliceLatLngs(e.getLatLngs().length-1,1)[0];this._markerGroup.removeLayer(t),e.getLatLngs().length<2&&this._map.removeLayer(e),this._vertexChanged(i,!1)}},addVertex:function(t){var e=this._markers.length;return e>0&&!this.options.allowIntersection&&this._poly.newLatLngIntersects(t)?void this._showErrorTooltip():(this._errorShown&&this._hideErrorTooltip(),this._markers.push(this._createMarker(t)),this._poly.addLatLng(t),2===this._poly.getLatLngs().length&&this._map.addLayer(this._poly),void this._vertexChanged(t,!0))},_finishShape:function(){var t=this._poly.newLatLngIntersects(this._poly.getLatLngs()[0],!0);return!this.options.allowIntersection&&t||!this._shapeIsValid()?void this._showErrorTooltip():(this._fireCreatedEvent(),this.disable(),void(this.options.repeatMode&&this.enable()))},_shapeIsValid:function(){return!0},_onZoomEnd:function(){this._updateGuide()},_onMouseMove:function(t){var e=t.layerPoint,i=t.latlng;this._currentLatLng=i,this._updateTooltip(i),this._updateGuide(e),this._mouseMarker.setLatLng(i),L.DomEvent.preventDefault(t.originalEvent)},_vertexChanged:function(t,e){this._updateFinishHandler(),this._updateRunningMeasure(t,e),this._clearGuides(),this._updateTooltip()},_onMouseDown:function(t){var e=t.originalEvent;this._mouseDownOrigin=L.point(e.clientX,e.clientY)},_onMouseUp:function(e){if(this._mouseDownOrigin){var i=L.point(e.originalEvent.clientX,e.originalEvent.clientY).distanceTo(this._mouseDownOrigin);Math.abs(i)<9*(t.devicePixelRatio||1)&&this.addVertex(e.latlng)}this._mouseDownOrigin=null},_updateFinishHandler:function(){var t=this._markers.length;t>1&&this._markers[t-1].on("click",this._finishShape,this),t>2&&this._markers[t-2].off("click",this._finishShape,this)},_createMarker:function(t){var e=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset});return this._markerGroup.addLayer(e),e},_updateGuide:function(t){var e=this._markers.length;e>0&&(t=t||this._map.latLngToLayerPoint(this._currentLatLng),this._clearGuides(),this._drawGuide(this._map.latLngToLayerPoint(this._markers[e-1].getLatLng()),t))},_updateTooltip:function(t){var e=this._getTooltipText();t&&this._tooltip.updatePosition(t),this._errorShown||this._tooltip.updateContent(e)},_drawGuide:function(t,e){var i,o,a,s=Math.floor(Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))),r=this.options.guidelineDistance,n=this.options.maxGuideLineLength,l=s>n?s-n:r;for(this._guidesContainer||(this._guidesContainer=L.DomUtil.create("div","leaflet-draw-guides",this._overlayPane));s>l;l+=this.options.guidelineDistance)i=l/s,o={x:Math.floor(t.x*(1-i)+i*e.x),y:Math.floor(t.y*(1-i)+i*e.y)},a=L.DomUtil.create("div","leaflet-draw-guide-dash",this._guidesContainer),a.style.backgroundColor=this._errorShown?this.options.drawError.color:this.options.shapeOptions.color,L.DomUtil.setPosition(a,o)},_updateGuideColor:function(t){if(this._guidesContainer)for(var e=0,i=this._guidesContainer.childNodes.length;i>e;e++)this._guidesContainer.childNodes[e].style.backgroundColor=t},_clearGuides:function(){if(this._guidesContainer)for(;this._guidesContainer.firstChild;)this._guidesContainer.removeChild(this._guidesContainer.firstChild)},_getTooltipText:function(){var t,e,i=this.options.showLength;return 0===this._markers.length?t={text:L.drawLocal.draw.handlers.polyline.tooltip.start}:(e=i?this._getMeasurementString():"",t=1===this._markers.length?{text:L.drawLocal.draw.handlers.polyline.tooltip.cont,subtext:e}:{text:L.drawLocal.draw.handlers.polyline.tooltip.end,subtext:e}),t},_updateRunningMeasure:function(t,e){var i,o,a=this._markers.length;1===this._markers.length?this._measurementRunningTotal=0:(i=a-(e?2:1),o=t.distanceTo(this._markers[i].getLatLng()),this._measurementRunningTotal+=o*(e?1:-1))},_getMeasurementString:function(){var t,e=this._currentLatLng,i=this._markers[this._markers.length-1].getLatLng();return t=this._measurementRunningTotal+e.distanceTo(i),L.GeometryUtil.readableDistance(t,this.options.metric)},_showErrorTooltip:function(){this._errorShown=!0,this._tooltip.showAsError().updateContent({text:this.options.drawError.message}),this._updateGuideColor(this.options.drawError.color),this._poly.setStyle({color:this.options.drawError.color}),this._clearHideErrorTimeout(),this._hideErrorTimeout=setTimeout(L.Util.bind(this._hideErrorTooltip,this),this.options.drawError.timeout)},_hideErrorTooltip:function(){this._errorShown=!1,this._clearHideErrorTimeout(),this._tooltip.removeError().updateContent(this._getTooltipText()),this._updateGuideColor(this.options.shapeOptions.color),this._poly.setStyle({color:this.options.shapeOptions.color})},_clearHideErrorTimeout:function(){this._hideErrorTimeout&&(clearTimeout(this._hideErrorTimeout),this._hideErrorTimeout=null)},_cleanUpShape:function(){this._markers.length>1&&this._markers[this._markers.length-1].off("click",this._finishShape,this)},_fireCreatedEvent:function(){var t=new this.Poly(this._poly.getLatLngs(),this.options.shapeOptions);L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Polygon=L.Draw.Polyline.extend({statics:{TYPE:"polygon"},Poly:L.Polygon,options:{showArea:!1,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){L.Draw.Polyline.prototype.initialize.call(this,t,e),this.type=L.Draw.Polygon.TYPE},_updateFinishHandler:function(){var t=this._markers.length;1===t&&this._markers[0].on("click",this._finishShape,this),t>2&&(this._markers[t-1].on("dblclick",this._finishShape,this),t>3&&this._markers[t-2].off("dblclick",this._finishShape,this))},_getTooltipText:function(){var t,e;return 0===this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.start:this._markers.length<3?t=L.drawLocal.draw.handlers.polygon.tooltip.cont:(t=L.drawLocal.draw.handlers.polygon.tooltip.end,e=this._getMeasurementString()),{text:t,subtext:e}},_getMeasurementString:function(){var t=this._area;return t?L.GeometryUtil.readableArea(t,this.options.metric):null},_shapeIsValid:function(){return this._markers.length>=3},_vertexAdded:function(){if(!this.options.allowIntersection&&this.options.showArea){var t=this._poly.getLatLngs();this._area=L.GeometryUtil.geodesicArea(t)}},_cleanUpShape:function(){var t=this._markers.length;t>0&&(this._markers[0].off("click",this._finishShape,this),t>2&&this._markers[t-1].off("dblclick",this._finishShape,this))}}),L.SimpleShape={},L.Draw.SimpleShape=L.Draw.Feature.extend({options:{repeatMode:!1},initialize:function(t,e){this._endLabelText=L.drawLocal.draw.handlers.simpleshape.tooltip.end,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._mapDraggable=this._map.dragging.enabled(),this._mapDraggable&&this._map.dragging.disable(),this._container.style.cursor="crosshair",this._tooltip.updateContent({text:this._initialLabelText}),this._map.on("mousedown",this._onMouseDown,this).on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._mapDraggable&&this._map.dragging.enable(),this._container.style.cursor="",this._map.off("mousedown",this._onMouseDown,this).off("mousemove",this._onMouseMove,this),L.DomEvent.off(e,"mouseup",this._onMouseUp,this),this._shape&&(this._map.removeLayer(this._shape),delete this._shape)),this._isDrawing=!1},_onMouseDown:function(t){this._isDrawing=!0,this._startLatLng=t.latlng,L.DomEvent.on(e,"mouseup",this._onMouseUp,this).preventDefault(t.originalEvent)},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._isDrawing&&(this._tooltip.updateContent({text:this._endLabelText}),this._drawShape(e))},_onMouseUp:function(){this._shape&&this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()}}),L.Draw.Rectangle=L.Draw.SimpleShape.extend({statics:{TYPE:"rectangle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){this.type=L.Draw.Rectangle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.rectangle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setBounds(new L.LatLngBounds(this._startLatLng,t)):(this._shape=new L.Rectangle(new L.LatLngBounds(this._startLatLng,t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Rectangle(this._shape.getBounds(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Circle=L.Draw.SimpleShape.extend({statics:{TYPE:"circle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0},showRadius:!0,metric:!0},initialize:function(t,e){this.type=L.Draw.Circle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.circle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setRadius(this._startLatLng.distanceTo(t)):(this._shape=new L.Circle(this._startLatLng,this._startLatLng.distanceTo(t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Circle(this._startLatLng,this._shape.getRadius(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_onMouseMove:function(t){var e,i=t.latlng,o=this.options.showRadius,a=this.options.metric;this._tooltip.updatePosition(i),this._isDrawing&&(this._drawShape(i),e=this._shape.getRadius().toFixed(1),this._tooltip.updateContent({text:this._endLabelText,subtext:o?"Radius: "+L.GeometryUtil.readableDistance(e,a):""}))}}),L.Draw.Marker=L.Draw.Feature.extend({statics:{TYPE:"marker"},options:{icon:new L.Icon.Default,repeatMode:!1,zIndexOffset:2e3},initialize:function(t,e){this.type=L.Draw.Marker.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._tooltip.updateContent({text:L.drawLocal.draw.handlers.marker.tooltip.start}),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._marker&&(this._marker.off("click",this._onClick,this),this._map.off("click",this._onClick,this).removeLayer(this._marker),delete this._marker),this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._map.off("mousemove",this._onMouseMove,this))},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._mouseMarker.setLatLng(e),this._marker?(e=this._mouseMarker.getLatLng(),this._marker.setLatLng(e)):(this._marker=new L.Marker(e,{icon:this.options.icon,zIndexOffset:this.options.zIndexOffset}),this._marker.on("click",this._onClick,this),this._map.on("click",this._onClick,this).addLayer(this._marker))},_onClick:function(){this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()},_fireCreatedEvent:function(){var t=new L.Marker(this._marker.getLatLng(),{icon:this.options.icon});L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Edit=L.Edit||{},L.Edit.Poly=L.Handler.extend({options:{icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"})},initialize:function(t,e){this._poly=t,L.setOptions(this,e)},addHooks:function(){this._poly._map&&(this._markerGroup||this._initMarkers(),this._poly._map.addLayer(this._markerGroup))},removeHooks:function(){this._poly._map&&(this._poly._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers)},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._markers=[];var t,e,i,o,a=this._poly._latlngs;for(t=0,i=a.length;i>t;t++)o=this._createMarker(a[t],t),o.on("click",this._onMarkerClick,this),this._markers.push(o);var s,r;for(t=0,e=i-1;i>t;e=t++)(0!==t||L.Polygon&&this._poly instanceof L.Polygon)&&(s=this._markers[e],r=this._markers[t],this._createMiddleMarker(s,r),this._updatePrevNext(s,r))},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:this.options.icon});return i._origLatLng=t,i._index=e,i.on("drag",this._onMarkerDrag,this),i.on("dragend",this._fireEdit,this),this._markerGroup.addLayer(i),i},_removeMarker:function(t){var e=t._index;this._markerGroup.removeLayer(t),this._markers.splice(e,1),this._poly.spliceLatLngs(e,1),this._updateIndexes(e,-1),t.off("drag",this._onMarkerDrag,this).off("dragend",this._fireEdit,this).off("click",this._onMarkerClick,this)},_fireEdit:function(){this._poly.edited=!0,this._poly.fire("edit")},_onMarkerDrag:function(t){var e=t.target;L.extend(e._origLatLng,e._latlng),e._middleLeft&&e._middleLeft.setLatLng(this._getMiddleLatLng(e._prev,e)),e._middleRight&&e._middleRight.setLatLng(this._getMiddleLatLng(e,e._next)),this._poly.redraw()},_onMarkerClick:function(t){var e=L.Polygon&&this._poly instanceof L.Polygon?4:3,i=t.target;this._poly._latlngs.lengtht&&(i._index+=e)})},_createMiddleMarker:function(t,e){var i,o,a,s=this._getMiddleLatLng(t,e),r=this._createMarker(s);r.setOpacity(.6),t._middleRight=e._middleLeft=r,o=function(){var o=e._index;r._index=o,r.off("click",i,this).on("click",this._onMarkerClick,this),s.lat=r.getLatLng().lat,s.lng=r.getLatLng().lng,this._poly.spliceLatLngs(o,0,s),this._markers.splice(o,0,r),r.setOpacity(1),this._updateIndexes(o,1),e._index++,this._updatePrevNext(t,r),this._updatePrevNext(r,e),this._poly.fire("editstart")},a=function(){r.off("dragstart",o,this),r.off("dragend",a,this),this._createMiddleMarker(t,r),this._createMiddleMarker(r,e)},i=function(){o.call(this),a.call(this),this._fireEdit()},r.on("click",i,this).on("dragstart",o,this).on("dragend",a,this),this._markerGroup.addLayer(r)},_updatePrevNext:function(t,e){t&&(t._next=e),e&&(e._prev=t)},_getMiddleLatLng:function(t,e){var i=this._poly._map,o=i.project(t.getLatLng()),a=i.project(e.getLatLng());return i.unproject(o._add(a)._divideBy(2))}}),L.Polyline.addInitHook(function(){this.editing||(L.Edit.Poly&&(this.editing=new L.Edit.Poly(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()}))}),L.Edit=L.Edit||{},L.Edit.SimpleShape=L.Handler.extend({options:{moveIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move"}),resizeIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize"})},initialize:function(t,e){this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){this._shape._map&&(this._map=this._shape._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup))},removeHooks:function(){if(this._shape._map){this._unbindMarker(this._moveMarker);for(var t=0,e=this._resizeMarkers.length;e>t;t++)this._unbindMarker(this._resizeMarkers[t]);this._resizeMarkers=null,this._map.removeLayer(this._markerGroup),delete this._markerGroup}this._map=null},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._createMoveMarker(),this._createResizeMarker()},_createMoveMarker:function(){},_createResizeMarker:function(){},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:e,zIndexOffset:10});return this._bindMarker(i),this._markerGroup.addLayer(i),i},_bindMarker:function(t){t.on("dragstart",this._onMarkerDragStart,this).on("drag",this._onMarkerDrag,this).on("dragend",this._onMarkerDragEnd,this)},_unbindMarker:function(t){t.off("dragstart",this._onMarkerDragStart,this).off("drag",this._onMarkerDrag,this).off("dragend",this._onMarkerDragEnd,this)},_onMarkerDragStart:function(t){var e=t.target;e.setOpacity(0),this._shape.fire("editstart")},_fireEdit:function(){this._shape.edited=!0,this._shape.fire("edit")},_onMarkerDrag:function(t){var e=t.target,i=e.getLatLng();e===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw()},_onMarkerDragEnd:function(t){var e=t.target;e.setOpacity(1),this._fireEdit()},_move:function(){},_resize:function(){}}),L.Edit=L.Edit||{},L.Edit.Rectangle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getBounds(),e=t.getCenter();this._moveMarker=this._createMarker(e,this.options.moveIcon)},_createResizeMarker:function(){var t=this._getCorners();this._resizeMarkers=[];for(var e=0,i=t.length;i>e;e++)this._resizeMarkers.push(this._createMarker(t[e],this.options.resizeIcon)),this._resizeMarkers[e]._cornerIndex=e},_onMarkerDragStart:function(t){L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t);var e=this._getCorners(),i=t.target,o=i._cornerIndex;this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)},_onMarkerDragEnd:function(t){var e,i,o=t.target;o===this._moveMarker&&(e=this._shape.getBounds(),i=e.getCenter(),o.setLatLng(i)),this._toggleCornerMarkers(1),this._repositionCornerMarkers(),L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this,t)},_move:function(t){for(var e,i=this._shape.getLatLngs(),o=this._shape.getBounds(),a=o.getCenter(),s=[],r=0,n=i.length;n>r;r++)e=[i[r].lat-a.lat,i[r].lng-a.lng],s.push([t.lat+e[0],t.lng+e[1]]);this._shape.setLatLngs(s),this._repositionCornerMarkers()},_resize:function(t){var e;this._shape.setBounds(L.latLngBounds(t,this._oppositeCorner)),e=this._shape.getBounds(),this._moveMarker.setLatLng(e.getCenter())},_getCorners:function(){var t=this._shape.getBounds(),e=t.getNorthWest(),i=t.getNorthEast(),o=t.getSouthEast(),a=t.getSouthWest();return[e,i,o,a]},_toggleCornerMarkers:function(t){for(var e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setOpacity(t)},_repositionCornerMarkers:function(){for(var t=this._getCorners(),e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setLatLng(t[e])}}),L.Rectangle.addInitHook(function(){L.Edit.Rectangle&&(this.editing=new L.Edit.Rectangle(this),this.options.editable&&this.editing.enable())}),L.Edit=L.Edit||{},L.Edit.Circle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getLatLng();this._moveMarker=this._createMarker(t,this.options.moveIcon)},_createResizeMarker:function(){var t=this._shape.getLatLng(),e=this._getResizeMarkerPoint(t);this._resizeMarkers=[],this._resizeMarkers.push(this._createMarker(e,this.options.resizeIcon))},_getResizeMarkerPoint:function(t){var e=this._shape._radius*Math.cos(Math.PI/4),i=this._map.project(t);return this._map.unproject([i.x+e,i.y-e])},_move:function(t){var e=this._getResizeMarkerPoint(t);this._resizeMarkers[0].setLatLng(e),this._shape.setLatLng(t)},_resize:function(t){var e=this._moveMarker.getLatLng(),i=e.distanceTo(t);this._shape.setRadius(i)}}),L.Circle.addInitHook(function(){L.Edit.Circle&&(this.editing=new L.Edit.Circle(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()})}),L.LatLngUtil={cloneLatLngs:function(t){for(var e=[],i=0,o=t.length;o>i;i++)e.push(this.cloneLatLng(t[i]));return e},cloneLatLng:function(t){return L.latLng(t.lat,t.lng)}},L.GeometryUtil=L.extend(L.GeometryUtil||{},{geodesicArea:function(t){var e,i,o=t.length,a=0,s=L.LatLng.DEG_TO_RAD;if(o>2){for(var r=0;o>r;r++)e=t[r],i=t[(r+1)%o],a+=(i.lng-e.lng)*s*(2+Math.sin(e.lat*s)+Math.sin(i.lat*s));a=6378137*a*6378137/2}return Math.abs(a)},readableArea:function(t,e){var i;return e?i=t>=1e4?(1e-4*t).toFixed(2)+" ha":t.toFixed(2)+" m²":(t*=.836127,i=t>=3097600?(t/3097600).toFixed(2)+" mi²":t>=4840?(t/4840).toFixed(2)+" acres":Math.ceil(t)+" yd²"),i},readableDistance:function(t,e){var i;return e?i=t>1e3?(t/1e3).toFixed(2)+" km":Math.ceil(t)+" m":(t*=1.09361,i=t>1760?(t/1760).toFixed(2)+" miles":Math.ceil(t)+" yd"),i}}),L.Util.extend(L.LineUtil,{segmentsIntersect:function(t,e,i,o){return this._checkCounterclockwise(t,i,o)!==this._checkCounterclockwise(e,i,o)&&this._checkCounterclockwise(t,e,i)!==this._checkCounterclockwise(t,e,o)},_checkCounterclockwise:function(t,e,i){return(i.y-t.y)*(e.x-t.x)>(e.y-t.y)*(i.x-t.x)}}),L.Polyline.include({intersects:function(){var t,e,i,o=this._originalPoints,a=o?o.length:0;if(this._tooFewPointsForIntersection())return!1;for(t=a-1;t>=3;t--)if(e=o[t-1],i=o[t],this._lineSegmentsIntersectsRange(e,i,t-2))return!0;return!1},newLatLngIntersects:function(t,e){return this._map?this.newPointIntersects(this._map.latLngToLayerPoint(t),e):!1},newPointIntersects:function(t,e){var i=this._originalPoints,o=i?i.length:0,a=i?i[o-1]:null,s=o-2;return this._tooFewPointsForIntersection(1)?!1:this._lineSegmentsIntersectsRange(a,t,s,e?1:0)},_tooFewPointsForIntersection:function(t){var e=this._originalPoints,i=e?e.length:0;return i+=t||0,!this._originalPoints||3>=i},_lineSegmentsIntersectsRange:function(t,e,i,o){var a,s,r=this._originalPoints;o=o||0;for(var n=i;n>o;n--)if(a=r[n-1],s=r[n],L.LineUtil.segmentsIntersect(t,e,a,s))return!0;return!1}}),L.Polygon.include({intersects:function(){var t,e,i,o,a,s=this._originalPoints;return this._tooFewPointsForIntersection()?!1:(t=L.Polyline.prototype.intersects.call(this))?!0:(e=s.length,i=s[0],o=s[e-1],a=e-2,this._lineSegmentsIntersectsRange(o,i,a,1))}}),L.Control.Draw=L.Control.extend({options:{position:"topleft",draw:{},edit:!1},initialize:function(t){if(L.version<"0.7")throw new Error("Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/");L.Control.prototype.initialize.call(this,t);var e,i;this._toolbars={},L.DrawToolbar&&this.options.draw&&(i=new L.DrawToolbar(this.options.draw),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this)),L.EditToolbar&&this.options.edit&&(i=new L.EditToolbar(this.options.edit),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this))},onAdd:function(t){var e,i=L.DomUtil.create("div","leaflet-draw"),o=!1,a="leaflet-draw-toolbar-top";for(var s in this._toolbars)this._toolbars.hasOwnProperty(s)&&(e=this._toolbars[s].addToolbar(t),e&&(o||(L.DomUtil.hasClass(e,a)||L.DomUtil.addClass(e.childNodes[0],a),o=!0),i.appendChild(e)));return i},onRemove:function(){for(var t in this._toolbars)this._toolbars.hasOwnProperty(t)&&this._toolbars[t].removeToolbar()},setDrawingOptions:function(t){for(var e in this._toolbars)this._toolbars[e]instanceof L.DrawToolbar&&this._toolbars[e].setOptions(t)},_toolbarEnabled:function(t){var e=""+L.stamp(t.target);for(var i in this._toolbars)this._toolbars.hasOwnProperty(i)&&i!==e&&this._toolbars[i].disable()}}),L.Map.mergeOptions({drawControlTooltips:!0,drawControl:!1}),L.Map.addInitHook(function(){this.options.drawControl&&(this.drawControl=new L.Control.Draw,this.addControl(this.drawControl))}),L.Toolbar=L.Class.extend({includes:[L.Mixin.Events],initialize:function(t){L.setOptions(this,t),this._modes={},this._actionButtons=[],this._activeMode=null},enabled:function(){return null!==this._activeMode},disable:function(){this.enabled()&&this._activeMode.handler.disable()},addToolbar:function(t){var e,i=L.DomUtil.create("div","leaflet-draw-section"),o=0,a=this._toolbarClass||"",s=this.getModeHandlers(t);for(this._toolbarContainer=L.DomUtil.create("div","leaflet-draw-toolbar leaflet-bar"),this._map=t,e=0;ee;e++)this._disposeButton(this._actionButtons[e].button,this._actionButtons[e].callback,this);this._actionButtons=[],this._actionsContainer=null},_initModeHandler:function(t,e,i,o,a){var s=t.type;this._modes[s]={},this._modes[s].handler=t,this._modes[s].button=this._createButton({title:a,className:o+"-"+s,container:e,callback:this._modes[s].handler.enable,context:this._modes[s].handler}),this._modes[s].buttonIndex=i,this._modes[s].handler.on("enabled",this._handlerActivated,this).on("disabled",this._handlerDeactivated,this)},_createButton:function(t){var e=L.DomUtil.create("a",t.className||"",t.container);return e.href="#",t.text&&(e.innerHTML=t.text),t.title&&(e.title=t.title),L.DomEvent.on(e,"click",L.DomEvent.stopPropagation).on(e,"mousedown",L.DomEvent.stopPropagation).on(e,"dblclick",L.DomEvent.stopPropagation).on(e,"click",L.DomEvent.preventDefault).on(e,"click",t.callback,t.context),e},_disposeButton:function(t,e){L.DomEvent.off(t,"click",L.DomEvent.stopPropagation).off(t,"mousedown",L.DomEvent.stopPropagation).off(t,"dblclick",L.DomEvent.stopPropagation).off(t,"click",L.DomEvent.preventDefault).off(t,"click",e)},_handlerActivated:function(t){this.disable(),this._activeMode=this._modes[t.handler],L.DomUtil.addClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._showActionsToolbar(),this.fire("enable")},_handlerDeactivated:function(){this._hideActionsToolbar(),L.DomUtil.removeClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._activeMode=null,this.fire("disable")},_createActions:function(t){var e,i,o,a,s=this._actionsContainer,r=this.getActions(t),n=r.length;for(i=0,o=this._actionButtons.length;o>i;i++)this._disposeButton(this._actionButtons[i].button,this._actionButtons[i].callback);for(this._actionButtons=[];s.firstChild;)s.removeChild(s.firstChild);for(var l=0;n>l;l++)"enabled"in r[l]&&!r[l].enabled||(e=L.DomUtil.create("li","",s),a=this._createButton({title:r[l].title,text:r[l].text,container:e,callback:r[l].callback,context:r[l].context}),this._actionButtons.push({button:a,callback:r[l].callback}))},_showActionsToolbar:function(){var t=this._activeMode.buttonIndex,e=this._lastButtonIndex,i=this._activeMode.button.offsetTop-1;this._createActions(this._activeMode.handler),this._actionsContainer.style.top=i+"px",0===t&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-top")),t===e&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-bottom")),this._actionsContainer.style.display="block"
10 | },_hideActionsToolbar:function(){this._actionsContainer.style.display="none",L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-top"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-bottom")}}),L.Tooltip=L.Class.extend({initialize:function(t){this._map=t,this._popupPane=t._panes.popupPane,this._container=t.options.drawControlTooltips?L.DomUtil.create("div","leaflet-draw-tooltip",this._popupPane):null,this._singleLineLabel=!1},dispose:function(){this._container&&(this._popupPane.removeChild(this._container),this._container=null)},updateContent:function(t){return this._container?(t.subtext=t.subtext||"",0!==t.subtext.length||this._singleLineLabel?t.subtext.length>0&&this._singleLineLabel&&(L.DomUtil.removeClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!1):(L.DomUtil.addClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!0),this._container.innerHTML=(t.subtext.length>0?''+t.subtext+" ":"")+""+t.text+" ",this):this},updatePosition:function(t){var e=this._map.latLngToLayerPoint(t),i=this._container;return this._container&&(i.style.visibility="inherit",L.DomUtil.setPosition(i,e)),this},showAsError:function(){return this._container&&L.DomUtil.addClass(this._container,"leaflet-error-draw-tooltip"),this},removeError:function(){return this._container&&L.DomUtil.removeClass(this._container,"leaflet-error-draw-tooltip"),this}}),L.DrawToolbar=L.Toolbar.extend({options:{polyline:{},polygon:{},rectangle:{},circle:{},marker:{}},initialize:function(t){for(var e in this.options)this.options.hasOwnProperty(e)&&t[e]&&(t[e]=L.extend({},this.options[e],t[e]));this._toolbarClass="leaflet-draw-draw",L.Toolbar.prototype.initialize.call(this,t)},getModeHandlers:function(t){return[{enabled:this.options.polyline,handler:new L.Draw.Polyline(t,this.options.polyline),title:L.drawLocal.draw.toolbar.buttons.polyline},{enabled:this.options.polygon,handler:new L.Draw.Polygon(t,this.options.polygon),title:L.drawLocal.draw.toolbar.buttons.polygon},{enabled:this.options.rectangle,handler:new L.Draw.Rectangle(t,this.options.rectangle),title:L.drawLocal.draw.toolbar.buttons.rectangle},{enabled:this.options.circle,handler:new L.Draw.Circle(t,this.options.circle),title:L.drawLocal.draw.toolbar.buttons.circle},{enabled:this.options.marker,handler:new L.Draw.Marker(t,this.options.marker),title:L.drawLocal.draw.toolbar.buttons.marker}]},getActions:function(t){return[{enabled:t.deleteLastVertex,title:L.drawLocal.draw.toolbar.undo.title,text:L.drawLocal.draw.toolbar.undo.text,callback:t.deleteLastVertex,context:t},{title:L.drawLocal.draw.toolbar.actions.title,text:L.drawLocal.draw.toolbar.actions.text,callback:this.disable,context:this}]},setOptions:function(t){L.setOptions(this,t);for(var e in this._modes)this._modes.hasOwnProperty(e)&&t.hasOwnProperty(e)&&this._modes[e].handler.setOptions(t[e])}}),L.EditToolbar=L.Toolbar.extend({options:{edit:{selectedPathOptions:{color:"#fe57a1",opacity:.6,dashArray:"10, 10",fill:!0,fillColor:"#fe57a1",fillOpacity:.1}},remove:{},featureGroup:null},initialize:function(t){t.edit&&("undefined"==typeof t.edit.selectedPathOptions&&(t.edit.selectedPathOptions=this.options.edit.selectedPathOptions),t.edit=L.extend({},this.options.edit,t.edit)),t.remove&&(t.remove=L.extend({},this.options.remove,t.remove)),this._toolbarClass="leaflet-draw-edit",L.Toolbar.prototype.initialize.call(this,t),this._selectedFeatureCount=0},getModeHandlers:function(t){var e=this.options.featureGroup;return[{enabled:this.options.edit,handler:new L.EditToolbar.Edit(t,{featureGroup:e,selectedPathOptions:this.options.edit.selectedPathOptions}),title:L.drawLocal.edit.toolbar.buttons.edit},{enabled:this.options.remove,handler:new L.EditToolbar.Delete(t,{featureGroup:e}),title:L.drawLocal.edit.toolbar.buttons.remove}]},getActions:function(){return[{title:L.drawLocal.edit.toolbar.actions.save.title,text:L.drawLocal.edit.toolbar.actions.save.text,callback:this._save,context:this},{title:L.drawLocal.edit.toolbar.actions.cancel.title,text:L.drawLocal.edit.toolbar.actions.cancel.text,callback:this.disable,context:this}]},addToolbar:function(t){var e=L.Toolbar.prototype.addToolbar.call(this,t);return this._checkDisabled(),this.options.featureGroup.on("layeradd layerremove",this._checkDisabled,this),e},removeToolbar:function(){this.options.featureGroup.off("layeradd layerremove",this._checkDisabled,this),L.Toolbar.prototype.removeToolbar.call(this)},disable:function(){this.enabled()&&(this._activeMode.handler.revertLayers(),L.Toolbar.prototype.disable.call(this))},_save:function(){this._activeMode.handler.save(),this._activeMode.handler.disable()},_checkDisabled:function(){var t,e=this.options.featureGroup,i=0!==e.getLayers().length;this.options.edit&&(t=this._modes[L.EditToolbar.Edit.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.edit:L.drawLocal.edit.toolbar.buttons.editDisabled)),this.options.remove&&(t=this._modes[L.EditToolbar.Delete.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.remove:L.drawLocal.edit.toolbar.buttons.removeDisabled))}}),L.EditToolbar.Edit=L.Handler.extend({statics:{TYPE:"edit"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),this._selectedPathOptions=e.selectedPathOptions,this._featureGroup=e.featureGroup,!(this._featureGroup instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this._uneditedLayerProps={},this.type=L.EditToolbar.Edit.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire("draw:editstart",{handler:this.type}),L.Handler.prototype.enable.call(this),this._featureGroup.on("layeradd",this._enableLayerEdit,this).on("layerremove",this._disableLayerEdit,this))},disable:function(){this._enabled&&(this._featureGroup.off("layeradd",this._enableLayerEdit,this).off("layerremove",this._disableLayerEdit,this),L.Handler.prototype.disable.call(this),this._map.fire("draw:editstop",{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._featureGroup.eachLayer(this._enableLayerEdit,this),this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.edit.tooltip.text,subtext:L.drawLocal.edit.handlers.edit.tooltip.subtext}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._featureGroup.eachLayer(this._disableLayerEdit,this),this._uneditedLayerProps={},this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._featureGroup.eachLayer(function(t){this._revertLayer(t)},this)},save:function(){var t=new L.LayerGroup;this._featureGroup.eachLayer(function(e){e.edited&&(t.addLayer(e),e.edited=!1)}),this._map.fire("draw:edited",{layers:t})},_backupLayer:function(t){var e=L.Util.stamp(t);this._uneditedLayerProps[e]||(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?this._uneditedLayerProps[e]={latlngs:L.LatLngUtil.cloneLatLngs(t.getLatLngs())}:t instanceof L.Circle?this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng()),radius:t.getRadius()}:t instanceof L.Marker&&(this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng())}))},_revertLayer:function(t){var e=L.Util.stamp(t);t.edited=!1,this._uneditedLayerProps.hasOwnProperty(e)&&(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?t.setLatLngs(this._uneditedLayerProps[e].latlngs):t instanceof L.Circle?(t.setLatLng(this._uneditedLayerProps[e].latlng),t.setRadius(this._uneditedLayerProps[e].radius)):t instanceof L.Marker&&t.setLatLng(this._uneditedLayerProps[e].latlng))},_toggleMarkerHighlight:function(t){if(t._icon){var e=t._icon;e.style.display="none",L.DomUtil.hasClass(e,"leaflet-edit-marker-selected")?(L.DomUtil.removeClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,-4)):(L.DomUtil.addClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,4)),e.style.display=""}},_offsetMarker:function(t,e){var i=parseInt(t.style.marginTop,10)-e,o=parseInt(t.style.marginLeft,10)-e;t.style.marginTop=i+"px",t.style.marginLeft=o+"px"},_enableLayerEdit:function(t){var e,i=t.layer||t.target||t,o=i instanceof L.Marker;(!o||i._icon)&&(this._backupLayer(i),this._selectedPathOptions&&(e=L.Util.extend({},this._selectedPathOptions),o?this._toggleMarkerHighlight(i):(i.options.previousOptions=L.Util.extend({dashArray:null},i.options),i instanceof L.Circle||i instanceof L.Polygon||i instanceof L.Rectangle||(e.fill=!1),i.setStyle(e))),o?(i.dragging.enable(),i.on("dragend",this._onMarkerDragEnd)):i.editing.enable())},_disableLayerEdit:function(t){var e=t.layer||t.target||t;e.edited=!1,this._selectedPathOptions&&(e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions)),e instanceof L.Marker?(e.dragging.disable(),e.off("dragend",this._onMarkerDragEnd,this)):e.editing.disable()},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._featureGroup.getLayers().length}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:"remove"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this.type=L.EditToolbar.Delete.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire("draw:deletestart",{handler:this.type}),L.Handler.prototype.enable.call(this),this._deletableLayers.on("layeradd",this._enableLayerDelete,this).on("layerremove",this._disableLayerDelete,this))},disable:function(){this._enabled&&(this._deletableLayers.off("layeradd",this._enableLayerDelete,this).off("layerremove",this._disableLayerDelete,this),L.Handler.prototype.disable.call(this),this._map.fire("draw:deletestop",{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.layerGroup,this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.remove.tooltip.text}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t)},this)},save:function(){this._map.fire("draw:deleted",{layers:this._deletedLayers})},_enableLayerDelete:function(t){var e=t.layer||t.target||t;e.on("click",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off("click",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e)},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._deletableLayers.getLayers().length}})}(window,document);
11 | /*
12 | Leaflet.fullscreen
13 | */
14 | L.Control.Fullscreen=L.Control.extend({options:{position:"topleft",title:{"false":"View Fullscreen","true":"Exit Fullscreen"}},onAdd:function(map){var container=L.DomUtil.create("div","leaflet-control-fullscreen leaflet-bar leaflet-control");this.link=L.DomUtil.create("a","leaflet-control-fullscreen-button leaflet-bar-part",container);this.link.href="#";this._map=map;this._map.on("fullscreenchange",this._toggleTitle,this);this._toggleTitle();L.DomEvent.on(this.link,"click",this._click,this);return container},_click:function(e){L.DomEvent.stopPropagation(e);L.DomEvent.preventDefault(e);this._map.toggleFullscreen(this.options)},_toggleTitle:function(){this.link.title=this.options.title[this._map.isFullscreen()]}});L.Map.include({isFullscreen:function(){return this._isFullscreen||false},toggleFullscreen:function(options){var container=this.getContainer();if(this.isFullscreen()){if(options&&options.pseudoFullscreen){this._disablePseudoFullscreen(container)}else if(document.exitFullscreen){document.exitFullscreen()}else if(document.mozCancelFullScreen){document.mozCancelFullScreen()}else if(document.webkitCancelFullScreen){document.webkitCancelFullScreen()}else if(document.msExitFullscreen){document.msExitFullscreen()}else{this._disablePseudoFullscreen(container)}}else{if(options&&options.pseudoFullscreen){this._enablePseudoFullscreen(container)}else if(container.requestFullscreen){container.requestFullscreen()}else if(container.mozRequestFullScreen){container.mozRequestFullScreen()}else if(container.webkitRequestFullscreen){container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else if(container.msRequestFullscreen){container.msRequestFullscreen()}else{this._enablePseudoFullscreen(container)}}},_enablePseudoFullscreen:function(container){L.DomUtil.addClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(true);this.invalidateSize();this.fire("fullscreenchange")},_disablePseudoFullscreen:function(container){L.DomUtil.removeClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(false);this.invalidateSize();this.fire("fullscreenchange")},_setFullscreen:function(fullscreen){this._isFullscreen=fullscreen;var container=this.getContainer();if(fullscreen){L.DomUtil.addClass(container,"leaflet-fullscreen-on")}else{L.DomUtil.removeClass(container,"leaflet-fullscreen-on")}},_onFullscreenChange:function(e){var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;if(fullscreenElement===this.getContainer()&&!this._isFullscreen){this._setFullscreen(true);this.fire("fullscreenchange")}else if(fullscreenElement!==this.getContainer()&&this._isFullscreen){this._setFullscreen(false);this.fire("fullscreenchange")}}});L.Map.mergeOptions({fullscreenControl:false});L.Map.addInitHook(function(){if(this.options.fullscreenControl){this.fullscreenControl=new L.Control.Fullscreen(this.options.fullscreenControl);this.addControl(this.fullscreenControl)}var fullscreenchange;if("onfullscreenchange"in document){fullscreenchange="fullscreenchange"}else if("onmozfullscreenchange"in document){fullscreenchange="mozfullscreenchange"}else if("onwebkitfullscreenchange"in document){fullscreenchange="webkitfullscreenchange"}else if("onmsfullscreenchange"in document){fullscreenchange="MSFullscreenChange"}if(fullscreenchange){var onFullscreenChange=L.bind(this._onFullscreenChange,this);this.whenReady(function(){L.DomEvent.on(document,fullscreenchange,onFullscreenChange)});this.on("unload",function(){L.DomEvent.off(document,fullscreenchange,onFullscreenChange)})}});L.control.fullscreen=function(options){return new L.Control.Fullscreen(options)};
15 | /*
16 | Leaflet.sync
17 | */
18 | var NO_ANIMATION ={animate:false,reset:true}; L.Map = L.Map.extend({sync:function(map,options){this._initSync();options = L.extend({noInitialSync:false,syncCursor:false,syncCursorMarkerOptions:{radius:10,fillOpacity:0.3,color:'#da291c',fillColor:'#fff'}},options); if(this._syncMaps.indexOf(map)=== -1){this._syncMaps.push(map);} if(!options.noInitialSync){map.setView(this.getCenter(),this.getZoom(),NO_ANIMATION);}if(options.syncCursor){map.cursor = L.circleMarker([0,0],options.syncCursorMarkerOptions).addTo(map); this._cursors.push(map.cursor); this.on('mousemove',this._cursorSyncMove,this);this.on('mouseout',this._cursorSyncOut,this);}return this;}, _cursorSyncMove:function(e){this._cursors.forEach(function(cursor){cursor.setLatLng(e.latlng);});}, _cursorSyncOut:function(e){this._cursors.forEach(function(cursor){cursor.setLatLng([0,0]);});}, unsync:function(map){var self = this; if(this._syncMaps){this._syncMaps.forEach(function(synced,id){if(map === synced){self._syncMaps.splice(id,1);if(map.cursor){map.cursor.removeFrom(map);}}});}this.off('mousemove',this._cursorSyncMove,this);this.off('mouseout',this._cursorSyncOut,this); return this;}, isSynced:function(){return(this.hasOwnProperty('_syncMaps')&& Object.keys(this._syncMaps).length > 0);}, _initSync:function(){if(this._syncMaps){return;}var originalMap = this; this._syncMaps = [];this._cursors = []; L.extend(originalMap,{setView:function(center,zoom,options,sync){if(!sync){originalMap._syncMaps.forEach(function(toSync){toSync.setView(center,zoom,options,true);});}return L.Map.prototype.setView.call(this,center,zoom,options);}, panBy:function(offset,options,sync){if(!sync){originalMap._syncMaps.forEach(function(toSync){toSync.panBy(offset,options,true);});}return L.Map.prototype.panBy.call(this,offset,options);}, _onResize:function(event,sync){if(!sync){originalMap._syncMaps.forEach(function(toSync){toSync._onResize(event,true);});}return L.Map.prototype._onResize.call(this,event);}}); originalMap.on('zoomend',function(){originalMap._syncMaps.forEach(function(toSync){toSync.setView(originalMap.getCenter(),originalMap.getZoom(),NO_ANIMATION);});},this); originalMap.dragging._draggable._updatePosition = function(){L.Draggable.prototype._updatePosition.call(this);var self = this;originalMap._syncMaps.forEach(function(toSync){L.DomUtil.setPosition(toSync.dragging._draggable._element,self._newPos);toSync.eachLayer(function(layer){if(layer._google !== undefined){layer._google.setCenter(originalMap.getCenter());}});toSync.fire('moveend');});};}});
--------------------------------------------------------------------------------
/docs/libs.js:
--------------------------------------------------------------------------------
1 | /*
2 | Leaflet.draw, a plugin that adds drawing and editing tools to Leaflet powered maps.
3 | (c) 2012-2013, Jacob Toye, Smartrak
4 |
5 | https://github.com/Leaflet/Leaflet.draw
6 | http://leafletjs.com
7 | https://github.com/jacobtoye
8 | */
9 | !function(t,e){L.drawVersion="0.2.3",L.drawLocal={draw:{toolbar:{actions:{title:"Cancel drawing",text:"Cancel"},undo:{title:"Delete last point drawn",text:"Delete last point"},buttons:{polyline:"Draw a polyline",polygon:"Draw a polygon",rectangle:"Draw a rectangle",circle:"Draw a circle",marker:"Draw a marker"}},handlers:{circle:{tooltip:{start:"Click and drag to draw circle."}},marker:{tooltip:{start:"Click map to place marker."}},polygon:{tooltip:{start:"Click to start drawing shape.",cont:"Click to continue drawing shape.",end:"Click first point to close this shape."}},polyline:{error:"Error: shape edges cannot cross!",tooltip:{start:"Click to start drawing line.",cont:"Click to continue drawing line.",end:"Click last point to finish line."}},rectangle:{tooltip:{start:"Click and drag to draw rectangle."}},simpleshape:{tooltip:{end:"Release mouse to finish drawing."}}}},edit:{toolbar:{actions:{save:{title:"Save changes.",text:"Save"},cancel:{title:"Cancel editing, discards all changes.",text:"Cancel"}},buttons:{edit:"Edit layers.",editDisabled:"No layers to edit.",remove:"Delete layers.",removeDisabled:"No layers to delete."}},handlers:{edit:{tooltip:{text:"Drag handles, or marker to edit feature.",subtext:"Click cancel to undo changes."}},remove:{tooltip:{text:"Click on a feature to remove"}}}}},L.Draw={},L.Draw.Feature=L.Handler.extend({includes:L.Mixin.Events,initialize:function(t,e){this._map=t,this._container=t._container,this._overlayPane=t._panes.overlayPane,this._popupPane=t._panes.popupPane,e&&e.shapeOptions&&(e.shapeOptions=L.Util.extend({},this.options.shapeOptions,e.shapeOptions)),L.setOptions(this,e)},enable:function(){this._enabled||(this.fire("enabled",{handler:this.type}),this._map.fire("draw:drawstart",{layerType:this.type}),L.Handler.prototype.enable.call(this))},disable:function(){this._enabled&&(L.Handler.prototype.disable.call(this),this._map.fire("draw:drawstop",{layerType:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(L.DomUtil.disableTextSelection(),t.getContainer().focus(),this._tooltip=new L.Tooltip(this._map),L.DomEvent.on(this._container,"keyup",this._cancelDrawing,this))},removeHooks:function(){this._map&&(L.DomUtil.enableTextSelection(),this._tooltip.dispose(),this._tooltip=null,L.DomEvent.off(this._container,"keyup",this._cancelDrawing,this))},setOptions:function(t){L.setOptions(this,t)},_fireCreatedEvent:function(t){this._map.fire("draw:created",{layer:t,layerType:this.type})},_cancelDrawing:function(t){27===t.keyCode&&this.disable()}}),L.Draw.Polyline=L.Draw.Feature.extend({statics:{TYPE:"polyline"},Poly:L.Polyline,options:{allowIntersection:!0,repeatMode:!1,drawError:{color:"#b00b00",timeout:2500},icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"}),guidelineDistance:20,maxGuideLineLength:4e3,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!1,clickable:!0},metric:!0,showLength:!0,zIndexOffset:2e3},initialize:function(t,e){this.options.drawError.message=L.drawLocal.draw.handlers.polyline.error,e&&e.drawError&&(e.drawError=L.Util.extend({},this.options.drawError,e.drawError)),this.type=L.Draw.Polyline.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._markers=[],this._markerGroup=new L.LayerGroup,this._map.addLayer(this._markerGroup),this._poly=new L.Polyline([],this.options.shapeOptions),this._tooltip.updateContent(this._getTooltipText()),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("mousedown",this._onMouseDown,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this).on("mouseup",this._onMouseUp,this).on("zoomend",this._onZoomEnd,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._clearHideErrorTimeout(),this._cleanUpShape(),this._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers,this._map.removeLayer(this._poly),delete this._poly,this._mouseMarker.off("mousedown",this._onMouseDown,this).off("mouseup",this._onMouseUp,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._clearGuides(),this._map.off("mousemove",this._onMouseMove,this).off("zoomend",this._onZoomEnd,this)},deleteLastVertex:function(){if(!(this._markers.length<=1)){var t=this._markers.pop(),e=this._poly,i=this._poly.spliceLatLngs(e.getLatLngs().length-1,1)[0];this._markerGroup.removeLayer(t),e.getLatLngs().length<2&&this._map.removeLayer(e),this._vertexChanged(i,!1)}},addVertex:function(t){var e=this._markers.length;return e>0&&!this.options.allowIntersection&&this._poly.newLatLngIntersects(t)?void this._showErrorTooltip():(this._errorShown&&this._hideErrorTooltip(),this._markers.push(this._createMarker(t)),this._poly.addLatLng(t),2===this._poly.getLatLngs().length&&this._map.addLayer(this._poly),void this._vertexChanged(t,!0))},_finishShape:function(){var t=this._poly.newLatLngIntersects(this._poly.getLatLngs()[0],!0);return!this.options.allowIntersection&&t||!this._shapeIsValid()?void this._showErrorTooltip():(this._fireCreatedEvent(),this.disable(),void(this.options.repeatMode&&this.enable()))},_shapeIsValid:function(){return!0},_onZoomEnd:function(){this._updateGuide()},_onMouseMove:function(t){var e=t.layerPoint,i=t.latlng;this._currentLatLng=i,this._updateTooltip(i),this._updateGuide(e),this._mouseMarker.setLatLng(i),L.DomEvent.preventDefault(t.originalEvent)},_vertexChanged:function(t,e){this._updateFinishHandler(),this._updateRunningMeasure(t,e),this._clearGuides(),this._updateTooltip()},_onMouseDown:function(t){var e=t.originalEvent;this._mouseDownOrigin=L.point(e.clientX,e.clientY)},_onMouseUp:function(e){if(this._mouseDownOrigin){var i=L.point(e.originalEvent.clientX,e.originalEvent.clientY).distanceTo(this._mouseDownOrigin);Math.abs(i)<9*(t.devicePixelRatio||1)&&this.addVertex(e.latlng)}this._mouseDownOrigin=null},_updateFinishHandler:function(){var t=this._markers.length;t>1&&this._markers[t-1].on("click",this._finishShape,this),t>2&&this._markers[t-2].off("click",this._finishShape,this)},_createMarker:function(t){var e=new L.Marker(t,{icon:this.options.icon,zIndexOffset:2*this.options.zIndexOffset});return this._markerGroup.addLayer(e),e},_updateGuide:function(t){var e=this._markers.length;e>0&&(t=t||this._map.latLngToLayerPoint(this._currentLatLng),this._clearGuides(),this._drawGuide(this._map.latLngToLayerPoint(this._markers[e-1].getLatLng()),t))},_updateTooltip:function(t){var e=this._getTooltipText();t&&this._tooltip.updatePosition(t),this._errorShown||this._tooltip.updateContent(e)},_drawGuide:function(t,e){var i,o,a,s=Math.floor(Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))),r=this.options.guidelineDistance,n=this.options.maxGuideLineLength,l=s>n?s-n:r;for(this._guidesContainer||(this._guidesContainer=L.DomUtil.create("div","leaflet-draw-guides",this._overlayPane));s>l;l+=this.options.guidelineDistance)i=l/s,o={x:Math.floor(t.x*(1-i)+i*e.x),y:Math.floor(t.y*(1-i)+i*e.y)},a=L.DomUtil.create("div","leaflet-draw-guide-dash",this._guidesContainer),a.style.backgroundColor=this._errorShown?this.options.drawError.color:this.options.shapeOptions.color,L.DomUtil.setPosition(a,o)},_updateGuideColor:function(t){if(this._guidesContainer)for(var e=0,i=this._guidesContainer.childNodes.length;i>e;e++)this._guidesContainer.childNodes[e].style.backgroundColor=t},_clearGuides:function(){if(this._guidesContainer)for(;this._guidesContainer.firstChild;)this._guidesContainer.removeChild(this._guidesContainer.firstChild)},_getTooltipText:function(){var t,e,i=this.options.showLength;return 0===this._markers.length?t={text:L.drawLocal.draw.handlers.polyline.tooltip.start}:(e=i?this._getMeasurementString():"",t=1===this._markers.length?{text:L.drawLocal.draw.handlers.polyline.tooltip.cont,subtext:e}:{text:L.drawLocal.draw.handlers.polyline.tooltip.end,subtext:e}),t},_updateRunningMeasure:function(t,e){var i,o,a=this._markers.length;1===this._markers.length?this._measurementRunningTotal=0:(i=a-(e?2:1),o=t.distanceTo(this._markers[i].getLatLng()),this._measurementRunningTotal+=o*(e?1:-1))},_getMeasurementString:function(){var t,e=this._currentLatLng,i=this._markers[this._markers.length-1].getLatLng();return t=this._measurementRunningTotal+e.distanceTo(i),L.GeometryUtil.readableDistance(t,this.options.metric)},_showErrorTooltip:function(){this._errorShown=!0,this._tooltip.showAsError().updateContent({text:this.options.drawError.message}),this._updateGuideColor(this.options.drawError.color),this._poly.setStyle({color:this.options.drawError.color}),this._clearHideErrorTimeout(),this._hideErrorTimeout=setTimeout(L.Util.bind(this._hideErrorTooltip,this),this.options.drawError.timeout)},_hideErrorTooltip:function(){this._errorShown=!1,this._clearHideErrorTimeout(),this._tooltip.removeError().updateContent(this._getTooltipText()),this._updateGuideColor(this.options.shapeOptions.color),this._poly.setStyle({color:this.options.shapeOptions.color})},_clearHideErrorTimeout:function(){this._hideErrorTimeout&&(clearTimeout(this._hideErrorTimeout),this._hideErrorTimeout=null)},_cleanUpShape:function(){this._markers.length>1&&this._markers[this._markers.length-1].off("click",this._finishShape,this)},_fireCreatedEvent:function(){var t=new this.Poly(this._poly.getLatLngs(),this.options.shapeOptions);L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Polygon=L.Draw.Polyline.extend({statics:{TYPE:"polygon"},Poly:L.Polygon,options:{showArea:!1,shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){L.Draw.Polyline.prototype.initialize.call(this,t,e),this.type=L.Draw.Polygon.TYPE},_updateFinishHandler:function(){var t=this._markers.length;1===t&&this._markers[0].on("click",this._finishShape,this),t>2&&(this._markers[t-1].on("dblclick",this._finishShape,this),t>3&&this._markers[t-2].off("dblclick",this._finishShape,this))},_getTooltipText:function(){var t,e;return 0===this._markers.length?t=L.drawLocal.draw.handlers.polygon.tooltip.start:this._markers.length<3?t=L.drawLocal.draw.handlers.polygon.tooltip.cont:(t=L.drawLocal.draw.handlers.polygon.tooltip.end,e=this._getMeasurementString()),{text:t,subtext:e}},_getMeasurementString:function(){var t=this._area;return t?L.GeometryUtil.readableArea(t,this.options.metric):null},_shapeIsValid:function(){return this._markers.length>=3},_vertexAdded:function(){if(!this.options.allowIntersection&&this.options.showArea){var t=this._poly.getLatLngs();this._area=L.GeometryUtil.geodesicArea(t)}},_cleanUpShape:function(){var t=this._markers.length;t>0&&(this._markers[0].off("click",this._finishShape,this),t>2&&this._markers[t-1].off("dblclick",this._finishShape,this))}}),L.SimpleShape={},L.Draw.SimpleShape=L.Draw.Feature.extend({options:{repeatMode:!1},initialize:function(t,e){this._endLabelText=L.drawLocal.draw.handlers.simpleshape.tooltip.end,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._mapDraggable=this._map.dragging.enabled(),this._mapDraggable&&this._map.dragging.disable(),this._container.style.cursor="crosshair",this._tooltip.updateContent({text:this._initialLabelText}),this._map.on("mousedown",this._onMouseDown,this).on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._mapDraggable&&this._map.dragging.enable(),this._container.style.cursor="",this._map.off("mousedown",this._onMouseDown,this).off("mousemove",this._onMouseMove,this),L.DomEvent.off(e,"mouseup",this._onMouseUp,this),this._shape&&(this._map.removeLayer(this._shape),delete this._shape)),this._isDrawing=!1},_onMouseDown:function(t){this._isDrawing=!0,this._startLatLng=t.latlng,L.DomEvent.on(e,"mouseup",this._onMouseUp,this).preventDefault(t.originalEvent)},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._isDrawing&&(this._tooltip.updateContent({text:this._endLabelText}),this._drawShape(e))},_onMouseUp:function(){this._shape&&this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()}}),L.Draw.Rectangle=L.Draw.SimpleShape.extend({statics:{TYPE:"rectangle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0}},initialize:function(t,e){this.type=L.Draw.Rectangle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.rectangle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setBounds(new L.LatLngBounds(this._startLatLng,t)):(this._shape=new L.Rectangle(new L.LatLngBounds(this._startLatLng,t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Rectangle(this._shape.getBounds(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)}}),L.Draw.Circle=L.Draw.SimpleShape.extend({statics:{TYPE:"circle"},options:{shapeOptions:{stroke:!0,color:"#f06eaa",weight:4,opacity:.5,fill:!0,fillColor:null,fillOpacity:.2,clickable:!0},showRadius:!0,metric:!0},initialize:function(t,e){this.type=L.Draw.Circle.TYPE,this._initialLabelText=L.drawLocal.draw.handlers.circle.tooltip.start,L.Draw.SimpleShape.prototype.initialize.call(this,t,e)},_drawShape:function(t){this._shape?this._shape.setRadius(this._startLatLng.distanceTo(t)):(this._shape=new L.Circle(this._startLatLng,this._startLatLng.distanceTo(t),this.options.shapeOptions),this._map.addLayer(this._shape))},_fireCreatedEvent:function(){var t=new L.Circle(this._startLatLng,this._shape.getRadius(),this.options.shapeOptions);L.Draw.SimpleShape.prototype._fireCreatedEvent.call(this,t)},_onMouseMove:function(t){var e,i=t.latlng,o=this.options.showRadius,a=this.options.metric;this._tooltip.updatePosition(i),this._isDrawing&&(this._drawShape(i),e=this._shape.getRadius().toFixed(1),this._tooltip.updateContent({text:this._endLabelText,subtext:o?"Radius: "+L.GeometryUtil.readableDistance(e,a):""}))}}),L.Draw.Marker=L.Draw.Feature.extend({statics:{TYPE:"marker"},options:{icon:new L.Icon.Default,repeatMode:!1,zIndexOffset:2e3},initialize:function(t,e){this.type=L.Draw.Marker.TYPE,L.Draw.Feature.prototype.initialize.call(this,t,e)},addHooks:function(){L.Draw.Feature.prototype.addHooks.call(this),this._map&&(this._tooltip.updateContent({text:L.drawLocal.draw.handlers.marker.tooltip.start}),this._mouseMarker||(this._mouseMarker=L.marker(this._map.getCenter(),{icon:L.divIcon({className:"leaflet-mouse-marker",iconAnchor:[20,20],iconSize:[40,40]}),opacity:0,zIndexOffset:this.options.zIndexOffset})),this._mouseMarker.on("click",this._onClick,this).addTo(this._map),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){L.Draw.Feature.prototype.removeHooks.call(this),this._map&&(this._marker&&(this._marker.off("click",this._onClick,this),this._map.off("click",this._onClick,this).removeLayer(this._marker),delete this._marker),this._mouseMarker.off("click",this._onClick,this),this._map.removeLayer(this._mouseMarker),delete this._mouseMarker,this._map.off("mousemove",this._onMouseMove,this))},_onMouseMove:function(t){var e=t.latlng;this._tooltip.updatePosition(e),this._mouseMarker.setLatLng(e),this._marker?(e=this._mouseMarker.getLatLng(),this._marker.setLatLng(e)):(this._marker=new L.Marker(e,{icon:this.options.icon,zIndexOffset:this.options.zIndexOffset}),this._marker.on("click",this._onClick,this),this._map.on("click",this._onClick,this).addLayer(this._marker))},_onClick:function(){this._fireCreatedEvent(),this.disable(),this.options.repeatMode&&this.enable()},_fireCreatedEvent:function(){var t=new L.Marker(this._marker.getLatLng(),{icon:this.options.icon});L.Draw.Feature.prototype._fireCreatedEvent.call(this,t)}}),L.Edit=L.Edit||{},L.Edit.Poly=L.Handler.extend({options:{icon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon"})},initialize:function(t,e){this._poly=t,L.setOptions(this,e)},addHooks:function(){this._poly._map&&(this._markerGroup||this._initMarkers(),this._poly._map.addLayer(this._markerGroup))},removeHooks:function(){this._poly._map&&(this._poly._map.removeLayer(this._markerGroup),delete this._markerGroup,delete this._markers)},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._markers=[];var t,e,i,o,a=this._poly._latlngs;for(t=0,i=a.length;i>t;t++)o=this._createMarker(a[t],t),o.on("click",this._onMarkerClick,this),this._markers.push(o);var s,r;for(t=0,e=i-1;i>t;e=t++)(0!==t||L.Polygon&&this._poly instanceof L.Polygon)&&(s=this._markers[e],r=this._markers[t],this._createMiddleMarker(s,r),this._updatePrevNext(s,r))},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:this.options.icon});return i._origLatLng=t,i._index=e,i.on("drag",this._onMarkerDrag,this),i.on("dragend",this._fireEdit,this),this._markerGroup.addLayer(i),i},_removeMarker:function(t){var e=t._index;this._markerGroup.removeLayer(t),this._markers.splice(e,1),this._poly.spliceLatLngs(e,1),this._updateIndexes(e,-1),t.off("drag",this._onMarkerDrag,this).off("dragend",this._fireEdit,this).off("click",this._onMarkerClick,this)},_fireEdit:function(){this._poly.edited=!0,this._poly.fire("edit")},_onMarkerDrag:function(t){var e=t.target;L.extend(e._origLatLng,e._latlng),e._middleLeft&&e._middleLeft.setLatLng(this._getMiddleLatLng(e._prev,e)),e._middleRight&&e._middleRight.setLatLng(this._getMiddleLatLng(e,e._next)),this._poly.redraw()},_onMarkerClick:function(t){var e=L.Polygon&&this._poly instanceof L.Polygon?4:3,i=t.target;this._poly._latlngs.lengtht&&(i._index+=e)})},_createMiddleMarker:function(t,e){var i,o,a,s=this._getMiddleLatLng(t,e),r=this._createMarker(s);r.setOpacity(.6),t._middleRight=e._middleLeft=r,o=function(){var o=e._index;r._index=o,r.off("click",i,this).on("click",this._onMarkerClick,this),s.lat=r.getLatLng().lat,s.lng=r.getLatLng().lng,this._poly.spliceLatLngs(o,0,s),this._markers.splice(o,0,r),r.setOpacity(1),this._updateIndexes(o,1),e._index++,this._updatePrevNext(t,r),this._updatePrevNext(r,e),this._poly.fire("editstart")},a=function(){r.off("dragstart",o,this),r.off("dragend",a,this),this._createMiddleMarker(t,r),this._createMiddleMarker(r,e)},i=function(){o.call(this),a.call(this),this._fireEdit()},r.on("click",i,this).on("dragstart",o,this).on("dragend",a,this),this._markerGroup.addLayer(r)},_updatePrevNext:function(t,e){t&&(t._next=e),e&&(e._prev=t)},_getMiddleLatLng:function(t,e){var i=this._poly._map,o=i.project(t.getLatLng()),a=i.project(e.getLatLng());return i.unproject(o._add(a)._divideBy(2))}}),L.Polyline.addInitHook(function(){this.editing||(L.Edit.Poly&&(this.editing=new L.Edit.Poly(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()}))}),L.Edit=L.Edit||{},L.Edit.SimpleShape=L.Handler.extend({options:{moveIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-move"}),resizeIcon:new L.DivIcon({iconSize:new L.Point(8,8),className:"leaflet-div-icon leaflet-editing-icon leaflet-edit-resize"})},initialize:function(t,e){this._shape=t,L.Util.setOptions(this,e)},addHooks:function(){this._shape._map&&(this._map=this._shape._map,this._markerGroup||this._initMarkers(),this._map.addLayer(this._markerGroup))},removeHooks:function(){if(this._shape._map){this._unbindMarker(this._moveMarker);for(var t=0,e=this._resizeMarkers.length;e>t;t++)this._unbindMarker(this._resizeMarkers[t]);this._resizeMarkers=null,this._map.removeLayer(this._markerGroup),delete this._markerGroup}this._map=null},updateMarkers:function(){this._markerGroup.clearLayers(),this._initMarkers()},_initMarkers:function(){this._markerGroup||(this._markerGroup=new L.LayerGroup),this._createMoveMarker(),this._createResizeMarker()},_createMoveMarker:function(){},_createResizeMarker:function(){},_createMarker:function(t,e){var i=new L.Marker(t,{draggable:!0,icon:e,zIndexOffset:10});return this._bindMarker(i),this._markerGroup.addLayer(i),i},_bindMarker:function(t){t.on("dragstart",this._onMarkerDragStart,this).on("drag",this._onMarkerDrag,this).on("dragend",this._onMarkerDragEnd,this)},_unbindMarker:function(t){t.off("dragstart",this._onMarkerDragStart,this).off("drag",this._onMarkerDrag,this).off("dragend",this._onMarkerDragEnd,this)},_onMarkerDragStart:function(t){var e=t.target;e.setOpacity(0),this._shape.fire("editstart")},_fireEdit:function(){this._shape.edited=!0,this._shape.fire("edit")},_onMarkerDrag:function(t){var e=t.target,i=e.getLatLng();e===this._moveMarker?this._move(i):this._resize(i),this._shape.redraw()},_onMarkerDragEnd:function(t){var e=t.target;e.setOpacity(1),this._fireEdit()},_move:function(){},_resize:function(){}}),L.Edit=L.Edit||{},L.Edit.Rectangle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getBounds(),e=t.getCenter();this._moveMarker=this._createMarker(e,this.options.moveIcon)},_createResizeMarker:function(){var t=this._getCorners();this._resizeMarkers=[];for(var e=0,i=t.length;i>e;e++)this._resizeMarkers.push(this._createMarker(t[e],this.options.resizeIcon)),this._resizeMarkers[e]._cornerIndex=e},_onMarkerDragStart:function(t){L.Edit.SimpleShape.prototype._onMarkerDragStart.call(this,t);var e=this._getCorners(),i=t.target,o=i._cornerIndex;this._oppositeCorner=e[(o+2)%4],this._toggleCornerMarkers(0,o)},_onMarkerDragEnd:function(t){var e,i,o=t.target;o===this._moveMarker&&(e=this._shape.getBounds(),i=e.getCenter(),o.setLatLng(i)),this._toggleCornerMarkers(1),this._repositionCornerMarkers(),L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this,t)},_move:function(t){for(var e,i=this._shape.getLatLngs(),o=this._shape.getBounds(),a=o.getCenter(),s=[],r=0,n=i.length;n>r;r++)e=[i[r].lat-a.lat,i[r].lng-a.lng],s.push([t.lat+e[0],t.lng+e[1]]);this._shape.setLatLngs(s),this._repositionCornerMarkers()},_resize:function(t){var e;this._shape.setBounds(L.latLngBounds(t,this._oppositeCorner)),e=this._shape.getBounds(),this._moveMarker.setLatLng(e.getCenter())},_getCorners:function(){var t=this._shape.getBounds(),e=t.getNorthWest(),i=t.getNorthEast(),o=t.getSouthEast(),a=t.getSouthWest();return[e,i,o,a]},_toggleCornerMarkers:function(t){for(var e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setOpacity(t)},_repositionCornerMarkers:function(){for(var t=this._getCorners(),e=0,i=this._resizeMarkers.length;i>e;e++)this._resizeMarkers[e].setLatLng(t[e])}}),L.Rectangle.addInitHook(function(){L.Edit.Rectangle&&(this.editing=new L.Edit.Rectangle(this),this.options.editable&&this.editing.enable())}),L.Edit=L.Edit||{},L.Edit.Circle=L.Edit.SimpleShape.extend({_createMoveMarker:function(){var t=this._shape.getLatLng();this._moveMarker=this._createMarker(t,this.options.moveIcon)},_createResizeMarker:function(){var t=this._shape.getLatLng(),e=this._getResizeMarkerPoint(t);this._resizeMarkers=[],this._resizeMarkers.push(this._createMarker(e,this.options.resizeIcon))},_getResizeMarkerPoint:function(t){var e=this._shape._radius*Math.cos(Math.PI/4),i=this._map.project(t);return this._map.unproject([i.x+e,i.y-e])},_move:function(t){var e=this._getResizeMarkerPoint(t);this._resizeMarkers[0].setLatLng(e),this._shape.setLatLng(t)},_resize:function(t){var e=this._moveMarker.getLatLng(),i=e.distanceTo(t);this._shape.setRadius(i)}}),L.Circle.addInitHook(function(){L.Edit.Circle&&(this.editing=new L.Edit.Circle(this),this.options.editable&&this.editing.enable()),this.on("add",function(){this.editing&&this.editing.enabled()&&this.editing.addHooks()}),this.on("remove",function(){this.editing&&this.editing.enabled()&&this.editing.removeHooks()})}),L.LatLngUtil={cloneLatLngs:function(t){for(var e=[],i=0,o=t.length;o>i;i++)e.push(this.cloneLatLng(t[i]));return e},cloneLatLng:function(t){return L.latLng(t.lat,t.lng)}},L.GeometryUtil=L.extend(L.GeometryUtil||{},{geodesicArea:function(t){var e,i,o=t.length,a=0,s=L.LatLng.DEG_TO_RAD;if(o>2){for(var r=0;o>r;r++)e=t[r],i=t[(r+1)%o],a+=(i.lng-e.lng)*s*(2+Math.sin(e.lat*s)+Math.sin(i.lat*s));a=6378137*a*6378137/2}return Math.abs(a)},readableArea:function(t,e){var i;return e?i=t>=1e4?(1e-4*t).toFixed(2)+" ha":t.toFixed(2)+" m²":(t*=.836127,i=t>=3097600?(t/3097600).toFixed(2)+" mi²":t>=4840?(t/4840).toFixed(2)+" acres":Math.ceil(t)+" yd²"),i},readableDistance:function(t,e){var i;return e?i=t>1e3?(t/1e3).toFixed(2)+" km":Math.ceil(t)+" m":(t*=1.09361,i=t>1760?(t/1760).toFixed(2)+" miles":Math.ceil(t)+" yd"),i}}),L.Util.extend(L.LineUtil,{segmentsIntersect:function(t,e,i,o){return this._checkCounterclockwise(t,i,o)!==this._checkCounterclockwise(e,i,o)&&this._checkCounterclockwise(t,e,i)!==this._checkCounterclockwise(t,e,o)},_checkCounterclockwise:function(t,e,i){return(i.y-t.y)*(e.x-t.x)>(e.y-t.y)*(i.x-t.x)}}),L.Polyline.include({intersects:function(){var t,e,i,o=this._originalPoints,a=o?o.length:0;if(this._tooFewPointsForIntersection())return!1;for(t=a-1;t>=3;t--)if(e=o[t-1],i=o[t],this._lineSegmentsIntersectsRange(e,i,t-2))return!0;return!1},newLatLngIntersects:function(t,e){return this._map?this.newPointIntersects(this._map.latLngToLayerPoint(t),e):!1},newPointIntersects:function(t,e){var i=this._originalPoints,o=i?i.length:0,a=i?i[o-1]:null,s=o-2;return this._tooFewPointsForIntersection(1)?!1:this._lineSegmentsIntersectsRange(a,t,s,e?1:0)},_tooFewPointsForIntersection:function(t){var e=this._originalPoints,i=e?e.length:0;return i+=t||0,!this._originalPoints||3>=i},_lineSegmentsIntersectsRange:function(t,e,i,o){var a,s,r=this._originalPoints;o=o||0;for(var n=i;n>o;n--)if(a=r[n-1],s=r[n],L.LineUtil.segmentsIntersect(t,e,a,s))return!0;return!1}}),L.Polygon.include({intersects:function(){var t,e,i,o,a,s=this._originalPoints;return this._tooFewPointsForIntersection()?!1:(t=L.Polyline.prototype.intersects.call(this))?!0:(e=s.length,i=s[0],o=s[e-1],a=e-2,this._lineSegmentsIntersectsRange(o,i,a,1))}}),L.Control.Draw=L.Control.extend({options:{position:"topleft",draw:{},edit:!1},initialize:function(t){if(L.version<"0.7")throw new Error("Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/");L.Control.prototype.initialize.call(this,t);var e,i;this._toolbars={},L.DrawToolbar&&this.options.draw&&(i=new L.DrawToolbar(this.options.draw),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this)),L.EditToolbar&&this.options.edit&&(i=new L.EditToolbar(this.options.edit),e=L.stamp(i),this._toolbars[e]=i,this._toolbars[e].on("enable",this._toolbarEnabled,this))},onAdd:function(t){var e,i=L.DomUtil.create("div","leaflet-draw"),o=!1,a="leaflet-draw-toolbar-top";for(var s in this._toolbars)this._toolbars.hasOwnProperty(s)&&(e=this._toolbars[s].addToolbar(t),e&&(o||(L.DomUtil.hasClass(e,a)||L.DomUtil.addClass(e.childNodes[0],a),o=!0),i.appendChild(e)));return i},onRemove:function(){for(var t in this._toolbars)this._toolbars.hasOwnProperty(t)&&this._toolbars[t].removeToolbar()},setDrawingOptions:function(t){for(var e in this._toolbars)this._toolbars[e]instanceof L.DrawToolbar&&this._toolbars[e].setOptions(t)},_toolbarEnabled:function(t){var e=""+L.stamp(t.target);for(var i in this._toolbars)this._toolbars.hasOwnProperty(i)&&i!==e&&this._toolbars[i].disable()}}),L.Map.mergeOptions({drawControlTooltips:!0,drawControl:!1}),L.Map.addInitHook(function(){this.options.drawControl&&(this.drawControl=new L.Control.Draw,this.addControl(this.drawControl))}),L.Toolbar=L.Class.extend({includes:[L.Mixin.Events],initialize:function(t){L.setOptions(this,t),this._modes={},this._actionButtons=[],this._activeMode=null},enabled:function(){return null!==this._activeMode},disable:function(){this.enabled()&&this._activeMode.handler.disable()},addToolbar:function(t){var e,i=L.DomUtil.create("div","leaflet-draw-section"),o=0,a=this._toolbarClass||"",s=this.getModeHandlers(t);for(this._toolbarContainer=L.DomUtil.create("div","leaflet-draw-toolbar leaflet-bar"),this._map=t,e=0;ee;e++)this._disposeButton(this._actionButtons[e].button,this._actionButtons[e].callback,this);this._actionButtons=[],this._actionsContainer=null},_initModeHandler:function(t,e,i,o,a){var s=t.type;this._modes[s]={},this._modes[s].handler=t,this._modes[s].button=this._createButton({title:a,className:o+"-"+s,container:e,callback:this._modes[s].handler.enable,context:this._modes[s].handler}),this._modes[s].buttonIndex=i,this._modes[s].handler.on("enabled",this._handlerActivated,this).on("disabled",this._handlerDeactivated,this)},_createButton:function(t){var e=L.DomUtil.create("a",t.className||"",t.container);return e.href="#",t.text&&(e.innerHTML=t.text),t.title&&(e.title=t.title),L.DomEvent.on(e,"click",L.DomEvent.stopPropagation).on(e,"mousedown",L.DomEvent.stopPropagation).on(e,"dblclick",L.DomEvent.stopPropagation).on(e,"click",L.DomEvent.preventDefault).on(e,"click",t.callback,t.context),e},_disposeButton:function(t,e){L.DomEvent.off(t,"click",L.DomEvent.stopPropagation).off(t,"mousedown",L.DomEvent.stopPropagation).off(t,"dblclick",L.DomEvent.stopPropagation).off(t,"click",L.DomEvent.preventDefault).off(t,"click",e)},_handlerActivated:function(t){this.disable(),this._activeMode=this._modes[t.handler],L.DomUtil.addClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._showActionsToolbar(),this.fire("enable")},_handlerDeactivated:function(){this._hideActionsToolbar(),L.DomUtil.removeClass(this._activeMode.button,"leaflet-draw-toolbar-button-enabled"),this._activeMode=null,this.fire("disable")},_createActions:function(t){var e,i,o,a,s=this._actionsContainer,r=this.getActions(t),n=r.length;for(i=0,o=this._actionButtons.length;o>i;i++)this._disposeButton(this._actionButtons[i].button,this._actionButtons[i].callback);for(this._actionButtons=[];s.firstChild;)s.removeChild(s.firstChild);for(var l=0;n>l;l++)"enabled"in r[l]&&!r[l].enabled||(e=L.DomUtil.create("li","",s),a=this._createButton({title:r[l].title,text:r[l].text,container:e,callback:r[l].callback,context:r[l].context}),this._actionButtons.push({button:a,callback:r[l].callback}))},_showActionsToolbar:function(){var t=this._activeMode.buttonIndex,e=this._lastButtonIndex,i=this._activeMode.button.offsetTop-1;this._createActions(this._activeMode.handler),this._actionsContainer.style.top=i+"px",0===t&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-top")),t===e&&(L.DomUtil.addClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.addClass(this._actionsContainer,"leaflet-draw-actions-bottom")),this._actionsContainer.style.display="block"
10 | },_hideActionsToolbar:function(){this._actionsContainer.style.display="none",L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-notop"),L.DomUtil.removeClass(this._toolbarContainer,"leaflet-draw-toolbar-nobottom"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-top"),L.DomUtil.removeClass(this._actionsContainer,"leaflet-draw-actions-bottom")}}),L.Tooltip=L.Class.extend({initialize:function(t){this._map=t,this._popupPane=t._panes.popupPane,this._container=t.options.drawControlTooltips?L.DomUtil.create("div","leaflet-draw-tooltip",this._popupPane):null,this._singleLineLabel=!1},dispose:function(){this._container&&(this._popupPane.removeChild(this._container),this._container=null)},updateContent:function(t){return this._container?(t.subtext=t.subtext||"",0!==t.subtext.length||this._singleLineLabel?t.subtext.length>0&&this._singleLineLabel&&(L.DomUtil.removeClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!1):(L.DomUtil.addClass(this._container,"leaflet-draw-tooltip-single"),this._singleLineLabel=!0),this._container.innerHTML=(t.subtext.length>0?''+t.subtext+" ":"")+""+t.text+" ",this):this},updatePosition:function(t){var e=this._map.latLngToLayerPoint(t),i=this._container;return this._container&&(i.style.visibility="inherit",L.DomUtil.setPosition(i,e)),this},showAsError:function(){return this._container&&L.DomUtil.addClass(this._container,"leaflet-error-draw-tooltip"),this},removeError:function(){return this._container&&L.DomUtil.removeClass(this._container,"leaflet-error-draw-tooltip"),this}}),L.DrawToolbar=L.Toolbar.extend({options:{polyline:{},polygon:{},rectangle:{},circle:{},marker:{}},initialize:function(t){for(var e in this.options)this.options.hasOwnProperty(e)&&t[e]&&(t[e]=L.extend({},this.options[e],t[e]));this._toolbarClass="leaflet-draw-draw",L.Toolbar.prototype.initialize.call(this,t)},getModeHandlers:function(t){return[{enabled:this.options.polyline,handler:new L.Draw.Polyline(t,this.options.polyline),title:L.drawLocal.draw.toolbar.buttons.polyline},{enabled:this.options.polygon,handler:new L.Draw.Polygon(t,this.options.polygon),title:L.drawLocal.draw.toolbar.buttons.polygon},{enabled:this.options.rectangle,handler:new L.Draw.Rectangle(t,this.options.rectangle),title:L.drawLocal.draw.toolbar.buttons.rectangle},{enabled:this.options.circle,handler:new L.Draw.Circle(t,this.options.circle),title:L.drawLocal.draw.toolbar.buttons.circle},{enabled:this.options.marker,handler:new L.Draw.Marker(t,this.options.marker),title:L.drawLocal.draw.toolbar.buttons.marker}]},getActions:function(t){return[{enabled:t.deleteLastVertex,title:L.drawLocal.draw.toolbar.undo.title,text:L.drawLocal.draw.toolbar.undo.text,callback:t.deleteLastVertex,context:t},{title:L.drawLocal.draw.toolbar.actions.title,text:L.drawLocal.draw.toolbar.actions.text,callback:this.disable,context:this}]},setOptions:function(t){L.setOptions(this,t);for(var e in this._modes)this._modes.hasOwnProperty(e)&&t.hasOwnProperty(e)&&this._modes[e].handler.setOptions(t[e])}}),L.EditToolbar=L.Toolbar.extend({options:{edit:{selectedPathOptions:{color:"#fe57a1",opacity:.6,dashArray:"10, 10",fill:!0,fillColor:"#fe57a1",fillOpacity:.1}},remove:{},featureGroup:null},initialize:function(t){t.edit&&("undefined"==typeof t.edit.selectedPathOptions&&(t.edit.selectedPathOptions=this.options.edit.selectedPathOptions),t.edit=L.extend({},this.options.edit,t.edit)),t.remove&&(t.remove=L.extend({},this.options.remove,t.remove)),this._toolbarClass="leaflet-draw-edit",L.Toolbar.prototype.initialize.call(this,t),this._selectedFeatureCount=0},getModeHandlers:function(t){var e=this.options.featureGroup;return[{enabled:this.options.edit,handler:new L.EditToolbar.Edit(t,{featureGroup:e,selectedPathOptions:this.options.edit.selectedPathOptions}),title:L.drawLocal.edit.toolbar.buttons.edit},{enabled:this.options.remove,handler:new L.EditToolbar.Delete(t,{featureGroup:e}),title:L.drawLocal.edit.toolbar.buttons.remove}]},getActions:function(){return[{title:L.drawLocal.edit.toolbar.actions.save.title,text:L.drawLocal.edit.toolbar.actions.save.text,callback:this._save,context:this},{title:L.drawLocal.edit.toolbar.actions.cancel.title,text:L.drawLocal.edit.toolbar.actions.cancel.text,callback:this.disable,context:this}]},addToolbar:function(t){var e=L.Toolbar.prototype.addToolbar.call(this,t);return this._checkDisabled(),this.options.featureGroup.on("layeradd layerremove",this._checkDisabled,this),e},removeToolbar:function(){this.options.featureGroup.off("layeradd layerremove",this._checkDisabled,this),L.Toolbar.prototype.removeToolbar.call(this)},disable:function(){this.enabled()&&(this._activeMode.handler.revertLayers(),L.Toolbar.prototype.disable.call(this))},_save:function(){this._activeMode.handler.save(),this._activeMode.handler.disable()},_checkDisabled:function(){var t,e=this.options.featureGroup,i=0!==e.getLayers().length;this.options.edit&&(t=this._modes[L.EditToolbar.Edit.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.edit:L.drawLocal.edit.toolbar.buttons.editDisabled)),this.options.remove&&(t=this._modes[L.EditToolbar.Delete.TYPE].button,i?L.DomUtil.removeClass(t,"leaflet-disabled"):L.DomUtil.addClass(t,"leaflet-disabled"),t.setAttribute("title",i?L.drawLocal.edit.toolbar.buttons.remove:L.drawLocal.edit.toolbar.buttons.removeDisabled))}}),L.EditToolbar.Edit=L.Handler.extend({statics:{TYPE:"edit"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),this._selectedPathOptions=e.selectedPathOptions,this._featureGroup=e.featureGroup,!(this._featureGroup instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this._uneditedLayerProps={},this.type=L.EditToolbar.Edit.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire("draw:editstart",{handler:this.type}),L.Handler.prototype.enable.call(this),this._featureGroup.on("layeradd",this._enableLayerEdit,this).on("layerremove",this._disableLayerEdit,this))},disable:function(){this._enabled&&(this._featureGroup.off("layeradd",this._enableLayerEdit,this).off("layerremove",this._disableLayerEdit,this),L.Handler.prototype.disable.call(this),this._map.fire("draw:editstop",{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._featureGroup.eachLayer(this._enableLayerEdit,this),this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.edit.tooltip.text,subtext:L.drawLocal.edit.handlers.edit.tooltip.subtext}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._featureGroup.eachLayer(this._disableLayerEdit,this),this._uneditedLayerProps={},this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._featureGroup.eachLayer(function(t){this._revertLayer(t)},this)},save:function(){var t=new L.LayerGroup;this._featureGroup.eachLayer(function(e){e.edited&&(t.addLayer(e),e.edited=!1)}),this._map.fire("draw:edited",{layers:t})},_backupLayer:function(t){var e=L.Util.stamp(t);this._uneditedLayerProps[e]||(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?this._uneditedLayerProps[e]={latlngs:L.LatLngUtil.cloneLatLngs(t.getLatLngs())}:t instanceof L.Circle?this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng()),radius:t.getRadius()}:t instanceof L.Marker&&(this._uneditedLayerProps[e]={latlng:L.LatLngUtil.cloneLatLng(t.getLatLng())}))},_revertLayer:function(t){var e=L.Util.stamp(t);t.edited=!1,this._uneditedLayerProps.hasOwnProperty(e)&&(t instanceof L.Polyline||t instanceof L.Polygon||t instanceof L.Rectangle?t.setLatLngs(this._uneditedLayerProps[e].latlngs):t instanceof L.Circle?(t.setLatLng(this._uneditedLayerProps[e].latlng),t.setRadius(this._uneditedLayerProps[e].radius)):t instanceof L.Marker&&t.setLatLng(this._uneditedLayerProps[e].latlng))},_toggleMarkerHighlight:function(t){if(t._icon){var e=t._icon;e.style.display="none",L.DomUtil.hasClass(e,"leaflet-edit-marker-selected")?(L.DomUtil.removeClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,-4)):(L.DomUtil.addClass(e,"leaflet-edit-marker-selected"),this._offsetMarker(e,4)),e.style.display=""}},_offsetMarker:function(t,e){var i=parseInt(t.style.marginTop,10)-e,o=parseInt(t.style.marginLeft,10)-e;t.style.marginTop=i+"px",t.style.marginLeft=o+"px"},_enableLayerEdit:function(t){var e,i=t.layer||t.target||t,o=i instanceof L.Marker;(!o||i._icon)&&(this._backupLayer(i),this._selectedPathOptions&&(e=L.Util.extend({},this._selectedPathOptions),o?this._toggleMarkerHighlight(i):(i.options.previousOptions=L.Util.extend({dashArray:null},i.options),i instanceof L.Circle||i instanceof L.Polygon||i instanceof L.Rectangle||(e.fill=!1),i.setStyle(e))),o?(i.dragging.enable(),i.on("dragend",this._onMarkerDragEnd)):i.editing.enable())},_disableLayerEdit:function(t){var e=t.layer||t.target||t;e.edited=!1,this._selectedPathOptions&&(e instanceof L.Marker?this._toggleMarkerHighlight(e):(e.setStyle(e.options.previousOptions),delete e.options.previousOptions)),e instanceof L.Marker?(e.dragging.disable(),e.off("dragend",this._onMarkerDragEnd,this)):e.editing.disable()},_onMarkerDragEnd:function(t){var e=t.target;e.edited=!0},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._featureGroup.getLayers().length}}),L.EditToolbar.Delete=L.Handler.extend({statics:{TYPE:"remove"},includes:L.Mixin.Events,initialize:function(t,e){if(L.Handler.prototype.initialize.call(this,t),L.Util.setOptions(this,e),this._deletableLayers=this.options.featureGroup,!(this._deletableLayers instanceof L.FeatureGroup))throw new Error("options.featureGroup must be a L.FeatureGroup");this.type=L.EditToolbar.Delete.TYPE},enable:function(){!this._enabled&&this._hasAvailableLayers()&&(this.fire("enabled",{handler:this.type}),this._map.fire("draw:deletestart",{handler:this.type}),L.Handler.prototype.enable.call(this),this._deletableLayers.on("layeradd",this._enableLayerDelete,this).on("layerremove",this._disableLayerDelete,this))},disable:function(){this._enabled&&(this._deletableLayers.off("layeradd",this._enableLayerDelete,this).off("layerremove",this._disableLayerDelete,this),L.Handler.prototype.disable.call(this),this._map.fire("draw:deletestop",{handler:this.type}),this.fire("disabled",{handler:this.type}))},addHooks:function(){var t=this._map;t&&(t.getContainer().focus(),this._deletableLayers.eachLayer(this._enableLayerDelete,this),this._deletedLayers=new L.layerGroup,this._tooltip=new L.Tooltip(this._map),this._tooltip.updateContent({text:L.drawLocal.edit.handlers.remove.tooltip.text}),this._map.on("mousemove",this._onMouseMove,this))},removeHooks:function(){this._map&&(this._deletableLayers.eachLayer(this._disableLayerDelete,this),this._deletedLayers=null,this._tooltip.dispose(),this._tooltip=null,this._map.off("mousemove",this._onMouseMove,this))},revertLayers:function(){this._deletedLayers.eachLayer(function(t){this._deletableLayers.addLayer(t)},this)},save:function(){this._map.fire("draw:deleted",{layers:this._deletedLayers})},_enableLayerDelete:function(t){var e=t.layer||t.target||t;e.on("click",this._removeLayer,this)},_disableLayerDelete:function(t){var e=t.layer||t.target||t;e.off("click",this._removeLayer,this),this._deletedLayers.removeLayer(e)},_removeLayer:function(t){var e=t.layer||t.target||t;this._deletableLayers.removeLayer(e),this._deletedLayers.addLayer(e)},_onMouseMove:function(t){this._tooltip.updatePosition(t.latlng)},_hasAvailableLayers:function(){return 0!==this._deletableLayers.getLayers().length}})}(window,document);
11 | // Leaflet.fullscreen
12 | L.Control.Fullscreen=L.Control.extend({options:{position:"topleft",title:{"false":"View Fullscreen","true":"Exit Fullscreen"}},onAdd:function(map){var container=L.DomUtil.create("div","leaflet-control-fullscreen leaflet-bar leaflet-control");this.link=L.DomUtil.create("a","leaflet-control-fullscreen-button leaflet-bar-part",container);this.link.href="#";this._map=map;this._map.on("fullscreenchange",this._toggleTitle,this);this._toggleTitle();L.DomEvent.on(this.link,"click",this._click,this);return container},_click:function(e){L.DomEvent.stopPropagation(e);L.DomEvent.preventDefault(e);this._map.toggleFullscreen(this.options)},_toggleTitle:function(){this.link.title=this.options.title[this._map.isFullscreen()]}});L.Map.include({isFullscreen:function(){return this._isFullscreen||false},toggleFullscreen:function(options){var container=this.getContainer();if(this.isFullscreen()){if(options&&options.pseudoFullscreen){this._disablePseudoFullscreen(container)}else if(document.exitFullscreen){document.exitFullscreen()}else if(document.mozCancelFullScreen){document.mozCancelFullScreen()}else if(document.webkitCancelFullScreen){document.webkitCancelFullScreen()}else if(document.msExitFullscreen){document.msExitFullscreen()}else{this._disablePseudoFullscreen(container)}}else{if(options&&options.pseudoFullscreen){this._enablePseudoFullscreen(container)}else if(container.requestFullscreen){container.requestFullscreen()}else if(container.mozRequestFullScreen){container.mozRequestFullScreen()}else if(container.webkitRequestFullscreen){container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else if(container.msRequestFullscreen){container.msRequestFullscreen()}else{this._enablePseudoFullscreen(container)}}},_enablePseudoFullscreen:function(container){L.DomUtil.addClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(true);this.invalidateSize();this.fire("fullscreenchange")},_disablePseudoFullscreen:function(container){L.DomUtil.removeClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(false);this.invalidateSize();this.fire("fullscreenchange")},_setFullscreen:function(fullscreen){this._isFullscreen=fullscreen;var container=this.getContainer();if(fullscreen){L.DomUtil.addClass(container,"leaflet-fullscreen-on")}else{L.DomUtil.removeClass(container,"leaflet-fullscreen-on")}},_onFullscreenChange:function(e){var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;if(fullscreenElement===this.getContainer()&&!this._isFullscreen){this._setFullscreen(true);this.fire("fullscreenchange")}else if(fullscreenElement!==this.getContainer()&&this._isFullscreen){this._setFullscreen(false);this.fire("fullscreenchange")}}});L.Map.mergeOptions({fullscreenControl:false});L.Map.addInitHook(function(){if(this.options.fullscreenControl){this.fullscreenControl=new L.Control.Fullscreen(this.options.fullscreenControl);this.addControl(this.fullscreenControl)}var fullscreenchange;if("onfullscreenchange"in document){fullscreenchange="fullscreenchange"}else if("onmozfullscreenchange"in document){fullscreenchange="mozfullscreenchange"}else if("onwebkitfullscreenchange"in document){fullscreenchange="webkitfullscreenchange"}else if("onmsfullscreenchange"in document){fullscreenchange="MSFullscreenChange"}if(fullscreenchange){var onFullscreenChange=L.bind(this._onFullscreenChange,this);this.whenReady(function(){L.DomEvent.on(document,fullscreenchange,onFullscreenChange)});this.on("unload",function(){L.DomEvent.off(document,fullscreenchange,onFullscreenChange)})}});L.control.fullscreen=function(options){return new L.Control.Fullscreen(options)};
13 | // Leaflet.sync
14 | var NO_ANIMATION ={animate:false,reset:true}; L.Map = L.Map.extend({sync:function(map,options){this._initSync();options = L.extend({noInitialSync:false,syncCursor:false,syncCursorMarkerOptions:{radius:10,fillOpacity:0.3,color:'#da291c',fillColor:'#fff'}},options); if(this._syncMaps.indexOf(map)=== -1){this._syncMaps.push(map);} if(!options.noInitialSync){map.setView(this.getCenter(),this.getZoom(),NO_ANIMATION);}if(options.syncCursor){map.cursor = L.circleMarker([0,0],options.syncCursorMarkerOptions).addTo(map); this._cursors.push(map.cursor); this.on('mousemove',this._cursorSyncMove,this);this.on('mouseout',this._cursorSyncOut,this);}return this;}, _cursorSyncMove:function(e){this._cursors.forEach(function(cursor){cursor.setLatLng(e.latlng);});}, _cursorSyncOut:function(e){this._cursors.forEach(function(cursor){cursor.setLatLng([0,0]);});}, unsync:function(map){var self = this; if(this._syncMaps){this._syncMaps.forEach(function(synced,id){if(map === synced){self._syncMaps.splice(id,1);if(map.cursor){map.cursor.removeFrom(map);}}});}this.off('mousemove',this._cursorSyncMove,this);this.off('mouseout',this._cursorSyncOut,this); return this;}, isSynced:function(){return(this.hasOwnProperty('_syncMaps')&& Object.keys(this._syncMaps).length > 0);}, _initSync:function(){if(this._syncMaps){return;}var originalMap = this; this._syncMaps = [];this._cursors = []; L.extend(originalMap,{setView:function(center,zoom,options,sync){if(!sync){originalMap._syncMaps.forEach(function(toSync){toSync.setView(center,zoom,options,true);});}return L.Map.prototype.setView.call(this,center,zoom,options);}, panBy:function(offset,options,sync){if(!sync){originalMap._syncMaps.forEach(function(toSync){toSync.panBy(offset,options,true);});}return L.Map.prototype.panBy.call(this,offset,options);}, _onResize:function(event,sync){if(!sync){originalMap._syncMaps.forEach(function(toSync){toSync._onResize(event,true);});}return L.Map.prototype._onResize.call(this,event);}}); originalMap.on('zoomend',function(){originalMap._syncMaps.forEach(function(toSync){toSync.setView(originalMap.getCenter(),originalMap.getZoom(),NO_ANIMATION);});},this); originalMap.dragging._draggable._updatePosition = function(){L.Draggable.prototype._updatePosition.call(this);var self = this;originalMap._syncMaps.forEach(function(toSync){L.DomUtil.setPosition(toSync.dragging._draggable._element,self._newPos);toSync.eachLayer(function(layer){if(layer._google !== undefined){layer._google.setCenter(originalMap.getCenter());}});toSync.fire('moveend');});};}});
15 |
16 | // https://d3js.org/d3-collection/ Version 1.0.0. Copyright 2016 Mike Bostock.
17 | !function(n,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(n.d3=n.d3||{})}(this,function(n){"use strict";function t(){}function e(n,e){var r=new t;if(n instanceof t)n.each(function(n,t){r.set(t,n)});else if(Array.isArray(n)){var i,u=-1,o=n.length;if(null==e)for(;++u=a.length)return null!=f?f(t):null!=r?t.sort(r):t;for(var s,c,h,l=-1,v=t.length,p=a[i++],y=e(),d=u();++la.length)return n;var r,i=h[e-1];return null!=f&&e>=a.length?r=n.entries():(r=[],n.each(function(n,i){r.push({key:i,values:t(n,e)})})),null!=i?r.sort(function(n,t){return i(n.key,t.key)}):r}var r,f,c,a=[],h=[];return c={object:function(t){return n(t,0,i,u)},map:function(t){return n(t,0,o,s)},entries:function(e){return t(n(e,0,o,s),0)},key:function(n){return a.push(n),c},sortKeys:function(n){return h[a.length-1]=n,c},sortValues:function(n){return r=n,c},rollup:function(n){return f=n,c}}}function i(){return{}}function u(n,t,e){n[t]=e}function o(){return e()}function s(n,t,e){n.set(t,e)}function f(){}function c(n,t){var e=new f;if(n instanceof f)n.each(function(n){e.add(n)});else if(n){var r=-1,i=n.length;if(null==t)for(;++r=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),Ut.hasOwnProperty(n)?{space:Ut[n],local:t}:t}function e(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===It&&n.documentElement.namespaceURI===It?n.createElement(t):n.createElementNS(e,t)}}function r(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function i(t){var i=n(t);return(i.local?r:e)(i)}function o(){return new u}function u(){this._="@"+(++kt).toString(36)}function c(t,n,e){return t=s(t,n,e),function(n){var e=n.relatedTarget;e&&(e===this||8&e.compareDocumentPosition(this))||t.call(this,n)}}function s(n,e,r){return function(i){var o=t.event;t.event=i;try{n.call(this,this.__data__,e,r)}finally{t.event=o}}}function a(t){return t.trim().split(/^|\s+/).map(function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}})}function l(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r=A&&(A=w+1);!(g=d[A])&&++A<_;);y._next=g||null}}return u=new Dt(u,r),u._enter=c,u._exit=s,u}function T(){return new Dt(this._exit||this._groups.map(b),this._parents)}function q(t){for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),u=new Array(r),c=0;c=0;)(r=i[o])&&(u&&u!==r.nextSibling&&u.parentNode.insertBefore(r,u),u=r);return this}function B(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=D);for(var e=this._groups,r=e.length,i=new Array(r),o=0;on?1:t>=n?0:NaN}function V(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this}function R(){var t=new Array(this.size()),n=-1;return this.each(function(){t[++n]=this}),t}function j(){for(var t=this._groups,n=0,e=t.length;n1?this.each((null==n?K:"function"==typeof n?W:Q)(t,n,null==e?"":e)):J(r=this.node()).getComputedStyle(r,null).getPropertyValue(t)}function tt(t){return function(){delete this[t]}}function nt(t,n){return function(){this[t]=n}}function et(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function rt(t,n){return arguments.length>1?this.each((null==n?tt:"function"==typeof n?et:nt)(t,n)):this.node()[t]}function it(t){return t.trim().split(/^|\s+/)}function ot(t){return t.classList||new ut(t)}function ut(t){this._node=t,this._names=it(t.getAttribute("class")||"")}function ct(t,n){for(var e=ot(t),r=-1,i=n.length;++r=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var Qt=[null];Dt.prototype=Vt.prototype={constructor:Dt,select:g,selectAll:x,filter:S,data:P,enter:E,exit:T,merge:q,order:O,sort:B,call:V,nodes:R,node:j,size:z,empty:H,each:I,attr:F,style:Z,property:rt,classed:ht,text:dt,html:wt,raise:xt,lower:bt,append:Et,insert:Ct,remove:Lt,datum:Pt,on:h,dispatch:Bt},t.creator=i,t.local=o,t.matcher=$t,t.mouse=d,t.namespace=n,t.namespaces=Ut,t.select=Rt,t.selectAll=jt,t.selection=Vt,t.selector=y,t.selectorAll=A,t.touch=zt,t.touches=Ht,t.window=J,t.customEvent=p,Object.defineProperty(t,"__esModule",{value:!0})});
20 | // https://d3js.org/d3-dispatch/ Version 1.0.0. Copyright 2016 Mike Bostock.
21 | !function(n,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e(n.d3=n.d3||{})}(this,function(n){"use strict";function e(){for(var n,e=0,r=arguments.length,o={};r>e;++e){if(!(n=arguments[e]+"")||n in o)throw new Error("illegal type: "+n);o[n]=[]}return new t(o)}function t(n){this._=n}function r(n,e){return n.trim().split(/^|\s+/).map(function(n){var t="",r=n.indexOf(".");if(r>=0&&(t=n.slice(r+1),n=n.slice(0,r)),n&&!e.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:t}})}function o(n,e){for(var t,r=0,o=n.length;o>r;++r)if((t=n[r]).name===e)return t.value}function i(n,e,t){for(var r=0,o=n.length;o>r;++r)if(n[r].name===e){n[r]=f,n=n.slice(0,r).concat(n.slice(r+1));break}return null!=t&&n.push({name:e,value:t}),n}var f={value:function(){}};t.prototype=e.prototype={constructor:t,on:function(n,e){var t,f=this._,l=r(n+"",f),u=-1,a=l.length;{if(!(arguments.length<2)){if(null!=e&&"function"!=typeof e)throw new Error("invalid callback: "+e);for(;++u0)for(var t,r,o=new Array(t),i=0;t>i;++i)o[i]=arguments[i+2];if(!this._.hasOwnProperty(n))throw new Error("unknown type: "+n);for(r=this._[n],i=0,t=r.length;t>i;++i)r[i].value.apply(e,o)},apply:function(n,e,t){if(!this._.hasOwnProperty(n))throw new Error("unknown type: "+n);for(var r=this._[n],o=0,i=r.length;i>o;++o)r[o].value.apply(e,t)}},n.dispatch=e,Object.defineProperty(n,"__esModule",{value:!0})});
22 | // https://d3js.org/d3-request/ Version 1.0.0. Copyright 2016 Mike Bostock.
23 | !function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("d3-collection"),require("d3-dispatch"),require("d3-dsv")):"function"==typeof define&&define.amd?define(["exports","d3-collection","d3-dispatch","d3-dsv"],n):n(e.d3=e.d3||{},e.d3,e.d3,e.d3)}(this,function(e,n,t,r){"use strict";function o(e,r){function o(e){var n,t=d.status;if(!t&&s(d)||t>=200&&300>t||304===t){if(c)try{n=c.call(l,d)}catch(r){return void p.call("error",l,r)}else n=d;p.call("load",l,n)}else p.call("error",l,e)}var l,i,c,a,p=t.dispatch("beforesend","progress","load","error"),f=n.map(),d=new XMLHttpRequest,h=null,m=null,v=0;return"undefined"==typeof XDomainRequest||"withCredentials"in d||!/^(http(s)?:)?\/\//.test(e)||(d=new XDomainRequest),"onload"in d?d.onload=d.onerror=d.ontimeout=o:d.onreadystatechange=function(e){d.readyState>3&&o(e)},d.onprogress=function(e){p.call("progress",l,e)},l={header:function(e,n){return e=(e+"").toLowerCase(),arguments.length<2?f.get(e):(null==n?f.remove(e):f.set(e,n+""),l)},mimeType:function(e){return arguments.length?(i=null==e?null:e+"",l):i},responseType:function(e){return arguments.length?(a=e,l):a},timeout:function(e){return arguments.length?(v=+e,l):v},user:function(e){return arguments.length<1?h:(h=null==e?null:e+"",l)},password:function(e){return arguments.length<1?m:(m=null==e?null:e+"",l)},response:function(e){return c=e,l},get:function(e,n){return l.send("GET",e,n)},post:function(e,n){return l.send("POST",e,n)},send:function(n,t,r){return r||"function"!=typeof t||(r=t,t=null),r&&1===r.length&&(r=u(r)),d.open(n,e,!0,h,m),null==i||f.has("accept")||f.set("accept",i+",*/*"),d.setRequestHeader&&f.each(function(e,n){d.setRequestHeader(n,e)}),null!=i&&d.overrideMimeType&&d.overrideMimeType(i),null!=a&&(d.responseType=a),v>0&&(d.timeout=v),r&&l.on("error",r).on("load",function(e){r(null,e)}),p.call("beforesend",l,d),d.send(null==t?null:t),l},abort:function(){return d.abort(),l},on:function(){var e=p.on.apply(p,arguments);return e===p?l:e}},r?l.get(r):l}function u(e){return function(n,t){e(null==n?t:null)}}function s(e){var n=e.responseType;return n&&"text"!==n?e.response:e.responseText}function l(e,n){return function(t,r){var u=o(t).mimeType(e).response(n);return r?u.get(r):u}}function i(e,n){return function(t,r,u){arguments.length<3&&(u=r,r=null);var s=o(t).mimeType(e);return s.row=function(e){return arguments.length?s.response(c(n,r=e)):r},s.row(r),u?s.get(u):s}}function c(e,n){return function(t){return e(t.responseText,n)}}var a=l("text/html",function(e){return document.createRange().createContextualFragment(e.responseText)}),p=l("application/json",function(e){return JSON.parse(e.responseText)}),f=l("text/plain",function(e){return e.responseText}),d=l("application/xml",function(e){var n=e.responseXML;if(!n)throw new Error("parse error");return n}),h=i("text/csv",r.csvParse),m=i("text/tab-separated-values",r.tsvParse);e.request=o,e.html=a,e.json=p,e.text=f,e.xml=d,e.csv=h,e.tsv=m,Object.defineProperty(e,"__esModule",{value:!0})});
--------------------------------------------------------------------------------
/docs/map.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Where2 map
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/docs/script.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | document.onreadystatechange = function () {
4 | if (document.readyState !== "interactive") return;
5 |
6 | d3.selectAll("header, title").html(snippets.title + " — API Docs");
7 | d3.select("#description").html(snippets.description);
8 | d3.select("#datasets").html(Object.keys(schema).map(function (d) {
9 | return '' + d + ' ' + " Property Type Example " + Object.keys(schema[d]).map(function (p) {
10 | return "" + p + " " + schema[d][p].type + " " + schema[d][p].example + " ";
11 | }).join("") + "
";
12 | }).join(" ") + " ");
13 | d3.select("#opt-dataset").html(Object.keys(schema).map(function (d) {
14 | return "" + d + " ";
15 | }).join(""));
16 |
17 | d3.select(".opt-spatial").on("change", function () {
18 | d3.select("input.in-spatial").style("display", d3.event.target.value === "DistWithin" ? "inline-block" : "none");
19 | });
20 |
21 | fillProperties();
22 | d3.select("#opt-dataset").on("change", fillProperties);
23 |
24 | d3.selectAll(".cb").on("change", function () {
25 | d3.selectAll(".in-" + d3.event.target.id.split("-")[1]).property('disabled', !d3.event.target.checked);
26 | });
27 |
28 | var map1 = L.map('map1', {
29 | scrollWheelZoom: false
30 | }).setView(snippets.map_center, snippets.map_zoom);
31 | var map2 = L.map('map2', {
32 | scrollWheelZoom: false
33 | }).setView(snippets.map_center, snippets.map_zoom);
34 |
35 | map1.sync(map2);
36 | map2.sync(map1);
37 |
38 | d3.select('#sel-datasets').on("click", toggleView);
39 | d3.select('#sel-documentation').on("click", toggleView);
40 | d3.select('#sel-query-builder').on("click", function () {
41 | toggleView();
42 | map1.invalidateSize();
43 | map2.invalidateSize();
44 | });
45 |
46 | function toggleView() {
47 | d3.selectAll('.view').style("display", "none");
48 | d3.select('#' + d3.event.target.id.split("sel-")[1]).style("display", "block");
49 | d3.select('.selection .selected').classed('selected', false);
50 | d3.select('#' + d3.event.target.id).classed('selected', true);
51 | }
52 |
53 | L.control.fullscreen().addTo(map2);
54 |
55 | var drawControl = new L.Control.Draw({
56 | draw: {
57 | circle: false
58 | }
59 | });
60 |
61 | map1.addControl(drawControl);
62 |
63 | map1.addLayer(L.tileLayer('http://a.tile.stamen.com/toner/${z}/${x}/${y}.png', {
64 | attribution: '© OpenStreetMap contributors',
65 | subdomains: 'abcd',
66 | minZoom: 0,
67 | maxZoom: 18
68 | }));
69 | map2.addLayer(L.tileLayer('http://a.tile.stamen.com/toner/${z}/${x}/${y}.png', {
70 | attribution: '© OpenStreetMap contributors',
71 | subdomains: 'abcd',
72 | minZoom: 0,
73 | maxZoom: 18
74 | }));
75 |
76 | var drawingLayer, geojsonLayer;
77 |
78 | map1.on('draw:created', function (e) {
79 | var type = e.layerType;
80 | drawingLayer = e.layer;
81 | drawingLayer.addTo(map1);
82 | });
83 |
84 | map1.on('draw:drawstart', function () {
85 | if (drawingLayer) map1.removeLayer(drawingLayer);
86 | });
87 |
88 | map2.on('fullscreenchange', function () {
89 | if (map2.isFullscreen()) {
90 | map1.unsync(map2);
91 | map2.unsync(map1);
92 | map2.scrollWheelZoom.enable();
93 | } else {
94 | map2.scrollWheelZoom.disable();
95 | map2.invalidateSize();
96 | map1.panTo(map2.getCenter());
97 | map1.setZoom(map2.getZoom());
98 | map1.sync(map2);
99 | map2.sync(map1);
100 | }
101 | });
102 |
103 | d3.select("#send").on("click", function () {
104 | if (geojsonLayer) map2.removeLayer(geojsonLayer);
105 |
106 | var where = {
107 | dataset: d3.select("#opt-dataset").property("value")
108 | };
109 | if (d3.select("#cb-query").node().checked) where.query = {
110 | prop: d3.select("#container-query .opt-properties").property("value"),
111 | op: d3.select("#query-operator").property("value"),
112 | val: isNaN(+d3.select("#query-value").property("value")) ? d3.select("#query-value").property("value") : +d3.select("#query-value").property("value")
113 | };
114 | if (d3.select("#cb-spatial").node().checked) {
115 | where.spatial = {
116 | relation: d3.select(".opt-spatial").property("value"),
117 | geometry: drawingLayer ? drawingLayer.toGeoJSON().geometry : ""
118 | };
119 | if (where.spatial.relation === "DistWithin") where.spatial.distance = +d3.select("input.in-spatial").property("value");
120 | }
121 | if (d3.select("#cb-properties").node().checked) where.properties = d3.selectAll("#container-properties .in-properties").nodes().map(function (el) {
122 | return el.checked ? el.value : false;
123 | }).filter(function (el) {
124 | return el;
125 | });
126 | if (d3.select("#cb-sort").node().checked) where.sort = {
127 | by: d3.select(".opt-properties.in-sort").property("value"),
128 | desc: d3.select("#cb-desc").node().checked
129 | };
130 | if (d3.select("#cb-limit").node().checked) where.limit = d3.select(".in-limit").property("value");
131 | if (d3.select("#cb-offset").node().checked) where.offset = d3.select(".in-offset").property("value");
132 |
133 | d3.select("#req_URL").attr("href", url + "/q/" + encodeURIComponent(JSON.stringify(where))).text(url + "/q/" + encodeURIComponent(JSON.stringify(where)));
134 | d3.select("#map_URL").attr("href", url + "/map/" + encodeURIComponent(JSON.stringify(where))).text(url + "/map/" + encodeURIComponent(JSON.stringify(where)));
135 | d3.select("#req_body").text(JSON.stringify(where, null, " "));
136 | d3.select("#request").style("display", "block");
137 |
138 | d3.request(url + "/q").header("X-Requested-With", "XMLHttpRequest").header("Content-Type", "application/json").post(JSON.stringify(where), function (err, data) {
139 | if (err) throw err;
140 |
141 | d3.select("#res_body").text(JSON.stringify(JSON.parse(data.response), null, " "));
142 | geojsonLayer = L.geoJson(JSON.parse(data.response), {
143 | onEachFeature: function onEachFeature(feature, layer) {
144 | layer.bindPopup("" + Object.keys(feature.properties).map(function (k) {
145 | return "" + k + " " + feature.properties[k] + " ";
146 | }).join("") + "
");
147 | }
148 | });
149 | map2.fitBounds(geojsonLayer.getBounds());
150 | geojsonLayer.addTo(map2);
151 | });
152 | });
153 | };
154 |
155 | function fillProperties() {
156 | d3.selectAll(".opt-properties").html(Object.keys(schema[d3.select("#opt-dataset").property("value")]).map(function (d) {
157 | return "" + d + " ";
158 | }).join(""));
159 | d3.select("#container-properties").html(Object.keys(schema[d3.select("#opt-dataset").property("value")]).map(function (d) {
160 | return ' ' + d + ' ';
161 | }).join(""));
162 | }
163 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 |
2 | var fork = require('child_process').fork,
3 | cron = require('node-cron'),
4 | restify = require('restify'),
5 | sqlite = require('spatialite'),
6 | docs = require('./docs/docs.js'),
7 |
8 | config = require('./config.json')
9 |
10 | var db, structure = {}, ready
11 |
12 | init_server()
13 |
14 | function create_db() {
15 | fork('db/db_init.js').on('message', (m) => {
16 | if (m === "done") {
17 | create_table(0)
18 | }
19 | })
20 | }
21 |
22 | function create_table(i) {
23 | if (i === config.data.length) {
24 | schedule()
25 | init_db()
26 | return
27 | }
28 | var opt = {
29 | db_name: config.db_name,
30 | data_dir: config.data_dir,
31 | dataset: config.data[i]
32 | }
33 | fork('db/db_update.js', [JSON.stringify(opt)]).on('message', (m) => {
34 | structure[m.dataset] = m.schema
35 | console.log(m.dataset + " created at " + new Date().toISOString())
36 | create_table(i + 1)
37 | })
38 | }
39 |
40 | function init_db() {
41 | db = new sqlite.Database(config.db_name, sqlite.OPEN_READONLY, function() {
42 | ready = true
43 | console.log("ready")
44 | })
45 | }
46 |
47 | function init_server() {
48 | var server = restify.createServer()
49 |
50 | server.use(restify.CORS())
51 |
52 | restify.CORS.ALLOW_HEADERS.push("authorization")
53 | restify.CORS.ALLOW_HEADERS.push("withcredentials")
54 | restify.CORS.ALLOW_HEADERS.push("x-requested-with")
55 | restify.CORS.ALLOW_HEADERS.push("x-forwarded-for")
56 | restify.CORS.ALLOW_HEADERS.push("x-real-ip")
57 | restify.CORS.ALLOW_HEADERS.push("x-customheader")
58 | restify.CORS.ALLOW_HEADERS.push("user-agent")
59 | restify.CORS.ALLOW_HEADERS.push("keep-alive")
60 | restify.CORS.ALLOW_HEADERS.push("host")
61 | restify.CORS.ALLOW_HEADERS.push("accept")
62 | restify.CORS.ALLOW_HEADERS.push("connection")
63 | restify.CORS.ALLOW_HEADERS.push("upgrade")
64 | restify.CORS.ALLOW_HEADERS.push("content-type")
65 | restify.CORS.ALLOW_HEADERS.push("dnt") // Do not track
66 | restify.CORS.ALLOW_HEADERS.push("if-modified-since")
67 | restify.CORS.ALLOW_HEADERS.push("cache-control")
68 |
69 | server.on("MethodNotAllowed", function(request, response) {
70 | if (request.method.toUpperCase() === "OPTIONS") {
71 | response.header("Access-Control-Allow-Credentials", true)
72 | response.header("Access-Control-Allow-Headers", restify.CORS.ALLOW_HEADERS.join(", "))
73 | response.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
74 | response.header("Access-Control-Allow-Origin", request.headers.origin)
75 | response.header("Access-Control-Max-Age", 0)
76 | response.header("Content-type", "text/plain charset=UTF-8")
77 | response.header("Content-length", 0)
78 | response.send(204)
79 | } else {
80 | response.send(new restify.MethodNotAllowedError())
81 | }
82 | })
83 |
84 | server.get('/', (req, res) => {
85 | getDocs(res)
86 | })
87 |
88 | server.get('/q/:query', (req, res) => {
89 | try {
90 | prepare_query(JSON.parse(req.params.query), res)
91 | } catch (e) {
92 | res.send(400, {
93 | error: 'malformed request'
94 | })
95 | }
96 | })
97 |
98 | server.get('/map/:query', (req, res) => {
99 | getMap(JSON.parse(req.params.query), res)
100 | })
101 |
102 |
103 | server.use(restify.bodyParser())
104 | server.post('/q', (req, res) => {
105 | try {
106 | prepare_query(req.params, res)
107 | } catch (e) {
108 | res.send(400, {
109 | error: 'malformed request'
110 | })
111 | }
112 | })
113 |
114 | server.listen((process.env.PORT || config.server_port), function() {
115 | console.log('where2 listening at port %s', (process.env.PORT || config.server_port))
116 | create_db()
117 | })
118 | }
119 |
120 | function prepare_query(req, res) {
121 | if (!req.dataset) {
122 | res.send(400, {
123 | error: 'missing parameter \'dataset\'',
124 | 'avaiable datasets': Object.keys(config.data)
125 | })
126 | return
127 | }
128 | if (Object.keys(structure).indexOf(req.dataset) == -1) {
129 | res.send(404, {
130 | error: 'dataset \'' + req.dataset + "\' does not exist",
131 | 'avaiable datasets': Object.keys(structure)
132 | })
133 | return
134 | }
135 |
136 | new Promise(function(resolve) {
137 | db_query(req, resolve)
138 | }).then(function(result) {
139 | res.send(result.status, result.response)
140 | })
141 | }
142 |
143 | function db_query(req, resolve) {
144 | var query = "SELECT AsGeoJSON(_where_geom) as geometry, "
145 | try {
146 | query += parseProperties(req.properties, req.dataset)
147 | query += req.distance ? parseDistance(req.distance, "where_distance") : ""
148 | query += (req.spatial && req.spatial.relation.toLowerCase() === "distwithin") ? parseDistance(req.spatial.geometry, "where_distance_temp") : ""
149 | query += " FROM "
150 | query += req.dataset
151 | query += req.query ? " WHERE (" + parseQuery(req.query, req.dataset) + ")" : ""
152 | query += req.spatial ? (req.query ? " AND " : " WHERE ") + parseSpatial(req.spatial, req.dataset) : ""
153 |
154 | query += req.sort ? " ORDER BY " + parseSort(req.sort, req.dataset) : ""
155 | query += req.limit ? " LIMIT " + validateNumeric(req.limit, "limit") : ""
156 | query += req.offset ? " OFFSET " + validateNumeric(req.offset, "offset") : ""
157 |
158 |
159 | } catch (e) {
160 | resolve({
161 | status: 400,
162 | response: {
163 | error: "invalid query",
164 | msg: e
165 | }
166 | })
167 | return
168 | }
169 |
170 | db.spatialite(function(err) {
171 | db.all(query, function(err, res) {
172 | if (err) {
173 | resolve({
174 | status: 500,
175 | response: err
176 | })
177 | } else {
178 | var geojson = {
179 | "name": req.dataset,
180 | "type": "FeatureCollection",
181 | "features": []
182 | }
183 | res.forEach(function(feature) {
184 | delete feature.where_distance_temp
185 | geojson.features.push({
186 | "type": "Feature",
187 | "geometry": JSON.parse(feature.geometry),
188 | "properties": feature
189 | })
190 | delete geojson.features[geojson.features.length - 1].properties.geometry
191 | })
192 | resolve({
193 | status: 201,
194 | response: geojson
195 | })
196 | }
197 | })
198 | })
199 | }
200 |
201 | function parseQuery(a) {
202 | if (a.and) {
203 | return "(" + a.and.map(parseQuery).join(" AND ") + ")"
204 | } else if (a.or) {
205 | return "(" + a.or.map(parseQuery).join(" OR ") + ")"
206 | } else {
207 |
208 | var prop = '`' + a.prop + '`'
209 | var val = a.val
210 | var op = a.op ? a.op : '='
211 | var c = typeof a.val === 'string' && !a.c ? true : false
212 |
213 | switch (op) {
214 | case "$":
215 | op = "LIKE"
216 | val = "%" + val + "%"
217 | break
218 | case "!$":
219 | op = "NOT LIKE"
220 | val = "%" + val + "%"
221 | break
222 | case "$=":
223 | op = "LIKE"
224 | val = "%" + val
225 | break
226 | case "!$=":
227 | op = "NOT LIKE"
228 | val = "%" + val
229 | break
230 | case "=$":
231 | op = "LIKE"
232 | val = val + "%"
233 | break
234 | case "!=$":
235 | op = "NOT LIKE"
236 | val = val + "%"
237 | break
238 | case ">":
239 | case "<":
240 | case ">=":
241 | case "<=":
242 | case "=":
243 | case "!=":
244 | break
245 | default:
246 | throw "Error: " + op + " is not a valid Operator"
247 | }
248 |
249 | val = typeof val === 'string' ? '"' + val + '"' : val
250 |
251 | if (c) {
252 | prop = "LOWER(" + prop + ")"
253 | val = "LOWER(" + val + ")"
254 | }
255 |
256 | var q = [prop, op, val].join(' ')
257 |
258 | return q
259 | }
260 | }
261 |
262 | function parseSpatial(s, dataset) {
263 | if (s.relation.toLowerCase() == 'distwithin') {
264 | var spatial = ["(`where_distance_temp` < " + s.distance + ") AND ROWID IN (SELECT ROWID FROM SpatialIndex WHERE f_table_name = '" + dataset + "' AND search_frame = BuildMbr(MbrMinX(BUFFER(", ")),MbrMinY(BUFFER(", ")),MbrMaxX(BUFFER(", ")),MbrMaxY(BUFFER(", ")), 4326))"]
265 | if (typeof s.geometry === "string")
266 | return spatial.join("GeomFromText('" + s.geometry + "')," + (s.distance * 0.0000090053))
267 | else
268 | return spatial.join("GeomFromGeoJSON('" + JSON.stringify(s.geometry) + "')," + (s.distance * 0.0000090053))
269 | }
270 |
271 | var spatial = [" AND ROWID IN (SELECT ROWID FROM SpatialIndex WHERE f_table_name = '" + dataset + "' AND search_frame = BuildMbr(MbrMinX(", "),MbrMinY(", "),MbrMaxX(", "),MbrMaxY(", "), 4326))"]
272 |
273 | if (['equals', 'disjoint', 'touches', 'within', 'overlaps', 'crosses', 'intersects', 'contains', 'covers', 'coveredby'].indexOf(s.relation.toLowerCase()) === -1)
274 | throw "Error: " + s.relation + " is not a valid spatial relationship function"
275 |
276 | if (typeof s.geometry === "string")
277 | return s.relation.toUpperCase() + "(_where_geom, GeomFromText('" + s.geometry + "'))" + spatial.join("GeomFromText('" + s.geometry + "')")
278 | else
279 | return s.relation.toUpperCase() + "(_where_geom, GeomFromGeoJSON('" + JSON.stringify(s.geometry) + "'))" + spatial.join("GeomFromGeoJSON('" + JSON.stringify(s.geometry) + "')")
280 | }
281 |
282 | function parseDistance(d, as) {
283 | if (typeof d === "string")
284 | return ", Distance(_where_geom,GeomFromText('" + d + "'),0) as " + as
285 | else
286 | return ", Distance(_where_geom,GeomFromGeoJSON('" + JSON.stringify(d) + "'),0) as " + as
287 | }
288 |
289 | function parseSort(sort, dataset) {
290 | if (!sort.by)
291 | throw "Error: missing value sort.by"
292 | if (Object.keys(structure[dataset]).indexOf(sort.by.trim()) == -1 && sort.by.trim() != "where_distance")
293 | throw "Error: sort by property '" + sort.trim() + "' doesn't exist"
294 |
295 | return "`" + sort.by.trim() + "`" + (sort.desc === true ? " DESC" : "")
296 | }
297 |
298 | function parseProperties(properties, dataset) {
299 | if (properties) {
300 | var filter = "`" + properties.map((p) => {
301 | if (Object.keys(structure[dataset]).indexOf(p) == -1)
302 | throw "Error: property '" + p + "' doesn't exist"
303 | return p
304 | }).join("`, `") + "`"
305 | return filter
306 | } else {
307 | return "`" + Object.keys(structure[dataset]).join("`, `") + "`"
308 | }
309 | }
310 |
311 | function validateNumeric(value, property) {
312 | if (isNaN(value))
313 | throw "Error: value for '" + property + "' is not a number"
314 | return value
315 | }
316 |
317 | function schedule() {
318 | config.data.forEach((d) => {
319 | if(d.schedule){
320 | cron.schedule(d.schedule, function() {
321 | var opt = {
322 | db_name: config.db_name,
323 | data_dir: config.data_dir,
324 | dataset: d,
325 | update: true
326 | }
327 | fork('db/db_update.js', [JSON.stringify(opt)]).on('message', (m) => {
328 | structure[m.dataset] = m.schema
329 | console.log(m.dataset + " updated at " + new Date().toISOString())
330 | })
331 | })
332 | }
333 | })
334 | }
335 |
336 | function getDocs(res) {
337 | res.contentType = 'text/html'
338 | res.header('Content-Type', 'text/html')
339 | res.end(ready ? docs.docs(structure, config.docs, config.host) : docs.launch())
340 | }
341 |
342 | function getMap(q, res) {
343 | res.contentType = 'text/html'
344 | res.header('Content-Type', 'text/html')
345 | res.end(ready ? docs.map(q, config.host) : docs.launch())
346 | }
347 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "where2",
3 | "version": "0.0.1",
4 | "description": "easily create APIs from GeoJSON files",
5 | "main": "index.js",
6 | "scripts": {
7 | "start": "node index.js"
8 | },
9 | "version": "0.0.2",
10 | "dependencies": {
11 | "spatialite" : "0.0.6",
12 | "node-cron": "1.1.1",
13 | "request": "2.72.0",
14 | "restify": "4.0.4"
15 | },
16 | "engines": {
17 | "node": "4.4.5"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "https://github.com/fidelthomet/WHERE"
22 | },
23 | "keywords": [
24 | "node",
25 | "spatialite",
26 | "gis",
27 | "api",
28 | "geojson"
29 | ],
30 | "license": "MIT"
31 | }
32 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # Where2
2 |
3 | ## Introduction
4 |
5 | Where2 turns static GeoJSON files into queryable APIs. Have a look at the [demo application](https://where2demo.herokuapp.com/) to see how it works.
6 |
7 | Where2 is a Node.js based application, which creates APIs from GeoJSON files. Where2 supports spatial (Equals, Disjoint, Touches, Within, Overlaps, Crosses, Intersects, Contains, DistWithin) and property-based queries and returns GeoJSON. Where2 also automatically creates API docs which come with a query builder that makes it easy to get started with your queries.
8 |
9 | ## Getting Started
10 |
11 | The [demo application](https://where2demo.herokuapp.com/) allows you to query data from Zurich's Open Data Catalogue. Follow these instructions to set up your own instance of Where2 with datasets of your own choosing.
12 |
13 | ### Prerequisites
14 | **Where2** requieres Node.js. If you don’t have it yet, go download and install [Node.js](https://nodejs.org/en/download/).
15 |
16 | ### Installing
17 | Grab a copy of **Where2**, open your Terminal (or other Command Line Interface), `cd` into the directory and install the dependencies using npm:
18 | ```
19 | npm install
20 | ```
21 | To test the application run this command:
22 | ```
23 | node where.js
24 | ```
25 | ## Configuration
26 | To use your own datasets and to make the documentation work you have to do a few changes in `config.json`
27 |
28 | ### General Settings
29 | - Open config.json and change `host` to your hostname (eg: `http://localhost:33333` or `https://example.herokuapp.com`).
30 | - Under `docs` change `title` and `description` as you like. Modify `map_center` and `map_zoom` to define the map view in the query-builder.
31 |
32 | ### Datasets
33 | All datasets are listed under `data`. To make a dataset available you need to define a `name` and an `url` (for hosted files) or a `path` (for files in the data directory).
34 |
35 | ```json
36 | {
37 | "name": "addresses",
38 | "url": "https://example.org/addresses.json"
39 | }
40 | ```
41 | or
42 | ```json
43 | {
44 | "name": "addresses",
45 | "path": "addresses.json"
46 | }
47 | ```
48 |
49 | #### Scheduling
50 | Scheduling allows you to automatically update datasets periodically. To define a `schedule` you need to provide a [cron expression](http://merencia.com/node-cron/#cron-syntax). E.g. `0 3 1 * *` to update at 3 am on the first of each month or `15 0 * * 3` to update every wednesday at 0:15 am.
51 |
52 | #### Schema Definition
53 | Where2 automatically detects the schema of the GeoJSON feature properties based on the first feature. Defining a custom schema instead is helpful if the properties contain stringified numbers, which could lead to unexpected results when performing queries using the less and greater than operators.
54 |
55 | ```json
56 | "schema": {
57 | "city": "TEXT",
58 | "street": "TEXT",
59 | "house-number": "INT"
60 | }
61 | ```
62 |
63 | ### Advanced Options
64 |
65 | | Property | Description |
66 | | --- | --- |
67 | | `port` | sets server port (may be overwritten by setting environment variable `PORT`) |
68 | | `data_dir` | directory for local GeoJSON-files |
69 | | `db_name`| sets the name of the SQLite database which will be created on startup |
70 |
71 | ### Example Configuration
72 | ```json
73 | {
74 | "host": "https://example.herokuapp.com",
75 | "docs": {
76 | "description": "My very own instance of Where2",
77 | "title": "My Where2",
78 | },
79 | "data": [{
80 | "name": "addresses",
81 | "url": "https://example.org/addresses.json",
82 | "schedule": "15 0 * * 3",
83 | "schema": {
84 | "city": "TEXT",
85 | "street": "TEXT",
86 | "house-number": "INT"
87 | }
88 | }],
89 | "server_port": "33333",
90 | "data_dir": "data/",
91 | "db_name": "db.db"
92 | }
93 | ```
94 |
95 | ## Deploy Where2 on Heroku
96 | 1. Sign in to [Heroku](https://www.heroku.com)
97 | 2. Create a new App
98 | 3. Choose an App Name and Runtime Selection
99 |
100 | 4. Switch to [GitHub](https://github.com)
101 | 5. Fork your own copy of Where2 to your account
102 | 6. Select Branch "Heroku"[^Where2 depends on [node-spatialite](https://github.com/zhm/node-spatialite). To get it running on Heroku we have to use [the branch with compiled binaries](https://github.com/zhm/node-spatialite/tree/binaries)]
103 | 7. Modify `config.json` to fit your needs
104 |
105 | 8. Back on Heroku choose GitHub under **Deployment Method**
106 | 9. Connect your GitHub Account with Heroku
107 | 10. Select the repository
108 | 11. Under **Manual Deploy** choose the Branch Heroku and click on **Deploy Branch**
109 | 12. Wait
110 |
111 | ## Licence
112 | Copyright 2016 Fidel Thomet
113 | Licensed under the [MIT License](http://opensource.org/licenses/MIT).
114 |
--------------------------------------------------------------------------------