forked from MapComplete/MapComplete
Merge develop
This commit is contained in:
commit
1571fa478b
42 changed files with 927 additions and 461 deletions
|
@ -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}]`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -336,5 +336,7 @@ export interface LayoutConfigJson {
|
|||
enableGeolocation?: boolean;
|
||||
enableBackgroundLayerSelection?: boolean;
|
||||
enableShowAllQuestions?: boolean;
|
||||
enableExportButton?: boolean;
|
||||
enableDownload?: boolean;
|
||||
enablePdfDownload?: boolean;
|
||||
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,25 +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 LeftControls from "./UI/BigComponents/LeftControls";
|
||||
import RightControls from "./UI/BigComponents/RightControls";
|
||||
|
||||
export class InitUiElements {
|
||||
static InitAll(
|
||||
|
@ -189,38 +185,10 @@ 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])
|
||||
.SetClass("flex flex-col")
|
||||
.AttachTo("bottom-right");
|
||||
|
||||
if (layoutToUse.id === personal.id) {
|
||||
updateFavs();
|
||||
}
|
||||
|
||||
InitUiElements.setupAllLayerElements();
|
||||
|
||||
if (layoutToUse.id === personal.id) {
|
||||
|
@ -328,82 +296,7 @@ export class InitUiElements {
|
|||
Hash.hash.data == "welcome"
|
||||
);
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
|
||||
new Combine([copyrightButton, layerControl, filterControl])
|
||||
.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);
|
||||
|
@ -537,7 +430,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 ------------
|
||||
|
||||
|
|
|
@ -1,37 +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 Minimap from "../../UI/Base/Minimap";
|
||||
import { PDFLayout } from "./PDFLayout";
|
||||
|
||||
export default class ExportPDF {
|
||||
constructor(
|
||||
name: string,
|
||||
layout: "natuurpunt"
|
||||
){
|
||||
const screenshotter = new SimpleMapScreenshoter();
|
||||
//let temporaryMap = new Minimap();
|
||||
//temporaryMap.SetStyle('visibility: hidden');
|
||||
//temporaryMap.AttachTo("tempScreenshotDiv");
|
||||
//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);
|
||||
doc.save(name);
|
||||
})
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/**
|
||||
* Adds a theme to the pdf
|
||||
*/
|
||||
|
||||
import jsPDF from "jspdf";
|
||||
|
||||
export class PDFLayout {
|
||||
public AddLayout(layout: string, 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;
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
});
|
||||
|
|
|
@ -437,6 +437,11 @@ 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)
|
||||
// This is probably part of a relation which hasn't been fully downloaded
|
||||
continue;
|
||||
}
|
||||
const cp = node.centerpoint();
|
||||
this.coordinates.push(cp);
|
||||
latSum = cp[0]
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
37
State.ts
37
State.ts
|
@ -61,7 +61,7 @@ export default class State {
|
|||
|
||||
public osmApiFeatureSource: OsmApiFeatureSource;
|
||||
|
||||
public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([],"filteredLayers");
|
||||
public filteredLayers: UIEventSource<FilteredLayer[]> = new UIEventSource<FilteredLayer[]>([], "filteredLayers");
|
||||
|
||||
/**
|
||||
The latest element that was selected
|
||||
|
@ -79,7 +79,7 @@ export default class State {
|
|||
|
||||
public readonly featureSwitchUserbadge: UIEventSource<boolean>;
|
||||
public readonly featureSwitchSearch: UIEventSource<boolean>;
|
||||
public readonly featureSwitchLayers: UIEventSource<boolean>;
|
||||
public readonly featureSwitchBackgroundSlection: UIEventSource<boolean>;
|
||||
public readonly featureSwitchAddNew: UIEventSource<boolean>;
|
||||
public readonly featureSwitchWelcomeMessage: UIEventSource<boolean>;
|
||||
public readonly featureSwitchIframe: UIEventSource<boolean>;
|
||||
|
@ -93,7 +93,7 @@ export default class State {
|
|||
public readonly featureSwitchFilter: UIEventSource<boolean>;
|
||||
public readonly featureSwitchEnableExport: UIEventSource<boolean>;
|
||||
public readonly featureSwitchFakeUser: UIEventSource<boolean>;
|
||||
|
||||
public readonly featureSwitchExportAsPdf: UIEventSource<boolean>;
|
||||
|
||||
public featurePipeline: FeaturePipeline;
|
||||
|
||||
|
@ -125,11 +125,11 @@ export default class State {
|
|||
public layoutDefinition: string;
|
||||
public installedThemes: UIEventSource<{ layout: LayoutConfig; definition: string }[]>;
|
||||
|
||||
public layerControlIsOpened: UIEventSource<boolean> =
|
||||
public downloadControlIsOpened: UIEventSource<boolean> =
|
||||
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<boolean>(
|
||||
(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,
|
||||
|
@ -295,6 +296,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 +339,6 @@ export default class State {
|
|||
);
|
||||
|
||||
|
||||
|
||||
this.featureSwitchUserbadge.addCallbackAndRun(userbadge => {
|
||||
if (!userbadge) {
|
||||
this.featureSwitchAddNew.setData(false)
|
||||
|
@ -372,9 +383,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);
|
||||
|
|
|
@ -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<BaseLayer>,
|
||||
location?: UIEventSource<Loc>,
|
||||
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);
|
||||
})
|
||||
|
||||
|
|
56
UI/BigComponents/AllDownloads.ts
Normal file
56
UI/BigComponents/AllDownloads.ts
Normal file
|
@ -0,0 +1,56 @@
|
|||
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<boolean>) {
|
||||
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(),
|
||||
new Combine([Translations.t.general.download.downloadAsPdf.Clone().SetClass("font-bold"),
|
||||
Translations.t.general.download.downloadAsPdfHelper.Clone()]
|
||||
).SetClass("flex flex-col"))
|
||||
.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");
|
||||
}
|
||||
}
|
|
@ -50,6 +50,8 @@ export class Basemap {
|
|||
}
|
||||
previousLayer = newLayer;
|
||||
self.map.addLayer(newLayer);
|
||||
extraAttribution.AttachTo('leaflet-attribution')
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
|
|
@ -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<FilteredLayer[]>) {
|
||||
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)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,52 +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<boolean>) {
|
||||
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
|
||||
))
|
||||
|
||||
|
||||
|
||||
elements.push(
|
||||
new Toggle(
|
||||
new DownloadPanel(),
|
||||
undefined,
|
||||
State.state.featureSwitchEnableExport
|
||||
)
|
||||
);
|
||||
|
||||
return new Combine(elements).SetClass("flex flex-col");
|
||||
}
|
||||
}
|
96
UI/BigComponents/LeftControls.ts
Normal file
96
UI/BigComponents/LeftControls.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
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())
|
||||
.onClick(() => toggledCopyright.isShown.setData(true)),
|
||||
toggledCopyright.isShown
|
||||
)
|
||||
.SetClass("p-0.5");
|
||||
|
||||
const toggledDownload = new Toggle(
|
||||
new AllDownloads(
|
||||
State.state.downloadControlIsOpened
|
||||
).SetClass("block p-1 rounded-full"),
|
||||
new MapControlButton(Svg.download_svg())
|
||||
.onClick(() => State.state.downloadControlIsOpened.setData(true)),
|
||||
State.state.downloadControlIsOpened
|
||||
)
|
||||
|
||||
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())
|
||||
.onClick(() => State.state.filterIsOpened.setData(true)),
|
||||
State.state.filterIsOpened
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
43
UI/BigComponents/RightControls.ts
Normal file
43
UI/BigComponents/RightControls.ts
Normal file
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
193
UI/ExportPDF.ts
Normal file
193
UI/ExportPDF.ts
Normal file
|
@ -0,0 +1,193 @@
|
|||
/**
|
||||
* 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";
|
||||
import State from "../State";
|
||||
import Constants from "../Models/Constants";
|
||||
|
||||
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<LayoutConfig>;
|
||||
private _screenhotTaken = false;
|
||||
|
||||
constructor(
|
||||
options: {
|
||||
freeDivId: string,
|
||||
location: UIEventSource<Loc>,
|
||||
background?: UIEventSource<BaseLayer>
|
||||
features: UIEventSource<{ feature: any }[]>,
|
||||
layout: UIEventSource<LayoutConfig>
|
||||
}
|
||||
) {
|
||||
|
||||
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 l = options.location.data;
|
||||
const loc = {
|
||||
lat: l.lat,
|
||||
lon: l.lon,
|
||||
zoom: l.zoom + 1
|
||||
}
|
||||
|
||||
const minimap = new Minimap({
|
||||
location: new UIEventSource<Loc>(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(() => {
|
||||
if (self._screenhotTaken) {
|
||||
return;
|
||||
}
|
||||
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)
|
||||
this._screenhotTaken = true;
|
||||
}
|
||||
|
||||
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, 10, 145, 25, 5, 5, 'FD')
|
||||
|
||||
doc.setFontSize(20)
|
||||
doc.textWithLink(layout.title.txt, 40, 18.5, {
|
||||
maxWidth: 125,
|
||||
url: window.location.href
|
||||
})
|
||||
doc.setFontSize(10)
|
||||
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
|
||||
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_${layout.title.txt}_${date}.pdf`);
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -142,7 +142,7 @@ export default class LengthInput extends InputElement<string> {
|
|||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -16,14 +16,13 @@ export default class ShowDataLayer {
|
|||
private readonly _leafletMap: UIEventSource<L.Map>;
|
||||
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<L.Map>,
|
||||
layoutToUse: UIEventSource<LayoutConfig>,
|
||||
enablePopups = true,
|
||||
zoomToFeatures = false,
|
||||
name?: string) {
|
||||
zoomToFeatures = false) {
|
||||
this._leafletMap = leafletMap;
|
||||
this._enablePopups = enablePopups;
|
||||
this._features = features;
|
||||
|
|
|
@ -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}]}
|
||||
{"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}]}
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -252,8 +252,8 @@
|
|||
{
|
||||
"if": "red_turn:right:bicycle=yes",
|
||||
"then": {
|
||||
"en": "A cyclist can turn right if the light is red <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='height: 3em'>",
|
||||
"nl": "Een fietser mag wel rechtsaf slaan als het licht rood is <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='height: 3em'>"
|
||||
"en": "A cyclist can turn right if the light is red <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='width: 3em'>",
|
||||
"nl": "Een fietser mag wel rechtsaf slaan als het licht rood is <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='width: 3em'>"
|
||||
},
|
||||
"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 <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='height: 3em'>",
|
||||
"nl": "Een fietser mag wel rechtdoor gaan als het licht rood is <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='height: 3em'>"
|
||||
"en": "A cyclist can go straight on if the light is red <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='width: 3em'>",
|
||||
"nl": "Een fietser mag wel rechtdoor gaan als het licht rood is <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be"
|
||||
},
|
||||
|
|
|
@ -30,7 +30,12 @@
|
|||
"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 +265,7 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"if": "toilets:position=urinals",
|
||||
"if": "toilets:position=urinal",
|
||||
"then": {
|
||||
"en": "There are only urinals here",
|
||||
"de": "Hier gibt es nur Pissoirs",
|
||||
|
@ -280,7 +285,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",
|
||||
|
|
|
@ -169,19 +169,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."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,67 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8.08 8.86C8.13 8.53 8.24 8.24 8.38 7.99C8.52 7.74 8.72 7.53 8.97 7.37C9.21 7.22 9.51 7.15 9.88 7.14C10.11 7.15 10.32 7.19 10.51 7.27C10.71 7.36 10.89 7.48 11.03 7.63C11.17 7.78 11.28 7.96 11.37 8.16C11.46 8.36 11.5 8.58 11.51 8.8H13.3C13.28 8.33 13.19 7.9 13.02 7.51C12.85 7.12 12.62 6.78 12.32 6.5C12.02 6.22 11.66 6 11.24 5.84C10.82 5.68 10.36 5.61 9.85 5.61C9.2 5.61 8.63 5.72 8.15 5.95C7.67 6.18 7.27 6.48 6.95 6.87C6.63 7.26 6.39 7.71 6.24 8.23C6.09 8.75 6 9.29 6 9.87V10.14C6 10.72 6.08 11.26 6.23 11.78C6.38 12.3 6.62 12.75 6.94 13.13C7.26 13.51 7.66 13.82 8.14 14.04C8.62 14.26 9.19 14.38 9.84 14.38C10.31 14.38 10.75 14.3 11.16 14.15C11.57 14 11.93 13.79 12.24 13.52C12.55 13.25 12.8 12.94 12.98 12.58C13.16 12.22 13.27 11.84 13.28 11.43H11.49C11.48 11.64 11.43 11.83 11.34 12.01C11.25 12.19 11.13 12.34 10.98 12.47C10.83 12.6 10.66 12.7 10.46 12.77C10.27 12.84 10.07 12.86 9.86 12.87C9.5 12.86 9.2 12.79 8.97 12.64C8.72 12.48 8.52 12.27 8.38 12.02C8.24 11.77 8.13 11.47 8.08 11.14C8.03 10.81 8 10.47 8 10.14V9.87C8 9.52 8.03 9.19 8.08 8.86V8.86ZM10 0C4.48 0 0 4.48 0 10C0 15.52 4.48 20 10 20C15.52 20 20 15.52 20 10C20 4.48 15.52 0 10 0ZM10 18C5.59 18 2 14.41 2 10C2 5.59 5.59 2 10 2C14.41 2 18 5.59 18 10C18 14.41 14.41 18 10 18Z" fill="white"/>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 600 600"
|
||||
enable-background="new 0 0 600 600"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="download.svg"
|
||||
inkscape:version="0.92.5 (2060ec1f9f, 2020-04-08)"><metadata
|
||||
id="metadata17"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs15">
|
||||
|
||||
|
||||
|
||||
</defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="999"
|
||||
id="namedview13"
|
||||
showgrid="false"
|
||||
inkscape:zoom="0.78666667"
|
||||
inkscape:cx="257.94125"
|
||||
inkscape:cy="387.47074"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
<rect
|
||||
display="none"
|
||||
fill="#020202"
|
||||
stroke="#000000"
|
||||
stroke-width="1.1344"
|
||||
stroke-miterlimit="10"
|
||||
width="600"
|
||||
height="600"
|
||||
id="rect2" />
|
||||
<polygon
|
||||
display="none"
|
||||
fill="#FFFFFF"
|
||||
points="0,0 0,600 600,300 "
|
||||
id="polygon4" />
|
||||
<path
|
||||
d="M 449.2,197.8 H 349.4 V 44.5 c 0,-14 -11.2,-25.5 -25,-25.5 h -49.9 c -13.7,0 -25,11.5 -25,25.5 v 153.3 h -99.8 l 149.7,204.4 z m 112.4,76.7 c -20.7,0 -37.4,17.2 -37.4,38.3 V 504.4 H 74.9 V 312.8 C 74.9,291.6 58.1,274.5 37.5,274.5 16.8,274.5 0,291.6 0,312.8 V 542.7 C 0,563.8 16.8,581 37.4,581 h 524.1 c 20.7,0 37.4,-17.2 37.4,-38.3 V 312.8 c 0.1,-21.2 -16.7,-38.3 -37.3,-38.3 z"
|
||||
id="path6"
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
</svg>
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
@ -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",
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
"startLat": 51,
|
||||
"startLon": 3.75,
|
||||
"startZoom": 11,
|
||||
"widenFactor": 0.05,
|
||||
"widenFactor": 0,
|
||||
"socialImage": "./assets/themes/cycle_infra/cycle-infra.svg",
|
||||
"enableExportButton": true,
|
||||
"enableDownload": true,
|
||||
"layers": [
|
||||
{
|
||||
"id": "cycleways",
|
||||
|
@ -33,7 +33,7 @@
|
|||
"en": "Cycleways",
|
||||
"nl": "Fietspaden"
|
||||
},
|
||||
"minzoom": 14,
|
||||
"minzoom": 16,
|
||||
"source": {
|
||||
"osmTags": {
|
||||
"or": [
|
||||
|
@ -239,7 +239,7 @@
|
|||
"if": "cyclestreet=",
|
||||
"then": {
|
||||
"en": "This is not a cyclestreet.",
|
||||
"nl": "Dit is niet een fietstraat"
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -625,8 +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)?",
|
||||
|
@ -648,24 +659,24 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D7",
|
||||
"then": {
|
||||
"en": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>",
|
||||
"nl": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"en": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>",
|
||||
"nl": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be"
|
||||
},
|
||||
{
|
||||
"if": "cycleway:traffic_sign~BE:D7;.*",
|
||||
"then": {
|
||||
"en": "Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'> ",
|
||||
"nl": "Verplicht fietspad (met onderbord)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"en": "Compulsory cycleway (with supplementary sign)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> ",
|
||||
"nl": "Verplicht fietspad (met onderbord)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
{
|
||||
"if": "cycleway:traffic_sign=BE:D9",
|
||||
"then": {
|
||||
"en": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>",
|
||||
"nl": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>"
|
||||
"en": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>",
|
||||
"nl": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -676,8 +687,8 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D10",
|
||||
"then": {
|
||||
"en": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>",
|
||||
"nl": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>"
|
||||
"en": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>",
|
||||
"nl": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -709,8 +720,8 @@
|
|||
{
|
||||
"if": "traffic_sign=BE:D7",
|
||||
"then": {
|
||||
"en": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>",
|
||||
"nl": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"en": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>",
|
||||
"nl": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -723,16 +734,16 @@
|
|||
{
|
||||
"if": "traffic_sign~BE:D7;.*",
|
||||
"then": {
|
||||
"en": "Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'> ",
|
||||
"nl": "Verplicht fietspad (met onderbord)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"en": "Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> ",
|
||||
"nl": "Verplicht fietspad (met onderbord)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": true
|
||||
},
|
||||
{
|
||||
"if": "traffic_sign=BE:D9",
|
||||
"then": {
|
||||
"en": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>",
|
||||
"nl": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>"
|
||||
"en": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>",
|
||||
"nl": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -747,8 +758,8 @@
|
|||
{
|
||||
"if": "traffic_sign=BE:D10",
|
||||
"then": {
|
||||
"en": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>",
|
||||
"nl": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>"
|
||||
"en": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>",
|
||||
"nl": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -771,8 +782,8 @@
|
|||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) have a supplementary sign?",
|
||||
"nl": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) een onderbord?"
|
||||
"en": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) have a supplementary sign?",
|
||||
"nl": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) een onderbord?"
|
||||
},
|
||||
"condition": {
|
||||
"or": [
|
||||
|
@ -784,8 +795,8 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D7;BE:M6",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -795,8 +806,8 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D7;BE:M13",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -806,8 +817,8 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D7;BE:M14",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -818,8 +829,8 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D7;BE:M7",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -829,8 +840,8 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D7;BE:M15",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -840,8 +851,8 @@
|
|||
{
|
||||
"if": "cycleway:traffic_sign=BE:D7;BE:M16",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -860,8 +871,8 @@
|
|||
},
|
||||
{
|
||||
"question": {
|
||||
"en": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) have a supplementary sign?",
|
||||
"nl": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) een onderbord?"
|
||||
"en": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) have a supplementary sign?",
|
||||
"nl": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) een onderbord?"
|
||||
},
|
||||
"condition": {
|
||||
"or": [
|
||||
|
@ -873,8 +884,8 @@
|
|||
{
|
||||
"if": "traffic_sign=BE:D7;BE:M6",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -884,8 +895,8 @@
|
|||
{
|
||||
"if": "traffic_sign=BE:D7;BE:M13",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -895,8 +906,8 @@
|
|||
{
|
||||
"if": "traffic_sign=BE:D7;BE:M14",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -907,8 +918,8 @@
|
|||
{
|
||||
"if": "traffic_sign=BE:D7;BE:M7",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -918,8 +929,8 @@
|
|||
{
|
||||
"if": ":traffic_sign=BE:D7;BE:M15",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -929,8 +940,8 @@
|
|||
{
|
||||
"if": "traffic_sign=BE:D7;BE:M16",
|
||||
"then": {
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>"
|
||||
"en": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>",
|
||||
"nl": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>"
|
||||
},
|
||||
"hideInAnswer": "_country!=be",
|
||||
"addExtraTags": [
|
||||
|
@ -964,7 +975,11 @@
|
|||
},
|
||||
"freeform": {
|
||||
"key": "cycleway:buffer",
|
||||
"type": "pfloat"
|
||||
"type": "length",
|
||||
"helperArgs": [
|
||||
"20",
|
||||
"map"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1151,7 +1166,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": {
|
||||
|
@ -1286,13 +1301,31 @@
|
|||
"if": "cyclestreet=",
|
||||
"then": {
|
||||
"en": "This is not a cyclestreet.",
|
||||
"nl": "Dit is niet een fietstraat"
|
||||
"nl": "Dit is geen fietsstraat"
|
||||
},
|
||||
"addExtraTags": [
|
||||
"overtaking:motor_vehicle="
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"render": {
|
||||
"en": "The carriage width of this road is <strong>{width:carriageway}m</strong>",
|
||||
"nl": "De breedte van deze rijbaan in deze straat is <strong>{width:carriageway}m</strong>"
|
||||
},
|
||||
"freeform": {
|
||||
"key": "width:carriageway",
|
||||
"type": "length",
|
||||
"helperArgs": [
|
||||
"20",
|
||||
"map"
|
||||
]
|
||||
},
|
||||
"question": {
|
||||
"en": "What is the carriage width of this road (in meters)?<br/><span class='subtle'>This is measured from kerb to kerb, including parking lanes</span>",
|
||||
"nl": "Hoe breed is de rijbaan in deze straat (in meters)?<br/><span class='subtle'>Gemeten van stoepsteen tot stoepsten, inclusief parkeerstroken</span>"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1465,7 +1498,8 @@
|
|||
{
|
||||
"if": "cycle_barrier:type=squeeze",
|
||||
"then": {
|
||||
"en": "Squeeze gate, gap is smaller at top, than at the bottom <img src='./assets/themes/cycle_infra/Cycle_barrier_squeeze.png' style='width:8em'>"
|
||||
"en": "Squeeze gate, gap is smaller at top, than at the bottom <img src='./assets/themes/cycle_infra/Cycle_barrier_squeeze.png' style='width:8em'>",
|
||||
"nl": "Knijppoort, ruimte is smaller aan de top, dan aan de bodem <img src='./assets/themes/cycle_infra/Cycle_barrier_squeeze.png' style='width:8em'>"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -1487,15 +1521,21 @@
|
|||
},
|
||||
"freeform": {
|
||||
"key": "maxwidth:physical",
|
||||
"type": "pfloat"
|
||||
"type": "length",
|
||||
"helperArgs": [
|
||||
"20",
|
||||
"map"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": [
|
||||
|
@ -1505,15 +1545,21 @@
|
|||
},
|
||||
"freeform": {
|
||||
"key": "width:seperation",
|
||||
"type": "pfloat"
|
||||
"type": "length",
|
||||
"helperArgs": [
|
||||
"20",
|
||||
"map"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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 +1577,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": [
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
"widenFactor": 0.05,
|
||||
"socialImage": "",
|
||||
"defaultBackgroundId": "CartoDB.Positron",
|
||||
"enablePdfDownload": true,
|
||||
"enableDownload": true,
|
||||
"layers": [
|
||||
{
|
||||
"#": "Nature reserve with geometry, z>=13",
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<!-- WARNING: index.html serves as a template. If you want to change something, change it there -->
|
||||
<html lang="en">
|
||||
|
@ -24,8 +23,9 @@
|
|||
<link rel="icon" href="./assets/svg/add.svg" sizes="any" type="image/svg+xml">
|
||||
<meta property="og:image" content="./assets/SocialImage.png">
|
||||
<meta property="og:title" content="MapComplete - editable, thematic maps with OpenStreetMap">
|
||||
<meta property="og:description" content="MapComplete is a platform to visualize OpenStreetMap on a specific topic and to easily contribute data back to it.">
|
||||
|
||||
<meta property="og:description"
|
||||
content="MapComplete is a platform to visualize OpenStreetMap on a specific topic and to easily contribute data back to it.">
|
||||
|
||||
<link rel="apple-touch-icon" sizes="512x512" href="./assets/generated/svg_mapcomplete_logo512.png">
|
||||
<link rel="apple-touch-icon" sizes="384x384" href="./assets/generated/svg_mapcomplete_logo384.png">
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="./assets/generated/svg_mapcomplete_logo192.png">
|
||||
|
@ -74,7 +74,7 @@
|
|||
Loading MapComplete, hang on...
|
||||
</div>
|
||||
|
||||
|
||||
<span id="belowmap" class="absolute" style="z-index: -1">Below</span>
|
||||
<div id="leafletDiv"></div>
|
||||
|
||||
<script src="./index.ts"></script>
|
||||
|
|
|
@ -61,6 +61,12 @@
|
|||
"readMessages": "You have unread messages. Read these before deleting a point - someone might have feedback"
|
||||
},
|
||||
"general": {
|
||||
"pdf": {
|
||||
"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!",
|
||||
"loginToStart": "Login to answer this question",
|
||||
|
@ -159,9 +165,11 @@
|
|||
},
|
||||
"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",
|
||||
"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, ...)",
|
||||
"licenseInfo": "<h3>Copyright notice</h3>The provided is available under ODbL. Reusing this data is free for any purpose, but <ul><li>the attribution <b>© OpenStreetMap contributors</b> is required</li><li>Any change to this data must be republished under the same license</li></ul> Please read the full <a href='https://www.openstreetmap.org/copyright' target='_blank'>copyright notice</a> for details",
|
||||
|
|
|
@ -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 <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='height: 3em'>"
|
||||
"then": "A cyclist can turn right if the light is red <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='width: 3em'>"
|
||||
},
|
||||
"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 <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='height: 3em'>"
|
||||
"then": "A cyclist can go straight on if the light is red <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "A cyclist can go straight on if the light is red"
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -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 <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='height: 3em'>"
|
||||
"then": "Een fietser mag wel rechtsaf slaan als het licht rood is <img src='./assets/layers/crossings/Belgian_road_sign_B22.svg' style='width: 3em'>"
|
||||
},
|
||||
"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 <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='height: 3em'>"
|
||||
"then": "Een fietser mag wel rechtdoor gaan als het licht rood is <img src='./assets/layers/crossings/Belgian_road_sign_B23.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "Een fietser mag wel rechtdoor gaan als het licht rood is"
|
||||
|
@ -2364,12 +2364,6 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"presets": {
|
||||
"0": {
|
||||
"title": "Paden",
|
||||
"description": "Voeg een ontbrekend, erkend pad toe."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
@ -933,16 +933,16 @@
|
|||
"question": "What traffic sign does this cycleway have?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"then": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'> "
|
||||
"then": "Compulsory cycleway (with supplementary sign)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> "
|
||||
},
|
||||
"2": {
|
||||
"then": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>"
|
||||
"then": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>"
|
||||
"then": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "No traffic sign present"
|
||||
|
@ -953,16 +953,16 @@
|
|||
"question": "What traffic sign does this cycleway have?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"then": "Compulsory cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'> "
|
||||
"then": "Compulsory cycleway (with supplementary sign)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'> "
|
||||
},
|
||||
"2": {
|
||||
"then": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>"
|
||||
"then": "Segregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>"
|
||||
"then": "Unsegregated foot/cycleway <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "No traffic sign present"
|
||||
|
@ -970,25 +970,25 @@
|
|||
}
|
||||
},
|
||||
"11": {
|
||||
"question": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) have a supplementary sign?",
|
||||
"question": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) have a supplementary sign?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>"
|
||||
},
|
||||
"2": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>"
|
||||
},
|
||||
"5": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>"
|
||||
},
|
||||
"6": {
|
||||
"then": "No supplementary traffic sign present"
|
||||
|
@ -996,25 +996,25 @@
|
|||
}
|
||||
},
|
||||
"12": {
|
||||
"question": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) have a supplementary sign?",
|
||||
"question": "Does the traffic sign D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) have a supplementary sign?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>"
|
||||
},
|
||||
"2": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>"
|
||||
},
|
||||
"5": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>"
|
||||
},
|
||||
"6": {
|
||||
"then": "No supplementary traffic sign present"
|
||||
|
@ -1108,6 +1108,10 @@
|
|||
"then": "This is not a cyclestreet."
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"render": "The carriage width of this road is <strong>{width:carriageway}m</strong>",
|
||||
"question": "What is the carriage width of this road (in meters)?<br/><span class='subtle'>This is measured from kerb to kerb, including parking lanes</span>"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -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}",
|
||||
|
@ -769,16 +795,16 @@
|
|||
"question": "Welk verkeersbord heeft dit fietspad?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"then": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "Verplicht fietspad (met onderbord)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"then": "Verplicht fietspad (met onderbord)<br><img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"2": {
|
||||
"then": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>"
|
||||
"then": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>"
|
||||
"then": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "Geen verkeersbord aanwezig"
|
||||
|
@ -789,16 +815,16 @@
|
|||
"question": "Welk verkeersbord heeft dit fietspad?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"then": "Verplicht fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "Verplicht fietspad (met onderbord)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 3em'>"
|
||||
"then": "Verplicht fietspad (met onderbord)<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 3em'>"
|
||||
},
|
||||
"2": {
|
||||
"then": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='height: 3em'>"
|
||||
"then": "Afgescheiden voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D09.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='height: 3em'>"
|
||||
"then": "Gedeeld voet-/fietspad <img src='./assets/themes/cycle_infra/Belgian_road_sign_D10.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "Geen verkeersbord aanwezig"
|
||||
|
@ -806,25 +832,25 @@
|
|||
}
|
||||
},
|
||||
"11": {
|
||||
"question": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) een onderbord?",
|
||||
"question": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) een onderbord?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>"
|
||||
},
|
||||
"2": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>"
|
||||
},
|
||||
"5": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>"
|
||||
},
|
||||
"6": {
|
||||
"then": "Geen onderbord aanwezig"
|
||||
|
@ -832,25 +858,25 @@
|
|||
}
|
||||
},
|
||||
"12": {
|
||||
"question": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='height: 1.5em'>) een onderbord?",
|
||||
"question": "Heeft het verkeersbord D7 (<img src='./assets/themes/cycle_infra/Belgian_road_sign_D07.svg' style='width: 1.5em'>) een onderbord?",
|
||||
"mappings": {
|
||||
"0": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M6.svg' style='width: 3em'>"
|
||||
},
|
||||
"1": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M13.svg' style='width: 3em'>"
|
||||
},
|
||||
"2": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M14.svg' style='width: 3em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M7.svg' style='width: 3em'>"
|
||||
},
|
||||
"4": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M15.svg' style='width: 3em'>"
|
||||
},
|
||||
"5": {
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='height: 3em'>"
|
||||
"then": "<img src='./assets/themes/cycle_infra/Belgian_traffic_sign_M16.svg' style='width: 3em'>"
|
||||
},
|
||||
"6": {
|
||||
"then": "Geen onderbord aanwezig"
|
||||
|
@ -935,15 +961,19 @@
|
|||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
"2": {
|
||||
"render": "De breedte van deze rijbaan in deze straat is <strong>{width:carriageway}m</strong>",
|
||||
"question": "Hoe breed is de rijbaan in deze straat (in meters)?<br/><span class='subtle'>Gemeten van stoepsteen tot stoepsten, inclusief parkeerstroken</span>"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1014,12 +1044,26 @@
|
|||
},
|
||||
"2": {
|
||||
"then": "Drievoudig, drie hekjes achter elkaar <img src='./assets/themes/cycle_infra/Cycle_barrier_triple.png' style='width:8em'>"
|
||||
},
|
||||
"3": {
|
||||
"then": "Knijppoort, ruimte is smaller aan de top, dan aan de bodem <img src='./assets/themes/cycle_infra/Cycle_barrier_squeeze.png' style='width:8em'>"
|
||||
}
|
||||
}
|
||||
},
|
||||
"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?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 !== "") {
|
||||
|
|
47
test.ts
47
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<LayoutConfig>(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))
|
||||
|
||||
|
Loading…
Reference in a new issue