diff --git a/css/style.css b/css/style.css index 99cc7b3..fb38eb7 100644 --- a/css/style.css +++ b/css/style.css @@ -203,6 +203,9 @@ input#trackname:focus:invalid { .circlego-outside { cursor: not-allowed; } +.leaflet-popup-content p { + margin: 0.5em 0; +} #map { /* center error message horizontally */ diff --git a/js/plugin/CircleGoArea.js b/js/plugin/CircleGoArea.js index 02686f3..a17250f 100644 --- a/js/plugin/CircleGoArea.js +++ b/js/plugin/CircleGoArea.js @@ -94,12 +94,16 @@ BR.CircleGoArea = L.Control.extend({ this.routing.draw(false); this.pois.draw(false); this.map.on('click', this.onMapClick, this); - this.map.addLayer(this.countriesMask); + if (this.countriesMask) { + this.map.addLayer(this.countriesMask); + } this._unlockOutsideArea(); L.DomUtil.addClass(this.map.getContainer(), 'circlego-draw-enabled'); } else { this.map.off('click', this.onMapClick, this); - this.map.removeLayer(this.countriesMask); + if (this.countriesMask && this.map.hasLayer(this.countriesMask)) { + this.map.removeLayer(this.countriesMask); + } this._lockOutsideArea(); L.DomUtil.removeClass(this.map.getContainer(), 'circlego-draw-enabled'); } @@ -475,57 +479,7 @@ BR.CircleGoArea = L.Control.extend({ }, setCircle: function (center, polylines) { - var self = this; - var icon = (this.icon = L.VectorMarkers.icon({ - icon: 'home', - markerColor: BR.conf.markerColors.circlego, - })); - this.iconSpinner = L.VectorMarkers.icon({ - icon: 'spinner', - spin: true, - markerColor: BR.conf.markerColors.circlego, - }); - - var popupContent = - ''; - - var marker = (this.marker = L.marker([center[1], center[0]], { - icon: icon, - draggable: true, - // prevent being on top of route markers - zIndexOffset: -500, - }) - .bindPopup(popupContent) - .on('dragend', function (e) { - self.setNogoRing([e.target.getLatLng().lng, e.target.getLatLng().lat]); - }) - .on('click', function () { - var drawing = self.drawButton.state() == 'deactivate-circlego'; - if (drawing) { - self.circleLayer.removeLayer(marker); - self.setNogoRing(undefined); - } - }) - .on('popupopen', function (evt) { - var popup = evt.popup; - var html = ''; - if (self.radius) { - if (self.boundaryLayer) { - var name = self.boundaryLayer.getLayers()[0].feature.properties.name; - html += BR.Util.sanitizeHTMLContent(name) + '
+ '; - } - html += (self.radius / 1000).toFixed() + ' km

'; - } else { - html += i18next.t('map.not-applicable-here') + '

'; - } - popup.setContent(html + popupContent); - - $('#remove-ringgo-marker').on('click', function (e) { - e.preventDefault(); - self.circleLayer.removeLayer(marker); - self.setNogoRing(undefined); - }); - })); + var marker = (this.marker = this._createMarker(center)); this.clear(); marker.addTo(this.circleLayer); @@ -549,6 +503,123 @@ BR.CircleGoArea = L.Control.extend({ this.draw(false); }, + _createMarker: function (center) { + var self = this; + var icon = (this.icon = L.VectorMarkers.icon({ + icon: 'home', + markerColor: BR.conf.markerColors.circlego, + })); + this.iconSpinner = L.VectorMarkers.icon({ + icon: 'spinner', + spin: true, + markerColor: BR.conf.markerColors.circlego, + }); + + var popupContent = + ''; + + var marker = L.marker([center[1], center[0]], { + icon: icon, + draggable: true, + // prevent being on top of route markers + zIndexOffset: -500, + }) + .bindPopup(popupContent) + .on('dragend', function (e) { + self.setNogoRing([e.target.getLatLng().lng, e.target.getLatLng().lat]); + }) + .on('click', function () { + var drawing = self.drawButton.state() == 'deactivate-circlego'; + if (drawing) { + self.circleLayer.removeLayer(marker); + self.setNogoRing(undefined); + } + }) + .on( + 'popupopen', + function (evt) { + this._onPopupOpen(evt.popup, popupContent); + }, + this + ) + .on('popupclose', this._onPopupClose, this); + + return marker; + }, + + _onPopupOpen: function (popup, popupContent) { + var exportName = ''; + var html = '

'; + if (this.radius) { + if (this.boundaryLayer) { + var name = this.boundaryLayer.getLayers()[0].feature.properties.name; + exportName += name + ' + '; + html += BR.Util.sanitizeHTMLContent(name) + '
+ '; + } + var radiusText = (this.radius / 1000).toFixed(); + exportName += radiusText + ' km'; + html += radiusText + ' km'; + if (this.nogoPolylines) { + html += '

'; + html += + '' + + i18next.t('export.format_gpx') + + ''; + html += '
'; + html += + '' + + i18next.t('export.format_geojson') + + ''; + } + } else { + html += i18next.t('map.not-applicable-here'); + } + html += '

