diff --git a/config/_default/config.toml b/config/_default/config.toml deleted file mode 100644 index 6e2511c..0000000 --- a/config/_default/config.toml +++ /dev/null @@ -1,44 +0,0 @@ -baseURL = 'https://new.tfcconnection.org/' -languageCode = 'en-us' -title = 'TFC Connection' -theme = "blowfish" - -DefaultContentLanguage = "en" -# SectionPagesMenu = "main" -enableRobotsTXT = true - -Paginate = 10 # this is set low for demonstrating with dummy content. Set to a higher number -SummaryLength = 20 - -buildDrafts = false -buildFuture = false -outputs.home = ["HTML", "RSS", "JSON"] - -[taxonomies] - tag = "tags" - category = "categories" - author = "authors" - series = "series" - -[sitemap] - changefreq = 'daily' - filename = 'sitemap.xml' - priority = 0.5 - -[params] - favicon = "favicon-16x16.png" - site_logo = "img/logo.png" - description = "Connecting teens with the truth of Jesus Christ… teaching and equipping them to live out the Great Commission." - - -# Privacy -[privacy] - [privacy.disqus] - disable = true - [privacy.googleAnalytics] - disable = true - [privacy.instagram] - [privacy.twitter] - [privacy.vimeo] - [privacy.youtube] - diff --git a/config/_default/config.yaml b/config/_default/config.yaml new file mode 100644 index 0000000..2e0ed90 --- /dev/null +++ b/config/_default/config.yaml @@ -0,0 +1,56 @@ +baseURL: 'https://new.tfcconnection.org/' +languageCode: en-us +title: TFC Connection +theme: blowfish +DefaultContentLanguage: en +enableRobotsTXT: true +Paginate: 10 +SummaryLength: 20 +buildDrafts: false +buildFuture: false +outputs: + home: + - HTML + - RSS + - JSON +taxonomies: + tag: tags + category: categories + author: authors + series: series +sitemap: + changefreq: daily + filename: sitemap.xml + priority: 0.5 +params: + favicon: favicon-16x16.png + site_logo: img/logo.png + description: >- + Connecting teens with the truth of Jesus Christ… teaching and equipping them + to live out the Great Commission. + hugoLeaflet: + css: + - href: "https://unpkg.com/leaflet@1.6.0/dist/leaflet.css" + params: + integrity: "sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ==" + crossorigin: "" + - href: "https://unpkg.com/@raruto/leaflet-elevation@1.1.1/dist/leaflet-elevation.css" + - href: "css/leaflet.extra-markers.min.css" + js: + - src: "https://unpkg.com/leaflet@1.6.0/dist/leaflet.js" + params: + integrity: "sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew==" + crossorigin: "" + - src: "js/leaflet.elevation.js" + - src: "js/leaflet.hugo.js" + - src: "js/leaflet.extra-markers.min.js" + +privacy: + disqus: + disable: true + googleAnalytics: + disable: true + instagram: {} + twitter: {} + vimeo: {} + youtube: {} diff --git a/config/_default/params.toml b/config/_default/params.toml deleted file mode 100644 index 880e4b9..0000000 --- a/config/_default/params.toml +++ /dev/null @@ -1,58 +0,0 @@ -colorScheme = "blowfish" -defaultAppearance = "dark" -autoSwitchAppearance = false -enableSearch = true -logo = "logo.png" - -[author] -name = "TFC Connection" -links = [ - {facebook = "https://facebook.com/tfcconnection"}, - {instagram = "https://instagram.com/tfcconnection"} -] - -[header] - layout = "basic" - -[homepage] - layout = "page" # valid options: page, profile, hero, card, background, custom - # homepageImage = "/img/iceland.jpg" # used in: hero, and card - showRecent = false - showRecentItems = 5 - showMoreLink = true - showMoreLinkDest = "docs" - -[article] - showDate = false - showDateUpdated = false - showAuthor = true - showHero = true - heroStyle = "background" # valid options: basic, big, background - showBreadcrumbs = true - showDraftLabel = true - showEdit = true - seriesOpened = false - showHeadingAnchors = true - showPagination = true - invertPagination = false - showReadingTime = false - showTableOfContents = true - showTaxonomies = true - showAuthorsBadges = true - showWordCount = false - showSummary = true - sharingLinks = [ "twitter", "reddit", "facebook", "instagram", "email"] - -[list] - showBreadcrumbs = true - showSummary = true - showTableOfContents = true - showCards = true - groupByYear = false - -[footer] - showMenu = true - showCopyright = true - showThemeAttribution = true - showAppearanceSwitcher = false - showScrollToTop = true diff --git a/config/_default/params.yaml b/config/_default/params.yaml new file mode 100644 index 0000000..9e5d72a --- /dev/null +++ b/config/_default/params.yaml @@ -0,0 +1,55 @@ +colorScheme: blowfish +defaultAppearance: dark +autoSwitchAppearance: false +enableSearch: true +logo: logo.png +author: + name: TFC Connection + links: + - facebook: 'https://facebook.com/tfcconnection' + - instagram: 'https://instagram.com/tfcconnection' +header: + layout: basic +homepage: + layout: page + showRecent: false + showRecentItems: 5 + showMoreLink: true + showMoreLinkDest: docs +article: + showDate: false + showDateUpdated: false + showAuthor: true + showHero: true + heroStyle: background + showBreadcrumbs: true + showDraftLabel: true + showEdit: true + seriesOpened: false + showHeadingAnchors: true + showPagination: true + invertPagination: false + showReadingTime: false + showTableOfContents: true + showTaxonomies: true + showAuthorsBadges: true + showWordCount: false + showSummary: true + sharingLinks: + - twitter + - reddit + - facebook + - instagram + - email +list: + showBreadcrumbs: true + showSummary: true + showTableOfContents: true + showCards: true + groupByYear: false +footer: + showMenu: true + showCopyright: true + showThemeAttribution: true + showAppearanceSwitcher: false + showScrollToTop: true diff --git a/layouts/_default/baseof.html b/layouts/_default/baseof.html index 0a24569..7026507 100644 --- a/layouts/_default/baseof.html +++ b/layouts/_default/baseof.html @@ -39,21 +39,22 @@
- - ↑ - + + ↑ +
- {{ end }} + {{ end }} {{- partial "footer.html" . -}} {{ if .Site.Params.enableSearch | default false }} - {{- partial "search.html" . -}} + {{- partial "search.html" . -}} {{ end }} + {{ partial "leaflet-loader" . }} diff --git a/layouts/partials/leaflet-loader.html b/layouts/partials/leaflet-loader.html new file mode 100644 index 0000000..b3b92f4 --- /dev/null +++ b/layouts/partials/leaflet-loader.html @@ -0,0 +1,21 @@ +{{ range $.Site.Params.hugoLeaflet.css }} + +{{ end }} + +{{ range $.Site.Params.hugoLeaflet.js }} + +{{ end }} + + diff --git a/layouts/shortcodes/leaflet-map.html b/layouts/shortcodes/leaflet-map.html new file mode 100644 index 0000000..1d2da88 --- /dev/null +++ b/layouts/shortcodes/leaflet-map.html @@ -0,0 +1,30 @@ +{{ if .IsNamedParams }} + +{{ $mapLat := default "" (.Get "mapLat") }} +{{ $mapLon := default "" (.Get "mapLon") }} +{{ $zoom := default "13" (.Get "zoom") }} +{{ $mapWidth := default "100%" (.Get "mapWidth") }} +{{ $mapHeight := default "400px" (.Get "mapHeight") }} +{{ $mapId := default (md5 (printf "%s%s" $mapLat $mapLon)) (.Get "mapId") }} +{{ $scrollWheelZoom := default "true" (.Get "scrollWheelZoom") }} + + +
+ + +{{.Inner}} + +{{ else }} +{{ errorf "Leaflet Hugo Shortcode: please provide named Parameters" }} +{{ end }} diff --git a/layouts/shortcodes/leaflet-marker.html b/layouts/shortcodes/leaflet-marker.html new file mode 100644 index 0000000..d6974bf --- /dev/null +++ b/layouts/shortcodes/leaflet-marker.html @@ -0,0 +1,32 @@ +{{ if .IsNamedParams }} + +{{ $markerLat := default "" (.Get "markerLat") }} +{{ $markerLon := default "" (.Get "markerLon") }} +{{ $markerContent := default "" (.Get "markerContent") }} + + {{ with .Parent }} + + {{ $mapLat := default "" (.Get "mapLat") }} + {{ $mapLon := default "" (.Get "mapLon") }} + {{ $mapId := default (md5 (printf "%s%s" $mapLat $mapLon)) (.Get "mapId") }} + {{ $markerId := md5 (printf "%s%s%s" $mapId $markerLat $markerLon)}} + + + + {{ else }} + {{ errorf "Leaflet Hugo Shortcode: impossible using marker outside leaflet-map" }} + {{ end }} + +{{ else }} +{{ errorf "Leaflet Hugo Shortcode: please provide named Parameters for marker" }} +{{ end }} + + + diff --git a/layouts/shortcodes/leaflet-track.html b/layouts/shortcodes/leaflet-track.html new file mode 100644 index 0000000..07cffd9 --- /dev/null +++ b/layouts/shortcodes/leaflet-track.html @@ -0,0 +1,82 @@ +{{ if .IsNamedParams }} + +{{ $trackPath := default "" (.Get "trackPath") }} +{{ $lineColor := default "#006EFF" (.Get "lineColor") }} +{{ $lineWeight := default "3" (.Get "lineWeight") }} +{{ $lineOpacity := default "1" (.Get "lineOpacity") }} + +{{ $graphPosition := default "topright" (.Get "graphPosition") }} +{{ $graphTheme := default "steelblue-theme" (.Get "graphTheme") }} +{{ $graphWidth := default "500" (.Get "graphWidth") }} +{{ $graphHeight := default "150" (.Get "graphHeight") }} +{{ $graphFollowMarker := default false (.Get "graphFollowMarker") }} +{{ $graphCollapsed := default false (.Get "graphCollapsed") }} +{{ $graphDetached := default true (.Get "graphDetached") }} + +{{ $markerIcon := default "fa-thumb-tack" (.Get "markerIcon") }} +{{ $markerIconColor := default "cyan" (.Get "markerIconColor") }} +{{ $markerIconShape := default "penta" (.Get "markerIconShape") }} +{{ $markerIconClasses := default "fa-icon-marker" (.Get "markerIconClasses") }} +{{ $markerStartIcon := default "fa-play" (.Get "markerStartIcon") }} +{{ $markerStartIconColor := default "green-light" (.Get "markerStartIconColor") }} +{{ $markerStartIconShape := default "circle" (.Get "markerStartIconShape") }} +{{ $markerStartIconClasses := default "fa-icon-marker fa-icon-start-stop" (.Get "markerStartIconClasses") }} +{{ $markerEndIcon := default "fa-flag-checkered" (.Get "markerEndIcon") }} +{{ $markerEndIconColor := default "red" (.Get "markerEndIconColor") }} +{{ $markerEndIconShape := default "circle" (.Get "markerEndIconShape") }} +{{ $markerEndIconClasses := default "fa-icon-marker fa-icon-start-stop" (.Get "markerEndIconClasses") }} + +{{ with .Parent }} + +{{ $mapLat := default "" (.Get "mapLat") }} +{{ $mapLon := default "" (.Get "mapLon") }} +{{ $mapId := default (md5 (printf "%s%s" $mapLat $mapLon)) (.Get "mapId") }} +{{ $trackId := md5 (printf "%s%s" $mapId $trackPath)}} + + + +
+ +{{ else }} +{{ errorf "Leaflet Hugo Shortcode: impossible using track outside leaflet-map" }} +{{ end }} + +{{ else }} +{{ errorf "Leaflet Hugo Shortcode: please provide named Parameters for marker" }} +{{ end }} + + + 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 + * @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/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/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: '', + 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: '', + 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('Total Length: ' + this.track_info.distance.toFixed(2) + ' ' + this._xLabel + 'Max Elevation: ' + this.track_info.elevation_max.toFixed(2) + ' ' + this._yLabel + 'Min Elevation: ' + this.track_info.elevation_min.toFixed(2) + ' ' + this._yLabel + ''); + } + 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: '',\n square: '',\n star: '',\n penta: ''\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 += '';\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 + * @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:'',square:'',star:'',penta:''}[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+="'},_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;