forked from MapComplete/MapComplete
		
	Finish the export functionality: move logic around a bit, add license information for reusers, wire the functionality as feature switch
This commit is contained in:
		
							parent
							
								
									3001a563d2
								
							
						
					
					
						commit
						abd7db100d
					
				
					 10 changed files with 98 additions and 65 deletions
				
			
		|  | @ -42,6 +42,7 @@ export default class LayoutConfig { | |||
|     public readonly enableGeolocation: boolean; | ||||
|     public readonly enableBackgroundLayerSelection: boolean; | ||||
|     public readonly enableShowAllQuestions: boolean; | ||||
|     public readonly enableExportButton: boolean; | ||||
|     public readonly customCss?: string; | ||||
|     /* | ||||
|     How long is the cache valid, in seconds? | ||||
|  | @ -152,6 +153,7 @@ export default class LayoutConfig { | |||
|         this.enableAddNewPoints = json.enableAddNewPoints ?? true; | ||||
|         this.enableBackgroundLayerSelection = json.enableBackgroundLayerSelection ?? true; | ||||
|         this.enableShowAllQuestions = json.enableShowAllQuestions ?? false; | ||||
|         this.enableExportButton = json.enableExportButton ?? false; | ||||
|         this.customCss = json.customCss; | ||||
|         this.cacheTimeout = json.cacheTimout ?? (60 * 24 * 60 * 60) | ||||
| 
 | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ import UnitConfigJson from "./UnitConfigJson"; | |||
|  * General remark: a type (string | any) indicates either a fixed or a translatable string. | ||||
|  */ | ||||
| export interface LayoutConfigJson { | ||||
|     | ||||
|     /** | ||||
|      * The id of this layout. | ||||
|      * | ||||
|  | @ -335,4 +336,5 @@ export interface LayoutConfigJson { | |||
|     enableGeolocation?: boolean; | ||||
|     enableBackgroundLayerSelection?: boolean; | ||||
|     enableShowAllQuestions?: boolean; | ||||
|     enableExportButton?: boolean; | ||||
| } | ||||
|  |  | |||
|  | @ -1,9 +1,45 @@ | |||
| import {UIEventSource} from "../UIEventSource"; | ||||
| import {Utils} from "../../Utils"; | ||||
| 
 | ||||
| export default interface FeatureSource { | ||||
|     features: UIEventSource<{feature: any, freshness: Date}[]>; | ||||
|     features: UIEventSource<{ feature: any, freshness: Date }[]>; | ||||
|     /** | ||||
|      * Mainly used for debuging | ||||
|      */ | ||||
|     name: string; | ||||
| } | ||||
| 
 | ||||
| export class FeatureSourceUtils { | ||||
| 
 | ||||
|     /** | ||||
|      * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) | ||||
|      * @param featurePipeline The FeaturePipeline you want to export | ||||
|      * @param options The options object | ||||
|      * @param options.metadata True if you want to include the MapComplete metadata, false otherwise | ||||
|      */ | ||||
|     public static extractGeoJson(featurePipeline: FeatureSource, options: { metadata?: boolean } = {}) { | ||||
|         let defaults = { | ||||
|             metadata: false, | ||||
|         } | ||||
|         options = Utils.setDefaults(options, defaults); | ||||
| 
 | ||||
|         // Select all features, ignore the freshness and other data
 | ||||
|         let featureList: any[] = featurePipeline.features.data.map((feature) => feature.feature); | ||||
| 
 | ||||
|         if (!options.metadata) { | ||||
|             for (let i = 0; i < featureList.length; i++) { | ||||
|                 let feature = featureList[i]; | ||||
|                 for (let property in feature.properties) { | ||||
|                     if (property[0] == "_") { | ||||
|                         delete featureList[i]["properties"][property]; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return {type: "FeatureCollection", features: featureList} | ||||
| 
 | ||||
|    | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -1,39 +0,0 @@ | |||
| import FeaturePipeline from "./FeaturePipeline"; | ||||
| import {Utils} from "../../Utils"; | ||||
| 
 | ||||
| /** | ||||
|  * Exports given featurePipeline as a geojson FeatureLists (downloads as a json) | ||||
|  * @param featurePipeline The FeaturePipeline you want to export | ||||
|  * @param options The options object | ||||
|  * @param options.metadata True if you want to include the MapComplete metadata, false otherwise | ||||
|  */ | ||||
| export function exportAsGeoJson(featurePipeline: FeaturePipeline, options: { metadata?: boolean} = {}) { | ||||
|     let defaults = { | ||||
|         metadata: false, | ||||
|     } | ||||
|     options = Utils.setDefaults(options, defaults); | ||||
| 
 | ||||
|     // Select all features, ignore the freshness and other data
 | ||||
|     let featureList: JSON[] = featurePipeline ? featurePipeline.features.data.map((feature) => feature.feature) : ["I'm empty"]; | ||||
| 
 | ||||
|     /** | ||||
|      * Removes the metadata of MapComplete (all properties starting with an underscore) | ||||
|      * @param featureList JsonList containing features, output object | ||||
|      */ | ||||
|     function removeMetaData(featureList: JSON[]) { | ||||
|         for (let i=0; i < featureList.length; i++) { | ||||
|             let feature = featureList[i]; | ||||
|             for (let property in feature.properties) { | ||||
|                 if (property[0] == "_") { | ||||
|                     delete featureList[i]["properties"][property]; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (!options.metadata) removeMetaData(featureList); | ||||
| 
 | ||||
|     let geojson = {type: "FeatureCollection", features: featureList} | ||||
| 
 | ||||
|     Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), "Geodata.json"); | ||||
| } | ||||
							
								
								
									
										6
									
								
								State.ts
									
										
									
									
									
								
							
							
						
						
									
										6
									
								
								State.ts
									
										
									
									
									
								
							|  | @ -96,6 +96,10 @@ export default class State { | |||
|     public readonly featureSwitchIsDebugging: UIEventSource<boolean>; | ||||
|     public readonly featureSwitchShowAllQuestions: UIEventSource<boolean>; | ||||
|     public readonly featureSwitchApiURL: UIEventSource<string>; | ||||
|    public readonly featureSwitchEnableExport: UIEventSource<boolean>; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     public readonly featurePipeline: FeaturePipeline; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -201,6 +205,8 @@ export default class State { | |||
|                 "Disables/Enables the geolocation button"); | ||||
|             this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, | ||||
|                 "Always show all questions"); | ||||
|             this.featureSwitchEnableExport = featSw("fs-export",(layoutToUse) => layoutToUse?.enableExportButton ?? false, | ||||
|                 "If set, enables the 'download'-button to download everything as geojson") | ||||
| 
 | ||||
|             this.featureSwitchIsTesting = QueryParameters.GetQueryParameter("test", "false", | ||||
|                 "If true, 'dryrun' mode is activated. The app will behave as normal, except that changes to OSM will be printed onto the console instead of actually uploaded to osm.org") | ||||
|  |  | |||
							
								
								
									
										2
									
								
								Svg.ts
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								Svg.ts
									
										
									
									
									
								
							|  | @ -94,7 +94,7 @@ export default class Svg { | |||
|     public static crosshair_empty_svg() { return new Img(Svg.crosshair_empty, true);} | ||||
|     public static crosshair_empty_ui() { return new FixedUiElement(Svg.crosshair_empty_img);} | ||||
| 
 | ||||
|     public static crosshair_locked = " <!-- Created with Inkscape (http://www.inkscape.org/) -->  <svg    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"    xmlns:cc=\"http://creativecommons.org/ns#\"    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"    xmlns:svg=\"http://www.w3.org/2000/svg\"    xmlns=\"http://www.w3.org/2000/svg\"    xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"    xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"    width=\"100\"    height=\"100\"    viewBox=\"0 0 26.458333 26.458334\"    version=\"1.1\"    id=\"svg8\"    inkscape:version=\"0.92.5 (2060ec1f9f, 2020-04-08)\"    sodipodi:docname=\"crosshair-locked.svg\">   <defs      id=\"defs2\" />   <sodipodi:namedview      id=\"base\"      pagecolor=\"#ffffff\"      bordercolor=\"#666666\"      borderopacity=\"1.0\"      inkscape:pageopacity=\"0.0\"      inkscape:pageshadow=\"2\"      inkscape:zoom=\"2.8284271\"      inkscape:cx=\"67.47399\"      inkscape:cy=\"29.788021\"      inkscape:document-units=\"px\"      inkscape:current-layer=\"layer1\"      showgrid=\"false\"      units=\"px\"      showguides=\"true\"      inkscape:guide-bbox=\"true\"      inkscape:window-width=\"1920\"      inkscape:window-height=\"999\"      inkscape:window-x=\"0\"      inkscape:window-y=\"0\"      inkscape:window-maximized=\"1\"      inkscape:snap-global=\"false\">     <sodipodi:guide        position=\"13.229167,23.859748\"        orientation=\"1,0\"        id=\"guide815\"        inkscape:locked=\"false\" />     <sodipodi:guide        position=\"14.944824,13.229167\"        orientation=\"0,1\"        id=\"guide817\"        inkscape:locked=\"false\" />   </sodipodi:namedview>   <metadata      id=\"metadata5\">     <rdf:RDF>       <cc:Work          rdf:about=\"\">         <dc:format>image/svg+xml</dc:format>         <dc:type            rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />         <dc:title />       </cc:Work>     </rdf:RDF>   </metadata>   <g      inkscape:label=\"Layer 1\"      inkscape:groupmode=\"layer\"      id=\"layer1\"      transform=\"translate(0,-270.54165)\">     <circle        style=\"fill: none !important;fill-opacity:1;stroke:#5555ec;stroke-width:2.64583335;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529\"        id=\"path815\"        cx=\"13.16302\"        cy=\"283.77081\"        r=\"8.8715391\" />     <path        style=\"fill: none !important;stroke:#5555ec;stroke-width:2.09723878;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\"        d=\"M 3.2841366,283.77082 H 1.0418969\"        id=\"path817\"        inkscape:connector-curvature=\"0\" />     <path        style=\"fill: none !important;stroke:#5555ec;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\"        d=\"M 25.405696,283.77082 H 23.286471\"        id=\"path817-3\"        inkscape:connector-curvature=\"0\" />     <path        style=\"fill: none !important;stroke:#5555ec;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\"        d=\"m 13.229167,295.9489 v -2.11763\"        id=\"path817-3-6\"        inkscape:connector-curvature=\"0\" />     <path        style=\"fill: none !important;stroke:#5555ec;stroke-width:2.11666668;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\"        d=\"m 13.229167,275.05759 v -3.44507\"        id=\"path817-3-6-7\"        inkscape:connector-curvature=\"0\" />     <g        id=\"g824\"        transform=\"matrix(0.63953151,0,0,0.64343684,6.732623,276.71502)\"        style=\"fill:#ffcc33\">       <path          id=\"path822\"          d=\"M 16.07,8 H 15 V 5 C 15,5 15,0 10,0 5,0 5,5 5,5 V 8 H 3.93 A 1.93,1.93 0 0 0 2,9.93 v 8.15 A 1.93,1.93 0 0 0 3.93,20 H 16.07 A 1.93,1.93 0 0 0 18,18.07 V 9.93 A 1.93,1.93 0 0 0 16.07,8 Z M 10,16 a 2,2 0 1 1 2,-2 2,2 0 0 1 -2,2 z M 13,8 H 7 V 5.5 C 7,4 7,2 10,2 c 3,0 3,2 3,3.5 z\"          inkscape:connector-curvature=\"0\" />     </g>   </g> </svg> " | ||||
|     public static crosshair_locked = " <!-- Created with Inkscape (http://www.inkscape.org/) -->  <svg    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"    xmlns:cc=\"http://creativecommons.org/ns#\"    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"    xmlns:svg=\"http://www.w3.org/2000/svg\"    xmlns=\"http://www.w3.org/2000/svg\"    xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"    xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"    width=\"100\"    height=\"100\"    viewBox=\"0 0 26.458333 26.458334\"    version=\"1.1\"    id=\"svg8\"    inkscape:version=\"0.92.5 (2060ec1f9f, 2020-04-08)\"    sodipodi:docname=\"crosshair-locked.svg\">   <defs      id=\"defs2\" />   <sodipodi:namedview      id=\"base\"      pagecolor=\"#ffffff\"      bordercolor=\"#666666\"      borderopacity=\"1.0\"      inkscape:pageopacity=\"0.0\"      inkscape:pageshadow=\"2\"      inkscape:zoom=\"5.6568542\"      inkscape:cx=\"27.044982\"      inkscape:cy=\"77.667126\"      inkscape:document-units=\"px\"      inkscape:current-layer=\"layer1\"      showgrid=\"false\"      units=\"px\"      showguides=\"true\"      inkscape:guide-bbox=\"true\"      inkscape:window-width=\"1920\"      inkscape:window-height=\"999\"      inkscape:window-x=\"0\"      inkscape:window-y=\"0\"      inkscape:window-maximized=\"1\"      inkscape:snap-global=\"false\">     <sodipodi:guide        position=\"13.229167,23.859748\"        orientation=\"1,0\"        id=\"guide815\"        inkscape:locked=\"false\" />     <sodipodi:guide        position=\"14.944824,13.229167\"        orientation=\"0,1\"        id=\"guide817\"        inkscape:locked=\"false\" />   </sodipodi:namedview>   <metadata      id=\"metadata5\">     <rdf:RDF>       <cc:Work          rdf:about=\"\">         <dc:format>image/svg+xml</dc:format>         <dc:type            rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\" />         <dc:title />       </cc:Work>     </rdf:RDF>   </metadata>   <g      inkscape:label=\"Layer 1\"      inkscape:groupmode=\"layer\"      id=\"layer1\"      transform=\"translate(0,-270.54165)\">     <g        id=\"g827\">       <circle          r=\"8.8715391\"          cy=\"283.77081\"          cx=\"13.16302\"          id=\"path815\"          style=\"fill: none !important;fill-opacity:1;stroke:#5555ec;stroke-width:2.64583335;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.98823529\" />       <path          inkscape:connector-curvature=\"0\"          id=\"path817\"          d=\"M 3.2841366,283.77082 H 1.0418969\"          style=\"fill: none !important;stroke:#5555ec;stroke-width:2.09723878;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" />       <path          inkscape:connector-curvature=\"0\"          id=\"path817-3\"          d=\"M 25.405696,283.77082 H 23.286471\"          style=\"fill: none !important;stroke:#5555ec;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" />       <path          inkscape:connector-curvature=\"0\"          id=\"path817-3-6\"          d=\"m 13.229167,295.9489 v -2.11763\"          style=\"fill: none !important;stroke:#5555ec;stroke-width:2.11666679;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" />       <path          inkscape:connector-curvature=\"0\"          id=\"path817-3-6-7\"          d=\"m 13.229167,275.05759 v -3.44507\"          style=\"fill: none !important;stroke:#5555ec;stroke-width:2.11666668;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.98823529\" />     </g>     <path        style=\"fill:#5555ec;fill-opacity:0.98823529;stroke-width:0.6151033\"        inkscape:connector-curvature=\"0\"        d=\"m 16.850267,281.91543 h -0.65616 v -1.85094 c 0,0 0,-3.08489 -3.066169,-3.08489 -3.066169,0 -3.066169,3.08489 -3.066169,3.08489 v 1.85094 H 9.4056091 a 1.1835412,1.1907685 0 0 0 -1.1835412,1.19077 v 5.02838 a 1.1835412,1.1907685 0 0 0 1.1835412,1.1846 h 7.4446579 a 1.1835412,1.1907685 0 0 0 1.183541,-1.19078 v -5.0222 a 1.1835412,1.1907685 0 0 0 -1.183541,-1.19077 z m -3.722329,4.93583 a 1.2264675,1.233957 0 1 1 1.226468,-1.23395 1.2264675,1.233957 0 0 1 -1.226468,1.23395 z m 1.839702,-4.93583 h -3.679403 v -1.54245 c 0,-0.92546 0,-2.15942 1.839701,-2.15942 1.839702,0 1.839702,1.23396 1.839702,2.15942 z\"        id=\"path822\" />   </g> </svg> " | ||||
|     public static crosshair_locked_img = Img.AsImageElement(Svg.crosshair_locked) | ||||
|     public static crosshair_locked_svg() { return new Img(Svg.crosshair_locked, true);} | ||||
|     public static crosshair_locked_ui() { return new FixedUiElement(Svg.crosshair_locked_img);} | ||||
|  |  | |||
							
								
								
									
										21
									
								
								UI/BigComponents/ExportDataButton.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								UI/BigComponents/ExportDataButton.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| import {SubtleButton} from "../Base/SubtleButton"; | ||||
| import Svg from "../../Svg"; | ||||
| import Translations from "../i18n/Translations"; | ||||
| import State from "../../State"; | ||||
| import {FeatureSourceUtils} from "../../Logic/FeatureSource/FeatureSource"; | ||||
| import {Utils} from "../../Utils"; | ||||
| import Combine from "../Base/Combine"; | ||||
| 
 | ||||
| export class ExportDataButton extends Combine { | ||||
|     constructor() { | ||||
|         const t = Translations.t.general.download | ||||
|         const button = new SubtleButton(Svg.floppy_ui(), t.downloadGeojson.Clone().SetClass("font-bold")) | ||||
|             .onClick(() => { | ||||
|                 const geojson = FeatureSourceUtils.extractGeoJson(State.state.featurePipeline) | ||||
|                 const name = State.state.layoutToUse.data.id; | ||||
|                 Utils.offerContentsAsDownloadableFile(JSON.stringify(geojson), `MapComplete_${name}_export_${new Date().toISOString().substr(0,19)}.geojson`); | ||||
|             }) | ||||
|          | ||||
|         super([button, t.licenseInfo.Clone().SetClass("link-underline")]) | ||||
|     } | ||||
| } | ||||
|  | @ -2,11 +2,12 @@ import State from "../../State"; | |||
| import BackgroundSelector from "./BackgroundSelector"; | ||||
| import LayerSelection from "./LayerSelection"; | ||||
| import Combine from "../Base/Combine"; | ||||
| import {FixedUiElement} from "../Base/FixedUiElement"; | ||||
| import ScrollableFullScreen from "../Base/ScrollableFullScreen"; | ||||
| import Translations from "../i18n/Translations"; | ||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | ||||
| import BaseUIElement from "../BaseUIElement"; | ||||
| import Toggle from "../Input/Toggle"; | ||||
| import {ExportDataButton} from "./ExportDataButton"; | ||||
| 
 | ||||
| export default class LayerControlPanel extends ScrollableFullScreen { | ||||
| 
 | ||||
|  | @ -14,27 +15,34 @@ export default class LayerControlPanel extends ScrollableFullScreen { | |||
|         super(LayerControlPanel.GenTitle, LayerControlPanel.GeneratePanel, "layers", isShown); | ||||
|     } | ||||
| 
 | ||||
|     private static GenTitle():BaseUIElement { | ||||
|     private static GenTitle(): BaseUIElement { | ||||
|         return Translations.t.general.layerSelection.title.Clone().SetClass("text-2xl break-words font-bold p-2") | ||||
|     } | ||||
| 
 | ||||
|     private static GeneratePanel() : BaseUIElement { | ||||
|         let layerControlPanel: BaseUIElement = new FixedUiElement(""); | ||||
|     private static GeneratePanel(): BaseUIElement { | ||||
|         const elements: BaseUIElement[] = [] | ||||
| 
 | ||||
|         if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { | ||||
|             layerControlPanel = new BackgroundSelector(); | ||||
|             layerControlPanel.SetStyle("margin:1em"); | ||||
|             layerControlPanel.onClick(() => { | ||||
|             const backgroundSelector = new BackgroundSelector(); | ||||
|             backgroundSelector.SetStyle("margin:1em"); | ||||
|             backgroundSelector.onClick(() => { | ||||
|             }); | ||||
|             elements.push(backgroundSelector) | ||||
|         } | ||||
| 
 | ||||
|         if (State.state.filteredLayers.data.length > 1) { | ||||
|             const layerSelection = new LayerSelection(State.state.filteredLayers); | ||||
|             layerSelection.onClick(() => { | ||||
|             }); | ||||
|             layerControlPanel = new Combine([layerSelection, "<br/>", layerControlPanel]); | ||||
|         } | ||||
|         elements.push(new Toggle( | ||||
|             new LayerSelection(State.state.filteredLayers), | ||||
|             undefined, | ||||
|             State.state.filteredLayers.map(layers => layers.length > 1) | ||||
|         )) | ||||
| 
 | ||||
|         return layerControlPanel; | ||||
|         elements.push(new Toggle( | ||||
|             new ExportDataButton(), | ||||
|             undefined, | ||||
|             State.state.featureSwitchEnableExport | ||||
|         )) | ||||
| 
 | ||||
|         return new Combine(elements).SetClass("flex flex-col") | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -7,8 +7,6 @@ import Translations from "../i18n/Translations"; | |||
| import LayerConfig from "../../Customizations/JSON/LayerConfig"; | ||||
| import BaseUIElement from "../BaseUIElement"; | ||||
| import {Translation} from "../i18n/Translation"; | ||||
| import {SubtleButton} from "../Base/SubtleButton"; | ||||
| import {exportAsGeoJson} from "../../Logic/FeatureSource/GeoJsonExport"; | ||||
| 
 | ||||
| /** | ||||
|  * Shows the panel with all layers and a toggle for each of them | ||||
|  | @ -76,10 +74,6 @@ export default class LayerSelection extends Combine { | |||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         const downloadButton = new SubtleButton("./assets/svg/floppy.svg", Translations.t.general.layerSelection.downloadGeojson.Clone()) | ||||
|         downloadButton.onClick(() => exportAsGeoJson(State.state.featurePipeline)) | ||||
|         checkboxes.push(downloadButton) | ||||
| 
 | ||||
|         super(checkboxes) | ||||
|         this.SetStyle("display:flex;flex-direction:column;") | ||||
| 
 | ||||
|  |  | |||
|  | @ -147,8 +147,11 @@ | |||
|     "loginOnlyNeededToEdit": "if you want to edit the map", | ||||
|     "layerSelection": { | ||||
|       "zoomInToSeeThisLayer": "Zoom in to see this layer", | ||||
|       "title": "Select layers", | ||||
|       "downloadGeojson": "Download layer features as geojson" | ||||
|       "title": "Select layers" | ||||
|     }, | ||||
|     "download": { | ||||
|       "downloadGeojson": "Download visible data as geojson", | ||||
|       "licenseInfo": "<h3>Copyright notice</h3>The provided is available under ODbL. Reusing this data is free for any purpose, but <ul><li>the attribution <b>© OpenStreetMap contributors</b></li><li>Any change to this data must be republished under the same license</li></ul>. Please see the full <a href='https://www.openstreetmap.org/copyright' target='_blank'>copyright notice</a> for details" | ||||
|     }, | ||||
|     "weekdays": { | ||||
|       "abbreviations": { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue