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 enableGeolocation: boolean; | ||||||
|     public readonly enableBackgroundLayerSelection: boolean; |     public readonly enableBackgroundLayerSelection: boolean; | ||||||
|     public readonly enableShowAllQuestions: boolean; |     public readonly enableShowAllQuestions: boolean; | ||||||
|  |     public readonly enableExportButton: boolean; | ||||||
|     public readonly customCss?: string; |     public readonly customCss?: string; | ||||||
|     /* |     /* | ||||||
|     How long is the cache valid, in seconds? |     How long is the cache valid, in seconds? | ||||||
|  | @ -152,6 +153,7 @@ export default class LayoutConfig { | ||||||
|         this.enableAddNewPoints = json.enableAddNewPoints ?? true; |         this.enableAddNewPoints = json.enableAddNewPoints ?? true; | ||||||
|         this.enableBackgroundLayerSelection = json.enableBackgroundLayerSelection ?? true; |         this.enableBackgroundLayerSelection = json.enableBackgroundLayerSelection ?? true; | ||||||
|         this.enableShowAllQuestions = json.enableShowAllQuestions ?? false; |         this.enableShowAllQuestions = json.enableShowAllQuestions ?? false; | ||||||
|  |         this.enableExportButton = json.enableExportButton ?? false; | ||||||
|         this.customCss = json.customCss; |         this.customCss = json.customCss; | ||||||
|         this.cacheTimeout = json.cacheTimout ?? (60 * 24 * 60 * 60) |         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. |  * General remark: a type (string | any) indicates either a fixed or a translatable string. | ||||||
|  */ |  */ | ||||||
| export interface LayoutConfigJson { | export interface LayoutConfigJson { | ||||||
|  |     | ||||||
|     /** |     /** | ||||||
|      * The id of this layout. |      * The id of this layout. | ||||||
|      * |      * | ||||||
|  | @ -335,4 +336,5 @@ export interface LayoutConfigJson { | ||||||
|     enableGeolocation?: boolean; |     enableGeolocation?: boolean; | ||||||
|     enableBackgroundLayerSelection?: boolean; |     enableBackgroundLayerSelection?: boolean; | ||||||
|     enableShowAllQuestions?: boolean; |     enableShowAllQuestions?: boolean; | ||||||
|  |     enableExportButton?: boolean; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,9 +1,45 @@ | ||||||
| import {UIEventSource} from "../UIEventSource"; | import {UIEventSource} from "../UIEventSource"; | ||||||
|  | import {Utils} from "../../Utils"; | ||||||
| 
 | 
 | ||||||
| export default interface FeatureSource { | export default interface FeatureSource { | ||||||
|     features: UIEventSource<{feature: any, freshness: Date}[]>; |     features: UIEventSource<{ feature: any, freshness: Date }[]>; | ||||||
|     /** |     /** | ||||||
|      * Mainly used for debuging |      * Mainly used for debuging | ||||||
|      */ |      */ | ||||||
|     name: string; |     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"); |  | ||||||
| } |  | ||||||
							
								
								
									
										10
									
								
								State.ts
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								State.ts
									
										
									
									
									
								
							|  | @ -96,6 +96,10 @@ export default class State { | ||||||
|     public readonly featureSwitchIsDebugging: UIEventSource<boolean>; |     public readonly featureSwitchIsDebugging: UIEventSource<boolean>; | ||||||
|     public readonly featureSwitchShowAllQuestions: UIEventSource<boolean>; |     public readonly featureSwitchShowAllQuestions: UIEventSource<boolean>; | ||||||
|     public readonly featureSwitchApiURL: UIEventSource<string>; |     public readonly featureSwitchApiURL: UIEventSource<string>; | ||||||
|  |    public readonly featureSwitchEnableExport: UIEventSource<boolean>; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|     public readonly featurePipeline: FeaturePipeline; |     public readonly featurePipeline: FeaturePipeline; | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -127,7 +131,7 @@ export default class State { | ||||||
|     public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`).map<number>( |     public welcomeMessageOpenedTab = QueryParameters.GetQueryParameter("tab", "0", `The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`).map<number>( | ||||||
|         str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n |         str => isNaN(Number(str)) ? 0 : Number(str), [], n => "" + n | ||||||
|     ); |     ); | ||||||
|   |     | ||||||
|     constructor(layoutToUse: LayoutConfig) { |     constructor(layoutToUse: LayoutConfig) { | ||||||
|         const self = this; |         const self = this; | ||||||
| 
 | 
 | ||||||
|  | @ -201,6 +205,8 @@ export default class State { | ||||||
|                 "Disables/Enables the geolocation button"); |                 "Disables/Enables the geolocation button"); | ||||||
|             this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, |             this.featureSwitchShowAllQuestions = featSw("fs-all-questions", (layoutToUse) => layoutToUse?.enableShowAllQuestions ?? false, | ||||||
|                 "Always show all questions"); |                 "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", |             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") |                 "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") | ||||||
|  | @ -212,7 +218,7 @@ export default class State { | ||||||
| 
 | 
 | ||||||
|             this.featureSwitchApiURL = QueryParameters.GetQueryParameter("backend","osm", |             this.featureSwitchApiURL = QueryParameters.GetQueryParameter("backend","osm", | ||||||
|                 "The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test'") |                 "The OSM backend to use - can be used to redirect mapcomplete to the testing backend when using 'osm-test'") | ||||||
| 
 |          | ||||||
|         } |         } | ||||||
|         { |         { | ||||||
|             // Some other feature switches
 |             // Some other feature switches
 | ||||||
|  |  | ||||||
							
								
								
									
										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_svg() { return new Img(Svg.crosshair_empty, true);} | ||||||
|     public static crosshair_empty_ui() { return new FixedUiElement(Svg.crosshair_empty_img);} |     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_img = Img.AsImageElement(Svg.crosshair_locked) | ||||||
|     public static crosshair_locked_svg() { return new Img(Svg.crosshair_locked, true);} |     public static crosshair_locked_svg() { return new Img(Svg.crosshair_locked, true);} | ||||||
|     public static crosshair_locked_ui() { return new FixedUiElement(Svg.crosshair_locked_img);} |     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 BackgroundSelector from "./BackgroundSelector"; | ||||||
| import LayerSelection from "./LayerSelection"; | import LayerSelection from "./LayerSelection"; | ||||||
| import Combine from "../Base/Combine"; | import Combine from "../Base/Combine"; | ||||||
| import {FixedUiElement} from "../Base/FixedUiElement"; |  | ||||||
| import ScrollableFullScreen from "../Base/ScrollableFullScreen"; | import ScrollableFullScreen from "../Base/ScrollableFullScreen"; | ||||||
| import Translations from "../i18n/Translations"; | import Translations from "../i18n/Translations"; | ||||||
| import {UIEventSource} from "../../Logic/UIEventSource"; | import {UIEventSource} from "../../Logic/UIEventSource"; | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement"; | ||||||
|  | import Toggle from "../Input/Toggle"; | ||||||
|  | import {ExportDataButton} from "./ExportDataButton"; | ||||||
| 
 | 
 | ||||||
| export default class LayerControlPanel extends ScrollableFullScreen { | export default class LayerControlPanel extends ScrollableFullScreen { | ||||||
| 
 | 
 | ||||||
|  | @ -14,27 +15,34 @@ export default class LayerControlPanel extends ScrollableFullScreen { | ||||||
|         super(LayerControlPanel.GenTitle, LayerControlPanel.GeneratePanel, "layers", isShown); |         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") |         return Translations.t.general.layerSelection.title.Clone().SetClass("text-2xl break-words font-bold p-2") | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private static GeneratePanel() : BaseUIElement { |     private static GeneratePanel(): BaseUIElement { | ||||||
|         let layerControlPanel: BaseUIElement = new FixedUiElement(""); |         const elements: BaseUIElement[] = [] | ||||||
|  | 
 | ||||||
|         if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { |         if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { | ||||||
|             layerControlPanel = new BackgroundSelector(); |             const backgroundSelector = new BackgroundSelector(); | ||||||
|             layerControlPanel.SetStyle("margin:1em"); |             backgroundSelector.SetStyle("margin:1em"); | ||||||
|             layerControlPanel.onClick(() => { |             backgroundSelector.onClick(() => { | ||||||
|             }); |             }); | ||||||
|  |             elements.push(backgroundSelector) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (State.state.filteredLayers.data.length > 1) { |         elements.push(new Toggle( | ||||||
|             const layerSelection = new LayerSelection(State.state.filteredLayers); |             new LayerSelection(State.state.filteredLayers), | ||||||
|             layerSelection.onClick(() => { |             undefined, | ||||||
|             }); |             State.state.filteredLayers.map(layers => layers.length > 1) | ||||||
|             layerControlPanel = new Combine([layerSelection, "<br/>", layerControlPanel]); |         )) | ||||||
|         } |  | ||||||
| 
 | 
 | ||||||
|         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 LayerConfig from "../../Customizations/JSON/LayerConfig"; | ||||||
| import BaseUIElement from "../BaseUIElement"; | import BaseUIElement from "../BaseUIElement"; | ||||||
| import {Translation} from "../i18n/Translation"; | 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 |  * 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) |         super(checkboxes) | ||||||
|         this.SetStyle("display:flex;flex-direction:column;") |         this.SetStyle("display:flex;flex-direction:column;") | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -147,8 +147,11 @@ | ||||||
|     "loginOnlyNeededToEdit": "if you want to edit the map", |     "loginOnlyNeededToEdit": "if you want to edit the map", | ||||||
|     "layerSelection": { |     "layerSelection": { | ||||||
|       "zoomInToSeeThisLayer": "Zoom in to see this layer", |       "zoomInToSeeThisLayer": "Zoom in to see this layer", | ||||||
|       "title": "Select layers", |       "title": "Select layers" | ||||||
|       "downloadGeojson": "Download layer features as geojson" |     }, | ||||||
|  |     "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": { |     "weekdays": { | ||||||
|       "abbreviations": { |       "abbreviations": { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue