diff --git a/justfile b/justfile index 9ae82e8..ff784ce 100644 --- a/justfile +++ b/justfile @@ -7,7 +7,7 @@ serve: uglify: uglifyjs ./src/js/main.js --compress --mangle -o ./static/js/main.js && uglifyjs ./src/js/page.js --compress --mangle -o ./static/js/page.js && uglifyjs ./src/js/search.js --compress --mangle -o ./static/js/search.js && uglifyjs ./src/js/lang.js --compress --mangle -o ./static/js/lang.js dev: - NODE_ENV=development ./themes/blowfish/node_modules/tailwindcss/lib/cli.js -c ./themes/blowfish/tailwind.config.js -i ./themes/blowfish/assets/css/main.css -o ./assets/css/compiled/main.css --jit -w + tailwindcss -i static/css/base.css -o static/css/main.css --watch api: cargo build clean: diff --git a/static/android-chrome-192x192.png b/static/android-chrome-192x192.png new file mode 100644 index 0000000..3360f18 Binary files /dev/null and b/static/android-chrome-192x192.png differ diff --git a/static/android-chrome-512x512.png b/static/android-chrome-512x512.png new file mode 100644 index 0000000..1d633c1 Binary files /dev/null and b/static/android-chrome-512x512.png differ diff --git a/static/apple-touch-icon.png b/static/apple-touch-icon.png new file mode 100644 index 0000000..c9277fc Binary files /dev/null and b/static/apple-touch-icon.png differ diff --git a/static/css/leaflet.extra-markers.min.css b/static/css/leaflet.extra-markers.min.css new file mode 100755 index 0000000..2638d59 --- /dev/null +++ b/static/css/leaflet.extra-markers.min.css @@ -0,0 +1,8 @@ +/*! + * leaflet-extra-markers + * Custom Markers for Leaflet JS based on Awesome Markers + * Leaflet ExtraMarkers + * https://github.com/coryasilva/Leaflet.ExtraMarkers/ + * @author coryasilva <https://github.com/coryasilva> + * @version 1.2.1 + */.extra-marker{background:url("../img/markers_default.png") no-repeat 0 0;width:35px;height:46px;position:absolute;left:0;top:0;display:block;text-align:center} .extra-marker-shadow{background:url("../img/markers_shadow.png") no-repeat 0 0;width:36px;height:16px}@media (min--moz-device-pixel-ratio:1.5),(-webkit-min-device-pixel-ratio:1.5),(min-device-pixel-ratio:1.5),(min-resolution:1.5dppx){.extra-marker{background-image:url("../img/markers_default@2x.png");background-size:540px 184px} .extra-marker-shadow{background-image:url("../img/markers_shadow@2x.png");background-size:35px 16px}} .extra-marker.extra-marker-svg{background:none} .extra-marker.extra-marker-svg .svg-inline--fa,.extra-marker.extra-marker-svg i{position:absolute;left:0;width:35px} .extra-marker .svg-inline--fa,.extra-marker i{color:#fff;margin-top:7px;display:inline-block;font-size:14px} .extra-marker .svg-inline--fa{margin-top:10px;background:none} .extra-marker .svg-inline--fa,.extra-marker i.fa,.extra-marker i.fab,.extra-marker i.fas,.extra-marker i.far,.extra-marker i.fal{margin-top:10px} .extra-marker .svg-inline--fa.fa-2x,.extra-marker i.fa.fa-2x,.extra-marker i.fab.fa-2x,.extra-marker i.fas.fa-2x,.extra-marker i.far.fa-2x,.extra-marker i.fal.fa-2x{font-size:16px;margin-top:9px} .extra-marker .svg-inline--fa.fa-3x,.extra-marker i.fa.fa-3x,.extra-marker i.fab.fa-3x,.extra-marker i.fas.fa-3x,.extra-marker i.far.fa-3x,.extra-marker i.fal.fa-3x{font-size:18px;margin-top:9px} .extra-marker .svg-inline--fa.fa-4x,.extra-marker i.fa.fa-4x,.extra-marker i.fab.fa-4x,.extra-marker i.fas.fa-4x,.extra-marker i.far.fa-4x,.extra-marker i.fal.fa-4x{font-size:20px;margin-top:8px} .extra-marker .svg-inline--fa.fa-5x,.extra-marker i.fa.fa-5x,.extra-marker i.fab.fa-5x,.extra-marker i.fas.fa-5x,.extra-marker i.far.fa-5x,.extra-marker i.fal.fa-5x{font-size:24px;margin-top:6px} .extra-marker .fa-number:before{content:attr(number)} .extra-marker i.glyphicon{margin-top:10px} .extra-marker i.icon{margin-right:0;opacity:1} .extra-marker-circle-red{background-position:0 0} .extra-marker-circle-orange-dark{background-position:-36px 0} .extra-marker-circle-orange{background-position:-72px 0} .extra-marker-circle-yellow{background-position:-108px 0} .extra-marker-circle-blue-dark{background-position:-144px 0} .extra-marker-circle-blue{background-position:-180px 0} .extra-marker-circle-cyan{background-position:-216px 0} .extra-marker-circle-purple{background-position:-252px 0} .extra-marker-circle-violet{background-position:-288px 0} .extra-marker-circle-pink{background-position:-324px 0} .extra-marker-circle-green-dark{background-position:-360px 0} .extra-marker-circle-green{background-position:-396px 0} .extra-marker-circle-green-light{background-position:-432px 0} .extra-marker-circle-black{background-position:-468px 0} .extra-marker-circle-white{background-position:-504px 0} .extra-marker-square-red{background-position:0 -46px} .extra-marker-square-orange-dark{background-position:-36px -46px} .extra-marker-square-orange{background-position:-72px -46px} .extra-marker-square-yellow{background-position:-108px -46px} .extra-marker-square-blue-dark{background-position:-144px -46px} .extra-marker-square-blue{background-position:-180px -46px} .extra-marker-square-cyan{background-position:-216px -46px} .extra-marker-square-purple{background-position:-252px -46px} .extra-marker-square-violet{background-position:-288px -46px} .extra-marker-square-pink{background-position:-324px -46px} .extra-marker-square-green-dark{background-position:-360px -46px} .extra-marker-square-green{background-position:-396px -46px} .extra-marker-square-green-light{background-position:-432px -46px} .extra-marker-square-black{background-position:-468px -46px} .extra-marker-square-white{background-position:-504px -46px} .extra-marker-star-red{background-position:0 -92px} .extra-marker-star-orange-dark{background-position:-36px -92px} .extra-marker-star-orange{background-position:-72px -92px} .extra-marker-star-yellow{background-position:-108px -92px} .extra-marker-star-blue-dark{background-position:-144px -92px} .extra-marker-star-blue{background-position:-180px -92px} .extra-marker-star-cyan{background-position:-216px -92px} .extra-marker-star-purple{background-position:-252px -92px} .extra-marker-star-violet{background-position:-288px -92px} .extra-marker-star-pink{background-position:-324px -92px} .extra-marker-star-green-dark{background-position:-360px -92px} .extra-marker-star-green{background-position:-396px -92px} .extra-marker-star-green-light{background-position:-432px -92px} .extra-marker-star-black{background-position:-468px -92px} .extra-marker-star-white{background-position:-504px -92px} .extra-marker-penta-red{background-position:0 -138px} .extra-marker-penta-orange-dark{background-position:-36px -138px} .extra-marker-penta-orange{background-position:-72px -138px} .extra-marker-penta-yellow{background-position:-108px -138px} .extra-marker-penta-blue-dark{background-position:-144px -138px} .extra-marker-penta-blue{background-position:-180px -138px} .extra-marker-penta-cyan{background-position:-216px -138px} .extra-marker-penta-purple{background-position:-252px -138px} .extra-marker-penta-violet{background-position:-288px -138px} .extra-marker-penta-pink{background-position:-324px -138px} .extra-marker-penta-green-dark{background-position:-360px -138px} .extra-marker-penta-green{background-position:-396px -138px} .extra-marker-penta-green-light{background-position:-432px -138px} .extra-marker-penta-black{background-position:-468px -138px} .extra-marker-penta-white{background-position:-504px -138px} diff --git a/static/css/main.css b/static/css/main.css index 53dc04f..c3352a3 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -25,9 +25,7 @@ --color-gray-700: oklch(37.3% 0.034 259.733); --color-gray-800: oklch(27.8% 0.033 256.848); --color-gray-900: oklch(21% 0.034 264.665); - --color-neutral-50: oklch(98.5% 0 0); --color-neutral-100: oklch(97% 0 0); - --color-neutral-300: oklch(87% 0 0); --color-neutral-500: oklch(55.6% 0 0); --color-black: #000; --color-white: #fff; @@ -209,6 +207,9 @@ .pointer-events-none { pointer-events: none; } + .collapse { + visibility: collapse; + } .invisible { visibility: hidden; } @@ -259,9 +260,6 @@ .bottom-4 { bottom: calc(var(--spacing) * 4); } - .-left-1 { - left: calc(var(--spacing) * -1); - } .-left-1\/2 { left: calc(calc(1/2 * 100%) * -1); } @@ -428,9 +426,6 @@ .h-0 { height: calc(var(--spacing) * 0); } - .h-2 { - height: calc(var(--spacing) * 2); - } .h-2\/3 { height: calc(2/3 * 100%); } @@ -473,21 +468,12 @@ .h-screen { height: 100vh; } - .max-h-8 { - max-height: calc(var(--spacing) * 8); - } .max-h-12 { max-height: calc(var(--spacing) * 12); } - .w-1 { - width: calc(var(--spacing) * 1); - } .w-1\/3 { width: calc(1/3 * 100%); } - .w-2 { - width: calc(var(--spacing) * 2); - } .w-2\/3 { width: calc(2/3 * 100%); } @@ -503,9 +489,6 @@ .w-9 { width: calc(var(--spacing) * 9); } - .w-11 { - width: calc(var(--spacing) * 11); - } .w-11\/12 { width: calc(11/12 * 100%); } @@ -551,15 +534,9 @@ .flex-none { flex: none; } - .flex-shrink { - flex-shrink: 1; - } .flex-shrink-0 { flex-shrink: 0; } - .flex-grow { - flex-grow: 1; - } .grow { flex-grow: 1; } @@ -783,9 +760,6 @@ .bg-indigo-500 { background-color: var(--color-indigo-500); } - .bg-neutral-500 { - background-color: var(--color-neutral-500); - } .bg-transparent { background-color: transparent; } @@ -810,9 +784,6 @@ .p-5 { padding: calc(var(--spacing) * 5); } - .px-1 { - padding-inline: calc(var(--spacing) * 1); - } .px-1\.5 { padding-inline: calc(var(--spacing) * 1.5); } @@ -828,9 +799,6 @@ .px-6 { padding-inline: calc(var(--spacing) * 6); } - .py-0 { - padding-block: calc(var(--spacing) * 0); - } .py-0\.5 { padding-block: calc(var(--spacing) * 0.5); } @@ -849,12 +817,6 @@ .py-6 { padding-block: calc(var(--spacing) * 6); } - .ps-4 { - padding-inline-start: calc(var(--spacing) * 4); - } - .pe-4 { - padding-inline-end: calc(var(--spacing) * 4); - } .pt-1 { padding-top: calc(var(--spacing) * 1); } @@ -971,9 +933,6 @@ .text-indigo-500 { color: var(--color-indigo-500); } - .text-neutral-50 { - color: var(--color-neutral-50); - } .text-white { color: var(--color-white); } @@ -983,6 +942,9 @@ .\!no-underline { text-decoration-line: none !important; } + .line-through { + text-decoration-line: line-through; + } .no-underline { text-decoration-line: none; } @@ -994,11 +956,6 @@ color: var(--color-gray-300); } } - .placeholder-neutral-300 { - &::placeholder { - color: var(--color-neutral-300); - } - } .opacity-0 { opacity: 0%; } @@ -1008,6 +965,10 @@ .opacity-100 { opacity: 100%; } + .shadow { + --tw-shadow: 0 1px 3px 0 var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 1px 2px -1px var(--tw-shadow-color, rgb(0 0 0 / 0.1)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } .shadow-2xl { --tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); @@ -1023,17 +984,10 @@ .ring-black { --tw-ring-color: var(--color-black); } - .outline { - outline-style: var(--tw-outline-style); - outline-width: 1px; - } .blur { --tw-blur: blur(8px); filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); } - .filter { - filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); - } .transition { transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter; transition-timing-function: var(--tw-ease, var(--default-transition-timing-function)); @@ -1865,11 +1819,6 @@ inherits: false; initial-value: 0 0 #0000; } -@property --tw-outline-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} @property --tw-blur { syntax: "*"; inherits: false; @@ -1965,7 +1914,6 @@ --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; - --tw-outline-style: solid; --tw-blur: initial; --tw-brightness: initial; --tw-contrast: initial; diff --git a/static/favicon-16x16.png b/static/favicon-16x16.png new file mode 100644 index 0000000..f26915f Binary files /dev/null and b/static/favicon-16x16.png differ diff --git a/static/favicon-32x32.png b/static/favicon-32x32.png new file mode 100644 index 0000000..3e4484b Binary files /dev/null and b/static/favicon-32x32.png differ diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..010781f Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/img/april.jpg b/static/img/april.jpg new file mode 100644 index 0000000..155d397 Binary files /dev/null and b/static/img/april.jpg differ diff --git a/static/img/atwood-hs.jpg b/static/img/atwood-hs.jpg new file mode 100644 index 0000000..5644cac Binary files /dev/null and b/static/img/atwood-hs.jpg differ diff --git a/static/img/atwood-jh.jpg b/static/img/atwood-jh.jpg new file mode 100644 index 0000000..c8a41e5 Binary files /dev/null and b/static/img/atwood-jh.jpg differ diff --git a/static/img/brain.jpg b/static/img/brain.jpg new file mode 100644 index 0000000..11a5db2 Binary files /dev/null and b/static/img/brain.jpg differ diff --git a/static/img/camp.jpg b/static/img/camp.jpg new file mode 100644 index 0000000..3cc7be6 Binary files /dev/null and b/static/img/camp.jpg differ diff --git a/static/img/chris.jpg b/static/img/chris.jpg new file mode 100644 index 0000000..f959c47 Binary files /dev/null and b/static/img/chris.jpg differ diff --git a/static/img/ethan.jpg b/static/img/ethan.jpg new file mode 100644 index 0000000..517fe6a Binary files /dev/null and b/static/img/ethan.jpg differ diff --git a/static/img/janice.jpg b/static/img/janice.jpg new file mode 100644 index 0000000..e56ea0f Binary files /dev/null and b/static/img/janice.jpg differ diff --git a/static/img/jenny.png b/static/img/jenny.png new file mode 100644 index 0000000..020b45d Binary files /dev/null and b/static/img/jenny.png differ diff --git a/static/img/lavonne.jpg b/static/img/lavonne.jpg new file mode 100644 index 0000000..07aa6ba Binary files /dev/null and b/static/img/lavonne.jpg differ diff --git a/static/img/lewis.jpg b/static/img/lewis.jpg new file mode 100644 index 0000000..f4b58e7 Binary files /dev/null and b/static/img/lewis.jpg differ diff --git a/static/img/logan.jpg b/static/img/logan.jpg new file mode 100644 index 0000000..64e25de Binary files /dev/null and b/static/img/logan.jpg differ diff --git a/static/img/logo.png b/static/img/logo.png new file mode 100644 index 0000000..36e04dc Binary files /dev/null and b/static/img/logo.png differ diff --git a/static/img/markers_default.png b/static/img/markers_default.png new file mode 100755 index 0000000..2c81d15 Binary files /dev/null and b/static/img/markers_default.png differ diff --git a/static/img/markers_default@2x.png b/static/img/markers_default@2x.png new file mode 100755 index 0000000..35ff61b Binary files /dev/null and b/static/img/markers_default@2x.png differ diff --git a/static/img/markers_shadow.png b/static/img/markers_shadow.png new file mode 100755 index 0000000..33cf955 Binary files /dev/null and b/static/img/markers_shadow.png differ diff --git a/static/img/markers_shadow@2x.png b/static/img/markers_shadow@2x.png new file mode 100755 index 0000000..1116503 Binary files /dev/null and b/static/img/markers_shadow@2x.png differ diff --git a/static/img/mt.jpg b/static/img/mt.jpg new file mode 100644 index 0000000..5913bde Binary files /dev/null and b/static/img/mt.jpg differ diff --git a/static/img/mt2.jpg b/static/img/mt2.jpg new file mode 100644 index 0000000..040bf25 Binary files /dev/null and b/static/img/mt2.jpg differ diff --git a/static/img/nv.jpg b/static/img/nv.jpg new file mode 100644 index 0000000..777690a Binary files /dev/null and b/static/img/nv.jpg differ diff --git a/static/img/pburg.jpg b/static/img/pburg.jpg new file mode 100644 index 0000000..df5dc61 Binary files /dev/null and b/static/img/pburg.jpg differ diff --git a/static/img/rob.jpg b/static/img/rob.jpg new file mode 100644 index 0000000..b31ebac Binary files /dev/null and b/static/img/rob.jpg differ diff --git a/static/img/shawn-dust.jpg b/static/img/shawn-dust.jpg new file mode 100644 index 0000000..4a143a8 Binary files /dev/null and b/static/img/shawn-dust.jpg differ diff --git a/static/img/smith-center.jpg b/static/img/smith-center.jpg new file mode 100644 index 0000000..b9dc39c Binary files /dev/null and b/static/img/smith-center.jpg differ diff --git a/static/img/staff.jpg b/static/img/staff.jpg new file mode 100644 index 0000000..35c0cee Binary files /dev/null and b/static/img/staff.jpg differ diff --git a/static/img/sv.jpg b/static/img/sv.jpg new file mode 100644 index 0000000..8f208ce Binary files /dev/null and b/static/img/sv.jpg differ diff --git a/static/img/tr.png b/static/img/tr.png new file mode 100644 index 0000000..5510f66 Binary files /dev/null and b/static/img/tr.png differ diff --git a/static/img/wakeeney.jpg b/static/img/wakeeney.jpg new file mode 100644 index 0000000..2d45192 Binary files /dev/null and b/static/img/wakeeney.jpg differ diff --git a/static/js/leaflet.elevation.js b/static/js/leaflet.elevation.js new file mode 100644 index 0000000..1b0bf91 --- /dev/null +++ b/static/js/leaflet.elevation.js @@ -0,0 +1,1660 @@ +/* + * Copyright (c) 2019, GPL-3.0+ Project, altrdev + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2019, GPL-3.0+ Project, Raruto + * + * This file is free software: you may copy, redistribute and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation, either version 2 of the License, or (at your + * option) any later version. + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright (c) 2013-2016, MIT License, Felix “MrMufflon” Bache + * + * Permission to use, copy, modify, and/or distribute this software + * for any purpose with or without fee is hereby granted, provided + * that the above copyright notice and this permission notice appear + * in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE + * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS + * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +L.Control.Elevation = L.Control.extend({ + + includes: L.Evented ? L.Evented.prototype : L.Mixin.Events, + + options: { + autohide: true, + autohideMarker: true, + collapsed: false, + controlButton: { + iconCssClass: "elevation-toggle-icon", + title: "Elevation" + }, + detached: true, + distanceFactor: 1, + downloadLink: 'link', + elevationDiv: "#elevation-div", + followMarker: true, + forceAxisBounds: false, + gpxOptions: { + async: true, + marker_options: { + startIconUrl: null, + endIconUrl: null, + shadowUrl: null, + wptIcons: { + '': L.divIcon({ + className: 'elevation-waypoint-marker', + html: '<i class="elevation-waypoint-icon"></i>', + iconSize: [30, 30], + iconAnchor: [8, 30], + }) + }, + }, + polyline_options: { + className: '', + color: '#566B13', + opacity: 0.75, + weight: 5, + lineCap: 'round' + }, + }, + height: 200, + heightFactor: 1, + hoverNumber: { + decimalsX: 2, + decimalsY: 0, + formatter: undefined + }, + imperial: false, + interpolation: "curveLinear", + lazyLoadJS: true, + legend: true, + loadData: { + defer: false, + lazy: false, + }, + marker: 'elevation-line', + markerIcon: L.divIcon({ + className: 'elevation-position-marker', + html: '<i class="elevation-position-icon"></i>', + iconSize: [32, 32], + iconAnchor: [16, 16], + }), + placeholder: false, + position: "topright", + reverseCoords: false, + skipNullZCoords: false, + theme: "lightblue-theme", + margins: { + top: 10, + right: 20, + bottom: 30, + left: 50 + }, + responsive: true, + summary: 'inline', + width: 600, + xLabel: "km", + xTicks: undefined, + yAxisMax: undefined, + yAxisMin: undefined, + yLabel: "m", + yTicks: undefined, + zFollow: 13, + }, + __mileFactor: 0.621371, + __footFactor: 3.28084, + + /* + * Add data to the diagram either from GPX or GeoJSON and update the axis domain and data + */ + addData: function(d, layer) { + this._addData(d); + + if (this._container) { + this._applyData(); + } + if ((typeof layer === "undefined" || layer === null) && d.on) { + layer = d; + } + if (layer) { + if (layer._path) { + L.DomUtil.addClass(layer._path, 'elevation-polyline ' + this.options.theme); + } + layer + .on("mousemove", this._mousemoveLayerHandler, this) + .on("mouseout", this._mouseoutHandler, this); + } + + this.track_info = this.track_info || {}; + this.track_info.distance = this._distance; + this.track_info.elevation_max = this._maxElevation; + this.track_info.elevation_min = this._minElevation; + + this._layers = this._layers || {}; + this._layers[L.Util.stamp(layer)] = layer; + + var evt = { + data: d, + layer: layer, + track_info: this.track_info, + }; + if (this.fire) this.fire("eledata_added", evt, true); + if (this._map) this._map.fire("eledata_added", evt, true); + }, + + addTo: function(map) { + if (this.options.detached) { + this._addToChartDiv(map); + } else { + L.Control.prototype.addTo.call(this, map); + } + return this; + }, + + /* + * Reset data and display + */ + clear: function() { + + this._clearPath(); + this._clearChart(); + this._clearData(); + + if (this.fire) this.fire("eledata_clear"); + if (this._map) this._map.fire("eledata_clear"); + }, + + disableDragging: function() { + this._draggingEnabled = false; + this._resetDrag(); + }, + + enableDragging: function() { + this._draggingEnabled = true; + }, + + fitBounds: function(bounds) { + bounds = bounds || this._fullExtent; + if (this._map && bounds) this._map.fitBounds(bounds); + }, + + getZFollow: function() { + return this._zFollow; + }, + + hide: function() { + this._container.style.display = "none"; + }, + + initialize: function(options) { + this.options.autohide = typeof options.autohide !== "undefined" ? options.autohide : !L.Browser.mobile; + + // Aliases. + if (typeof options.detachedView !== "undefined") this.options.detached = options.detachedView; + if (typeof options.responsiveView !== "undefined") this.options.responsive = options.responsiveView; + if (typeof options.showTrackInfo !== "undefined") this.options.summary = options.showTrackInfo; + if (typeof options.summaryType !== "undefined") this.options.summary = options.summaryType; + if (typeof options.autohidePositionMarker !== "undefined") this.options.autohideMarker = options.autohidePositionMarker; + if (typeof options.followPositionMarker !== "undefined") this.options.followMarker = options.followPositionMarker; + if (typeof options.useLeafletMarker !== "undefined") this.options.marker = options.useLeafletMarker ? 'position-marker' : 'elevation-line'; + if (typeof options.leafletMarkerIcon !== "undefined") this.options.markerIcon = options.leafletMarkerIcon; + if (typeof options.download !== "undefined") this.options.downloadLink = options.download; + + // L.Util.setOptions(this, options); + this.options = this._deepMerge({}, this.options, options); + + this._draggingEnabled = !L.Browser.mobile; + this._chartEnabled = true; + + if (options.imperial) { + this._distanceFactor = this.__mileFactor; + this._heightFactor = this.__footFactor; + this._xLabel = "mi"; + this._yLabel = "ft"; + } else { + this._distanceFactor = this.options.distanceFactor; + this._heightFactor = this.options.heightFactor; + this._xLabel = this.options.xLabel; + this._yLabel = this.options.yLabel; + } + + this._zFollow = this.options.zFollow; + + if (this.options.followMarker) this._setMapView = L.Util.throttle(this._setMapView, 300, this); + if (this.options.placeholder) this.options.loadData.lazy = this.options.loadData.defer = true; + }, + + /** + * Alias for loadData + */ + load: function(data, opts) { + this.loadData(data, opts); + }, + + /** + * Alias for addTo + */ + loadChart: function(map) { + this.addTo(map); + }, + + loadData: function(data, opts) { + opts = L.extend({}, this.options.loadData, opts); + if (opts.defer) { + this.loadDefer(data, opts); + } else if (opts.lazy) { + this.loadLazy(data, opts); + } else if (this._isXMLDoc(data)) { + this.loadGPX(data); + } else if (this._isJSONDoc(data)) { + this.loadGeoJSON(data); + } else { + this.loadFile(data); + } + }, + + loadDefer: function(data, opts) { + opts = L.extend({}, this.options.loadData, opts); + opts.defer = false; + if (document.readyState !== 'complete') window.addEventListener("load", L.bind(this.loadData, this, data, opts), { once: true }); + else this.loadData(data, opts) + }, + + loadFile: function(url) { + this._downloadURL = url; // TODO: handle multiple urls? + try { + var xhr = new XMLHttpRequest(); + xhr.responseType = "text"; + xhr.open('GET', url); + xhr.onload = function() { + if (xhr.status !== 200) { + throw "Error " + xhr.status + " while fetching remote file: " + url; + } else { + this.loadData(xhr.response, { lazy: false, defer: false }); + } + }.bind(this); + xhr.send(); + } catch (e) { + console.warn(e); + } + }, + + loadGeoJSON: function(data) { + if (typeof data === "string") { + data = JSON.parse(data); + } + + this.layer = this.geojson = L.geoJson(data, { + style: function(feature) { + return { + color: '#566B13', + className: 'elevation-polyline ' + this.options.theme, + }; + }.bind(this), + onEachFeature: function(feature, layer) { + this.addData(feature, layer); + + this.track_info = this.track_info || {}; + this.track_info.type = "geojson"; + this.track_info.name = data.name; + this.track_info.distance = this._distance; + this.track_info.elevation_max = this._maxElevation; + this.track_info.elevation_min = this._minElevation; + + }.bind(this), + }); + if (this._map) { + this._map.once('layeradd', function(e) { + this.fitBounds(this.layer.getBounds()); + var evt = { + data: data, + layer: this.layer, + name: this.track_info.name, + track_info: this.track_info, + }; + if (this.fire) this.fire("eledata_loaded", evt, true); + if (this._map) this._map.fire("eledata_loaded", evt, true); + }, this); + + this.layer.addTo(this._map); + } else { + console.warn("Undefined elevation map object"); + } + }, + + loadGPX: function(data) { + var callback = function(data) { + this.options.gpxOptions.polyline_options.className += 'elevation-polyline ' + this.options.theme; + + this.layer = this.gpx = new L.GPX(data, this.options.gpxOptions); + + this.layer.on('loaded', function(e) { + this.fitBounds(e.target.getBounds()); + }, this); + this.layer.on('addpoint', function(e) { + + if(e.point_type === "start" || e.point_type === "end") { + e.point.setZIndexOffset(10000); + } + if (e.point._popup) { + e.point._popup.options.className = 'elevation-popup'; + e.point._popup._content = decodeURI(e.point._popup._content); + } + if (e.point._popup && e.point._popup._content) { + e.point.bindTooltip(e.point._popup._content, { direction: 'top', sticky: true, opacity: 1, className: 'elevation-tooltip' }).openTooltip(); + } + }); + this.layer.once("addline", function(e) { + this.addData(e.line /*, this.layer*/ ); + + this.track_info = this.track_info || {}; + this.track_info.type = "gpx"; + this.track_info.name = this.layer.get_name(); + this.track_info.distance = this._distance; + this.track_info.elevation_max = this._maxElevation; + this.track_info.elevation_min = this._minElevation; + + var evt = { + data: data, + layer: this.layer, + name: this.track_info.name, + track_info: this.track_info, + }; + + if (this.fire) this.fire("eledata_loaded", evt, true); + if (this._map) this._map.fire("eledata_loaded", evt, true); + }, this); + + if (this._map) { + this.layer.addTo(this._map); + } else { + console.warn("Undefined elevation map object"); + } + }.bind(this, data); + if (typeof L.GPX !== 'function' && this.options.lazyLoadJS) { + L.Control.Elevation._gpxLazyLoader = this._lazyLoadJS('https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/1.5.0/gpx.js', L.Control.Elevation._gpxLazyLoader); + L.Control.Elevation._gpxLazyLoader.then(callback); + } else { + callback.call(); + } + }, + + loadLazy: function(data, opts) { + opts = L.extend({}, this.options.loadData, opts); + opts.lazy = false; + let ticking = false; + let scrollFn = L.bind(function(data) { + if (!ticking) { + L.Util.requestAnimFrame(function() { + if (this._isVisible(this.placeholder)) { + window.removeEventListener('scroll', scrollFn); + this.loadData(data, opts); + this.once('eledata_loaded', function() { + if (this.placeholder && this.placeholder.parentNode) { + this.placeholder.parentNode.removeChild(this.placeholder); + } + }, this) + } + ticking = false; + }, this); + ticking = true; + } + }, this, data); + window.addEventListener('scroll', scrollFn); + if (this.placeholder) this.placeholder.addEventListener('mouseenter', scrollFn, { once: true }); + scrollFn(); + }, + + onAdd: function(map) { + this._map = map; + + var container = this._container = L.DomUtil.create("div", "elevation-control elevation"); + + if (!this.options.detached) { + L.DomUtil.addClass(container, 'leaflet-control'); + } + + if (this.options.theme) { + L.DomUtil.addClass(container, this.options.theme); // append theme to control + } + + if (this.options.placeholder && !this._data) { + this.placeholder = L.DomUtil.create('img', 'elevation-placeholder'); + if (typeof this.options.placeholder === 'string') { + this.placeholder.src = this.options.placeholder; + this.placeholder.alt = ''; + } else { + for (let i in this.options.placeholder) { this.placeholder.setAttribute(i, this.options.placeholder[i]); } + } + container.insertBefore(this.placeholder, container.firstChild); + } + + var callback = function(map, container) { + this._initToggle(container); + this._initChart(container); + + this._applyData(); + + this._map.on('zoom viewreset zoomanim', this._hidePositionMarker, this); + this._map.on('resize', this._resetView, this); + this._map.on('resize', this._resizeChart, this); + this._map.on('mousedown', this._resetDrag, this); + + this._map.on('eledata_loaded', this._updateSummary, this); + + L.DomEvent.on(this._map._container, 'mousewheel', this._resetDrag, this); + L.DomEvent.on(this._map._container, 'touchstart', this._resetDrag, this); + + }.bind(this, map, container); + if (typeof d3 !== 'object' && this.options.lazyLoadJS) { + L.Control.Elevation._d3LazyLoader = this._lazyLoadJS('https://unpkg.com/d3@4.13.0/build/d3.min.js', L.Control.Elevation._d3LazyLoader); + L.Control.Elevation._d3LazyLoader.then(callback); + } else { + callback.call(); + } + return container; + }, + + onRemove: function(map) { + this._container = null; + }, + + redraw: function() { + this._resizeChart(); + }, + + setZFollow: function(zoom) { + this._zFollow = zoom; + }, + + show: function() { + this._container.style.display = "block"; + }, + + /* + * Parsing data either from GPX or GeoJSON and update the diagram data + */ + _addData: function(d) { + var geom = d && d.geometry && d.geometry; + var i; + + if (geom) { + switch (geom.type) { + case 'LineString': + this._addGeoJSONData(geom.coordinates); + break; + + case 'MultiLineString': + for (i = 0; i < geom.coordinates.length; i++) { + this._addGeoJSONData(geom.coordinates[i]); + } + break; + + default: + console.warn('Unsopperted GeoJSON feature geometry type:' + geom.type); + } + } + + var feat = d && d.type === "FeatureCollection"; + if (feat) { + for (i = 0; i < d.features.length; i++) { + this._addData(d.features[i]); + } + } + + if (d && d._latlngs) { + this._addGPXdata(d._latlngs); + } + }, + + /* + * Parsing of GeoJSON data lines and their elevation in z-coordinate + */ + _addGeoJSONData: function(coords) { + if (coords) { + for (var i = 0; i < coords.length; i++) { + this._addPoint(coords[i][1], coords[i][0], coords[i][2]); + } + } + }, + + /* + * Parsing function for GPX data and their elevation in z-coordinate + */ + _addGPXdata: function(coords) { + if (coords) { + for (var i = 0; i < coords.length; i++) { + this._addPoint(coords[i].lat, coords[i].lng, coords[i].meta.ele); + } + } + }, + + _addPoint: function(x, y, z) { + if (this.options.reverseCoords) { + var tmp = x; + x = y; + y = tmp; + } + + var data = this._data || []; + var eleMax = this._maxElevation || -Infinity; + var eleMin = this._minElevation || +Infinity; + var dist = this._distance || 0; + + var curr = new L.LatLng(x, y); + var prev = data.length ? data[data.length - 1].latlng : curr; + + var delta = curr.distanceTo(prev) * this._distanceFactor; + + dist = dist + Math.round(delta / 1000 * 100000) / 100000; + + // check and fix missing elevation data on last added point + if (!this.options.skipNullZCoords && data.length > 0) { + var prevZ = data[data.length - 1].z; + if (isNaN(prevZ)) { + var lastZ = this._lastValidZ; + var currZ = z * this._heightFactor; + if (!isNaN(lastZ) && !isNaN(currZ)) { + prevZ = (lastZ + currZ) / 2; + } else if (!isNaN(lastZ)) { + prevZ = lastZ; + } else if (!isNaN(currZ)) { + prevZ = currZ; + } + if (!isNaN(prevZ)) data[data.length - 1].z = prevZ; + else data.splice(data.length - 1, 1); + } + } + + z = z * this._heightFactor; + + // skip point if it has not elevation + if (!isNaN(z)) { + eleMax = eleMax < z ? z : eleMax; + eleMin = eleMin > z ? z : eleMin; + this._lastValidZ = z; + } + + data.push({ + dist: dist, + x: x, + y: y, + z: z, + latlng: curr + }); + + this._data = data; + this._distance = dist; + this._maxElevation = eleMax; + this._minElevation = eleMin; + }, + + _addToChartDiv: function(map) { + this._appendElevationDiv(map._container).appendChild(this.onAdd(map)); + }, + + _appendChart: function(svg) { + var g = svg + .append("g") + .attr("transform", "translate(" + this.options.margins.left + "," + this.options.margins.top + ")"); + + this._appendGrid(g); + this._appendAreaPath(g); + this._appendAxis(g); + this._appendFocusRect(g); + this._appendMouseFocusG(g); + this._appendLegend(g); + }, + + _appendElevationDiv: function(container) { + var eleDiv = document.querySelector(this.options.elevationDiv); + if (!eleDiv) { + eleDiv = L.DomUtil.create('div', 'leaflet-control elevation elevation-div'); + this.options.elevationDiv = '#elevation-div_' + Math.random().toString(36).substr(2, 9); + eleDiv.id = this.options.elevationDiv.substr(1); + container.parentNode.insertBefore(eleDiv, container.nextSibling); // insert after end of container. + } + if (this.options.detached) { + L.DomUtil.addClass(eleDiv, 'elevation-detached'); + L.DomUtil.removeClass(eleDiv, 'leaflet-control'); + } + this.eleDiv = eleDiv; + return this.eleDiv; + }, + + _appendXaxis: function(axis) { + axis + .append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + this._height() + ")") + .call( + d3 + .axisBottom() + .scale(this._x) + .ticks(this.options.xTicks) + ) + .append("text") + .attr("x", this._width() + 6) + .attr("y", 30) + .text(this._xLabel); + }, + + _appendXGrid: function(grid) { + grid.append("g") + .attr("class", "x grid") + .attr("transform", "translate(0," + this._height() + ")") + .call( + d3 + .axisBottom() + .scale(this._x) + .ticks(this.options.xTicks) + .tickSize(-this._height()) + .tickFormat("") + ); + + }, + + _appendYaxis: function(axis) { + axis + .append("g") + .attr("class", "y axis") + .call( + d3 + .axisLeft() + .scale(this._y) + .ticks(this.options.yTicks) + ) + .append("text") + .attr("x", -30) + .attr("y", -5) + .text(this._yLabel); + }, + + _appendYGrid: function(grid) { + grid.append("g") + .attr("class", "y grid") + .call( + d3 + .axisLeft() + .scale(this._y) + .ticks(this.options.yTicks) + .tickSize(-this._width()) + .tickFormat("") + ); + }, + + _appendAreaPath: function(g) { + this._areapath = g.append("path") + .attr("class", "area"); + }, + + _appendAxis: function(g) { + this._axis = g.append("g") + .attr("class", "axis"); + this._appendXaxis(this._axis); + this._appendYaxis(this._axis); + }, + + _appendFocusRect: function(g) { + var focusRect = this._focusRect = g.append("rect") + .attr("width", this._width()) + .attr("height", this._height()) + .style("fill", "none") + .style("stroke", "none") + .style("pointer-events", "all"); + + if (L.Browser.mobile) { + focusRect + .on("touchmove.drag", this._dragHandler.bind(this)) + .on("touchstart.drag", this._dragStartHandler.bind(this)) + .on("touchstart.focus", this._mousemoveHandler.bind(this)) + .on("touchmove.focus", this._mousemoveHandler.bind(this)); + L.DomEvent.on(this._container, 'touchend', this._dragEndHandler, this); + } + + focusRect + .on("mousemove.drag", this._dragHandler.bind(this)) + .on("mousedown.drag", this._dragStartHandler.bind(this)) + .on("mouseenter.focus", this._mouseenterHandler.bind(this)) + .on("mousemove.focus", this._mousemoveHandler.bind(this)) + .on("mouseout.focus", this._mouseoutHandler.bind(this)); + L.DomEvent.on(this._container, 'mouseup', this._dragEndHandler, this); + }, + + _appendGrid: function(g) { + this._grid = g.append("g") + .attr("class", "grid"); + this._appendXGrid(this._grid); + this._appendYGrid(this._grid); + }, + + _appendMouseFocusG: function(g) { + var focusG = this._focusG = g.append("g") + .attr("class", "mouse-focus-group"); + + this._mousefocus = focusG.append('svg:line') + .attr('class', 'mouse-focus-line') + .attr('x2', '0') + .attr('y2', '0') + .attr('x1', '0') + .attr('y1', '0'); + + this._focuslabelrect = focusG.append("rect") + .attr('class', 'mouse-focus-label') + .attr("x", 0) + .attr("y", 0) + .attr("width", 0) + .attr("height", 0) + .attr("rx", 3) + .attr("ry", 3); + + this._focuslabeltext = focusG.append("svg:text") + .attr("class", "mouse-focus-label-text"); + this._focuslabelY = this._focuslabeltext.append("svg:tspan") + .attr("class", "mouse-focus-label-y") + .attr("dy", "-1em"); + this._focuslabelX = this._focuslabeltext.append("svg:tspan") + .attr("class", "mouse-focus-label-x") + .attr("dy", "2em"); + }, + + _appendLegend: function(g) { + if (!this.options.legend) return; + + var legend = this._legend = g.append('g') + .attr("class", "legend"); + + var altitude = this._altitudeLegend = this._legend.append('g') + .attr("class", "legend-altitude"); + + altitude.append("rect") + .attr("class", "area") + .attr("x", (this._width() / 2) - 50) + .attr("y", this._height() + this.options.margins.bottom - 17) + .attr("width", 50) + .attr("height", 5) + .attr("opacity", 0.75); + + altitude.append('text') + .text('Altitude') + .attr("x", (this._width() / 2) + 5) + .attr("font-size", 10) + .style("text-decoration-thickness", "2px") + .style("font-weight", "700") + .attr('y', this._height() + this.options.margins.bottom - 11); + + }, + + _appendPositionMarker: function(pane) { + var theme = this.options.theme; + var heightG = pane.select("g"); + + this._mouseHeightFocus = heightG.append('svg:line') + .attr("class", theme + " height-focus line") + .attr("x2", 0) + .attr("y2", 0) + .attr("x1", 0) + .attr("y1", 0); + + this._pointG = heightG.append("g"); + this._pointG.append("svg:circle") + .attr("class", theme + " height-focus circle-lower") + .attr("r", 6) + .attr("cx", 0) + .attr("cy", 0); + + this._mouseHeightFocusLabel = heightG.append("svg:text") + .attr("class", theme + " height-focus-label") + .style("pointer-events", "none"); + }, + + _applyData: function() { + if (!this._data) return; + + var xdomain = d3.extent(this._data, function(d) { + return d.dist; + }); + var ydomain = d3.extent(this._data, function(d) { + return d.z; + }); + var opts = this.options; + + if (opts.yAxisMin !== undefined && (opts.yAxisMin < ydomain[0] || opts.forceAxisBounds)) { + ydomain[0] = opts.yAxisMin; + } + if (opts.yAxisMax !== undefined && (opts.yAxisMax > ydomain[1] || opts.forceAxisBounds)) { + ydomain[1] = opts.yAxisMax; + } + + this._x.domain(xdomain); + this._y.domain(ydomain); + this._areapath.datum(this._data) + .attr("d", this._area); + this._updateAxis(); + + this._fullExtent = this._calculateFullExtent(this._data); + }, + + /* + * Calculates the full extent of the data array + */ + _calculateFullExtent: function(data) { + if (!data || data.length < 1) { + throw new Error("no data in parameters"); + } + + var ext = new L.latLngBounds(data[0].latlng, data[0].latlng); + + data.forEach(function(item) { + ext.extend(item.latlng); + }); + + return ext; + }, + + _clearChart: function() { + this._resetDrag(); + if (this._areapath) { + // workaround for 'Error: Problem parsing d=""' in Webkit when empty data + // https://groups.google.com/d/msg/d3-js/7rFxpXKXFhI/HzIO_NPeDuMJ + //this._areapath.datum(this._data).attr("d", this._area); + this._areapath.attr("d", "M0 0"); + + this._x.domain([0, 1]); + this._y.domain([0, 1]); + this._updateAxis(); + } + if (this._altitudeLegend) { + this._altitudeLegend.select('text').style("text-decoration-line", "line-through"); + } + }, + + /* + * Reset data + */ + _clearData: function() { + this._data = null; + this._distance = null; + this._maxElevation = null; + this._minElevation = null; + this.track_info = null; + this._layers = null; + // if (this.layer) { + // this.layer.removeFrom(this._map); + // } + }, + + _clearPath: function() { + this._hidePositionMarker(); + for (var id in this._layers) { + L.DomUtil.removeClass(this._layers[id]._path, "elevation-polyline"); + L.DomUtil.removeClass(this._layers[id]._path, this.options.theme); + } + }, + + _collapse: function() { + if (this._container) { + L.DomUtil.removeClass(this._container, 'elevation-expanded'); + L.DomUtil.addClass(this._container, 'elevation-collapsed'); + } + }, + + _deepMerge: function(target, ...sources) { + if (!sources.length) return target; + const source = sources.shift(); + if (this._isObject(target) && this._isObject(source)) { + for (const key in source) { + if (this._isObject(source[key])) { + if (!target[key]) Object.assign(target, { + [key]: {} + }); + this._deepMerge(target[key], source[key]); + } else { + Object.assign(target, { + [key]: source[key] + }); + } + } + } + return this._deepMerge(target, ...sources); + }, + + _saveFile: function(fileUrl) { + var d = document, + a = d.createElement('a'), + b = d.body; + a.href = fileUrl; + a.target = '_new'; + a.download = ""; // fileName + a.style.display = 'none'; + b.appendChild(a); + a.click(); + b.removeChild(a); + }, + + _dragHandler: function() { + //we don't want map events to occur here + d3.event.preventDefault(); + d3.event.stopPropagation(); + + this._gotDragged = true; + this._drawDragRectangle(); + }, + + /* + * Handles end of drag operations. Zooms the map to the selected items extent. + */ + _dragEndHandler: function() { + if (!this._dragStartCoords || !this._dragCurrentCoords || !this._gotDragged) { + this._dragStartCoords = null; + this._gotDragged = false; + if (this._draggingEnabled) this._resetDrag(); + // autotoggle chart data on single click + /*if (this._chartEnabled) { + this._clearChart(); + this._clearPath(); + this._chartEnabled = false; + } else { + this._resizeChart(); + this._chartEnabled = true; + }*/ + return; + } + + var item1 = this._findItemForX(this._dragStartCoords[0]), + item2 = this._findItemForX(this._dragCurrentCoords[0]); + + if (item1 == item2) return; + + this._hidePositionMarker(); + + this._fitSection(item1, item2); + + this._dragStartCoords = null; + this._gotDragged = false; + + var evt = { + data: { + dragstart: this._data[item1], + dragend: this._data[item2] + } + }; + if (this.fire) this.fire("elechart_dragged", evt, true); + if (this._map) this._map.fire("elechart_dragged", evt, true); + }, + + _dragStartHandler: function() { + d3.event.preventDefault(); + d3.event.stopPropagation(); + + this._gotDragged = false; + this._dragStartCoords = d3.mouse(this._focusRect.node()); + }, + + /* + * Draws the currently dragged rectangle over the chart. + */ + _drawDragRectangle: function() { + if (!this._dragStartCoords || !this._draggingEnabled) { + return; + } + + var dragEndCoords = this._dragCurrentCoords = d3.mouse(this._focusRect.node()); + + var x1 = Math.min(this._dragStartCoords[0], dragEndCoords[0]), + x2 = Math.max(this._dragStartCoords[0], dragEndCoords[0]); + + if (!this._dragRectangle && !this._dragRectangleG) { + var g = d3.select(this._container).select("svg").select("g"); + + this._dragRectangleG = g.insert("g", ".mouse-focus-group"); + + this._dragRectangle = this._dragRectangleG.append("rect") + .attr("width", x2 - x1) + .attr("height", this._height()) + .attr("x", x1) + .attr('class', 'mouse-drag') + .style("pointer-events", "none"); + } else { + this._dragRectangle.attr("width", x2 - x1) + .attr("x", x1); + } + }, + + _expand: function() { + if (this._container) { + L.DomUtil.removeClass(this._container, 'elevation-collapsed'); + L.DomUtil.addClass(this._container, 'elevation-expanded'); + } + }, + + /* + * Finds an item with the smallest delta in distance to the given latlng coords + */ + _findItemForLatLng: function(latlng) { + var result = null, + d = Infinity; + this._data.forEach(function(item) { + var dist = latlng.distanceTo(item.latlng); + if (dist < d) { + d = dist; + result = item; + } + }); + return result; + }, + + /* + * Finds a data entry for a given x-coordinate of the diagram + */ + _findItemForX: function(x) { + var bisect = d3.bisector(function(d) { + return d.dist; + }).left; + var xinvert = this._x.invert(x); + return bisect(this._data, xinvert); + }, + + /** + * Make the map fit the route section between given indexes. + */ + _fitSection: function(index1, index2) { + var start = Math.min(index1, index2); + var end = Math.max(index1, index2); + var ext = this._calculateFullExtent(this._data.slice(start, end)); + this.fitBounds(ext); + }, + + /* + * Fromatting funciton using the given decimals and seperator + */ + _formatter: function(num, dec, sep) { + var res; + if (dec === 0) { + res = Math.round(num) + ""; + } else { + res = L.Util.formatNum(num, dec) + ""; + } + var numbers = res.split("."); + if (numbers[1]) { + var d = dec - numbers[1].length; + for (; d > 0; d--) { + numbers[1] += "0"; + } + res = numbers.join(sep || "."); + } + return res; + }, + + _height: function() { + var opts = this.options; + return opts.height - opts.margins.top - opts.margins.bottom; + }, + + /* + * Hides the position/height indicator marker drawn onto the map + */ + _hidePositionMarker: function() { + if (!this.options.autohideMarker) { + return; + } + + this._selectedItem = null; + + if (this._marker) { + if (this._map) this._map.removeLayer(this._marker); + this._marker = null; + } + if (this._mouseHeightFocus) { + this._mouseHeightFocus.style("visibility", "hidden"); + this._mouseHeightFocusLabel.style("visibility", "hidden"); + } + if (this._pointG) { + this._pointG.style("visibility", "hidden"); + } + if (this._focusG) { + this._focusG.style("visibility", "hidden"); + } + }, + + _initChart: function() { + var opts = this.options; + opts.xTicks = opts.xTicks || Math.round(this._width() / 75); + opts.yTicks = opts.yTicks || Math.round(this._height() / 30); + opts.hoverNumber.formatter = opts.hoverNumber.formatter || this._formatter; + + if (opts.responsive) { + if (opts.detached) { + var offWi = this.eleDiv.offsetWidth; + var offHe = this.eleDiv.offsetHeight; + opts.width = offWi > 0 ? offWi : opts.width; + opts.height = (offHe - 20) > 0 ? offHe - 20 : opts.height; // 20 = horizontal scrollbar size. + } else { + opts._maxWidth = opts._maxWidth > opts.width ? opts._maxWidth : opts.width; + var containerWidth = this._map._container.clientWidth; + opts.width = opts._maxWidth > containerWidth ? containerWidth - 30 : opts.width; + } + } + + var x = this._x = d3.scaleLinear().range([0, this._width()]); + var y = this._y = d3.scaleLinear().range([this._height(), 0]); + + var interpolation = typeof opts.interpolation === 'function' ? opts.interpolation : d3[opts.interpolation]; + + var area = this._area = d3.area().curve(interpolation) + .x(function(d) { + return (d.xDiagCoord = x(d.dist)); + }) + .y0(this._height()) + .y1(function(d) { + return y(d.z); + }); + var line = this._line = d3.line() + .x(function(d) { + return d3.mouse(svg.select("g"))[0]; + }) + .y(function(d) { + return this._height(); + }); + + var container = d3.select(this._container); + + var svg = container.append("svg") + .attr("class", "background") + .attr("width", opts.width) + .attr("height", opts.height); + + var summary = this.summaryDiv = container.append("div") + .attr("class", "elevation-summary " + this.options.summary + "-summary").node(); + + this._appendChart(svg); + this._updateSummary(); + + }, + + /** + * Inspired by L.Control.Layers + */ + _initToggle: function(container) { + //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released + container.setAttribute('aria-haspopup', true); + + if (!this.options.detached) { + L.DomEvent + .disableClickPropagation(container); + //.disableScrollPropagation(container); + } + + if (L.Browser.mobile) { + L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation); + } + + //L.DomEvent.on(container, 'mousewheel', this._mousewheelHandler, this); + + if (!this.options.detached) { + var iconCssClass = "elevation-toggle " + this.options.controlButton.iconCssClass + (this.options.autohide ? "" : " close-button"); + var link = this._button = L.DomUtil.create('a', iconCssClass, container); + link.href = '#'; + link.title = this.options.controlButton.title; + + if (this.options.collapsed) { + this._collapse(); + if (this.options.autohide) { + L.DomEvent + .on(container, 'mouseover', this._expand, this) + .on(container, 'mouseout', this._collapse, this); + } else { + L.DomEvent + .on(link, 'click', L.DomEvent.stop) + .on(link, 'click', this._toggle, this); + } + + L.DomEvent.on(link, 'focus', this._toggle, this); + + this._map.on('click', this._collapse, this); + // TODO: keyboard accessibility + } + } else { + // TODO: handle autohide when detached=true + } + }, + + _isObject: function(item) { + return (item && typeof item === 'object' && !Array.isArray(item)); + }, + + _isJSONDoc: function(doc, lazy) { + lazy = typeof lazy === "undefined" ? true : lazy; + if (typeof doc === "string" && lazy) { + doc = doc.trim(); + return doc.indexOf("{") == 0 || doc.indexOf("[") == 0; + } else { + try { + JSON.parse(doc.toString()); + } catch (e) { + if (typeof doc === "object" && lazy) return true; + console.warn(e); + return false; + } + return true; + } + }, + + _isXMLDoc: function(doc, lazy) { + lazy = typeof lazy === "undefined" ? true : lazy; + if (typeof doc === "string" && lazy) { + doc = doc.trim(); + return doc.indexOf("<") == 0; + } else { + var documentElement = (doc ? doc.ownerDocument || doc : 0).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; + } + }, + + _isDomVisible: function(elem) { + return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length); + }, + + _isVisible: function(elem) { + if (!elem) return false; + + let styles = window.getComputedStyle(elem); + + function isVisibleByStyles(elem, styles) { + return styles.visibility !== 'hidden' && styles.display !== 'none'; + } + + function isAboveOtherElements(elem, styles) { + let boundingRect = elem.getBoundingClientRect(); + let left = boundingRect.left + 1; + let right = boundingRect.right - 1; + let top = boundingRect.top + 1; + let bottom = boundingRect.bottom - 1; + let above = true; + + let pointerEvents = elem.style.pointerEvents; + + if (styles['pointer-events'] == 'none') elem.style.pointerEvents = 'auto'; + + if (document.elementFromPoint(left, top) !== elem) above = false; + if (document.elementFromPoint(right, top) !== elem) above = false; + + // Only for completely visible elements + // if (document.elementFromPoint(left, bottom) !== elem) above = false; + // if (document.elementFromPoint(right, bottom) !== elem) above = false; + + elem.style.pointerEvents = pointerEvents; + + return above; + } + + if (!isVisibleByStyles(elem, styles)) return false; + if (!isAboveOtherElements(elem, styles)) return false; + return true; + }, + + _lazyLoadJS: function(url, skip) { + if (typeof skip == "undefined") { + skip = false; + } + if (skip instanceof Promise) { + return skip; + } + return new Promise(function(resolve, reject) { + if (skip) return resolve(); + var tag = document.createElement("script"); + tag.addEventListener('load', resolve, { once: true }); + tag.src = url; + document.head.appendChild(tag); + }); + }, + + _mouseenterHandler: function() { + if (this.fire) { + this.fire("elechart_enter", null, true); + } + if (this._map) { + this._map.fire("elechart_enter", null, true); + } + }, + + /* + * Handles the moueseover the chart and displays distance and altitude level + */ + _mousemoveHandler: function(d, i, ctx) { + if (!this._data || this._data.length === 0 || !this._chartEnabled) { + return; + } + var coords = d3.mouse(this._focusRect.node()); + var xCoord = coords[0]; + var item = this._data[this._findItemForX(xCoord)]; + + this._hidePositionMarker(); + this._showDiagramIndicator(item, xCoord); + this._showPositionMarker(item); + this._setMapView(item); + + if (this._map && this._map._container) { + L.DomUtil.addClass(this._map._container, 'elechart-hover'); + } + + var evt = { + data: item + }; + if (this.fire) { + this.fire("elechart_change", evt, true); + this.fire("elechart_hover", evt, true); + } + if (this._map) { + this._map.fire("elechart_change", evt, true); + this._map.fire("elechart_hover", evt, true); + } + }, + + /* + * Handles mouseover events of the data layers on the map. + */ + _mousemoveLayerHandler: function(e) { + if (!this._data || this._data.length === 0) { + return; + } + var latlng = e.latlng; + var item = this._findItemForLatLng(latlng); + if (item) { + var xCoord = item.xDiagCoord; + + this._hidePositionMarker(); + this._showDiagramIndicator(item, xCoord); + this._showPositionMarker(item); + } + }, + + _mouseoutHandler: function() { + if (!this.options.detached) { + this._hidePositionMarker(); + } + + if (this._map && this._map._container) { + L.DomUtil.removeClass(this._map._container, 'elechart-hover'); + } + + if (this.fire) this.fire("elechart_leave", null, true); + if (this._map) this._map.fire("elechart_leave", null, true); + }, + + _mousewheelHandler: function(e) { + if (this._map.gestureHandling && this._map.gestureHandling._enabled) return; + var ll = this._selectedItem ? this._selectedItem.latlng : this._map.getCenter(); + var z = e.deltaY > 0 ? this._map.getZoom() - 1 : this._map.getZoom() + 1; + this._resetDrag(); + this._map.flyTo(ll, z); + + }, + + /* + * Removes the drag rectangle and zoms back to the total extent of the data. + */ + _resetDrag: function() { + if (this._dragRectangleG) { + this._dragRectangleG.remove(); + this._dragRectangleG = null; + this._dragRectangle = null; + this._hidePositionMarker(); + } + }, + + _resetView: function() { + if (this._map && this._map._isFullscreen) return; + this._resetDrag(); + this._hidePositionMarker(); + this.fitBounds(this._fullExtent); + }, + + _resizeChart: function() { + if (this.options.responsive) { + if (this.options.detached) { + var newWidth = this.eleDiv.offsetWidth; // - 20; + + if (newWidth <= 0) return; + + this.options.width = newWidth; + this.eleDiv.innerHTML = ""; + this.eleDiv.appendChild(this.onAdd(this._map)); + } else { + this._map.removeControl(this._container); + this.addTo(this._map); + } + } + }, + + _showDiagramIndicator: function(item, xCoordinate) { + if (!this._chartEnabled) return; + + var opts = this.options; + this._focusG.style("visibility", "visible"); + + this._mousefocus.attr('x1', xCoordinate) + .attr('y1', 0) + .attr('x2', xCoordinate) + .attr('y2', this._height()) + .classed('hidden', false); + + var alt = item.z, + dist = item.dist, + ll = item.latlng, + numY = opts.hoverNumber.formatter(alt, opts.hoverNumber.decimalsY), + numX = opts.hoverNumber.formatter(dist, opts.hoverNumber.decimalsX); + + this._focuslabeltext + // .attr("x", xCoordinate) + .attr("y", this._y(item.z)) + .style("font-weight", "700"); + + this._focuslabelX + .text(numX + " " + this._xLabel) + .attr("x", xCoordinate + 10); + + this._focuslabelY + .text(numY + " " + this._yLabel) + .attr("x", xCoordinate + 10); + + var focuslabeltext = this._focuslabeltext.node(); + if (this._isDomVisible(focuslabeltext)) { + var bbox = focuslabeltext.getBBox(); + var padding = 2; + + this._focuslabelrect + .attr("x", bbox.x - padding) + .attr("y", bbox.y - padding) + .attr("width", bbox.width + (padding * 2)) + .attr("height", bbox.height + (padding * 2)); + + // move focus label to left + if (xCoordinate >= this._width() / 2) { + this._focuslabelrect.attr("x", this._focuslabelrect.attr("x") - this._focuslabelrect.attr("width") - (padding * 2) - 10); + this._focuslabelX.attr("x", this._focuslabelX.attr("x") - this._focuslabelrect.attr("width") - (padding * 2) - 10); + this._focuslabelY.attr("x", this._focuslabelY.attr("x") - this._focuslabelrect.attr("width") - (padding * 2) - 10); + } + } + + }, + + _toggle: function() { + if (L.DomUtil.hasClass(this._container, "elevation-expanded")) + this._collapse(); + else + this._expand(); + }, + + _setMapView: function(item) { + if (!this.options.followMarker || !this._map) return; + var zoom = this._map.getZoom(); + zoom = zoom < this._zFollow ? this._zFollow : zoom; + this._map.setView(item.latlng, zoom, { animate: true, duration: 0.25 }); + }, + + _showPositionMarker: function(item) { + this._selectedItem = item; + + if (this._map && !this._map.getPane('elevationPane')) { + this._map.createPane('elevationPane'); + this._map.getPane('elevationPane').style.zIndex = 625; // This pane is above markers but below popups. + this._map.getPane('elevationPane').style.pointerEvents = 'none'; + } + + if (this.options.marker == 'elevation-line') { + this._updatePositionMarker(item); + } else if (this.options.marker == 'position-marker') { + this._updateLeafletMarker(item); + } + }, + + _updateAxis: function() { + this._grid.selectAll("g").remove(); + this._axis.selectAll("g").remove(); + this._appendXGrid(this._grid); + this._appendYGrid(this._grid); + this._appendXaxis(this._axis); + this._appendYaxis(this._axis); + }, + + _updateHeightIndicator: function(item) { + var opts = this.options; + + var numY = opts.hoverNumber.formatter(item.z, opts.hoverNumber.decimalsY), + numX = opts.hoverNumber.formatter(item.dist, opts.hoverNumber.decimalsX); + + var normalizedAlt = this._height() / this._maxElevation * item.z, + normalizedY = item.y - normalizedAlt; + + this._mouseHeightFocus + .attr("x1", item.x) + .attr("x2", item.x) + .attr("y1", item.y) + .attr("y2", normalizedY) + .style("visibility", "visible"); + + this._mouseHeightFocusLabel + .attr("x", item.x) + .attr("y", normalizedY) + .text(numY + " " + this._yLabel) + .style("visibility", "visible"); + }, + + _updateLeafletMarker: function(item) { + var ll = item.latlng; + + if (!this._marker) { + this._marker = new L.Marker(ll, { + icon: this.options.markerIcon, + zIndexOffset: 1000000, + }); + this._marker.addTo(this._map, { + pane: 'elevationPane', + }); + } else { + this._marker.setLatLng(ll); + } + }, + + _updatePointG: function(item) { + this._pointG + .attr("transform", "translate(" + item.x + "," + item.y + ")") + .style("visibility", "visible"); + }, + + _updatePositionMarker: function(item) { + var point = this._map.latLngToLayerPoint(item.latlng); + var layerpoint = { + dist: item.dist, + x: point.x, + y: point.y, + z: item.z, + }; + + if (!this._mouseHeightFocus) { + L.svg({ pane: "elevationPane" }).addTo(this._map); // default leaflet svg renderer + var layerpane = d3.select(this._map.getContainer()).select(".leaflet-elevation-pane svg"); + this._appendPositionMarker(layerpane); + } + + this._updatePointG(layerpoint); + this._updateHeightIndicator(layerpoint); + }, + + _updateSummary: function() { + if (this.options.summary && this.summaryDiv) { + this.track_info = this.track_info || {}; + this.track_info.distance = this._distance || 0; + this.track_info.elevation_max = this._maxElevation || 0; + this.track_info.elevation_min = this._minElevation || 0; + d3.select(this.summaryDiv).html('<span class="totlen"><span class="summarylabel">Total Length: </span><span class="summaryvalue">' + this.track_info.distance.toFixed(2) + ' ' + this._xLabel + '</span></span><span class="maxele"><span class="summarylabel">Max Elevation: </span><span class="summaryvalue">' + this.track_info.elevation_max.toFixed(2) + ' ' + this._yLabel + '</span></span><span class="minele"><span class="summarylabel">Min Elevation: </span><span class="summaryvalue">' + this.track_info.elevation_min.toFixed(2) + ' ' + this._yLabel + '</span></span>'); + } + if (this.options.downloadLink && this._downloadURL) { // TODO: generate dynamically file content instead of using static file urls. + var span = document.createElement('span'); + span.className = 'download'; + var save = document.createElement('a'); + save.innerHTML = "Download"; + save.href = "#"; + save.onclick = function(e) { + e.preventDefault(); + var evt = { confirm: this._saveFile.bind(this, this._downloadURL) }; + var type = this.options.downloadLink; + if (type == 'modal') { + if (typeof CustomEvent === "function") document.dispatchEvent(new CustomEvent("eletrack_download", { detail: evt })); + if (this.fire) this.fire('eletrack_download', evt); + if (this._map) this._map.fire('eletrack_download', evt); + } else if (type == 'link' || type === true) { + evt.confirm(); + } + }.bind(this); + + this.summaryDiv.appendChild(span).appendChild(save); + } + }, + + _width: function() { + var opts = this.options; + return opts.width - opts.margins.left - opts.margins.right; + }, + +}); + +L.control.elevation = function(options) { + return new L.Control.Elevation(options); +}; diff --git a/static/js/leaflet.extra-markers.js.map b/static/js/leaflet.extra-markers.js.map new file mode 100755 index 0000000..05faeeb --- /dev/null +++ b/static/js/leaflet.extra-markers.js.map @@ -0,0 +1 @@ +{"version":3,"file":null,"sources":["/Users/cory/Projects/Leaflet.ExtraMarkers/src/assets/js/leaflet.extra-markers.js"],"sourcesContent":["export var ExtraMarkers = L.ExtraMarkers = {};\nExtraMarkers.version = L.ExtraMarkers.version = \"1.2.1\";\nExtraMarkers.Icon = L.ExtraMarkers.Icon = L.Icon.extend({\n options: {\n iconSize: [ 35, 45 ],\n iconAnchor: [ 17, 42 ],\n popupAnchor: [ 1, -32 ],\n shadowAnchor: [ 10, 12 ],\n shadowSize: [ 36, 16 ],\n className: \"\",\n prefix: \"\",\n extraClasses: \"\",\n shape: \"circle\",\n icon: \"\",\n innerHTML: \"\",\n markerColor: \"red\",\n svgBorderColor: \"#fff\",\n svgOpacity: 1,\n iconColor: \"#fff\",\n iconRotate: 0,\n number: \"\",\n svg: false\n },\n initialize: function(options) {\n options = L.Util.setOptions(this, options);\n },\n createIcon: function() {\n var div = document.createElement(\"div\"), options = this.options;\n if (options.icon) {\n div.innerHTML = this._createInner();\n }\n if (options.innerHTML) {\n div.innerHTML = options.innerHTML;\n }\n if (options.bgPos) {\n div.style.backgroundPosition = -options.bgPos.x + \"px \" + -options.bgPos.y + \"px\";\n }\n if (!options.svg) {\n this._setIconStyles(div, options.shape + \"-\" + options.markerColor);\n } else {\n this._setIconStyles(div, \"svg\");\n }\n return div;\n },\n _getColorHex: function (color) {\n var colorMap = {\n red: \"#a23337\",\n \"orange-dark\": \"#d73e29\",\n orange: \"#ef9227\",\n yellow: \"#f5bb39\",\n \"blue-dark\": \"#276273\",\n cyan: \"#32a9dd\",\n purple: \"#440444\",\n violet: \"#90278d\",\n pink: \"#c057a0\",\n green: \"#006838\",\n white: \"#e8e8e8\",\n black: \"#211c1d\"\n };\n return colorMap[color] || color;\n },\n _createSvg: function (shape, markerColor) {\n var svgMap = {\n circle: '<svg width=\"32\" height=\"44\" viewBox=\"0 0 35 45\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M17.5 2.746c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.439-17.863.056-.08a15.422 15.422 0 002.343-6.112c.123-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307\" fill=\"' + markerColor + '\" /><path d=\"M17.488 2.748c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.44-17.863.055-.08a15.422 15.422 0 002.343-6.112c.124-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307m0 1.071c7.68 0 13.929 6.386 13.929 14.236 0 .685-.064 1.423-.193 2.258-.325 2.075-1.059 3.99-2.164 5.667l-.055.078-11.557 16.595L6.032 26.14l-.12-.174a14.256 14.256 0 01-2.105-5.29 14.698 14.698 0 01-.247-2.62c0-7.851 6.249-14.237 13.928-14.237\" fill=\"#231f20\" opacity=\".15\" /></svg>',\n square: '<svg width=\"33\" height=\"44\" viewBox=\"0 0 35 45\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M28.205 3.217H6.777c-2.367 0-4.286 1.87-4.286 4.179v19.847c0 2.308 1.919 4.179 4.286 4.179h5.357l5.337 13.58 5.377-13.58h5.357c2.366 0 4.285-1.87 4.285-4.179V7.396c0-2.308-1.919-4.179-4.285-4.179\" fill=\"' + markerColor + '\" /><g opacity=\".15\" transform=\"matrix(1.0714 0 0 -1.0714 -233.22 146.783)\"><path d=\"M244 134h-20c-2.209 0-4-1.746-4-3.9v-18.525c0-2.154 1.791-3.9 4-3.9h5L233.982 95 239 107.675h5c2.209 0 4 1.746 4 3.9V130.1c0 2.154-1.791 3.9-4 3.9m0-1c1.654 0 3-1.301 3-2.9v-18.525c0-1.599-1.346-2.9-3-2.9h-5.68l-.25-.632-4.084-10.318-4.055 10.316-.249.634H224c-1.654 0-3 1.301-3 2.9V130.1c0 1.599 1.346 2.9 3 2.9h20\" fill=\"#231f20\" /></g></svg>',\n star: '<svg width=\"34\" height=\"44\" viewBox=\"0 0 35 45\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M32.92 16.93l-3.525-3.525V8.419a1.983 1.983 0 00-1.983-1.982h-4.985L18.9 2.91a1.984 1.984 0 00-2.803 0l-3.524 3.526H7.588a1.983 1.983 0 00-1.982 1.982v4.986L2.081 16.93a1.982 1.982 0 000 2.803l3.525 3.526v4.984c0 1.096.888 1.983 1.982 1.983h4.986L17.457 45l4.97-14.773h4.985a1.983 1.983 0 001.983-1.983V23.26l3.525-3.526a1.982 1.982 0 000-2.803\" fill=\"' + markerColor + '\" /><g opacity=\".15\" transform=\"matrix(1.0667 0 0 -1.0667 -347.3 97.26)\"><path d=\"M342 89c-.476 0-.951-.181-1.314-.544l-3.305-3.305h-4.673a1.858 1.858 0 01-1.859-1.858v-4.674l-3.305-3.305a1.857 1.857 0 010-2.627l3.305-3.305v-4.674a1.86 1.86 0 011.859-1.859h4.673L341.959 49l4.659 13.849h4.674a1.86 1.86 0 011.859 1.859v4.674l3.305 3.305a1.858 1.858 0 010 2.627l-3.305 3.305v4.674a1.859 1.859 0 01-1.859 1.858h-4.674l-3.304 3.305A1.851 1.851 0 01342 89m0-1a.853.853 0 00.607-.251l3.304-3.305.293-.293h5.088a.86.86 0 00.859-.858v-5.088l3.598-3.598A.852.852 0 00356 74a.85.85 0 00-.251-.606l-3.598-3.598v-5.088a.86.86 0 00-.859-.859h-5.393l-.229-.681-3.702-11.006-3.637 11.001-.227.686h-5.396a.86.86 0 00-.859.859v5.088l-3.598 3.598c-.162.162-.251.377-.251.606s.089.445.251.607l3.598 3.598v5.088a.86.86 0 00.859.858h5.087l3.598 3.598A.853.853 0 00342 88\" fill=\"#231f20\" /></g></svg>',\n penta: '<svg width=\"33\" height=\"44\" viewBox=\"0 0 35 45\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1.872 17.35L9.679 2.993h15.615L33.1 17.35 17.486 44.992z\" fill=\"' + markerColor + '\" /><g opacity=\".15\" transform=\"matrix(1.0769 0 0 -1.0769 -272.731 48.23)\"><path d=\"M276.75 42h-14.5L255 28.668 269.5 3 284 28.668zm-.595-1l6.701-12.323L269.5 5.033l-13.356 23.644L262.845 41z\" fill=\"#231f20\" /></g></svg>'\n };\n return svgMap[shape];\n },\n _createInner: function() {\n var iconStyle = \"\", iconNumber = \"\", iconClass = \"\", result = \"\", options = this.options;\n if (options.iconColor) {\n iconStyle = \"color: \" + options.iconColor + \";\";\n }\n if (options.iconRotate !== 0) {\n iconStyle += \"-webkit-transform: rotate(\" + options.iconRotate + \"deg);\";\n iconStyle += \"-moz-transform: rotate(\" + options.iconRotate + \"deg);\";\n iconStyle += \"-o-transform: rotate(\" + options.iconRotate + \"deg);\";\n iconStyle += \"-ms-transform: rotate(\" + options.iconRotate + \"deg);\";\n iconStyle += \"transform: rotate(\" + options.iconRotate + \"deg);\";\n }\n if (options.number) {\n iconNumber = 'number=\"' + options.number + '\" ';\n }\n if (options.extraClasses.length) {\n iconClass += options.extraClasses + \" \";\n }\n if (options.prefix.length) {\n iconClass += options.prefix + \" \";\n }\n if (options.icon.length) {\n iconClass += options.icon + \" \";\n }\n if (options.svg) {\n result += this._createSvg(options.shape, this._getColorHex(options.markerColor));\n }\n result += '<i ' + iconNumber + 'style=\"' + iconStyle + '\" class=\"' + iconClass + '\"></i>';\n return result;\n },\n _setIconStyles: function(img, name) {\n var options = this.options, size = L.point(options[name === \"shadow\" ? \"shadowSize\" : \"iconSize\"]), anchor, leafletName;\n if (name === \"shadow\") {\n anchor = L.point(options.shadowAnchor || options.iconAnchor);\n leafletName = \"shadow\";\n } else {\n anchor = L.point(options.iconAnchor);\n leafletName = \"icon\";\n }\n if (!anchor && size) {\n anchor = size.divideBy(2, true);\n }\n img.className = \"leaflet-marker-\" + leafletName + \" extra-marker extra-marker-\" + name + \" \" + options.className;\n if (anchor) {\n img.style.marginLeft = -anchor.x + \"px\";\n img.style.marginTop = -anchor.y + \"px\";\n }\n if (size) {\n img.style.width = size.x + \"px\";\n img.style.height = size.y + \"px\";\n }\n },\n createShadow: function() {\n var div = document.createElement(\"div\");\n this._setIconStyles(div, \"shadow\");\n return div;\n }\n});\nExtraMarkers.icon = L.ExtraMarkers.icon = function(options) {\n return new L.ExtraMarkers.Icon(options);\n};"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/static/js/leaflet.extra-markers.min.js b/static/js/leaflet.extra-markers.min.js new file mode 100755 index 0000000..5b30f12 --- /dev/null +++ b/static/js/leaflet.extra-markers.min.js @@ -0,0 +1,10 @@ +/*! + * leaflet-extra-markers + * Custom Markers for Leaflet JS based on Awesome Markers + * Leaflet ExtraMarkers + * https://github.com/coryasilva/Leaflet.ExtraMarkers/ + * @author coryasilva <https://github.com/coryasilva> + * @version 1.2.1 + */ + +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e.leaflet=e.leaflet||{},e.leaflet["extra-markers"]={}))}(this,function(e){"use strict";var t=L.ExtraMarkers={};t.version=L.ExtraMarkers.version="1.2.1",t.Icon=L.ExtraMarkers.Icon=L.Icon.extend({options:{iconSize:[35,45],iconAnchor:[17,42],popupAnchor:[1,-32],shadowAnchor:[10,12],shadowSize:[36,16],className:"",prefix:"",extraClasses:"",shape:"circle",icon:"",innerHTML:"",markerColor:"red",svgBorderColor:"#fff",svgOpacity:1,iconColor:"#fff",iconRotate:0,number:"",svg:!1},initialize:function(e){e=L.Util.setOptions(this,e)},createIcon:function(){var e=document.createElement("div"),t=this.options;return t.icon&&(e.innerHTML=this._createInner()),t.innerHTML&&(e.innerHTML=t.innerHTML),t.bgPos&&(e.style.backgroundPosition=-t.bgPos.x+"px "+-t.bgPos.y+"px"),t.svg?this._setIconStyles(e,"svg"):this._setIconStyles(e,t.shape+"-"+t.markerColor),e},_getColorHex:function(e){return{red:"#a23337","orange-dark":"#d73e29",orange:"#ef9227",yellow:"#f5bb39","blue-dark":"#276273",cyan:"#32a9dd",purple:"#440444",violet:"#90278d",pink:"#c057a0",green:"#006838",white:"#e8e8e8",black:"#211c1d"}[e]||e},_createSvg:function(e,t){return{circle:'<svg width="32" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M17.5 2.746c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.439-17.863.056-.08a15.422 15.422 0 002.343-6.112c.123-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307" fill="'+t+'" /><path d="M17.488 2.748c-8.284 0-15 6.853-15 15.307 0 .963.098 1.902.265 2.816a15.413 15.413 0 002.262 5.684l.134.193 12.295 17.785 12.44-17.863.055-.08a15.422 15.422 0 002.343-6.112c.124-.791.206-1.597.206-2.423 0-8.454-6.716-15.307-15-15.307m0 1.071c7.68 0 13.929 6.386 13.929 14.236 0 .685-.064 1.423-.193 2.258-.325 2.075-1.059 3.99-2.164 5.667l-.055.078-11.557 16.595L6.032 26.14l-.12-.174a14.256 14.256 0 01-2.105-5.29 14.698 14.698 0 01-.247-2.62c0-7.851 6.249-14.237 13.928-14.237" fill="#231f20" opacity=".15" /></svg>',square:'<svg width="33" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M28.205 3.217H6.777c-2.367 0-4.286 1.87-4.286 4.179v19.847c0 2.308 1.919 4.179 4.286 4.179h5.357l5.337 13.58 5.377-13.58h5.357c2.366 0 4.285-1.87 4.285-4.179V7.396c0-2.308-1.919-4.179-4.285-4.179" fill="'+t+'" /><g opacity=".15" transform="matrix(1.0714 0 0 -1.0714 -233.22 146.783)"><path d="M244 134h-20c-2.209 0-4-1.746-4-3.9v-18.525c0-2.154 1.791-3.9 4-3.9h5L233.982 95 239 107.675h5c2.209 0 4 1.746 4 3.9V130.1c0 2.154-1.791 3.9-4 3.9m0-1c1.654 0 3-1.301 3-2.9v-18.525c0-1.599-1.346-2.9-3-2.9h-5.68l-.25-.632-4.084-10.318-4.055 10.316-.249.634H224c-1.654 0-3 1.301-3 2.9V130.1c0 1.599 1.346 2.9 3 2.9h20" fill="#231f20" /></g></svg>',star:'<svg width="34" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M32.92 16.93l-3.525-3.525V8.419a1.983 1.983 0 00-1.983-1.982h-4.985L18.9 2.91a1.984 1.984 0 00-2.803 0l-3.524 3.526H7.588a1.983 1.983 0 00-1.982 1.982v4.986L2.081 16.93a1.982 1.982 0 000 2.803l3.525 3.526v4.984c0 1.096.888 1.983 1.982 1.983h4.986L17.457 45l4.97-14.773h4.985a1.983 1.983 0 001.983-1.983V23.26l3.525-3.526a1.982 1.982 0 000-2.803" fill="'+t+'" /><g opacity=".15" transform="matrix(1.0667 0 0 -1.0667 -347.3 97.26)"><path d="M342 89c-.476 0-.951-.181-1.314-.544l-3.305-3.305h-4.673a1.858 1.858 0 01-1.859-1.858v-4.674l-3.305-3.305a1.857 1.857 0 010-2.627l3.305-3.305v-4.674a1.86 1.86 0 011.859-1.859h4.673L341.959 49l4.659 13.849h4.674a1.86 1.86 0 011.859 1.859v4.674l3.305 3.305a1.858 1.858 0 010 2.627l-3.305 3.305v4.674a1.859 1.859 0 01-1.859 1.858h-4.674l-3.304 3.305A1.851 1.851 0 01342 89m0-1a.853.853 0 00.607-.251l3.304-3.305.293-.293h5.088a.86.86 0 00.859-.858v-5.088l3.598-3.598A.852.852 0 00356 74a.85.85 0 00-.251-.606l-3.598-3.598v-5.088a.86.86 0 00-.859-.859h-5.393l-.229-.681-3.702-11.006-3.637 11.001-.227.686h-5.396a.86.86 0 00-.859.859v5.088l-3.598 3.598c-.162.162-.251.377-.251.606s.089.445.251.607l3.598 3.598v5.088a.86.86 0 00.859.858h5.087l3.598 3.598A.853.853 0 00342 88" fill="#231f20" /></g></svg>',penta:'<svg width="33" height="44" viewBox="0 0 35 45" xmlns="http://www.w3.org/2000/svg"><path d="M1.872 17.35L9.679 2.993h15.615L33.1 17.35 17.486 44.992z" fill="'+t+'" /><g opacity=".15" transform="matrix(1.0769 0 0 -1.0769 -272.731 48.23)"><path d="M276.75 42h-14.5L255 28.668 269.5 3 284 28.668zm-.595-1l6.701-12.323L269.5 5.033l-13.356 23.644L262.845 41z" fill="#231f20" /></g></svg>'}[e]},_createInner:function(){var e="",t="",o="",r="",a=this.options;return a.iconColor&&(e="color: "+a.iconColor+";"),0!==a.iconRotate&&(e+="-webkit-transform: rotate("+a.iconRotate+"deg);",e+="-moz-transform: rotate("+a.iconRotate+"deg);",e+="-o-transform: rotate("+a.iconRotate+"deg);",e+="-ms-transform: rotate("+a.iconRotate+"deg);",e+="transform: rotate("+a.iconRotate+"deg);"),a.number&&(t='number="'+a.number+'" '),a.extraClasses.length&&(o+=a.extraClasses+" "),a.prefix.length&&(o+=a.prefix+" "),a.icon.length&&(o+=a.icon+" "),a.svg&&(r+=this._createSvg(a.shape,this._getColorHex(a.markerColor))),r+="<i "+t+'style="'+e+'" class="'+o+'"></i>'},_setIconStyles:function(e,t){var o,r,a=this.options,n=L.point(a["shadow"===t?"shadowSize":"iconSize"]);r="shadow"===t?(o=L.point(a.shadowAnchor||a.iconAnchor),"shadow"):(o=L.point(a.iconAnchor),"icon"),!o&&n&&(o=n.divideBy(2,!0)),e.className="leaflet-marker-"+r+" extra-marker extra-marker-"+t+" "+a.className,o&&(e.style.marginLeft=-o.x+"px",e.style.marginTop=-o.y+"px"),n&&(e.style.width=n.x+"px",e.style.height=n.y+"px")},createShadow:function(){var e=document.createElement("div");return this._setIconStyles(e,"shadow"),e}}),t.icon=L.ExtraMarkers.icon=function(e){return new L.ExtraMarkers.Icon(e)},e.ExtraMarkers=t,Object.defineProperty(e,"__esModule",{value:!0})}); \ No newline at end of file diff --git a/static/js/leaflet.hugo.js b/static/js/leaflet.hugo.js new file mode 100644 index 0000000..8326bbc --- /dev/null +++ b/static/js/leaflet.hugo.js @@ -0,0 +1,108 @@ +let leafletMapsObj = {}; +let leafletMarkersObj = {}; + +function drawTrack(trackOpts, elevationOpts, markerOpts) { + var opts = { + elevationControl: { + options: { + position: elevationOpts.graphPosition, + theme: elevationOpts.graphTheme, + width: elevationOpts.graphWidth, + height: elevationOpts.graphHeight, + margins: { + top: 20, + right: 20, + bottom: 35, + left: 50 + }, + followMarker: elevationOpts.graphFollowMarker, + collapsed: elevationOpts.graphCollapsed, + detached: elevationOpts.graphDetached, + legend: false, + summary: false, + downloadLink: '', + gpxOptions: { + polyline_options: { + className: 'track-' + trackOpts.trackId + '-', + color: trackOpts.lineColor, + opacity: trackOpts.lineOpacity, + weight: trackOpts.lineWeight, + }, + marker_options: { + startIcon: new L.ExtraMarkers.icon({ + icon: markerOpts.iconStart, + markerColor: markerOpts.iconStartColor, + shape: markerOpts.iconStartShape, + prefix: 'fa', + extraClasses: markerOpts.iconStartClasses + }), + endIcon: new L.ExtraMarkers.icon({ + icon: markerOpts.iconEnd, + markerColor: markerOpts.iconEndColor, + shape: markerOpts.iconEndShape, + prefix: 'fa', + extraClasses: markerOpts.iconEndClasses + }), + wptIcons: { + '': new L.ExtraMarkers.icon({ + icon: markerOpts.icon, + markerColor: markerOpts.iconColor, + shape: markerOpts.iconShape, + prefix: 'fa', + extraClasses: markerOpts.iconClasses, + }) + } + } + }, + + }, + }, + }; + + L.control.elevation(opts.elevationControl.options).addTo(leafletMapsObj[trackOpts.mapId]).load(trackOpts.trackPath); + + /*map.on('eledata_loaded', function(e) { + track = e.track_info; + });*/ +} + +window.downloadFile = function (sUrl) { + + //iOS devices do not support downloading. We have to inform user about this. + if (/(iP)/g.test(navigator.userAgent)) { + alert('Your device does not support files downloading. Please try again in desktop browser.'); + return false; + } + + //If in Chrome or Safari - download via virtual link click + if (window.downloadFile.isChrome || window.downloadFile.isSafari) { + //Creating new link node. + var link = document.createElement('a'); + link.href = sUrl; + + if (link.download !== undefined) { + //Set HTML5 download attribute. This will prevent file from opening if supported. + var fileName = sUrl.substring(sUrl.lastIndexOf('/') + 1, sUrl.length); + link.download = fileName; + } + + //Dispatching click event. + if (document.createEvent) { + var e = document.createEvent('MouseEvents'); + e.initEvent('click', true, true); + link.dispatchEvent(e); + return true; + } + } + + // Force file download (whether supported by server). + if (sUrl.indexOf('?') === -1) { + sUrl += '?download'; + } + + window.open(sUrl, '_self'); + return true; +}; + +window.downloadFile.isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; +window.downloadFile.isSafari = navigator.userAgent.toLowerCase().indexOf('safari') > -1; diff --git a/static/js/map.js b/static/js/map.js new file mode 100644 index 0000000..d6fab8b --- /dev/null +++ b/static/js/map.js @@ -0,0 +1,41 @@ +function initMap() { + if ($('#map').length) { + let map_provider = $('#map-provider').val(); + let lat = $('#map-lat').val(); + let lng = $('#map-lng').val(); + let zoom = parseInt($('#map-zoom').val()); + let address = $('#map-dir').val(); + let api_key = $('#map-api-key').val(); + + let map = new L.map('map').setView([lat, lng], zoom); + if (map_provider === 'mapbox' && api_key.length) { + L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', { + attribution: + 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a>', + tileSize: 512, + maxZoom: 18, + zoomOffset: -1, + id: 'mapbox/streets-v11', + accessToken: api_key, + }).addTo(map); + } else { + L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>', + }).addTo(map); + } + let marker = L.marker([lat, lng]).addTo(map); + let url = lat + ',' + lng + '#map=' + zoom + '/' + lat + '/' + lng + '&layers=N'; + marker.bindPopup( + address + + '<p><a href="https://www.openstreetmap.org/directions?engine=osrm_car&route=' + + url + + '">Routing via OpenStreetMap</a></p>', + ); + } +} + +document.addEventListener('DOMContentLoaded', function () { + // Initialise street maps if necessary. + initMap(); +}); diff --git a/static/site.webmanifest b/static/site.webmanifest new file mode 100644 index 0000000..45dc8a2 --- /dev/null +++ b/static/site.webmanifest @@ -0,0 +1 @@ +{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} \ No newline at end of file