'; + popup.setContent(html + popupContent); + + if (this.nogoPolylines) { + var link = location.href.replace(/&polylines=[^&]*/, ''); + var geoJson = this.nogoPolylines.toGeoJSON(); + var gpx = togpx(geoJson, { metadata: { name: exportName, link: link } }); + this._setDownloadUrl(gpx, 'application/gpx+xml', 'ringgo-download-gpx'); + this._setDownloadUrl( + JSON.stringify(geoJson, null, 2), + 'application/vnd.geo+json', + 'ringgo-download-geojson' + ); + } + + $('#remove-ringgo-marker').on( + 'click', + L.bind(function (e) { + e.preventDefault(); + this.circleLayer.removeLayer(this.marker); + this.setNogoRing(undefined); + }, this) + ); + }, + + _onPopupClose: function (evt) { + this._revokeDownloadUrl('ringgo-download-gpx'); + this._revokeDownloadUrl('ringgo-download-geojson'); + }, + + _setDownloadUrl: function (text, mimeType, elementId) { + var blob = new Blob([text], { + type: mimeType + ';charset=utf-8', + }); + var objectUrl = URL.createObjectURL(blob); + var download = document.getElementById(elementId); + download.href = objectUrl; + }, + + _revokeDownloadUrl: function (elementId) { + var download = document.getElementById(elementId); + if (download) { + URL.revokeObjectURL(download.href); + } + }, + _clearLayers: function () { if (this.outsideArea) { this.map.removeLayer(this.outsideArea); diff --git a/js/plugin/POIMarkers.js b/js/plugin/POIMarkers.js index 30df878..500863b 100644 --- a/js/plugin/POIMarkers.js +++ b/js/plugin/POIMarkers.js @@ -97,7 +97,7 @@ BR.PoiMarkers = L.Control.extend({ markerColor: BR.conf.markerColors.poi, }); - var content = BR.Util.sanitizeHTMLContent(name) + '
'; + var content = '

' + BR.Util.sanitizeHTMLContent(name) + '

'; content += ""; var self = this; diff --git a/package.json b/package.json index c96a170..a63e274 100644 --- a/package.json +++ b/package.json @@ -74,6 +74,7 @@ "mapbbcode": "MapBBCode/mapbbcode#v1.2.0", "osmtogeojson": "^3.0.0-beta.4", "promise-polyfill": "^8.2.0", + "togpx": "^0.5.4", "topojson-client": "^3.1.0", "url-search-params": "~0.5.0", "whatwg-fetch": "^3.5.0" @@ -266,6 +267,11 @@ "main": [ "turf.min.js" ] + }, + "togpx": { + "main": [ + "togpx.js" + ] } } } diff --git a/yarn.lock b/yarn.lock index c31c649..cccffbc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1829,6 +1829,11 @@ base64-arraybuffer@0.1.5: resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= +base64-js@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.2.tgz#024f0f72afa25b75f9c0ee73cd4f55ec1bed9784" + integrity sha1-Ak8Pcq+iW3X5wO5zzU9V7Bvtl4Q= + base64id@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6" @@ -1927,6 +1932,14 @@ bootstrap@4.3.1, bootstrap@>=3.0.0: resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac" integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag== +bops@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/bops/-/bops-0.0.6.tgz#082d1d55fa01e60dbdc2ebc2dba37f659554cf3a" + integrity sha1-CC0dVfoB5g29wuvC26N/ZZVUzzo= + dependencies: + base64-js "0.0.2" + to-utf8 "0.0.1" + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -2502,6 +2515,13 @@ concat-stream@^1.6.0, concat-stream@~1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" +concat-stream@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.0.1.tgz#018b18bc1c7d073a2dc82aa48442341a2c4dd79f" + integrity sha1-AYsYvBx9BzotyCqkhEI0GixN158= + dependencies: + bops "0.0.6" + concat-stream@~1.5.1: version "1.5.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" @@ -5173,6 +5193,13 @@ just-debounce@^1.0.0: resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.0.0.tgz#87fccfaeffc0b68cd19d55f6722943f929ea35ea" integrity sha1-h/zPrv/AtozRnVX2cilD+SnqNeo= +jxon@~2.0.0-beta.5: + version "2.0.0-beta.5" + resolved "https://registry.yarnpkg.com/jxon/-/jxon-2.0.0-beta.5.tgz#3b6a94104f9801ee682fd056645ff5473d9b343e" + integrity sha1-O2qUEE+YAe5oL9BWZF/1Rz2bND4= + dependencies: + xmldom "^0.1.21" + kind-of@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" @@ -8168,6 +8195,21 @@ to-through@^2.0.0: dependencies: through2 "^2.0.3" +to-utf8@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/to-utf8/-/to-utf8-0.0.1.tgz#d17aea72ff2fba39b9e43601be7b3ff72e089852" + integrity sha1-0Xrqcv8vujm55DYBvns/9y4ImFI= + +togpx@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/togpx/-/togpx-0.5.4.tgz#b33dbb0541df04bd6ba4f50b86da953424bb7773" + integrity sha1-sz27BUHfBL1rpPULhtqVNCS7d3M= + dependencies: + concat-stream "~1.0.1" + jxon "~2.0.0-beta.5" + optimist "~0.3.5" + xmldom "~0.1.17" + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" @@ -8600,7 +8642,7 @@ ws@~6.1.0: dependencies: async-limiter "~1.0.0" -xmldom@~0.1.16: +xmldom@^0.1.21, xmldom@~0.1.16, xmldom@~0.1.17: version "0.1.31" resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==