From 261554a5d998909692b5ebb282c8206fefd9a337 Mon Sep 17 00:00:00 2001 From: LiamSimons Date: Tue, 27 Jul 2021 12:12:58 +0200 Subject: [PATCH 01/20] PDF export added - not working --- InitUiElements.ts | 11 ++++++++++- Logic/Actors/ExportPDF.ts | 34 ++++++++++++++++++++++++++++++++++ Logic/Actors/PDFLayout.ts | 26 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 Logic/Actors/ExportPDF.ts create mode 100644 Logic/Actors/PDFLayout.ts diff --git a/InitUiElements.ts b/InitUiElements.ts index bc804a2294..102c4fd3fe 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -40,6 +40,7 @@ import FeatureSource from "./Logic/FeatureSource/FeatureSource"; import AllKnownLayers from "./Customizations/AllKnownLayers"; import LayerConfig from "./Customizations/JSON/LayerConfig"; import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers"; +import ExportPDF from "./Logic/Actors/ExportPDF"; export class InitUiElements { @@ -189,7 +190,15 @@ export class InitUiElements { State.state.locationControl.ping(); }) - new Combine([plus, min, geolocationButton].map(el => el.SetClass("m-0.5 md:m-1"))) + const screenshot = new MapControlButton( + new FixedUiElement( + Img.AsImageElement(Svg.bug, "", "width:1.25rem;height:1.25rem") + ) + ).onClick(() => { + let createdPDF = new ExportPDF("Screenshot", "natuurpunt"); + }) + + new Combine([plus, min, geolocationButton, screenshot].map(el => el.SetClass("m-0.5 md:m-1"))) .SetClass("flex flex-col") .AttachTo("bottom-right"); diff --git a/Logic/Actors/ExportPDF.ts b/Logic/Actors/ExportPDF.ts new file mode 100644 index 0000000000..3eb3fa4d4b --- /dev/null +++ b/Logic/Actors/ExportPDF.ts @@ -0,0 +1,34 @@ +/** + * Creates screenshoter to take png screenshot + * Creates jspdf and downloads it + * - landscape pdf + * + * To add new layout: + * - add new possible layout name in constructor + * - add new layout in "PDFLayout" + * -> in there are more instructions + */ + + import jsPDF from "jspdf"; + import { SimpleMapScreenshoter } from "leaflet-simple-map-screenshoter"; + import State from "../../State"; + import { PDFLayout } from "./PDFLayout"; + + export default class ExportPDF { + constructor( + name: string, + layout: "natuurpunt" + ){ + const screenshotter = new SimpleMapScreenshoter(); + //minimap op index.html -> hidden daar alles op doen en dan weg + //minimap - leaflet map ophalen - boundaries ophalen - State.state.featurePipeline + screenshotter.addTo(State.state.leafletMap.data); + let doc = new jsPDF('l'); + screenshotter.takeScreen('image').then(image => { + let file = new PDFLayout(); + file.AddLayout(layout, doc, image); + console.log("SCREENSHOTTER"); + doc.save(name); + }) + } + } \ No newline at end of file diff --git a/Logic/Actors/PDFLayout.ts b/Logic/Actors/PDFLayout.ts new file mode 100644 index 0000000000..2478fb1183 --- /dev/null +++ b/Logic/Actors/PDFLayout.ts @@ -0,0 +1,26 @@ +/** + * Adds a theme to the pdf + * + * To add new layout: (first check ExportPDF.ts) + * - in AddLayout() -> add new name for your layout + * AddLayout(layout: "natuurpunt" ...) => AddLayout(layout: "natuurpunt" | "newlayout" ...) + * - add if statement that checks which layout you want + * - add new function to change the pdf layout + */ + + import jsPDF from "jspdf"; + + export class PDFLayout { + public AddLayout(layout: "natuurpunt", doc: jsPDF, image: Blob){ + if(layout === "natuurpunt") this.AddNatuurpuntLayout(doc, image); + } + public AddNatuurpuntLayout(doc: jsPDF, image: Blob){ + // Add Natuurpunt layout + const screenRatio = screen.width/screen.height; + let img = document.createElement('img'); + img.src = './assets/themes/natuurpunt/natuurpunt.png'; + doc.addImage(img, 'PNG', 15, 5, 20, 20); + doc.addImage(image, 'PNG', 15, 30, 150*screenRatio, 150); + return doc; + } + } \ No newline at end of file From ede67ca58c53951a95d85d2af0ef4407a3723c32 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 02:51:07 +0200 Subject: [PATCH 02/20] Fix pdf export, fix feature switches --- Customizations/JSON/LayoutConfig.ts | 7 +- Customizations/JSON/LayoutConfigJson.ts | 4 +- InitUiElements.ts | 44 ++++--- Logic/Actors/ExportPDF.ts | 38 ------ Logic/Actors/PDFLayout.ts | 26 ---- Logic/GeoOperations.ts | 45 ++++--- State.ts | 20 ++- UI/Base/Minimap.ts | 27 +++- UI/BigComponents/LayerControlPanel.ts | 14 +- UI/ExportPDF.ts | 145 +++++++++++++++++++++ UI/Popup/SplitRoadWizard.ts | 4 +- UI/ShowDataLayer.ts | 7 +- assets/svg/download.svg | 68 +++++++++- assets/svg/license_info.json | 10 ++ assets/themes/cycle_infra/cycle_infra.json | 18 +-- assets/themes/natuurpunt/natuurpunt.json | 2 + index.html | 5 +- langs/en.json | 3 + test.ts | 47 +++++++ 19 files changed, 390 insertions(+), 144 deletions(-) delete mode 100644 Logic/Actors/ExportPDF.ts delete mode 100644 Logic/Actors/PDFLayout.ts create mode 100644 UI/ExportPDF.ts diff --git a/Customizations/JSON/LayoutConfig.ts b/Customizations/JSON/LayoutConfig.ts index bda08db561..8032701eaa 100644 --- a/Customizations/JSON/LayoutConfig.ts +++ b/Customizations/JSON/LayoutConfig.ts @@ -43,6 +43,8 @@ export default class LayoutConfig { public readonly enableBackgroundLayerSelection: boolean; public readonly enableShowAllQuestions: boolean; public readonly enableExportButton: boolean; + public readonly enablePdfDownload: boolean; + public readonly customCss?: string; /* How long is the cache valid, in seconds? @@ -153,7 +155,8 @@ 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.enableExportButton = json.enableDownload ?? false; + this.enablePdfDownload = json.enablePdfDownload ?? false; this.customCss = json.customCss; this.cacheTimeout = json.cacheTimout ?? (60 * 24 * 60 * 60) @@ -176,7 +179,7 @@ export default class LayoutConfig { return } } else { - console.log("Layer ", layer," not kown, try one of", Array.from(AllKnownLayers.sharedLayers.keys()).join(", ")) + console.log("Layer ", layer, " not kown, try one of", Array.from(AllKnownLayers.sharedLayers.keys()).join(", ")) throw `Unknown builtin layer ${layer} at ${context}.layers[${i}]`; } } diff --git a/Customizations/JSON/LayoutConfigJson.ts b/Customizations/JSON/LayoutConfigJson.ts index d36a8463d6..c7dda8468c 100644 --- a/Customizations/JSON/LayoutConfigJson.ts +++ b/Customizations/JSON/LayoutConfigJson.ts @@ -336,5 +336,7 @@ export interface LayoutConfigJson { enableGeolocation?: boolean; enableBackgroundLayerSelection?: boolean; enableShowAllQuestions?: boolean; - enableExportButton?: boolean; + enableDownload?: boolean; + enablePdfDownload: boolean; + } diff --git a/InitUiElements.ts b/InitUiElements.ts index 494b000144..389171d2d7 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -40,9 +40,9 @@ import FeatureSource from "./Logic/FeatureSource/FeatureSource"; import AllKnownLayers from "./Customizations/AllKnownLayers"; import LayerConfig from "./Customizations/JSON/LayerConfig"; import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers"; -import ExportPDF from "./Logic/Actors/ExportPDF"; import {TagsFilter} from "./Logic/Tags/TagsFilter"; import FilterView from "./UI/BigComponents/FilterView"; +import ExportPDF from "./UI/ExportPDF"; export class InitUiElements { static InitAll( @@ -198,7 +198,7 @@ export class InitUiElements { State.state.leafletMap, State.state.layoutToUse ), { - dontStyle : true + dontStyle: true } ), undefined, @@ -206,28 +206,21 @@ export class InitUiElements { ); const plus = new MapControlButton( - Svg.plus_zoom_svg() + Svg.plus_zoom_svg() ).onClick(() => { State.state.locationControl.data.zoom++; State.state.locationControl.ping(); }); const min = new MapControlButton( - Svg.min_zoom_svg() + Svg.min_zoom_svg() ).onClick(() => { State.state.locationControl.data.zoom--; State.state.locationControl.ping(); }); - const screenshot = new MapControlButton( - Svg.bug_svg(), - ).onClick(() => { - // Will already export - new ExportPDF("Screenshot", "natuurpunt"); - - }) - new Combine([plus, min, geolocationButton, screenshot].map(el => el.SetClass("m-0.5 md:m-1"))) + new Combine([plus, min, geolocationButton].map(el => el.SetClass("m-0.5 md:m-1"))) .SetClass("flex flex-col") .AttachTo("bottom-right"); @@ -374,17 +367,17 @@ export class InitUiElements { ); - const filterView = + const filterView = new ScrollableFullScreen( () => Translations.t.general.layerSelection.title.Clone(), - () => + () => new FilterView(State.state.filteredLayers).SetClass( "block p-1 rounded-full" ), undefined, State.state.filterIsOpened ); - + const filterMapControlButton = new MapControlButton( Svg.filter_svg() @@ -402,7 +395,26 @@ export class InitUiElements { State.state.featureSwitchFilter ); - new Combine([copyrightButton, layerControl, filterControl]) + const screenshot = + new Toggle( + new MapControlButton( + Svg.download_svg(), + ).onClick(() => { + // Will already export + new ExportPDF( + { + freeDivId: "belowmap", + background: State.state.backgroundLayer, + location: State.state.locationControl, + features: State.state.featurePipeline.features, + layout: State.state.layoutToUse, + } + ); + + }), undefined, State.state.featureSwitchExportAsPdf) + + + new Combine([filterControl, layerControl, screenshot, copyrightButton,]) .SetClass("flex flex-col") .AttachTo("bottom-left"); diff --git a/Logic/Actors/ExportPDF.ts b/Logic/Actors/ExportPDF.ts deleted file mode 100644 index 78316be729..0000000000 --- a/Logic/Actors/ExportPDF.ts +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Creates screenshoter to take png screenshot - * Creates jspdf and downloads it - * - landscape pdf - * - * To add new layout: - * - add new possible layout name in constructor - * - add new layout in "PDFLayout" - * -> in there are more instructions - */ - - import jsPDF from "jspdf"; - import { SimpleMapScreenshoter } from "leaflet-simple-map-screenshoter"; - import State from "../../State"; - import { PDFLayout } from "./PDFLayout"; - - export default class ExportPDF { - constructor( - name: string, - layout: "natuurpunt" - ){ - const screenshotter = new SimpleMapScreenshoter(); - //minimap op index.html -> hidden daar alles op doen en dan weg - //minimap - leaflet map ophalen - boundaries ophalen - State.state.featurePipeline - screenshotter.addTo(State.state.leafletMap.data); - let doc = new jsPDF('landscape'); - console.log("Taking screenshot") - screenshotter.takeScreen('image').then(image => { - if(!(image instanceof Blob)){ - alert("Exporting failed :(") - return; - } - let file = new PDFLayout(); - file.AddLayout(layout, doc, image); - doc.save(name); - }) - } - } diff --git a/Logic/Actors/PDFLayout.ts b/Logic/Actors/PDFLayout.ts deleted file mode 100644 index db4ddd66d2..0000000000 --- a/Logic/Actors/PDFLayout.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Adds a theme to the pdf - * - * To add new layout: (first check ExportPDF.ts) - * - in AddLayout() -> add new name for your layout - * AddLayout(layout: "natuurpunt" ...) => AddLayout(layout: "natuurpunt" | "newlayout" ...) - * - add if statement that checks which layout you want - * - add new function to change the pdf layout - */ - - import jsPDF from "jspdf"; - - export class PDFLayout { - public AddLayout(layout: "natuurpunt", doc: jsPDF, image: Blob){ - if(layout === "natuurpunt") this.AddNatuurpuntLayout(doc, image); - } - public AddNatuurpuntLayout(doc: jsPDF, image: Blob){ - // Add Natuurpunt layout - const screenRatio = screen.width/screen.height; - let img = document.createElement('img'); - img.src = './assets/themes/natuurpunt/natuurpunt.png'; - doc.addImage(img, 'PNG', 15, 5, 20, 20); - doc.addImage(image, 'PNG', 15, 30, 150*screenRatio, 150); - return doc; - } - } diff --git a/Logic/GeoOperations.ts b/Logic/GeoOperations.ts index a513bb8e0a..be0c1d5263 100644 --- a/Logic/GeoOperations.ts +++ b/Logic/GeoOperations.ts @@ -322,7 +322,7 @@ export class GeoOperations { if (value === undefined) { line += "," } else { - line += JSON.stringify(value)+"," + line += JSON.stringify(value) + "," } } lines.push(line) @@ -334,7 +334,7 @@ export class GeoOperations { } -class BBox { +export class BBox { readonly maxLat: number; readonly maxLon: number; @@ -357,33 +357,20 @@ class BBox { this.check(); } + static fromLeafletBounds(bounds) { + return new BBox([[bounds.getWest(), bounds.getNorth()], [bounds.getEast(), bounds.getSouth()]]) + } + static get(feature) { if (feature.bbox?.overlapsWith === undefined) { - - if (feature.geometry.type === "MultiPolygon") { - let coordinates = []; - for (const coorlist of feature.geometry.coordinates) { - coordinates = coordinates.concat(coorlist[0]); - } - feature.bbox = new BBox(coordinates); - } else if (feature.geometry.type === "Polygon") { - feature.bbox = new BBox(feature.geometry.coordinates[0]); - } else if (feature.geometry.type === "LineString") { - feature.bbox = new BBox(feature.geometry.coordinates); - } else if (feature.geometry.type === "Point") { - // Point - feature.bbox = new BBox([feature.geometry.coordinates]); - } else { - throw "Cannot calculate bbox, unknown type " + feature.geometry.type; - } + const turfBbox: number[] = turf.bbox(feature) + feature.bbox = new BBox([[turfBbox[0], turfBbox[1]],[turfBbox[2], turfBbox[3]]]); } return feature.bbox; } public overlapsWith(other: BBox) { - this.check(); - other.check(); if (this.maxLon < other.minLon) { return false; } @@ -397,6 +384,22 @@ class BBox { } + public isContainedIn(other: BBox) { + if (this.maxLon > other.maxLon) { + return false; + } + if (this.maxLat > other.maxLat) { + return false; + } + if (this.minLon < other.minLon) { + return false; + } + if (this.minLat < other.minLat) { + return false + } + return true; + } + private check() { if (isNaN(this.maxLon) || isNaN(this.maxLat) || isNaN(this.minLon) || isNaN(this.minLat)) { console.log(this); diff --git a/State.ts b/State.ts index fe2e2fdf7a..ac0c4a390d 100644 --- a/State.ts +++ b/State.ts @@ -61,7 +61,7 @@ export default class State { public osmApiFeatureSource: OsmApiFeatureSource; - public filteredLayers: UIEventSource = new UIEventSource([],"filteredLayers"); + public filteredLayers: UIEventSource = new UIEventSource([], "filteredLayers"); /** The latest element that was selected @@ -93,7 +93,7 @@ export default class State { public readonly featureSwitchFilter: UIEventSource; public readonly featureSwitchEnableExport: UIEventSource; public readonly featureSwitchFakeUser: UIEventSource; - + public readonly featureSwitchExportAsPdf: UIEventSource; public featurePipeline: FeaturePipeline; @@ -295,6 +295,17 @@ export default class State { "Always show all questions" ); + this.featureSwitchEnableExport = featSw( + "fs-export", + (layoutToUse) => layoutToUse?.enableExportButton ?? false, + "Enable the export as GeoJSON and CSV button" + ); + this.featureSwitchExportAsPdf = featSw( + "fs-pdf", + (layoutToUse) => layoutToUse?.enablePdfDownload ?? false, + "Enable the PDF download button" + ); + this.featureSwitchIsTesting = QueryParameters.GetQueryParameter( "test", "false", @@ -327,7 +338,6 @@ export default class State { ); - this.featureSwitchUserbadge.addCallbackAndRun(userbadge => { if (!userbadge) { this.featureSwitchAddNew.setData(false) @@ -372,9 +382,9 @@ export default class State { this.allElements = new ElementStorage(); this.changes = new Changes(); - + new ChangeToElementsActor(this.changes, this.allElements) - + this.osmApiFeatureSource = new OsmApiFeatureSource() new PendingChangesUploader(this.changes, this.selectedElement); diff --git a/UI/Base/Minimap.ts b/UI/Base/Minimap.ts index 0c063b672e..871a14021c 100644 --- a/UI/Base/Minimap.ts +++ b/UI/Base/Minimap.ts @@ -17,12 +17,14 @@ export default class Minimap extends BaseUIElement { private _isInited = false; private _allowMoving: boolean; private readonly _leafletoptions: any; + private readonly _onFullyLoaded: (leaflet: L.Map) => void constructor(options?: { background?: UIEventSource, location?: UIEventSource, allowMoving?: boolean, - leafletOptions?: any + leafletOptions?: any, + onFullyLoaded?: (leaflet: L.Map) => void } ) { super() @@ -32,6 +34,7 @@ export default class Minimap extends BaseUIElement { this._id = "minimap" + Minimap._nextId; this._allowMoving = options.allowMoving ?? true; this._leafletoptions = options.leafletOptions ?? {} + this._onFullyLoaded = options.onFullyLoaded Minimap._nextId++ } @@ -74,10 +77,10 @@ export default class Minimap extends BaseUIElement { } this._isInited = true; const location = this._location; - + const self = this; let currentLayer = this._background.data.layer() const options = { - center: <[number, number]> [location.data?.lat ?? 0, location.data?.lon ?? 0], + center: <[number, number]>[location.data?.lat ?? 0, location.data?.lon ?? 0], zoom: location.data?.zoom ?? 2, layers: [currentLayer], zoomControl: false, @@ -90,10 +93,17 @@ export default class Minimap extends BaseUIElement { // Disabling this breaks the geojson layer - don't ask me why! zoomAnimation: this._allowMoving, fadeAnimation: this._allowMoving } - + Utils.Merge(this._leafletoptions, options) - + const map = L.map(this._id, options); + if (self._onFullyLoaded !== undefined) { + + currentLayer.on("load", () => { + console.log("Fully loaded all tiles!") + self._onFullyLoaded(map) + }) + } map.setMaxBounds( [[-100, -200], [100, 200]] @@ -105,6 +115,13 @@ export default class Minimap extends BaseUIElement { map.removeLayer(currentLayer); } currentLayer = newLayer; + if (self._onFullyLoaded !== undefined) { + + currentLayer.on("load", () => { + console.log("Fully loaded all tiles!") + self._onFullyLoaded(map) + }) + } map.addLayer(newLayer); }) diff --git a/UI/BigComponents/LayerControlPanel.ts b/UI/BigComponents/LayerControlPanel.ts index 656c7084f2..968902ee33 100644 --- a/UI/BigComponents/LayerControlPanel.ts +++ b/UI/BigComponents/LayerControlPanel.ts @@ -36,17 +36,7 @@ export default class LayerControlPanel extends ScrollableFullScreen { undefined, State.state.featureSwitchEnableExport )) - - - elements.push( - new Toggle( - new DownloadPanel(), - undefined, - State.state.featureSwitchEnableExport - ) - ); - - return new Combine(elements).SetClass("flex flex-col"); - } + return new Combine(elements).SetClass("flex flex-col"); + } } diff --git a/UI/ExportPDF.ts b/UI/ExportPDF.ts new file mode 100644 index 0000000000..5422f38de0 --- /dev/null +++ b/UI/ExportPDF.ts @@ -0,0 +1,145 @@ +/** + * Creates screenshoter to take png screenshot + * Creates jspdf and downloads it + * - landscape pdf + * + * To add new layout: + * - add new possible layout name in constructor + * - add new layout in "PDFLayout" + * -> in there are more instructions + */ + +import jsPDF from "jspdf"; +import {SimpleMapScreenshoter} from "leaflet-simple-map-screenshoter"; +import {UIEventSource} from "../Logic/UIEventSource"; +import Minimap from "./Base/Minimap"; +import Loc from "../Models/Loc"; +import {BBox} from "../Logic/GeoOperations"; +import ShowDataLayer from "./ShowDataLayer"; +import BaseLayer from "../Models/BaseLayer"; +import LayoutConfig from "../Customizations/JSON/LayoutConfig"; +import {FixedUiElement} from "./Base/FixedUiElement"; +import Translations from "./i18n/Translations"; + +export default class ExportPDF { + // dimensions of the map in milimeter + // A4: 297 * 210mm + private readonly mapW = 297; + private readonly mapH = 210; + private readonly scaling = 2 + private readonly freeDivId: string; + private readonly _layout: UIEventSource; + + constructor( + options: { + freeDivId: string, + location: UIEventSource, + background?: UIEventSource + features: UIEventSource<{ feature: any }[]>, + layout: UIEventSource + } + ) { + + this.freeDivId = options.freeDivId; + this._layout = options.layout; + const self = this; + + // We create a minimap at the given location and attach it to the given 'hidden' element + + + + const minimap = new Minimap({ + location: options.location.map(l => ({ + lat : l.lat, + lon: l.lon, + zoom: l.zoom + 1 + })), + background: options.background, + allowMoving: true, + onFullyLoaded: leaflet => window.setTimeout(() => { + try{ + self.CreatePdf(leaflet) + .then(() => self.cleanup()) + .catch(() => self.cleanup()) + }catch(e){ + console.error(e) + self.cleanup() + } + + }, 500) + }) + + minimap.SetStyle(`width: ${this.mapW * this.scaling}mm; height: ${this.mapH * this.scaling}mm;`) + minimap.AttachTo(options.freeDivId) + + // Next: we prepare the features. Only fully contained features are shown + const bounded = options.features.map(feats => { + + const leaflet = minimap.leafletMap.data; + if (leaflet === undefined) { + return feats + } + const bounds = BBox.fromLeafletBounds(leaflet.getBounds().pad(0.2)) + return feats.filter(f => BBox.get(f.feature).isContainedIn(bounds)) + + }, [minimap.leafletMap]) + + // Add the features to the minimap + new ShowDataLayer( + bounded, + minimap.leafletMap, + options.layout, + false + ) + + } + + private cleanup(){ + new FixedUiElement("Screenshot taken!").AttachTo(this.freeDivId) + } + + private async CreatePdf(leaflet: L.Map) { + const t = Translations.t.general.pdf; + const layout = this._layout.data + const screenshotter = new SimpleMapScreenshoter(); + //minimap op index.html -> hidden daar alles op doen en dan weg + //minimap - leaflet map ophalen - boundaries ophalen - State.state.featurePipeline + screenshotter.addTo(leaflet); + console.log("Taking screenshot") + + + let doc = new jsPDF('landscape'); + + + const image = (await screenshotter.takeScreen('image')) + // @ts-ignore + doc.addImage(image, 'PNG', 0, 0, this.mapW, this.mapH); + + + doc.setDrawColor(255, 255, 255) + doc.setFillColor(255, 255, 255) + doc.roundedRect(12, 5, 125, 30, 5, 5, 'FD') + + doc.setFontSize(20) + doc.text(layout.title.txt, 40, 20, { maxWidth: 100 + }) + doc.setFontSize(10) + doc.text(t.attr.txt, 40, 25, { + maxWidth: 100 + }) + // Add the logo of the layout + let img = document.createElement('img'); + const imgSource = layout.icon + img.src = imgSource + try { + doc.addImage(img, imgSource.substr(imgSource.lastIndexOf(".")), 15, 12, 20, 20); + } catch (e) { + // TODO: support svg rendering... + console.error(e) + } + + doc.save("MapComplete_export.pdf"); + + + } +} diff --git a/UI/Popup/SplitRoadWizard.ts b/UI/Popup/SplitRoadWizard.ts index f445263e38..f54126be6c 100644 --- a/UI/Popup/SplitRoadWizard.ts +++ b/UI/Popup/SplitRoadWizard.ts @@ -45,8 +45,8 @@ export default class SplitRoadWizard extends Toggle { const roadElement = State.state.allElements.ContainingFeatures.get(id) const roadEventSource = new UIEventSource([{feature: roadElement, freshness: new Date()}]); // Datalayer displaying the road and the cut points (if any) - new ShowDataLayer(roadEventSource, miniMap.leafletMap, State.state.layoutToUse, false, true, "splitRoadWay"); - new ShowDataLayer(splitPoints, miniMap.leafletMap, SplitRoadWizard.splitLayout, false, false, "splitRoad: splitpoints") + new ShowDataLayer(roadEventSource, miniMap.leafletMap, State.state.layoutToUse, false, true); + new ShowDataLayer(splitPoints, miniMap.leafletMap, SplitRoadWizard.splitLayout, false, false) /** * Handles a click on the overleaf map. diff --git a/UI/ShowDataLayer.ts b/UI/ShowDataLayer.ts index 3358266284..05a720b0ef 100644 --- a/UI/ShowDataLayer.ts +++ b/UI/ShowDataLayer.ts @@ -16,14 +16,13 @@ export default class ShowDataLayer { private readonly _leafletMap: UIEventSource; private _cleanCount = 0; private readonly _enablePopups: boolean; - private readonly _features: UIEventSource<{ feature: any, freshness: Date }[]> + private readonly _features: UIEventSource<{ feature: any}[]> - constructor(features: UIEventSource<{ feature: any, freshness: Date }[]>, + constructor(features: UIEventSource<{ feature: any}[]>, leafletMap: UIEventSource, layoutToUse: UIEventSource, enablePopups = true, - zoomToFeatures = false, - name?: string) { + zoomToFeatures = false) { this._leafletMap = leafletMap; this._enablePopups = enablePopups; this._features = features; diff --git a/assets/svg/download.svg b/assets/svg/download.svg index bfde059802..98921dec5e 100644 --- a/assets/svg/download.svg +++ b/assets/svg/download.svg @@ -1,3 +1,67 @@ - - + + + +image/svg+xml + + + + + + + \ No newline at end of file diff --git a/assets/svg/license_info.json b/assets/svg/license_info.json index 0ea2d3a2dc..377b4d2ba9 100644 --- a/assets/svg/license_info.json +++ b/assets/svg/license_info.json @@ -216,6 +216,16 @@ "license": "CC0; trivial", "sources": [] }, + { + "authors": [ + "Engr.eponce" + ], + "path": "download.svg", + "license": "CC-BY-SA 4.0", + "sources": [ + "https://commons.wikimedia.org/wiki/File:Download-icon.svg" + ] + }, { "authors": [], "path": "down.svg", diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index 8d4183a7c7..3193f27b18 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -25,7 +25,7 @@ "startZoom": 11, "widenFactor": 0.05, "socialImage": "./assets/themes/cycle_infra/cycle-infra.svg", - "enableExportButton": true, + "enableDownload": true, "layers": [ { "id": "cycleways", @@ -69,7 +69,7 @@ }, "then": { "nl": "Fietsweg", - "en": "Cycleway" + "en": "Bike road" } }, { @@ -89,7 +89,7 @@ { "if": "cycleway=track", "then": { - "en": "Cycleway next to the road", + "en": "Bike road next to the road", "nl": "Fietsweg naast de weg" } }, @@ -219,7 +219,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet, and a 30km/h zone.", - "nl": "Dit is een fietsstraat, en dus een 30km/h zone" + "nl": "Dit is een fietstraat, en dus een 30km/h zone" }, "addExtraTags": [ "overtaking:motor_vehicle=no", @@ -231,7 +231,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet", - "nl": "Dit is een fietsstraat" + "nl": "Dit is een fietstraat" }, "hideInAnswer": "_country=be" }, @@ -239,7 +239,7 @@ "if": "cyclestreet=", "then": { "en": "This is not a cyclestreet.", - "nl": "Dit is niet een fietsstraat" + "nl": "Dit is niet een fietstraat" }, "addExtraTags": [ "overtaking:motor_vehicle=" @@ -1266,7 +1266,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet, and a 30km/h zone.", - "nl": "Dit is een fietsstraat, en dus een 30km/h zone" + "nl": "Dit is een fietstraat, en dus een 30km/h zone" }, "addExtraTags": [ "overtaking:motor_vehicle=no", @@ -1278,7 +1278,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet", - "nl": "Dit is een fietsstraat" + "nl": "Dit is een fietstraat" }, "hideInAnswer": "_country=be" }, @@ -1286,7 +1286,7 @@ "if": "cyclestreet=", "then": { "en": "This is not a cyclestreet.", - "nl": "Dit is niet een fietsstraat" + "nl": "Dit is niet een fietstraat" }, "addExtraTags": [ "overtaking:motor_vehicle=" diff --git a/assets/themes/natuurpunt/natuurpunt.json b/assets/themes/natuurpunt/natuurpunt.json index 4d66fada57..4287536c41 100644 --- a/assets/themes/natuurpunt/natuurpunt.json +++ b/assets/themes/natuurpunt/natuurpunt.json @@ -26,6 +26,8 @@ "widenFactor": 0.05, "socialImage": "", "defaultBackgroundId": "CartoDB.Positron", + "enablePdfDownload": true, + "enableDownload": true, "layers": [ { "#": "Nature reserve with geometry, z>=13", diff --git a/index.html b/index.html index 22113fa9d5..a2192f281b 100644 --- a/index.html +++ b/index.html @@ -74,7 +74,10 @@ Loading MapComplete, hang on... - +Below
diff --git a/langs/en.json b/langs/en.json index 94ec9719c5..f8453d507b 100644 --- a/langs/en.json +++ b/langs/en.json @@ -61,6 +61,9 @@ "readMessages": "You have unread messages. Read these before deleting a point - someone might have feedback" }, "general": { + "pdf": { + "attr": "Generated with MapComplete.osm.be - map data © OpenStreetMap Contributors, reusable under ODbL" + }, "loginWithOpenStreetMap": "Login with OpenStreetMap", "welcomeBack": "You are logged in, welcome back!", "loginToStart": "Login to answer this question", diff --git a/test.ts b/test.ts index e69de29bb2..609529cbd8 100644 --- a/test.ts +++ b/test.ts @@ -0,0 +1,47 @@ +import {UIEventSource} from "./Logic/UIEventSource"; +import LayoutConfig from "./Customizations/JSON/LayoutConfig"; +import {AllKnownLayouts} from "./Customizations/AllKnownLayouts"; +import State from "./State"; + +const layout = new UIEventSource(AllKnownLayouts.allKnownLayouts.get("bookcases")) +State.state = new State(layout.data) + +const features = new UIEventSource<{ feature: any }[]>([ + { + feature: { + "type": "Feature", + "properties": {"amenity": "public_bookcase", "id": "node/123"}, + + id: "node/123", + _matching_layer_id: "public_bookcase", + "geometry": { + "type": "Point", + "coordinates": [ + 3.220506906509399, + 51.215009243433094 + ] + } + } + }, { + feature: { + "type": "Feature", + "properties": { + amenity: "public_bookcase", + id: "node/456" + }, + _matching_layer_id: "public_bookcase", + id: "node/456", + "geometry": { + "type": "Point", + "coordinates": [ + 3.4243011474609375, + 51.138432319543924 + ] + } + } + } +]) + +features.data.map(f => State.state.allElements.addOrGetElement(f.feature)) + + From 06ce2ebe8ce3ffa6f8972eb5b3e7a5ee87ad8607 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 02:54:51 +0200 Subject: [PATCH 03/20] Fix build --- Customizations/JSON/LayoutConfigJson.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Customizations/JSON/LayoutConfigJson.ts b/Customizations/JSON/LayoutConfigJson.ts index c7dda8468c..afbc0aebc3 100644 --- a/Customizations/JSON/LayoutConfigJson.ts +++ b/Customizations/JSON/LayoutConfigJson.ts @@ -337,6 +337,6 @@ export interface LayoutConfigJson { enableBackgroundLayerSelection?: boolean; enableShowAllQuestions?: boolean; enableDownload?: boolean; - enablePdfDownload: boolean; + enablePdfDownload?: boolean; } From b831da3c7831bfa8f3a58a3007644ea1de852194 Mon Sep 17 00:00:00 2001 From: Charlotte Delvaux <71268586+pgm-chardelv1@users.noreply.github.com> Date: Wed, 28 Jul 2021 07:57:33 +0200 Subject: [PATCH 04/20] Update crossings.json Edit Dutch translations / grammar --- assets/layers/crossings/crossings.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/layers/crossings/crossings.json b/assets/layers/crossings/crossings.json index 0dcfc9aa19..2fc2235b4b 100644 --- a/assets/layers/crossings/crossings.json +++ b/assets/layers/crossings/crossings.json @@ -132,7 +132,7 @@ "if": "crossing_ref=", "then": { "en": "This is not a zebra crossing", - "nl": "Dit is niet een zebrapad" + "nl": "Dit is geen zebrapad" } } ] @@ -155,7 +155,7 @@ "if": "bicycle=no", "then": { "en": "A cyclist can not use this crossing", - "nl": "Een fietser kan niet deze oversteekplaats gebruiken" + "nl": "Een fietser kan deze oversteekplaats niet gebruiken" } } ] @@ -178,7 +178,7 @@ "if": "crossing:island=no", "then": { "en": "This crossing does not have an island in the middle", - "nl": "Deze oversteekplaats heeft niet een verkeerseiland in het midden" + "nl": "Deze oversteekplaats heeft geen verkeerseiland in het midden" } } ] @@ -201,7 +201,7 @@ "if": "tactile_paving=no", "then": { "en": "This crossing does not have tactile paving", - "nl": "Deze oversteekplaats heeft niet een geleidelijn" + "nl": "Deze oversteekplaats heeft geen geleidelijn" } }, { @@ -237,7 +237,7 @@ "if": "button_operated=no", "then": { "en": "This traffic light does not have a button to request green light", - "nl": "Dit verkeerlicht heeft niet een knop voor groen licht" + "nl": "Dit verkeerlicht heeft geen knop voor groen licht" } } ] @@ -307,4 +307,4 @@ ] } ] -} \ No newline at end of file +} From 0983b9ffb0aa65b81731069e505d9b8e6432986c Mon Sep 17 00:00:00 2001 From: Charlotte Delvaux <71268586+pgm-chardelv1@users.noreply.github.com> Date: Wed, 28 Jul 2021 08:10:48 +0200 Subject: [PATCH 05/20] Update cycle_infra.json Add some translations --- assets/themes/cycle_infra/cycle_infra.json | 48 ++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index 8d4183a7c7..1b893047ae 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -239,7 +239,7 @@ "if": "cyclestreet=", "then": { "en": "This is not a cyclestreet.", - "nl": "Dit is niet een fietsstraat" + "nl": "Dit is geen fietsstraat" }, "addExtraTags": [ "overtaking:motor_vehicle=" @@ -427,49 +427,57 @@ { "if": "cycleway:smoothness=excellent", "then": { - "en": "Usable for thin rollers: rollerblade, skateboard" + "en": "Usable for thin rollers: rollerblade, skateboard", + "nl": "Geschikt voor fijne rollers: rollerblade, skateboard" } }, { "if": "cycleway:smoothness=good", "then": { - "en": "Usable for thin wheels: racing bike" + "en": "Usable for thin wheels: racing bike", + "nl": "Geschikt voor fijne wielen: racefiets" } }, { "if": "cycleway:smoothness=intermediate", "then": { - "en": "Usable for normal wheels: city bike, wheelchair, scooter" + "en": "Usable for normal wheels: city bike, wheelchair, scooter", + "nl": "Geschikt voor normale wielen: stadsfiets, rolstoel, scooter" } }, { "if": "cycleway:smoothness=bad", "then": { - "en": "Usable for robust wheels: trekking bike, car, rickshaw" + "en": "Usable for robust wheels: trekking bike, car, rickshaw", + "nl": "Geschikt voor brede wielen: trekfiets, auto, rickshaw" } }, { "if": "cycleway:smoothness=very_bad", "then": { - "en": "Usable for vehicles with high clearance: light duty off-road vehicle" + "en": "Usable for vehicles with high clearance: light duty off-road vehicle", + "nl": "Geschikt voor voertuigen met hoge banden: lichte terreinwagen" } }, { "if": "cycleway:smoothness=horrible", "then": { - "en": "Usable for off-road vehicles: heavy duty off-road vehicle" + "en": "Usable for off-road vehicles: heavy duty off-road vehicle", + "nl": "Geschikt voor terreinwagens: zware terreinwagen" } }, { "if": "cycleway:smoothness=very_horrible", "then": { - "en": "Usable for specialized off-road vehicles: tractor, ATV" + "en": "Usable for specialized off-road vehicles: tractor, ATV", + "nl": "Geschikt voor gespecialiseerde terreinwagens: tractor, alleterreinwagen" } }, { "if": "cycleway:smoothness=impassable", "then": { - "en": "Impassable / No wheeled vehicle" + "en": "Impassable / No wheeled vehicle", + "nl": "Niet geschikt voor voertuigen met wielen" } } ] @@ -1286,7 +1294,7 @@ "if": "cyclestreet=", "then": { "en": "This is not a cyclestreet.", - "nl": "Dit is niet een fietsstraat" + "nl": "Dit is geen fietsstraat" }, "addExtraTags": [ "overtaking:motor_vehicle=" @@ -1465,7 +1473,8 @@ { "if": "cycle_barrier:type=squeeze", "then": { - "en": "Squeeze gate, gap is smaller at top, than at the bottom " + "en": "Squeeze gate, gap is smaller at top, than at the bottom ", + "nl": "Knijppoort, ruimte is smaller aan de top, dan aan de bodem " } } ] @@ -1492,10 +1501,12 @@ }, { "render": { - "en": "Space between barriers (along the length of the road): {width:seperation} m" + "en": "Space between barriers (along the length of the road): {width:seperation} m", + "nl": "Ruimte tussen barrières (langs de lengte van de weg): {width:seperation} m" }, "question": { - "en": "How much space is there between the barriers (along the length of the road)?" + "en": "How much space is there between the barriers (along the length of the road)?", + "nl": "Hoeveel ruimte is er tussen de barrières (langs de lengte van de weg)?" }, "condition": { "or": [ @@ -1510,10 +1521,12 @@ }, { "render": { - "en": "Width of opening: {width:opening} m" + "en": "Width of opening: {width:opening} m", + "nl": "Breedte van de opening: {width:opening} m" }, "question": { - "en": "How wide is the smallest opening next to the barriers?" + "en": "How wide is the smallest opening next to the barriers?", + "nl": "Hoe breed is de smalste opening naast de barrières?" }, "condition": { "or": [ @@ -1531,7 +1544,8 @@ "en": "Overlap: {overlap} m" }, "question": { - "en": "How much overlap do the barriers have?" + "en": "How much overlap do the barriers have?", + "nl": "Hoeveel overlappen de barrières?" }, "condition": { "or": [ @@ -1548,4 +1562,4 @@ }, "crossings" ] -} \ No newline at end of file +} From 1d2d098167ba428d9bbaaa6583250075dda68d21 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 12:36:39 +0200 Subject: [PATCH 06/20] Small fixes --- Logic/FeatureSource/FeatureSource.ts | 5 +++-- UI/ExportPDF.ts | 15 ++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/Logic/FeatureSource/FeatureSource.ts b/Logic/FeatureSource/FeatureSource.ts index 171db39f6a..5b66e16508 100644 --- a/Logic/FeatureSource/FeatureSource.ts +++ b/Logic/FeatureSource/FeatureSource.ts @@ -24,13 +24,14 @@ export class FeatureSourceUtils { options = Utils.setDefaults(options, defaults); // Select all features, ignore the freshness and other data - let featureList: any[] = featurePipeline.features.data.map((feature) => feature.feature); + let featureList: any[] = featurePipeline.features.data.map((feature) => + JSON.parse(JSON.stringify((feature.feature)))); // Make a deep copy! if (!options.metadata) { for (let i = 0; i < featureList.length; i++) { let feature = featureList[i]; for (let property in feature.properties) { - if (property[0] == "_") { + if (property[0] == "_" && property !== "_lat" && property !== "_lon") { delete featureList[i]["properties"][property]; } } diff --git a/UI/ExportPDF.ts b/UI/ExportPDF.ts index 5422f38de0..6fc475bd80 100644 --- a/UI/ExportPDF.ts +++ b/UI/ExportPDF.ts @@ -46,16 +46,17 @@ export default class ExportPDF { // We create a minimap at the given location and attach it to the given 'hidden' element - + const l = options.location.data; + const loc = { + lat : l.lat, + lon: l.lon, + zoom: l.zoom + 1 + } const minimap = new Minimap({ - location: options.location.map(l => ({ - lat : l.lat, - lon: l.lon, - zoom: l.zoom + 1 - })), + location: new UIEventSource(loc), // We remove the link between the old and the new UI-event source as moving the map while the export is running fucks up the screenshot background: options.background, - allowMoving: true, + allowMoving: false, onFullyLoaded: leaflet => window.setTimeout(() => { try{ self.CreatePdf(leaflet) From a231f7f887089365e6266fc7f9492ea622ffc3f3 Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Wed, 28 Jul 2021 13:34:25 +0200 Subject: [PATCH 07/20] Update translations --- assets/layers/crossings/crossings.json | 2 +- assets/themes/cycle_infra/cycle_infra.json | 2 +- langs/layers/nl.json | 10 ++-- langs/themes/en.json | 4 +- langs/themes/nl.json | 54 +++++++++++++++++++--- 5 files changed, 56 insertions(+), 16 deletions(-) diff --git a/assets/layers/crossings/crossings.json b/assets/layers/crossings/crossings.json index 2fc2235b4b..00798a0214 100644 --- a/assets/layers/crossings/crossings.json +++ b/assets/layers/crossings/crossings.json @@ -307,4 +307,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index 1b893047ae..d1fd12f598 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -1562,4 +1562,4 @@ }, "crossings" ] -} +} \ No newline at end of file diff --git a/langs/layers/nl.json b/langs/layers/nl.json index c736486bbd..93788a2046 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -837,7 +837,7 @@ "then": "Dit is een zebrapad" }, "1": { - "then": "Dit is niet een zebrapad" + "then": "Dit is geen zebrapad" } } }, @@ -848,7 +848,7 @@ "then": "Een fietser kan deze oversteekplaats gebruiken" }, "1": { - "then": "Een fietser kan niet deze oversteekplaats gebruiken" + "then": "Een fietser kan deze oversteekplaats niet gebruiken" } } }, @@ -859,7 +859,7 @@ "then": "Deze oversteekplaats heeft een verkeerseiland in het midden" }, "1": { - "then": "Deze oversteekplaats heeft niet een verkeerseiland in het midden" + "then": "Deze oversteekplaats heeft geen verkeerseiland in het midden" } } }, @@ -870,7 +870,7 @@ "then": "Deze oversteekplaats heeft een geleidelijn" }, "1": { - "then": "Deze oversteekplaats heeft niet een geleidelijn" + "then": "Deze oversteekplaats heeft geen geleidelijn" }, "2": { "then": "Deze oversteekplaats heeft een geleidelijn, die incorrect is." @@ -884,7 +884,7 @@ "then": "Dit verkeerslicht heeft een knop voor groen licht" }, "1": { - "then": "Dit verkeerlicht heeft niet een knop voor groen licht" + "then": "Dit verkeerlicht heeft geen knop voor groen licht" } } }, diff --git a/langs/themes/en.json b/langs/themes/en.json index 94744363f7..113a1ba003 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -703,7 +703,7 @@ "render": "Cycleways", "mappings": { "0": { - "then": "Bike road" + "then": "Cycleway" }, "1": { "then": "Shared lane" @@ -712,7 +712,7 @@ "then": "Bike lane" }, "3": { - "then": "Bike road next to the road" + "then": "Cycleway next to the road" }, "4": { "then": "Cyclestreet" diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 5f39530463..2cbfdcb57c 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -652,13 +652,13 @@ "question": "Is dit een fietsstraat?", "mappings": { "0": { - "then": "Dit is een fietstraat, en dus een 30km/h zone" + "then": "Dit is een fietsstraat, en dus een 30km/h zone" }, "1": { - "then": "Dit is een fietstraat" + "then": "Dit is een fietsstraat" }, "2": { - "then": "Dit is niet een fietstraat" + "then": "Dit is geen fietsstraat" } } }, @@ -726,7 +726,33 @@ "question": "Waaruit is het oppervlak van het fietspad van gemaakt?" }, "5": { - "question": "Wat is de kwaliteit van dit fietspad?" + "question": "Wat is de kwaliteit van dit fietspad?", + "mappings": { + "0": { + "then": "Geschikt voor fijne rollers: rollerblade, skateboard" + }, + "1": { + "then": "Geschikt voor fijne wielen: racefiets" + }, + "2": { + "then": "Geschikt voor normale wielen: stadsfiets, rolstoel, scooter" + }, + "3": { + "then": "Geschikt voor brede wielen: trekfiets, auto, rickshaw" + }, + "4": { + "then": "Geschikt voor voertuigen met hoge banden: lichte terreinwagen" + }, + "5": { + "then": "Geschikt voor terreinwagens: zware terreinwagen" + }, + "6": { + "then": "Geschikt voor gespecialiseerde terreinwagens: tractor, alleterreinwagen" + }, + "7": { + "then": "Niet geschikt voor voertuigen met wielen" + } + } }, "6": { "render": "Deze weg is gemaakt van {surface}", @@ -935,13 +961,13 @@ "question": "Is dit een fietsstraat?", "mappings": { "0": { - "then": "Dit is een fietstraat, en dus een 30km/h zone" + "then": "Dit is een fietsstraat, en dus een 30km/h zone" }, "1": { - "then": "Dit is een fietstraat" + "then": "Dit is een fietsstraat" }, "2": { - "then": "Dit is niet een fietstraat" + "then": "Dit is geen fietsstraat" } } } @@ -1014,12 +1040,26 @@ }, "2": { "then": "Drievoudig, drie hekjes achter elkaar " + }, + "3": { + "then": "Knijppoort, ruimte is smaller aan de top, dan aan de bodem " } } }, "3": { "render": "Maximumbreedte: {maxwidth:physical} m", "question": "Hoe breed is de ruimte naast de barrière?" + }, + "4": { + "render": "Ruimte tussen barrières (langs de lengte van de weg): {width:seperation} m", + "question": "Hoeveel ruimte is er tussen de barrières (langs de lengte van de weg)?" + }, + "5": { + "render": "Breedte van de opening: {width:opening} m", + "question": "Hoe breed is de smalste opening naast de barrières?" + }, + "6": { + "question": "Hoeveel overlappen de barrières?" } } } From db37f0c6277a568f31a15b96dbcc68763d51e3df Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Wed, 28 Jul 2021 13:38:41 +0200 Subject: [PATCH 08/20] Update image styling --- assets/layers/crossings/crossings.json | 8 +- assets/themes/cycle_infra/cycle_infra.json | 88 +++++++++++----------- langs/layers/en.json | 4 +- langs/layers/nl.json | 4 +- langs/themes/en.json | 44 +++++------ langs/themes/nl.json | 44 +++++------ 6 files changed, 96 insertions(+), 96 deletions(-) diff --git a/assets/layers/crossings/crossings.json b/assets/layers/crossings/crossings.json index 00798a0214..bc3cf5f701 100644 --- a/assets/layers/crossings/crossings.json +++ b/assets/layers/crossings/crossings.json @@ -252,8 +252,8 @@ { "if": "red_turn:right:bicycle=yes", "then": { - "en": "A cyclist can turn right if the light is red ", - "nl": "Een fietser mag wel rechtsaf slaan als het licht rood is " + "en": "A cyclist can turn right if the light is red ", + "nl": "Een fietser mag wel rechtsaf slaan als het licht rood is " }, "hideInAnswer": "_country!=be" }, @@ -284,8 +284,8 @@ { "if": "red_turn:straight:bicycle=yes", "then": { - "en": "A cyclist can go straight on if the light is red ", - "nl": "Een fietser mag wel rechtdoor gaan als het licht rood is " + "en": "A cyclist can go straight on if the light is red ", + "nl": "Een fietser mag wel rechtdoor gaan als het licht rood is " }, "hideInAnswer": "_country!=be" }, diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index d1fd12f598..37d9c97235 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -656,24 +656,24 @@ { "if": "cycleway:traffic_sign=BE:D7", "then": { - "en": "Compulsory cycleway ", - "nl": "Verplicht fietspad " + "en": "Compulsory cycleway ", + "nl": "Verplicht fietspad " }, "hideInAnswer": "_country!=be" }, { "if": "cycleway:traffic_sign~BE:D7;.*", "then": { - "en": "Compulsory cycleway (with supplementary sign) ", - "nl": "Verplicht fietspad (met onderbord)" + "en": "Compulsory cycleway (with supplementary sign) ", + "nl": "Verplicht fietspad (met onderbord)" }, "hideInAnswer": true }, { "if": "cycleway:traffic_sign=BE:D9", "then": { - "en": "Segregated foot/cycleway ", - "nl": "Afgescheiden voet-/fietspad " + "en": "Segregated foot/cycleway ", + "nl": "Afgescheiden voet-/fietspad " }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -684,8 +684,8 @@ { "if": "cycleway:traffic_sign=BE:D10", "then": { - "en": "Unsegregated foot/cycleway ", - "nl": "Gedeeld voet-/fietspad " + "en": "Unsegregated foot/cycleway ", + "nl": "Gedeeld voet-/fietspad " }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -717,8 +717,8 @@ { "if": "traffic_sign=BE:D7", "then": { - "en": "Compulsory cycleway ", - "nl": "Verplicht fietspad " + "en": "Compulsory cycleway ", + "nl": "Verplicht fietspad " }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -731,16 +731,16 @@ { "if": "traffic_sign~BE:D7;.*", "then": { - "en": "Compulsory cycleway (with supplementary sign) ", - "nl": "Verplicht fietspad (met onderbord)" + "en": "Compulsory cycleway (with supplementary sign) ", + "nl": "Verplicht fietspad (met onderbord)" }, "hideInAnswer": true }, { "if": "traffic_sign=BE:D9", "then": { - "en": "Segregated foot/cycleway ", - "nl": "Afgescheiden voet-/fietspad " + "en": "Segregated foot/cycleway ", + "nl": "Afgescheiden voet-/fietspad " }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -755,8 +755,8 @@ { "if": "traffic_sign=BE:D10", "then": { - "en": "Unsegregated foot/cycleway ", - "nl": "Gedeeld voet-/fietspad " + "en": "Unsegregated foot/cycleway ", + "nl": "Gedeeld voet-/fietspad " }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -779,8 +779,8 @@ }, { "question": { - "en": "Does the traffic sign D7 () have a supplementary sign?", - "nl": "Heeft het verkeersbord D7 () een onderbord?" + "en": "Does the traffic sign D7 () have a supplementary sign?", + "nl": "Heeft het verkeersbord D7 () een onderbord?" }, "condition": { "or": [ @@ -792,8 +792,8 @@ { "if": "cycleway:traffic_sign=BE:D7;BE:M6", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -803,8 +803,8 @@ { "if": "cycleway:traffic_sign=BE:D7;BE:M13", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -814,8 +814,8 @@ { "if": "cycleway:traffic_sign=BE:D7;BE:M14", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -826,8 +826,8 @@ { "if": "cycleway:traffic_sign=BE:D7;BE:M7", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -837,8 +837,8 @@ { "if": "cycleway:traffic_sign=BE:D7;BE:M15", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -848,8 +848,8 @@ { "if": "cycleway:traffic_sign=BE:D7;BE:M16", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -868,8 +868,8 @@ }, { "question": { - "en": "Does the traffic sign D7 () have a supplementary sign?", - "nl": "Heeft het verkeersbord D7 () een onderbord?" + "en": "Does the traffic sign D7 () have a supplementary sign?", + "nl": "Heeft het verkeersbord D7 () een onderbord?" }, "condition": { "or": [ @@ -881,8 +881,8 @@ { "if": "traffic_sign=BE:D7;BE:M6", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -892,8 +892,8 @@ { "if": "traffic_sign=BE:D7;BE:M13", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -903,8 +903,8 @@ { "if": "traffic_sign=BE:D7;BE:M14", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -915,8 +915,8 @@ { "if": "traffic_sign=BE:D7;BE:M7", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -926,8 +926,8 @@ { "if": ":traffic_sign=BE:D7;BE:M15", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ @@ -937,8 +937,8 @@ { "if": "traffic_sign=BE:D7;BE:M16", "then": { - "en": "", - "nl": "" + "en": "", + "nl": "" }, "hideInAnswer": "_country!=be", "addExtraTags": [ diff --git a/langs/layers/en.json b/langs/layers/en.json index 44c0b1495e..e473112dc6 100644 --- a/langs/layers/en.json +++ b/langs/layers/en.json @@ -802,7 +802,7 @@ "question": "Can a cyclist turn right when the light is red?", "mappings": { "0": { - "then": "A cyclist can turn right if the light is red " + "then": "A cyclist can turn right if the light is red " }, "1": { "then": "A cyclist can turn right if the light is red" @@ -816,7 +816,7 @@ "question": "Can a cyclist go straight on when the light is red?", "mappings": { "0": { - "then": "A cyclist can go straight on if the light is red " + "then": "A cyclist can go straight on if the light is red " }, "1": { "then": "A cyclist can go straight on if the light is red" diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 93788a2046..416f4e3188 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -892,7 +892,7 @@ "question": "Mag een fietser rechtsaf slaan als het licht rood is?", "mappings": { "0": { - "then": "Een fietser mag wel rechtsaf slaan als het licht rood is " + "then": "Een fietser mag wel rechtsaf slaan als het licht rood is " }, "1": { "then": "Een fietser mag wel rechtsaf slaan als het licht rood is" @@ -906,7 +906,7 @@ "question": "Mag een fietser rechtdoor gaan als het licht rood is?", "mappings": { "0": { - "then": "Een fietser mag wel rechtdoor gaan als het licht rood is " + "then": "Een fietser mag wel rechtdoor gaan als het licht rood is " }, "1": { "then": "Een fietser mag wel rechtdoor gaan als het licht rood is" diff --git a/langs/themes/en.json b/langs/themes/en.json index 113a1ba003..95a73ba616 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -933,16 +933,16 @@ "question": "What traffic sign does this cycleway have?", "mappings": { "0": { - "then": "Compulsory cycleway " + "then": "Compulsory cycleway " }, "1": { - "then": "Compulsory cycleway (with supplementary sign) " + "then": "Compulsory cycleway (with supplementary sign) " }, "2": { - "then": "Segregated foot/cycleway " + "then": "Segregated foot/cycleway " }, "3": { - "then": "Unsegregated foot/cycleway " + "then": "Unsegregated foot/cycleway " }, "4": { "then": "No traffic sign present" @@ -953,16 +953,16 @@ "question": "What traffic sign does this cycleway have?", "mappings": { "0": { - "then": "Compulsory cycleway " + "then": "Compulsory cycleway " }, "1": { - "then": "Compulsory cycleway (with supplementary sign) " + "then": "Compulsory cycleway (with supplementary sign) " }, "2": { - "then": "Segregated foot/cycleway " + "then": "Segregated foot/cycleway " }, "3": { - "then": "Unsegregated foot/cycleway " + "then": "Unsegregated foot/cycleway " }, "4": { "then": "No traffic sign present" @@ -970,25 +970,25 @@ } }, "11": { - "question": "Does the traffic sign D7 () have a supplementary sign?", + "question": "Does the traffic sign D7 () have a supplementary sign?", "mappings": { "0": { - "then": "" + "then": "" }, "1": { - "then": "" + "then": "" }, "2": { - "then": "" + "then": "" }, "3": { - "then": "" + "then": "" }, "4": { - "then": "" + "then": "" }, "5": { - "then": "" + "then": "" }, "6": { "then": "No supplementary traffic sign present" @@ -996,25 +996,25 @@ } }, "12": { - "question": "Does the traffic sign D7 () have a supplementary sign?", + "question": "Does the traffic sign D7 () have a supplementary sign?", "mappings": { "0": { - "then": "" + "then": "" }, "1": { - "then": "" + "then": "" }, "2": { - "then": "" + "then": "" }, "3": { - "then": "" + "then": "" }, "4": { - "then": "" + "then": "" }, "5": { - "then": "" + "then": "" }, "6": { "then": "No supplementary traffic sign present" diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 2cbfdcb57c..a4df2dbee0 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -795,16 +795,16 @@ "question": "Welk verkeersbord heeft dit fietspad?", "mappings": { "0": { - "then": "Verplicht fietspad " + "then": "Verplicht fietspad " }, "1": { - "then": "Verplicht fietspad (met onderbord)" + "then": "Verplicht fietspad (met onderbord)" }, "2": { - "then": "Afgescheiden voet-/fietspad " + "then": "Afgescheiden voet-/fietspad " }, "3": { - "then": "Gedeeld voet-/fietspad " + "then": "Gedeeld voet-/fietspad " }, "4": { "then": "Geen verkeersbord aanwezig" @@ -815,16 +815,16 @@ "question": "Welk verkeersbord heeft dit fietspad?", "mappings": { "0": { - "then": "Verplicht fietspad " + "then": "Verplicht fietspad " }, "1": { - "then": "Verplicht fietspad (met onderbord)" + "then": "Verplicht fietspad (met onderbord)" }, "2": { - "then": "Afgescheiden voet-/fietspad " + "then": "Afgescheiden voet-/fietspad " }, "3": { - "then": "Gedeeld voet-/fietspad " + "then": "Gedeeld voet-/fietspad " }, "4": { "then": "Geen verkeersbord aanwezig" @@ -832,25 +832,25 @@ } }, "11": { - "question": "Heeft het verkeersbord D7 () een onderbord?", + "question": "Heeft het verkeersbord D7 () een onderbord?", "mappings": { "0": { - "then": "" + "then": "" }, "1": { - "then": "" + "then": "" }, "2": { - "then": "" + "then": "" }, "3": { - "then": "" + "then": "" }, "4": { - "then": "" + "then": "" }, "5": { - "then": "" + "then": "" }, "6": { "then": "Geen onderbord aanwezig" @@ -858,25 +858,25 @@ } }, "12": { - "question": "Heeft het verkeersbord D7 () een onderbord?", + "question": "Heeft het verkeersbord D7 () een onderbord?", "mappings": { "0": { - "then": "" + "then": "" }, "1": { - "then": "" + "then": "" }, "2": { - "then": "" + "then": "" }, "3": { - "then": "" + "then": "" }, "4": { - "then": "" + "then": "" }, "5": { - "then": "" + "then": "" }, "6": { "then": "Geen onderbord aanwezig" From 7505b232de1135d4bcd48fbe275552692827a0ca Mon Sep 17 00:00:00 2001 From: Robin van der Linde Date: Wed, 28 Jul 2021 14:26:09 +0200 Subject: [PATCH 09/20] Add line break --- langs/themes/en.json | 2 +- langs/themes/nl.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/langs/themes/en.json b/langs/themes/en.json index 95a73ba616..6fb0be0158 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -936,7 +936,7 @@ "then": "Compulsory cycleway " }, "1": { - "then": "Compulsory cycleway (with supplementary sign) " + "then": "Compulsory cycleway (with supplementary sign)
" }, "2": { "then": "Segregated foot/cycleway " diff --git a/langs/themes/nl.json b/langs/themes/nl.json index a4df2dbee0..17d236cdd1 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -798,7 +798,7 @@ "then": "Verplicht fietspad " }, "1": { - "then": "Verplicht fietspad (met onderbord)" + "then": "Verplicht fietspad (met onderbord)
" }, "2": { "then": "Afgescheiden voet-/fietspad " From 0ab0d159cc0d84ea0bd69df41b3662bb75adb798 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 15:14:13 +0200 Subject: [PATCH 10/20] Small tweaks --- Logic/Osm/Changes.ts | 12 +++++++++- Logic/Osm/OsmObject.ts | 3 +++ Logic/SimpleMetaTagger.ts | 2 +- UI/ExportPDF.ts | 28 +++++++++++++--------- UI/Popup/FeatureInfoBox.ts | 22 +++++++++++++---- assets/themes/cycle_infra/cycle_infra.json | 6 ++--- 6 files changed, 52 insertions(+), 21 deletions(-) diff --git a/Logic/Osm/Changes.ts b/Logic/Osm/Changes.ts index 806af3ba74..6c2acd0f9c 100644 --- a/Logic/Osm/Changes.ts +++ b/Logic/Osm/Changes.ts @@ -27,7 +27,9 @@ export class Changes { private readonly previouslyCreated : OsmObject[] = [] constructor() { - + this.isUploading.addCallbackAndRun(uploading => { + console.trace("Is uploading changed:", uploading) + }) } private static createChangesetFor(csId: string, @@ -255,6 +257,9 @@ export class Changes { console.log("Needed ids", neededIds) OsmObject.DownloadAll(neededIds, true).addCallbackAndRunD(osmObjects => { console.log("Got the fresh objects!", osmObjects, "pending: ", pending) + try{ + + const changes: { newObjects: OsmObject[], modifiedObjects: OsmObject[] @@ -283,6 +288,11 @@ export class Changes { return self.isUploading.setData(false); } // Failed - mark to try again ) + }catch(e){ + console.error("Could not handle changes - probably an old, pending changeset in localstorage with an invalid format; erasing those", e) + self.pendingChanges.setData([]) + self.isUploading.setData(false) + } return true; }); diff --git a/Logic/Osm/OsmObject.ts b/Logic/Osm/OsmObject.ts index fcc3da8886..51e19a3ab9 100644 --- a/Logic/Osm/OsmObject.ts +++ b/Logic/Osm/OsmObject.ts @@ -437,6 +437,9 @@ export class OsmWay extends OsmObject { for (const nodeId of element.nodes) { const node = nodeDict.get(nodeId) + if(node === undefined){ + console.error("Error: node ", nodeId, "not found in ", nodeDict) + } const cp = node.centerpoint(); this.coordinates.push(cp); latSum = cp[0] diff --git a/Logic/SimpleMetaTagger.ts b/Logic/SimpleMetaTagger.ts index 2337c97f3f..569e4645ef 100644 --- a/Logic/SimpleMetaTagger.ts +++ b/Logic/SimpleMetaTagger.ts @@ -305,7 +305,7 @@ export default class SimpleMetaTagger { } else if (_otherParkingMode.matchesProperties(properties)) { parallelParkingCount = 0; } else { - console.log("No parking data for ", properties.name, properties.id, properties) + console.log("No parking data for ", properties.name, properties.id) } diff --git a/UI/ExportPDF.ts b/UI/ExportPDF.ts index 6fc475bd80..a2aecec619 100644 --- a/UI/ExportPDF.ts +++ b/UI/ExportPDF.ts @@ -29,6 +29,7 @@ export default class ExportPDF { private readonly scaling = 2 private readonly freeDivId: string; private readonly _layout: UIEventSource; + private _screenhotTaken = false; constructor( options: { @@ -48,21 +49,24 @@ export default class ExportPDF { const l = options.location.data; const loc = { - lat : l.lat, + lat: l.lat, lon: l.lon, zoom: l.zoom + 1 } - + const minimap = new Minimap({ location: new UIEventSource(loc), // We remove the link between the old and the new UI-event source as moving the map while the export is running fucks up the screenshot background: options.background, allowMoving: false, onFullyLoaded: leaflet => window.setTimeout(() => { - try{ - self.CreatePdf(leaflet) - .then(() => self.cleanup()) - .catch(() => self.cleanup()) - }catch(e){ + if (self._screenhotTaken) { + return; + } + try { + self.CreatePdf(leaflet) + .then(() => self.cleanup()) + .catch(() => self.cleanup()) + } catch (e) { console.error(e) self.cleanup() } @@ -94,9 +98,10 @@ export default class ExportPDF { ) } - - private cleanup(){ + + private cleanup() { new FixedUiElement("Screenshot taken!").AttachTo(this.freeDivId) + this._screenhotTaken = true; } private async CreatePdf(leaflet: L.Map) { @@ -122,7 +127,8 @@ export default class ExportPDF { doc.roundedRect(12, 5, 125, 30, 5, 5, 'FD') doc.setFontSize(20) - doc.text(layout.title.txt, 40, 20, { maxWidth: 100 + doc.text(layout.title.txt, 40, 20, { + maxWidth: 100 }) doc.setFontSize(10) doc.text(t.attr.txt, 40, 25, { @@ -141,6 +147,6 @@ export default class ExportPDF { doc.save("MapComplete_export.pdf"); - + } } diff --git a/UI/Popup/FeatureInfoBox.ts b/UI/Popup/FeatureInfoBox.ts index 1bd09cb143..3f663a4b9f 100644 --- a/UI/Popup/FeatureInfoBox.ts +++ b/UI/Popup/FeatureInfoBox.ts @@ -63,13 +63,15 @@ export default class FeatureInfoBox extends ScrollableFullScreen { } return new EditableTagRendering(tags, tr, layerConfig.units); }); + + let editElements : BaseUIElement[] = [] if (!questionBoxIsUsed) { - renderings.push(questionBox); + editElements.push(questionBox); } if (layerConfig.deletion) { - renderings.push( + editElements.push( new VariableUiElement(tags.map(tags => tags.id).map(id => new DeleteWizard( id, @@ -79,7 +81,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen { } if (layerConfig.allowSplit) { - renderings.push( + editElements.push( new VariableUiElement(tags.map(tags => tags.id).map(id => new SplitRoadWizard(id)) )) @@ -91,7 +93,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen { renderings.push(new TagRenderingAnswer(tags, SharedTagRenderings.SharedTagRendering.get("minimap"))) } - renderings.push( + editElements.push( new VariableUiElement( State.state.osmConnection.userDetails .map(ud => ud.csCount) @@ -109,7 +111,7 @@ export default class FeatureInfoBox extends ScrollableFullScreen { ) - renderings.push( + editElements.push( new VariableUiElement( State.state.featureSwitchIsDebugging.map(isDebugging => { if (isDebugging) { @@ -119,6 +121,16 @@ export default class FeatureInfoBox extends ScrollableFullScreen { }) ) ) + + const editors = new VariableUiElement(State.state.featureSwitchUserbadge.map( + userbadge => { + if(!userbadge){ + return undefined + } + return new Combine(editElements) + } + )) + renderings.push(editors) return new Combine(renderings).SetClass("block") diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index 3193f27b18..e7e395b706 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -23,7 +23,7 @@ "startLat": 51, "startLon": 3.75, "startZoom": 11, - "widenFactor": 0.05, + "widenFactor": 0.0, "socialImage": "./assets/themes/cycle_infra/cycle-infra.svg", "enableDownload": true, "layers": [ @@ -33,7 +33,7 @@ "en": "Cycleways", "nl": "Fietspaden" }, - "minzoom": 14, + "minzoom": 16, "source": { "osmTags": { "or": [ @@ -1151,7 +1151,7 @@ "calculatedTags": [ "_comfort_score=feat.score('https://raw.githubusercontent.com/pietervdvn/AspectedRouting/master/Examples/bicycle/aspects/bicycle.comfort.json')" ], - "minzoom": 14, + "minzoom": 16, "wayHandling": 0, "title": { "render": { From 0c760c8458a10cb062cfec089470ac4282717b06 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 15:50:33 +0200 Subject: [PATCH 11/20] Fix making changes to relations --- Logic/Osm/OsmObject.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Logic/Osm/OsmObject.ts b/Logic/Osm/OsmObject.ts index 51e19a3ab9..8a97e9ba1c 100644 --- a/Logic/Osm/OsmObject.ts +++ b/Logic/Osm/OsmObject.ts @@ -439,6 +439,8 @@ export class OsmWay extends OsmObject { const node = nodeDict.get(nodeId) if(node === undefined){ console.error("Error: node ", nodeId, "not found in ", nodeDict) + // This is probably part of a relation which hasn't been fully downloaded + continue; } const cp = node.centerpoint(); this.coordinates.push(cp); From b5eb56980255d81767ae471a22ce961befe8568a Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 16:48:59 +0200 Subject: [PATCH 12/20] Streamline download buttons --- InitUiElements.ts | 145 +-------------------- State.ts | 17 +-- UI/BigComponents/AllDownloads.ts | 53 ++++++++ UI/BigComponents/FilterView.ts | 8 +- UI/BigComponents/LayerControlPanel.ts | 42 ------ UI/BigComponents/LeftControls.ts | 94 +++++++++++++ UI/BigComponents/RightControls.ts | 43 ++++++ UI/BigComponents/SimpleAddUI.ts | 10 +- assets/themes/cycle_infra/cycle_infra.json | 2 +- langs/en.json | 1 + 10 files changed, 222 insertions(+), 193 deletions(-) create mode 100644 UI/BigComponents/AllDownloads.ts delete mode 100644 UI/BigComponents/LayerControlPanel.ts create mode 100644 UI/BigComponents/LeftControls.ts create mode 100644 UI/BigComponents/RightControls.ts diff --git a/InitUiElements.ts b/InitUiElements.ts index 389171d2d7..b0e4109745 100644 --- a/InitUiElements.ts +++ b/InitUiElements.ts @@ -10,7 +10,6 @@ import SimpleAddUI from "./UI/BigComponents/SimpleAddUI"; import CenterMessageBox from "./UI/CenterMessageBox"; import UserBadge from "./UI/BigComponents/UserBadge"; import SearchAndGo from "./UI/BigComponents/SearchAndGo"; -import GeoLocationHandler from "./Logic/Actors/GeoLocationHandler"; import {LocalStorageSource} from "./Logic/Web/LocalStorageSource"; import {Utils} from "./Utils"; import Svg from "./Svg"; @@ -23,26 +22,22 @@ import UserDetails from "./Logic/Osm/OsmConnection"; import Attribution from "./UI/BigComponents/Attribution"; import LayerResetter from "./Logic/Actors/LayerResetter"; import FullWelcomePaneWithTabs from "./UI/BigComponents/FullWelcomePaneWithTabs"; -import LayerControlPanel from "./UI/BigComponents/LayerControlPanel"; import ShowDataLayer from "./UI/ShowDataLayer"; import Hash from "./Logic/Web/Hash"; import FeaturePipeline from "./Logic/FeatureSource/FeaturePipeline"; import ScrollableFullScreen from "./UI/Base/ScrollableFullScreen"; import Translations from "./UI/i18n/Translations"; import MapControlButton from "./UI/MapControlButton"; -import Combine from "./UI/Base/Combine"; import SelectedFeatureHandler from "./Logic/Actors/SelectedFeatureHandler"; import LZString from "lz-string"; import {LayoutConfigJson} from "./Customizations/JSON/LayoutConfigJson"; -import AttributionPanel from "./UI/BigComponents/AttributionPanel"; -import ContributorCount from "./Logic/ContributorCount"; import FeatureSource from "./Logic/FeatureSource/FeatureSource"; import AllKnownLayers from "./Customizations/AllKnownLayers"; import LayerConfig from "./Customizations/JSON/LayerConfig"; import AvailableBaseLayers from "./Logic/Actors/AvailableBaseLayers"; import {TagsFilter} from "./Logic/Tags/TagsFilter"; -import FilterView from "./UI/BigComponents/FilterView"; -import ExportPDF from "./UI/ExportPDF"; +import LeftControls from "./UI/BigComponents/LeftControls"; +import RightControls from "./UI/BigComponents/RightControls"; export class InitUiElements { static InitAll( @@ -191,42 +186,11 @@ export class InitUiElements { marker.addTo(State.state.leafletMap.data); }); - const geolocationButton = new Toggle( - new MapControlButton( - new GeoLocationHandler( - State.state.currentGPSLocation, - State.state.leafletMap, - State.state.layoutToUse - ), { - dontStyle: true - } - ), - undefined, - State.state.featureSwitchGeolocation - ); - - const plus = new MapControlButton( - Svg.plus_zoom_svg() - ).onClick(() => { - State.state.locationControl.data.zoom++; - State.state.locationControl.ping(); - }); - - const min = new MapControlButton( - Svg.min_zoom_svg() - ).onClick(() => { - State.state.locationControl.data.zoom--; - State.state.locationControl.ping(); - }); - - - new Combine([plus, min, geolocationButton].map(el => el.SetClass("m-0.5 md:m-1"))) - .SetClass("flex flex-col") - .AttachTo("bottom-right"); if (layoutToUse.id === personal.id) { updateFavs(); } + InitUiElements.setupAllLayerElements(); if (layoutToUse.id === personal.id) { @@ -331,105 +295,6 @@ export class InitUiElements { ); } - private static InitLayerSelection(featureSource: FeatureSource) { - const copyrightNotice = new ScrollableFullScreen( - () => Translations.t.general.attribution.attributionTitle.Clone(), - () => - new AttributionPanel( - State.state.layoutToUse, - new ContributorCount(featureSource).Contributors - ), - "copyright" - ); - - const copyrightButton = new Toggle( - copyrightNotice, - new MapControlButton(Svg.copyright_svg()), - copyrightNotice.isShown - ) - .ToggleOnClick() - .SetClass("p-0.5"); - - const layerControlPanel = new LayerControlPanel( - State.state.layerControlIsOpened - ).SetClass("block p-1 rounded-full"); - - const layerControlButton = new Toggle( - layerControlPanel, - new MapControlButton(Svg.layers_svg()), - State.state.layerControlIsOpened - ).ToggleOnClick(); - - const layerControl = new Toggle( - layerControlButton, - "", - State.state.featureSwitchLayers - ); - - - const filterView = - new ScrollableFullScreen( - () => Translations.t.general.layerSelection.title.Clone(), - () => - new FilterView(State.state.filteredLayers).SetClass( - "block p-1 rounded-full" - ), - undefined, - State.state.filterIsOpened - ); - - - const filterMapControlButton = new MapControlButton( - Svg.filter_svg() - ); - - const filterButton = new Toggle( - filterView, - filterMapControlButton, - State.state.filterIsOpened - ).ToggleOnClick(); - - const filterControl = new Toggle( - filterButton, - undefined, - State.state.featureSwitchFilter - ); - - const screenshot = - new Toggle( - new MapControlButton( - Svg.download_svg(), - ).onClick(() => { - // Will already export - new ExportPDF( - { - freeDivId: "belowmap", - background: State.state.backgroundLayer, - location: State.state.locationControl, - features: State.state.featurePipeline.features, - layout: State.state.layoutToUse, - } - ); - - }), undefined, State.state.featureSwitchExportAsPdf) - - - new Combine([filterControl, layerControl, screenshot, copyrightButton,]) - .SetClass("flex flex-col") - .AttachTo("bottom-left"); - - State.state.locationControl.addCallback(() => { - // Close the layer selection when the map is moved - layerControlButton.isEnabled.setData(false); - copyrightButton.isEnabled.setData(false); - }); - - State.state.selectedElement.addCallbackAndRunD((_) => { - layerControlButton.isEnabled.setData(false); - copyrightButton.isEnabled.setData(false); - }); - } - private static InitBaseMap() { State.state.availableBackgroundLayers = AvailableBaseLayers.AvailableLayersAt(State.state.locationControl); @@ -561,7 +426,9 @@ export class InitUiElements { // ------------- Setup the layers ------------------------------- const source = InitUiElements.InitLayers(); - InitUiElements.InitLayerSelection(source); + + new LeftControls(source).AttachTo("bottom-left"); + new RightControls().AttachTo("bottom-right"); // ------------------ Setup various other UI elements ------------ diff --git a/State.ts b/State.ts index ac0c4a390d..9b77755045 100644 --- a/State.ts +++ b/State.ts @@ -79,7 +79,7 @@ export default class State { public readonly featureSwitchUserbadge: UIEventSource; public readonly featureSwitchSearch: UIEventSource; - public readonly featureSwitchLayers: UIEventSource; + public readonly featureSwitchBackgroundSlection: UIEventSource; public readonly featureSwitchAddNew: UIEventSource; public readonly featureSwitchWelcomeMessage: UIEventSource; public readonly featureSwitchIframe: UIEventSource; @@ -125,11 +125,11 @@ export default class State { public layoutDefinition: string; public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>; - public layerControlIsOpened: UIEventSource = + public downloadControlIsOpened: UIEventSource = QueryParameters.GetQueryParameter( - "layer-control-toggle", + "download-control-toggle", "false", - "Whether or not the layer control is shown" + "Whether or not the download panel is shown" ).map( (str) => str !== "false", [], @@ -249,11 +249,12 @@ export default class State { (layoutToUse) => layoutToUse?.enableSearch ?? true, "Disables/Enables the search bar" ); - this.featureSwitchLayers = featSw( - "fs-layers", - (layoutToUse) => layoutToUse?.enableLayers ?? true, - "Disables/Enables the layer control" + this.featureSwitchBackgroundSlection = featSw( + "fs-background", + (layoutToUse) => layoutToUse?.enableBackgroundLayerSelection ?? true, + "Disables/Enables the background layer control" ); + this.featureSwitchFilter = featSw( "fs-filter", (layoutToUse) => layoutToUse?.enableLayers ?? true, diff --git a/UI/BigComponents/AllDownloads.ts b/UI/BigComponents/AllDownloads.ts new file mode 100644 index 0000000000..3911ab5383 --- /dev/null +++ b/UI/BigComponents/AllDownloads.ts @@ -0,0 +1,53 @@ +import State from "../../State"; +import Combine from "../Base/Combine"; +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 {DownloadPanel} from "./DownloadPanel"; +import {SubtleButton} from "../Base/SubtleButton"; +import Svg from "../../Svg"; +import ExportPDF from "../ExportPDF"; + +export default class AllDownloads extends ScrollableFullScreen { + + constructor(isShown: UIEventSource) { + super(AllDownloads.GenTitle, AllDownloads.GeneratePanel, "layers", isShown); + } + + private static GenTitle(): BaseUIElement { + return Translations.t.general.download.title + .Clone() + .SetClass("text-2xl break-words font-bold p-2"); + } + + private static GeneratePanel(): BaseUIElement { + const generatePdf = () => { + new ExportPDF( + { + freeDivId: "belowmap", + background: State.state.backgroundLayer, + location: State.state.locationControl, + features: State.state.featurePipeline.features, + layout: State.state.layoutToUse, + }) + } + + const pdf = new Toggle( + new SubtleButton(Svg.floppy_ui(), Translations.t.general.download.downloadAsPdf.Clone().SetClass("font-bold"),) + .onClick(generatePdf), + undefined, + + State.state.featureSwitchExportAsPdf + ) + + const exportPanel = new Toggle( + new DownloadPanel(), + undefined, + State.state.featureSwitchEnableExport + ) + + return new Combine([pdf, exportPanel]).SetClass("flex flex-col"); + } +} diff --git a/UI/BigComponents/FilterView.ts b/UI/BigComponents/FilterView.ts index 17318a6100..dfa486fd1d 100644 --- a/UI/BigComponents/FilterView.ts +++ b/UI/BigComponents/FilterView.ts @@ -15,6 +15,7 @@ import {UIEventSource} from "../../Logic/UIEventSource"; import BaseUIElement from "../BaseUIElement"; import State from "../../State"; import FilteredLayer from "../../Models/FilteredLayer"; +import BackgroundSelector from "./BackgroundSelector"; /** @@ -23,9 +24,14 @@ import FilteredLayer from "../../Models/FilteredLayer"; export default class FilterView extends VariableUiElement { constructor(filteredLayer: UIEventSource) { + const backgroundSelector = new Toggle( + new BackgroundSelector(), + undefined, + State.state.featureSwitchBackgroundSlection + ) super( filteredLayer.map((filteredLayers) => - filteredLayers?.map(l => FilterView.createOneFilteredLayerElement(l)) + filteredLayers?.map(l => FilterView.createOneFilteredLayerElement(l)).concat(backgroundSelector) ) ); } diff --git a/UI/BigComponents/LayerControlPanel.ts b/UI/BigComponents/LayerControlPanel.ts deleted file mode 100644 index 968902ee33..0000000000 --- a/UI/BigComponents/LayerControlPanel.ts +++ /dev/null @@ -1,42 +0,0 @@ -import State from "../../State"; -import BackgroundSelector from "./BackgroundSelector"; -import Combine from "../Base/Combine"; -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 {DownloadPanel} from "./DownloadPanel"; - -export default class LayerControlPanel extends ScrollableFullScreen { - - constructor(isShown: UIEventSource) { - super(LayerControlPanel.GenTitle, LayerControlPanel.GeneratePanel, "layers", isShown); - } - - private static GenTitle(): BaseUIElement { - return Translations.t.general.layerSelection.title - .Clone() - .SetClass("text-2xl break-words font-bold p-2"); - } - - private static GeneratePanel(): BaseUIElement { - const elements: BaseUIElement[] = []; - - if (State.state.layoutToUse.data.enableBackgroundLayerSelection) { - const backgroundSelector = new BackgroundSelector(); - backgroundSelector.SetStyle("margin:1em"); - backgroundSelector.onClick(() => { - }); - elements.push(backgroundSelector) - } - - elements.push(new Toggle( - new DownloadPanel(), - undefined, - State.state.featureSwitchEnableExport - )) - - return new Combine(elements).SetClass("flex flex-col"); - } -} diff --git a/UI/BigComponents/LeftControls.ts b/UI/BigComponents/LeftControls.ts new file mode 100644 index 0000000000..6f32c57d4e --- /dev/null +++ b/UI/BigComponents/LeftControls.ts @@ -0,0 +1,94 @@ +import Combine from "../Base/Combine"; +import ScrollableFullScreen from "../Base/ScrollableFullScreen"; +import Translations from "../i18n/Translations"; +import AttributionPanel from "./AttributionPanel"; +import State from "../../State"; +import ContributorCount from "../../Logic/ContributorCount"; +import Toggle from "../Input/Toggle"; +import MapControlButton from "../MapControlButton"; +import Svg from "../../Svg"; +import AllDownloads from "./AllDownloads"; +import FilterView from "./FilterView"; +import FeatureSource from "../../Logic/FeatureSource/FeatureSource"; + +export default class LeftControls extends Combine { + + constructor(featureSource: FeatureSource) { + + const toggledCopyright = new ScrollableFullScreen( + () => Translations.t.general.attribution.attributionTitle.Clone(), + () => + new AttributionPanel( + State.state.layoutToUse, + new ContributorCount(featureSource).Contributors + ), + undefined + ); + + const copyrightButton = new Toggle( + toggledCopyright, + new MapControlButton(Svg.copyright_svg()), + toggledCopyright.isShown + ) + .ToggleOnClick() + .SetClass("p-0.5"); + + const toggledDownload = new Toggle( + new AllDownloads( + State.state.downloadControlIsOpened + ).SetClass("block p-1 rounded-full"), + new MapControlButton(Svg.download_svg()), + State.state.downloadControlIsOpened + ).ToggleOnClick(); + + const downloadButtonn = new Toggle( + toggledDownload, + undefined, + State.state.featureSwitchEnableExport.map(downloadEnabled => downloadEnabled || State.state.featureSwitchExportAsPdf.data, + [State.state.featureSwitchExportAsPdf]) + ); + + + const toggledFilter = new Toggle( + new ScrollableFullScreen( + () => Translations.t.general.layerSelection.title.Clone(), + () => + new FilterView(State.state.filteredLayers).SetClass( + "block p-1 rounded-full" + ), + undefined, + State.state.filterIsOpened + ), + new MapControlButton(Svg.filter_svg()), + State.state.filterIsOpened + ).ToggleOnClick(); + + const filterButton = new Toggle( + toggledFilter, + undefined, + State.state.featureSwitchFilter + ); + + + State.state.locationControl.addCallback(() => { + // Close the layer selection when the map is moved + toggledDownload.isEnabled.setData(false); + copyrightButton.isEnabled.setData(false); + toggledFilter.isEnabled.setData(false); + }); + + State.state.selectedElement.addCallbackAndRunD((_) => { + toggledDownload.isEnabled.setData(false); + copyrightButton.isEnabled.setData(false); + toggledFilter.isEnabled.setData(false); + }); + super([filterButton, + downloadButtonn, + copyrightButton]) + + this.SetClass("flex flex-col") + + } + + +} \ No newline at end of file diff --git a/UI/BigComponents/RightControls.ts b/UI/BigComponents/RightControls.ts new file mode 100644 index 0000000000..dd4282b35c --- /dev/null +++ b/UI/BigComponents/RightControls.ts @@ -0,0 +1,43 @@ +import Combine from "../Base/Combine"; +import Toggle from "../Input/Toggle"; +import MapControlButton from "../MapControlButton"; +import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler"; +import State from "../../State"; +import Svg from "../../Svg"; + +export default class RightControls extends Combine { + + constructor() { + const geolocationButton = new Toggle( + new MapControlButton( + new GeoLocationHandler( + State.state.currentGPSLocation, + State.state.leafletMap, + State.state.layoutToUse + ), { + dontStyle: true + } + ), + undefined, + State.state.featureSwitchGeolocation + ); + + const plus = new MapControlButton( + Svg.plus_zoom_svg() + ).onClick(() => { + State.state.locationControl.data.zoom++; + State.state.locationControl.ping(); + }); + + const min = new MapControlButton( + Svg.min_zoom_svg() + ).onClick(() => { + State.state.locationControl.data.zoom--; + State.state.locationControl.ping(); + }); + + super([plus, min, geolocationButton].map(el => el.SetClass("m-0.5 md:m-1"))) + this.SetClass("flex flex-col") + } + +} \ No newline at end of file diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 62ea506bbd..9f2e4272df 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -166,7 +166,7 @@ export default class SimpleAddUI extends Toggle { ]) ) - .onClick(() => State.state.layerControlIsOpened.setData(true)) + .onClick(() => State.state.filterIsOpened.setData(true)) const openLayerOrConfirm = new Toggle( confirmButton, @@ -238,7 +238,13 @@ export default class SimpleAddUI extends Toggle { const allButtons = []; for (const layer of State.state.filteredLayers.data) { - if (layer.isDisplayed.data === false && State.state.featureSwitchLayers) { + if (layer.isDisplayed.data === false && State.state.featureSwitchFilter.data) { + // The layer is not displayed and we cannot enable the layer control -> we skip + continue; + } + + if(layer.layerDef.name === undefined){ + // this is a parlty hidden layer continue; } diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index e7e395b706..7bddff577c 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -23,7 +23,7 @@ "startLat": 51, "startLon": 3.75, "startZoom": 11, - "widenFactor": 0.0, + "widenFactor": 0, "socialImage": "./assets/themes/cycle_infra/cycle-infra.svg", "enableDownload": true, "layers": [ diff --git a/langs/en.json b/langs/en.json index f8453d507b..5f08870772 100644 --- a/langs/en.json +++ b/langs/en.json @@ -162,6 +162,7 @@ }, "download": { "title": "Download visible data", + "downloadAsPdf": "Download a PDF of the current map", "downloadGeojson": "Download visible data as geojson", "downloadGeoJsonHelper": "Compatible with QGIS, OsmAnd, ArcGIS, ESRI, ...", "downloadCSV": "Download as CSV", From ba84fd4a8d3889c094f17be73068557d960aa8f5 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 17:25:08 +0200 Subject: [PATCH 13/20] Fix typo in tagging: urinal instead of urinals --- assets/layers/toilet/toilet.json | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/assets/layers/toilet/toilet.json b/assets/layers/toilet/toilet.json index cbdd19d286..ceabeccdb9 100644 --- a/assets/layers/toilet/toilet.json +++ b/assets/layers/toilet/toilet.json @@ -30,7 +30,9 @@ "then": "./assets/layers/toilet/wheelchair.svg" }, { - "if": "toilets:position=urinals", + "if": { + "or": ["toilets:position=urinals", "toilets:position=urinal"] + }, "then": "./assets/layers/toilet/urinal.svg" } ] @@ -260,7 +262,7 @@ } }, { - "if": "toilets:position=urinals", + "if": "toilets:position=urinal", "then": { "en": "There are only urinals here", "de": "Hier gibt es nur Pissoirs", @@ -280,7 +282,7 @@ } }, { - "if": "toilets:position=seated;urinals", + "if": "toilets:position=seated;urinal", "then": { "en": "Both seated toilets and urinals are available here", "de": "Sowohl Sitztoiletten als auch Pissoirs sind hier verfügbar", From ae21e33077b7d63f9a00a63e6b304a91780e4652 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 18:20:59 +0200 Subject: [PATCH 14/20] Fix dissapearing attribution, fix toggle behaviour --- UI/BigComponents/Basemap.ts | 2 ++ UI/BigComponents/LeftControls.ts | 14 ++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/UI/BigComponents/Basemap.ts b/UI/BigComponents/Basemap.ts index a4afd6ec8b..9d627b6317 100644 --- a/UI/BigComponents/Basemap.ts +++ b/UI/BigComponents/Basemap.ts @@ -50,6 +50,8 @@ export class Basemap { } previousLayer = newLayer; self.map.addLayer(newLayer); + extraAttribution.AttachTo('leaflet-attribution') + }) diff --git a/UI/BigComponents/LeftControls.ts b/UI/BigComponents/LeftControls.ts index 6f32c57d4e..92a012bbf4 100644 --- a/UI/BigComponents/LeftControls.ts +++ b/UI/BigComponents/LeftControls.ts @@ -27,19 +27,20 @@ export default class LeftControls extends Combine { const copyrightButton = new Toggle( toggledCopyright, - new MapControlButton(Svg.copyright_svg()), + new MapControlButton(Svg.copyright_svg()) + .onClick(() => toggledCopyright.isShown.setData(true)), toggledCopyright.isShown ) - .ToggleOnClick() .SetClass("p-0.5"); const toggledDownload = new Toggle( new AllDownloads( State.state.downloadControlIsOpened ).SetClass("block p-1 rounded-full"), - new MapControlButton(Svg.download_svg()), + new MapControlButton(Svg.download_svg()) + .onClick(() => State.state.downloadControlIsOpened.setData(true)), State.state.downloadControlIsOpened - ).ToggleOnClick(); + ) const downloadButtonn = new Toggle( toggledDownload, @@ -59,9 +60,10 @@ export default class LeftControls extends Combine { undefined, State.state.filterIsOpened ), - new MapControlButton(Svg.filter_svg()), + new MapControlButton(Svg.filter_svg()) + .onClick(() => State.state.filterIsOpened.setData(true)), State.state.filterIsOpened - ).ToggleOnClick(); + ) const filterButton = new Toggle( toggledFilter, From 7ae6a7024f5f11aaa7a4f233f5c6bc85cddc0ab7 Mon Sep 17 00:00:00 2001 From: riQQ Date: Wed, 28 Jul 2021 19:04:05 +0200 Subject: [PATCH 15/20] Remove duplicate line from Readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index be23b733d6..c1c2e950dd 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,6 @@ The core strings and builtin themes of MapComplete are translated on [Hosted Web You can easily make an account and start translating in their web-environment - no installation required. [![Translation status](https://hosted.weblate.org/widgets/mapcomplete/-/multi-blue.svg)](https://hosted.weblate.org/engage/mapcomplete/) -[![Translation status](https://hosted.weblate.org/widgets/mapcomplete/-/multi-blue.svg)](https://hosted.weblate.org/engage/mapcomplete/) ## Architecture From 466527e0f8994cab88a3c615bbf83ca900bccc6a Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 23:20:46 +0200 Subject: [PATCH 16/20] Small improvements --- UI/BigComponents/AllDownloads.ts | 5 ++++- assets/layers/toilet/toilet.json | 5 ++++- assets/themes/cycle_infra/cycle_infra.json | 16 ++++++++-------- langs/en.json | 3 ++- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/UI/BigComponents/AllDownloads.ts b/UI/BigComponents/AllDownloads.ts index 3911ab5383..063fea9fb4 100644 --- a/UI/BigComponents/AllDownloads.ts +++ b/UI/BigComponents/AllDownloads.ts @@ -35,7 +35,10 @@ export default class AllDownloads extends ScrollableFullScreen { } const pdf = new Toggle( - new SubtleButton(Svg.floppy_ui(), Translations.t.general.download.downloadAsPdf.Clone().SetClass("font-bold"),) + new SubtleButton(Svg.floppy_ui(), + new Combine([Translations.t.general.download.downloadAsPdf.Clone().SetClass("font-bold"), + Translations.t.general.download.downloadAsPdfHelper.Clone()] + ).SetClass("flex flex-col")) .onClick(generatePdf), undefined, diff --git a/assets/layers/toilet/toilet.json b/assets/layers/toilet/toilet.json index ceabeccdb9..67ba9267a4 100644 --- a/assets/layers/toilet/toilet.json +++ b/assets/layers/toilet/toilet.json @@ -31,7 +31,10 @@ }, { "if": { - "or": ["toilets:position=urinals", "toilets:position=urinal"] + "or": [ + "toilets:position=urinals", + "toilets:position=urinal" + ] }, "then": "./assets/layers/toilet/urinal.svg" } diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index a9a526fe8e..2dc568c4a4 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -69,7 +69,7 @@ }, "then": { "nl": "Fietsweg", - "en": "Bike road" + "en": "Cycleway" } }, { @@ -89,7 +89,7 @@ { "if": "cycleway=track", "then": { - "en": "Bike road next to the road", + "en": "Cycleway next to the road", "nl": "Fietsweg naast de weg" } }, @@ -219,7 +219,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet, and a 30km/h zone.", - "nl": "Dit is een fietstraat, en dus een 30km/h zone" + "nl": "Dit is een fietsstraat, en dus een 30km/h zone" }, "addExtraTags": [ "overtaking:motor_vehicle=no", @@ -231,7 +231,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet", - "nl": "Dit is een fietstraat" + "nl": "Dit is een fietsstraat" }, "hideInAnswer": "_country=be" }, @@ -664,8 +664,8 @@ { "if": "cycleway:traffic_sign~BE:D7;.*", "then": { - "en": "Compulsory cycleway (with supplementary sign) ", - "nl": "Verplicht fietspad (met onderbord)" + "en": "Compulsory cycleway (with supplementary sign)
", + "nl": "Verplicht fietspad (met onderbord)
" }, "hideInAnswer": true }, @@ -1274,7 +1274,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet, and a 30km/h zone.", - "nl": "Dit is een fietstraat, en dus een 30km/h zone" + "nl": "Dit is een fietsstraat, en dus een 30km/h zone" }, "addExtraTags": [ "overtaking:motor_vehicle=no", @@ -1286,7 +1286,7 @@ "if": "cyclestreet=yes", "then": { "en": "This is a cyclestreet", - "nl": "Dit is een fietstraat" + "nl": "Dit is een fietsstraat" }, "hideInAnswer": "_country=be" }, diff --git a/langs/en.json b/langs/en.json index 5f08870772..7d794fee42 100644 --- a/langs/en.json +++ b/langs/en.json @@ -163,9 +163,10 @@ "download": { "title": "Download visible data", "downloadAsPdf": "Download a PDF of the current map", + "downloadAsPdfHelper": "Ideal to print the current map", "downloadGeojson": "Download visible data as geojson", "downloadGeoJsonHelper": "Compatible with QGIS, OsmAnd, ArcGIS, ESRI, ...", - "downloadCSV": "Download as CSV", + "downloadCSV": "Download visible data as CSV", "downloadCSVHelper": "Compatible with LibreOffice Calc, Excel, ...", "includeMetaData": "Include metadata (last editor, calculated values, ...)", "licenseInfo": "

Copyright notice

The provided is available under ODbL. Reusing this data is free for any purpose, but
  • the attribution © OpenStreetMap contributors is required
  • Any change to this data must be republished under the same license
Please read the full copyright notice for details", From de721c6c37ee4f74b1127888afb1b86e0fbc256d Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 28 Jul 2021 23:30:04 +0200 Subject: [PATCH 17/20] Update contributor list --- assets/contributors.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/contributors.json b/assets/contributors.json index a66dcc9bad..54a85eebc6 100644 --- a/assets/contributors.json +++ b/assets/contributors.json @@ -1 +1 @@ -{"contributors":[{"contributor":"pietervdvn", "commits":835},{"contributor":"Pieter Vander Vennet", "commits":746},{"contributor":"Weblate", "commits":38},{"contributor":"Tobias", "commits":35},{"contributor":"Christian Neumann", "commits":33},{"contributor":"Win Olario", "commits":31},{"contributor":"Pieter Fiers", "commits":31},{"contributor":"Sebastian Kürten", "commits":17},{"contributor":"Joost", "commits":17},{"contributor":"Marco", "commits":16},{"contributor":"Artem", "commits":16},{"contributor":"Allan Nordhøy", "commits":16},{"contributor":"ToastHawaii", "commits":15},{"contributor":"Supaplex", "commits":14},{"contributor":"J. Lavoie", "commits":14},{"contributor":"Bavo Vanderghote", "commits":12},{"contributor":"Jacque Fresco", "commits":9},{"contributor":"Midgard", "commits":8},{"contributor":"Mateusz Konieczny", "commits":8},{"contributor":"yopaseopor", "commits":7},{"contributor":"Hosted Weblate", "commits":7},{"contributor":"Flo Edelmann", "commits":7},{"contributor":"Binnette", "commits":7},{"contributor":"pelderson", "commits":6},{"contributor":"lvgx", "commits":6},{"contributor":"dependabot[bot]", "commits":6},{"contributor":"Alexey Shabanov", "commits":6},{"contributor":"SiegbjornSitumeang", "commits":4},{"contributor":"Polgár Sándor", "commits":4},{"contributor":"Hiroshi Miura", "commits":4},{"contributor":"Wiktor Przybylski", "commits":3},{"contributor":"vankos", "commits":3},{"contributor":"Léo Villeveygoux", "commits":3},{"contributor":"JCGF-OSM", "commits":3},{"contributor":"Jan Zabel", "commits":3},{"contributor":"Erik Palm", "commits":3},{"contributor":"David Haberthür", "commits":3},{"contributor":"快乐的老鼠宝宝", "commits":2},{"contributor":"Vinicius", "commits":2},{"contributor":"Stanislas Gueniffey", "commits":2},{"contributor":"Robin van der Linde", "commits":2},{"contributor":"riiga", "commits":2},{"contributor":"pbarban", "commits":2},{"contributor":"mic140", "commits":2},{"contributor":"Leo Alcaraz", "commits":2},{"contributor":"Jose Luis Infante", "commits":2},{"contributor":"Heiko", "commits":2},{"contributor":"graveelius", "commits":2},{"contributor":"Damian Tokarski", "commits":2},{"contributor":"Tomas Fiers", "commits":1},{"contributor":"Thibault Molleman", "commits":1},{"contributor":"tbowdecl97", "commits":1},{"contributor":"Sebastian", "commits":1},{"contributor":"Sean Young", "commits":1},{"contributor":"Schouppe Joost", "commits":1},{"contributor":"Noémie", "commits":1},{"contributor":"mozita", "commits":1},{"contributor":"Michał Targoński", "commits":1},{"contributor":"liimee", "commits":1},{"contributor":"Jeff Huang", "commits":1},{"contributor":"Iváns", "commits":1},{"contributor":"Eric Armijo", "commits":1},{"contributor":"Damian Pułka", "commits":1},{"contributor":"Carlos Ramos Carreño", "commits":1},{"contributor":"Beardhatcode", "commits":1}]} \ No newline at end of file +{"contributors":[{"contributor":"pietervdvn", "commits":1088},{"contributor":"Pieter Vander Vennet", "commits":775},{"contributor":"Weblate", "commits":47},{"contributor":"Robin van der Linde", "commits":45},{"contributor":"Tobias", "commits":35},{"contributor":"Christian Neumann", "commits":33},{"contributor":"Win Olario", "commits":31},{"contributor":"Pieter Fiers", "commits":31},{"contributor":"karelleketers", "commits":26},{"contributor":"Artem", "commits":22},{"contributor":"Ward", "commits":20},{"contributor":"Sebastian Kürten", "commits":19},{"contributor":"Arno Deceuninck", "commits":18},{"contributor":"pgm-chardelv1", "commits":17},{"contributor":"Joost", "commits":17},{"contributor":"Marco", "commits":16},{"contributor":"Allan Nordhøy", "commits":16},{"contributor":"ToastHawaii", "commits":15},{"contributor":"Supaplex", "commits":14},{"contributor":"J. Lavoie", "commits":14},{"contributor":"Bavo Vanderghote", "commits":12},{"contributor":"LiamSimons", "commits":10},{"contributor":"Jacque Fresco", "commits":9},{"contributor":"Midgard", "commits":8},{"contributor":"Mateusz Konieczny", "commits":8},{"contributor":"yopaseopor", "commits":7},{"contributor":"Hosted Weblate", "commits":7},{"contributor":"Flo Edelmann", "commits":7},{"contributor":"Binnette", "commits":7},{"contributor":"pelderson", "commits":6},{"contributor":"lvgx", "commits":6},{"contributor":"dependabot[bot]", "commits":6},{"contributor":"Alexey Shabanov", "commits":6},{"contributor":"Vinicius", "commits":5},{"contributor":"Irina", "commits":5},{"contributor":"Ward Beyens", "commits":4},{"contributor":"SiegbjornSitumeang", "commits":4},{"contributor":"Polgár Sándor", "commits":4},{"contributor":"Jan Zabel", "commits":4},{"contributor":"Hiroshi Miura", "commits":4},{"contributor":"Fabio Bettani", "commits":4},{"contributor":"Wiktor Przybylski", "commits":3},{"contributor":"vankos", "commits":3},{"contributor":"seppesantens", "commits":3},{"contributor":"Nikolay Korotkiy", "commits":3},{"contributor":"Léo Villeveygoux", "commits":3},{"contributor":"JCGF-OSM", "commits":3},{"contributor":"Erik Palm", "commits":3},{"contributor":"David Haberthür", "commits":3},{"contributor":"快乐的老鼠宝宝", "commits":2},{"contributor":"Stanislas Gueniffey", "commits":2},{"contributor":"riiga", "commits":2},{"contributor":"pbarban", "commits":2},{"contributor":"mic140", "commits":2},{"contributor":"Leo Alcaraz", "commits":2},{"contributor":"Jose Luis Infante", "commits":2},{"contributor":"Heiko", "commits":2},{"contributor":"graveelius", "commits":2},{"contributor":"Eduardo Addad de Oliveira", "commits":2},{"contributor":"Damian Tokarski", "commits":2},{"contributor":"Charlotte Delvaux", "commits":2},{"contributor":"Tomas Fiers", "commits":1},{"contributor":"Thibault Molleman", "commits":1},{"contributor":"tbowdecl97", "commits":1},{"contributor":"Seppe Santens", "commits":1},{"contributor":"Sebastian", "commits":1},{"contributor":"Sean Young", "commits":1},{"contributor":"Schouppe Joost", "commits":1},{"contributor":"root", "commits":1},{"contributor":"Rodrigo Tavares", "commits":1},{"contributor":"Raphael Das Gupta", "commits":1},{"contributor":"Noémie", "commits":1},{"contributor":"mozita", "commits":1},{"contributor":"Michał Targoński", "commits":1},{"contributor":"liimee", "commits":1},{"contributor":"Jeff Huang", "commits":1},{"contributor":"Iváns", "commits":1},{"contributor":"Eric Armijo", "commits":1},{"contributor":"Damian Pułka", "commits":1},{"contributor":"Carlos Ramos Carreño", "commits":1},{"contributor":"Beardhatcode", "commits":1}]} \ No newline at end of file From 1a4417545aa62a751112a57b016ac7b194b63111 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 29 Jul 2021 00:29:29 +0200 Subject: [PATCH 18/20] Small improvements --- Customizations/JSON/TagRenderingConfig.ts | 4 ++++ UI/Input/LengthInput.ts | 2 +- assets/layers/watermill/watermill.json | 16 +------------ assets/themes/cycle_infra/cycle_infra.json | 28 ++++++++++++++++------ langs/en.json | 2 +- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Customizations/JSON/TagRenderingConfig.ts b/Customizations/JSON/TagRenderingConfig.ts index 7b36dae44b..c3bb992739 100644 --- a/Customizations/JSON/TagRenderingConfig.ts +++ b/Customizations/JSON/TagRenderingConfig.ts @@ -87,6 +87,10 @@ export default class TagRenderingConfig { if (this.freeform.key === undefined || this.freeform.key === "") { throw `Freeform.key is undefined or the empty string - this is not allowed; either fill out something or remove the freeform block alltogether. Error in ${context}` } + if(json.freeform["args"] !== undefined){ + throw `Freeform.args is defined. This should probably be 'freeform.helperArgs' (at ${context})` + + } if (ValidatedTextField.AllTypes[this.freeform.type] === undefined) { diff --git a/UI/Input/LengthInput.ts b/UI/Input/LengthInput.ts index 0558069b29..7b690f6914 100644 --- a/UI/Input/LengthInput.ts +++ b/UI/Input/LengthInput.ts @@ -142,7 +142,7 @@ export default class LengthInput extends InputElement { if (leaflet) { const first = leaflet.layerPointToLatLng(firstClickXY) const last = leaflet.layerPointToLatLng([dx, dy]) - const geoDist = Math.floor(GeoOperations.distanceBetween([first.lng, first.lat], [last.lng, last.lat]) * 100000) / 100 + const geoDist = Math.floor(GeoOperations.distanceBetween([first.lng, first.lat], [last.lng, last.lat]) * 10000) / 10 self.value.setData("" + geoDist) } diff --git a/assets/layers/watermill/watermill.json b/assets/layers/watermill/watermill.json index 029c14b759..a0073bf26f 100644 --- a/assets/layers/watermill/watermill.json +++ b/assets/layers/watermill/watermill.json @@ -168,19 +168,5 @@ }, "color": { "render": "#FFC0CB" - }, - "presets": [ - { - "tags": [ - "man_made=watermill", - "fixme=Toegevoegd met MapComplete, geometry nog uit te tekenen" - ], - "title": { - "nl": "Paden" - }, - "description": { - "nl": "Voeg een ontbrekend, erkend pad toe." - } - } - ] + } } \ No newline at end of file diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index 2dc568c4a4..e24587e6e7 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -633,12 +633,11 @@ }, "freeform": { "key": "width:carriageway", - "addExtraTags": [], - "type": "pfloat" + "type": "length", "helperArgs": ["20", "map"] }, "question": { - "en": "What is the carriage width of this road (in meters)?", - "nl": "Hoe breed is de rijbaan in deze straat (in meters)?" + "en": "What is the carriage width of this road (in meters)?
This is measured from kerb to kerb, including parking lanes", + "nl": "Hoe breed is de rijbaan in deze straat (in meters)?
Gemeten van stoepsteen tot stoepsten, inclusief parkeerstroken" } }, { @@ -972,7 +971,7 @@ }, "freeform": { "key": "cycleway:buffer", - "type": "pfloat" + "type": "length", "helperArgs": ["20", "map"] } }, { @@ -1301,6 +1300,20 @@ ] } ] + }, + { + "render": { + "en": "The carriage width of this road is {width:carriageway}m", + "nl": "De breedte van deze rijbaan in deze straat is {width:carriageway}m" + }, + "freeform": { + "key": "width:carriageway", + "type": "length", "helperArgs": ["20", "map"] + }, + "question": { + "en": "What is the carriage width of this road (in meters)?
This is measured from kerb to kerb, including parking lanes", + "nl": "Hoe breed is de rijbaan in deze straat (in meters)?
Gemeten van stoepsteen tot stoepsten, inclusief parkeerstroken" + } } ] }, @@ -1496,7 +1509,7 @@ }, "freeform": { "key": "maxwidth:physical", - "type": "pfloat" + "type": "length", "helperArgs": ["20", "map"] } }, { @@ -1516,7 +1529,8 @@ }, "freeform": { "key": "width:seperation", - "type": "pfloat" + "type": "length", + "helperArgs": ["20", "map"] } }, { diff --git a/langs/en.json b/langs/en.json index 7d794fee42..007035aed1 100644 --- a/langs/en.json +++ b/langs/en.json @@ -165,7 +165,7 @@ "downloadAsPdf": "Download a PDF of the current map", "downloadAsPdfHelper": "Ideal to print the current map", "downloadGeojson": "Download visible data as geojson", - "downloadGeoJsonHelper": "Compatible with QGIS, OsmAnd, ArcGIS, ESRI, ...", + "downloadGeoJsonHelper": "Compatible with QGIS, ArcGIS, ESRI, ...", "downloadCSV": "Download visible data as CSV", "downloadCSVHelper": "Compatible with LibreOffice Calc, Excel, ...", "includeMetaData": "Include metadata (last editor, calculated values, ...)", From 38635ba8b23490bf6f10a3c9460e32a03889d73d Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 29 Jul 2021 00:43:16 +0200 Subject: [PATCH 19/20] Small fix: always show the buttons in the AddUI --- UI/BigComponents/SimpleAddUI.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UI/BigComponents/SimpleAddUI.ts b/UI/BigComponents/SimpleAddUI.ts index 9f2e4272df..7c59503d74 100644 --- a/UI/BigComponents/SimpleAddUI.ts +++ b/UI/BigComponents/SimpleAddUI.ts @@ -238,7 +238,7 @@ export default class SimpleAddUI extends Toggle { const allButtons = []; for (const layer of State.state.filteredLayers.data) { - if (layer.isDisplayed.data === false && State.state.featureSwitchFilter.data) { + if (layer.isDisplayed.data === false && !State.state.featureSwitchFilter.data) { // The layer is not displayed and we cannot enable the layer control -> we skip continue; } From f946ad38b7c8b3517d739e13828d192480e110e3 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Thu, 29 Jul 2021 01:57:45 +0200 Subject: [PATCH 20/20] Improvements to pdfExport, small tweaks to the themes --- UI/ExportPDF.ts | 65 ++++++++++++++++++---- assets/themes/cycle_infra/cycle_infra.json | 35 +++++++++--- index.html | 11 ++-- langs/en.json | 5 +- langs/layers/nl.json | 6 -- langs/themes/en.json | 4 ++ langs/themes/nl.json | 4 ++ scripts/generateTranslations.ts | 11 ++-- 8 files changed, 102 insertions(+), 39 deletions(-) diff --git a/UI/ExportPDF.ts b/UI/ExportPDF.ts index a2aecec619..fd431eb914 100644 --- a/UI/ExportPDF.ts +++ b/UI/ExportPDF.ts @@ -20,6 +20,8 @@ import BaseLayer from "../Models/BaseLayer"; import LayoutConfig from "../Customizations/JSON/LayoutConfig"; import {FixedUiElement} from "./Base/FixedUiElement"; import Translations from "./i18n/Translations"; +import State from "../State"; +import Constants from "../Models/Constants"; export default class ExportPDF { // dimensions of the map in milimeter @@ -100,7 +102,7 @@ export default class ExportPDF { } private cleanup() { - new FixedUiElement("Screenshot taken!").AttachTo(this.freeDivId) + // new FixedUiElement("Screenshot taken!").AttachTo(this.freeDivId) this._screenhotTaken = true; } @@ -124,28 +126,67 @@ export default class ExportPDF { doc.setDrawColor(255, 255, 255) doc.setFillColor(255, 255, 255) - doc.roundedRect(12, 5, 125, 30, 5, 5, 'FD') + doc.roundedRect(12, 10, 145, 25, 5, 5, 'FD') doc.setFontSize(20) - doc.text(layout.title.txt, 40, 20, { - maxWidth: 100 + doc.textWithLink(layout.title.txt, 40, 18.5, { + maxWidth: 125, + url: window.location.href }) doc.setFontSize(10) - doc.text(t.attr.txt, 40, 25, { - maxWidth: 100 + doc.text(t.generatedWith.txt, 40, 23, { + maxWidth: 125 }) + const backgroundLayer : BaseLayer = State.state.backgroundLayer.data + const attribution = new FixedUiElement(backgroundLayer.layer().getAttribution() ?? backgroundLayer.name).ConstructElement().innerText + doc.textWithLink(t.attr.txt, 40, 26.5, { + maxWidth: 125, + url: "https://www.openstreetmap.org/copyright" + }) + + doc.text(t.attrBackground.Subs({ + background: attribution + }).txt, 40, 30) + + let date = new Date().toISOString().substr(0,16) + + doc.setFontSize(7) + doc.text(t.versionInfo.Subs({ + version: Constants.vNumber, + date: date + }).txt, 40, 34, { + maxWidth: 125 + }) + // Add the logo of the layout let img = document.createElement('img'); const imgSource = layout.icon + const imgType = imgSource.substr(imgSource.lastIndexOf(".") + 1); img.src = imgSource - try { - doc.addImage(img, imgSource.substr(imgSource.lastIndexOf(".")), 15, 12, 20, 20); - } catch (e) { - // TODO: support svg rendering... - console.error(e) + console.log(imgType) + if (imgType.toLowerCase() === "svg") { + new FixedUiElement("").AttachTo(this.freeDivId) + + // This is an svg image, we use the canvas to convert it to a png + const canvas = document.createElement('canvas') + const ctx = canvas.getContext('2d'); + canvas.width = 500 + canvas.height = 500 + img.style.width = "100%" + img.style.height = "100%" + ctx.drawImage(img, 0, 0, 500, 500); + const base64img = canvas.toDataURL("image/png") + doc.addImage(base64img, 'png', 15, 12, 20, 20); + + } else { + try { + doc.addImage(img, imgType, 15, 12, 20, 20); + } catch (e) { + console.error(e) + } } - doc.save("MapComplete_export.pdf"); + doc.save(`MapComplete_${layout.title.txt}_${date}.pdf`); } diff --git a/assets/themes/cycle_infra/cycle_infra.json b/assets/themes/cycle_infra/cycle_infra.json index e24587e6e7..d29c483b93 100644 --- a/assets/themes/cycle_infra/cycle_infra.json +++ b/assets/themes/cycle_infra/cycle_infra.json @@ -633,11 +633,15 @@ }, "freeform": { "key": "width:carriageway", - "type": "length", "helperArgs": ["20", "map"] + "type": "length", + "helperArgs": [ + "20", + "map" + ] }, "question": { - "en": "What is the carriage width of this road (in meters)?
This is measured from kerb to kerb, including parking lanes", - "nl": "Hoe breed is de rijbaan in deze straat (in meters)?
Gemeten van stoepsteen tot stoepsten, inclusief parkeerstroken" + "en": "What is the carriage width of this road (in meters)?", + "nl": "Hoe breed is de rijbaan in deze straat (in meters)?" } }, { @@ -971,7 +975,11 @@ }, "freeform": { "key": "cycleway:buffer", - "type": "length", "helperArgs": ["20", "map"] + "type": "length", + "helperArgs": [ + "20", + "map" + ] } }, { @@ -1308,7 +1316,11 @@ }, "freeform": { "key": "width:carriageway", - "type": "length", "helperArgs": ["20", "map"] + "type": "length", + "helperArgs": [ + "20", + "map" + ] }, "question": { "en": "What is the carriage width of this road (in meters)?
This is measured from kerb to kerb, including parking lanes", @@ -1509,7 +1521,11 @@ }, "freeform": { "key": "maxwidth:physical", - "type": "length", "helperArgs": ["20", "map"] + "type": "length", + "helperArgs": [ + "20", + "map" + ] } }, { @@ -1529,8 +1545,11 @@ }, "freeform": { "key": "width:seperation", - "type": "length", - "helperArgs": ["20", "map"] + "type": "length", + "helperArgs": [ + "20", + "map" + ] } }, { diff --git a/index.html b/index.html index a2192f281b..eb870680e8 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,3 @@ - @@ -24,8 +23,9 @@ - - + + @@ -74,10 +74,7 @@ Loading MapComplete, hang on... -Below +Below
diff --git a/langs/en.json b/langs/en.json index 007035aed1..6dbde357d0 100644 --- a/langs/en.json +++ b/langs/en.json @@ -62,7 +62,10 @@ }, "general": { "pdf": { - "attr": "Generated with MapComplete.osm.be - map data © OpenStreetMap Contributors, reusable under ODbL" + "generatedWith": "Generated with MapComplete.osm.be", + "attr": "Map data © OpenStreetMap Contributors, reusable under ODbL", + "attrBackground": "Background layer: {background}", + "versionInfo": "v{version} - generated on {date}" }, "loginWithOpenStreetMap": "Login with OpenStreetMap", "welcomeBack": "You are logged in, welcome back!", diff --git a/langs/layers/nl.json b/langs/layers/nl.json index 416f4e3188..24f9088ce7 100644 --- a/langs/layers/nl.json +++ b/langs/layers/nl.json @@ -2364,12 +2364,6 @@ } } } - }, - "presets": { - "0": { - "title": "Paden", - "description": "Voeg een ontbrekend, erkend pad toe." - } } } } \ No newline at end of file diff --git a/langs/themes/en.json b/langs/themes/en.json index 6fb0be0158..e8885b11b2 100644 --- a/langs/themes/en.json +++ b/langs/themes/en.json @@ -1108,6 +1108,10 @@ "then": "This is not a cyclestreet." } } + }, + "2": { + "render": "The carriage width of this road is {width:carriageway}m", + "question": "What is the carriage width of this road (in meters)?
This is measured from kerb to kerb, including parking lanes" } } }, diff --git a/langs/themes/nl.json b/langs/themes/nl.json index 17d236cdd1..2a30a77cf4 100644 --- a/langs/themes/nl.json +++ b/langs/themes/nl.json @@ -970,6 +970,10 @@ "then": "Dit is geen fietsstraat" } } + }, + "2": { + "render": "De breedte van deze rijbaan in deze straat is {width:carriageway}m", + "question": "Hoe breed is de rijbaan in deze straat (in meters)?
Gemeten van stoepsteen tot stoepsten, inclusief parkeerstroken" } } }, diff --git a/scripts/generateTranslations.ts b/scripts/generateTranslations.ts index 9f957553ec..b66c97cde0 100644 --- a/scripts/generateTranslations.ts +++ b/scripts/generateTranslations.ts @@ -2,6 +2,7 @@ import * as fs from "fs"; import {readFileSync, writeFileSync} from "fs"; import {Utils} from "../Utils"; import ScriptUtils from "./ScriptUtils"; +import {Layer} from "leaflet"; const knownLanguages = ["en", "nl", "de", "fr", "es", "gl", "ca"]; @@ -40,12 +41,12 @@ class TranslationPart { } } - recursiveAdd(object: any) { + recursiveAdd(object: any, context: string) { const isProbablyTranslationObject = knownLanguages.map(l => object.hasOwnProperty(l)).filter(x => x).length > 0; if (isProbablyTranslationObject) { - this.addTranslationObject(object) + this.addTranslationObject(object, context) return; } @@ -68,7 +69,7 @@ class TranslationPart { this.contents.set(key, new TranslationPart()) } - (this.contents.get(key) as TranslationPart).recursiveAdd(v); + (this.contents.get(key) as TranslationPart).recursiveAdd(v, context + "." + key); } } @@ -190,7 +191,7 @@ function generateTranslationsObjectFrom(objects: { path: string, parsed: { id: s if (config === undefined) { throw "Got something not parsed! Path is " + layerFile.path } - layerTr.recursiveAdd(config) + layerTr.recursiveAdd(config, layerFile.path) tr.contents.set(config.id, layerTr) } @@ -301,7 +302,7 @@ function mergeThemeTranslations() { const oldLanguages = config.language; const allTranslations = new TranslationPart(); - allTranslations.recursiveAdd(config) + allTranslations.recursiveAdd(config, themeFile.path) const newLanguages = allTranslations.knownLanguages() const languageDiff = newLanguages.filter(l => oldLanguages.indexOf(l) < 0).join(", ") if (languageDiff !== "") {