Refactoring of GPS-location (uses featureSource too now), factoring out state, add ReplaceGeometryAction and conflation example

This commit is contained in:
Pieter Vander Vennet 2021-11-03 00:44:53 +01:00
parent 1db54f3c8e
commit 2484848cd6
37 changed files with 1035 additions and 467 deletions

28
UI/Base/AsyncLazy.ts Normal file
View file

@ -0,0 +1,28 @@
import BaseUIElement from "../BaseUIElement";
import {VariableUiElement} from "./VariableUIElement";
import {UIEventSource} from "../../Logic/UIEventSource";
import Loading from "./Loading";
export default class AsyncLazy extends BaseUIElement{
private readonly _f: () => Promise<BaseUIElement>;
constructor(f: () => Promise<BaseUIElement>) {
super();
this._f = f;
}
protected InnerConstructElement(): HTMLElement {
// The caching of the BaseUIElement will guarantee that _f will only be called once
return new VariableUiElement(
UIEventSource.FromPromise(this._f()).map(el => {
if(el === undefined){
return new Loading()
}
return el
})
).ConstructElement()
}
}

View file

@ -19,6 +19,7 @@ export interface MinimapOptions {
export interface MinimapObj {
readonly leafletMap: UIEventSource<any>,
installBounds(factor: number | BBox, showRange?: boolean) : void
TakeScreenshot(): Promise<any>;
}
export default class Minimap {

View file

@ -9,6 +9,7 @@ import {Map} from "leaflet";
import Minimap, {MinimapObj, MinimapOptions} from "./Minimap";
import {BBox} from "../../Logic/BBox";
import 'leaflet-polylineoffset'
import {SimpleMapScreenshoter} from "leaflet-simple-map-screenshoter";
export default class MinimapImplementation extends BaseUIElement implements MinimapObj {
private static _nextId = 0;
@ -278,4 +279,10 @@ export default class MinimapImplementation extends BaseUIElement implements Mini
this.leafletMap.setData(map)
}
public async TakeScreenshot(){
const screenshotter = new SimpleMapScreenshoter();
screenshotter.addTo(this.leafletMap.data);
return await screenshotter.takeScreen('image')
}
}

View file

@ -14,6 +14,9 @@ import Toggle from "../Input/Toggle";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import {Utils} from "../../Utils";
import UserRelatedState from "../../Logic/State/UserRelatedState";
import Loc from "../../Models/Loc";
import BaseLayer from "../../Models/BaseLayer";
import FilteredLayer from "../../Models/FilteredLayer";
export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
@ -24,7 +27,10 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
layoutToUse: LayoutConfig,
osmConnection: OsmConnection,
featureSwitchShareScreen: UIEventSource<boolean>,
featureSwitchMoreQuests: UIEventSource<boolean>
featureSwitchMoreQuests: UIEventSource<boolean>,
locationControl: UIEventSource<Loc>,
backgroundLayer: UIEventSource<BaseLayer>,
filteredLayers: UIEventSource<FilteredLayer[]>
} & UserRelatedState) {
const layoutToUse = state.layoutToUse;
super(
@ -39,7 +45,8 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
layoutToUse: LayoutConfig,
osmConnection: OsmConnection,
featureSwitchShareScreen: UIEventSource<boolean>,
featureSwitchMoreQuests: UIEventSource<boolean>
featureSwitchMoreQuests: UIEventSource<boolean>,
locationControl: UIEventSource<Loc>, backgroundLayer: UIEventSource<BaseLayer>, filteredLayers: UIEventSource<FilteredLayer[]>
} & UserRelatedState,
isShown: UIEventSource<boolean>):
{ header: string | BaseUIElement; content: BaseUIElement }[] {
@ -77,7 +84,8 @@ export default class FullWelcomePaneWithTabs extends ScrollableFullScreen {
layoutToUse: LayoutConfig,
osmConnection: OsmConnection,
featureSwitchShareScreen: UIEventSource<boolean>,
featureSwitchMoreQuests: UIEventSource<boolean>
featureSwitchMoreQuests: UIEventSource<boolean>,
locationControl: UIEventSource<Loc>, backgroundLayer: UIEventSource<BaseLayer>, filteredLayers: UIEventSource<FilteredLayer[]>
} & UserRelatedState, currentTab: UIEventSource<number>, isShown: UIEventSource<boolean>) {
const tabs = FullWelcomePaneWithTabs.ConstructBaseTabs(state, isShown)

View file

@ -9,7 +9,6 @@ import Toggle from "../Input/Toggle";
import CreateNewNodeAction from "../../Logic/Osm/Actions/CreateNewNodeAction";
import {Tag} from "../../Logic/Tags/Tag";
import Loading from "../Base/Loading";
import OsmChangeAction from "../../Logic/Osm/Actions/OsmChangeAction";
import CreateNewWayAction from "../../Logic/Osm/Actions/CreateNewWayAction";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
@ -26,6 +25,13 @@ import SpecialVisualizations, {SpecialVisualization} from "../SpecialVisualizati
import {FixedUiElement} from "../Base/FixedUiElement";
import Svg from "../../Svg";
import {Utils} from "../../Utils";
import Minimap from "../Base/Minimap";
import ShowDataLayer from "../ShowDataLayer/ShowDataLayer";
import AllKnownLayers from "../../Customizations/AllKnownLayers";
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource";
import ShowDataMultiLayer from "../ShowDataLayer/ShowDataMultiLayer";
import BaseLayer from "../../Models/BaseLayer";
import ReplaceGeometryAction from "../../Logic/Osm/Actions/ReplaceGeometryAction";
export interface ImportButtonState {
@ -38,6 +44,8 @@ export interface ImportButtonState {
feature: any,
minZoom: number,
state: {
backgroundLayer: UIEventSource<BaseLayer>;
filteredLayers: UIEventSource<FilteredLayer[]>;
featureSwitchUserbadge: UIEventSource<boolean>;
featurePipeline: FeaturePipeline;
allElements: ElementStorage;
@ -48,8 +56,14 @@ export interface ImportButtonState {
locationControl: UIEventSource<{ zoom: number }>
},
guiState: { filterViewIsOpened: UIEventSource<boolean> },
snapToLayers?: string[],
snapToLayersMaxDist?: number
snapSettings?: {
snapToLayers: string[],
snapToLayersMaxDist?: number
},
conflationSettings?: {
conflateWayId: string
}
}
export class ImportButtonSpecialViz implements SpecialVisualization {
@ -83,7 +97,7 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
#### Specifying which tags to copy or add
The first argument of the import button takes a \`;\`-seperated list of tags to add.
The argument \`tags\` of the import button takes a \`;\`-seperated list of tags to add.
${Utils.Special_visualizations_tagsToApplyHelpText}
@ -113,8 +127,9 @@ ${Utils.Special_visualizations_tagsToApplyHelpText}
doc: "How far the contributor must zoom in before being able to import the point",
defaultValue: "18"
}, {
name: "Snap onto layer(s)",
doc: "If a way of the given layer is closeby, will snap the new point onto this way (similar as preset might snap). To show multiple layers to snap onto, use a `;`-seperated list",
name: "Snap onto layer(s)/replace geometry with this other way",
doc: " - If the value corresponding with this key starts with 'way/' and the feature is a LineString or Polygon, the original OSM-way geometry will be changed to match the new geometry\n" +
" - If a way of the given layer(s) is closeby, will snap the new point onto this way (similar as preset might snap). To show multiple layers to snap onto, use a `;`-seperated list",
}, {
name: "snap max distance",
doc: "The maximum distance that this point will move to snap onto a layer (in meters)",
@ -130,7 +145,7 @@ ${Utils.Special_visualizations_tagsToApplyHelpText}
const id = tagSource.data.id;
const feature = state.allElements.ContainingFeatures.get(id)
let minZoom = args[4] == "" ? 18 : Number(args[4])
if(isNaN(minZoom)){
if (isNaN(minZoom)) {
console.warn("Invalid minzoom:", minZoom)
minZoom = 18
}
@ -145,13 +160,29 @@ ${Utils.Special_visualizations_tagsToApplyHelpText}
img = () => Svg.add_ui()
}
const snapToLayers = args[5]?.split(";").filter(s => s !== "")
const snapToLayersMaxDist = Number(args[6] ?? 6)
if (targetLayer === undefined) {
const e = "Target layer not defined: error in import button for theme: " + state.layoutToUse.id + ": layer " + args[0] + " not found"
console.error(e)
return new FixedUiElement(e).SetClass("alert")
let snapSettings = undefined
let conflationSettings = undefined
const possibleWayId = tagSource.data[args[5]]
if (possibleWayId?.startsWith("way/")) {
// This is a conflation
conflationSettings = {
conflateWayId: possibleWayId
}
} else {
const snapToLayers = args[5]?.split(";").filter(s => s !== "")
const snapToLayersMaxDist = Number(args[6] ?? 6)
if (targetLayer === undefined) {
const e = "Target layer not defined: error in import button for theme: " + state.layoutToUse.id + ": layer " + args[0] + " not found"
console.error(e)
return new FixedUiElement(e).SetClass("alert")
}
snapSettings = {
snapToLayers,
snapToLayersMaxDist
}
}
return new ImportButton(
@ -160,8 +191,8 @@ ${Utils.Special_visualizations_tagsToApplyHelpText}
feature, newTags, message, minZoom,
originalTags: tagSource,
targetLayer,
snapToLayers,
snapToLayersMaxDist
snapSettings,
conflationSettings
}
);
}
@ -201,7 +232,7 @@ export default class ImportButton extends Toggle {
const importClicked = new UIEventSource(false);
const importFlow = new Toggle(
new Lazy(() => ImportButton.createConfirmPanel(o, isImported, importClicked)),
ImportButton.createConfirmPanel(o, isImported, importClicked),
importButton,
importClicked
)
@ -228,7 +259,121 @@ export default class ImportButton extends Toggle {
)
}
public static createConfirmPanel(
public static createConfirmPanel(o: ImportButtonState,
isImported: UIEventSource<boolean>,
importClicked: UIEventSource<boolean>) {
const geometry = o.feature.geometry
if (geometry.type === "Point") {
return new Lazy(() => ImportButton.createConfirmPanelForPoint(o, isImported, importClicked))
}
if (geometry.type === "Polygon" || geometry.type == "LineString") {
return new Lazy(() => ImportButton.createConfirmForWay(o, isImported, importClicked))
}
console.error("Invalid type to import", geometry.type)
return new FixedUiElement("Invalid geometry type:" + geometry.type).SetClass("alert")
}
public static createConfirmForWay(o: ImportButtonState,
isImported: UIEventSource<boolean>,
importClicked: UIEventSource<boolean>): BaseUIElement {
const confirmationMap = Minimap.createMiniMap({
allowMoving: false,
background: o.state.backgroundLayer
})
confirmationMap.SetStyle("height: 20rem; overflow: hidden").SetClass("rounded-xl")
const relevantFeatures = Utils.NoNull([o.feature, o.state.allElements?.ContainingFeatures?.get(o.conflationSettings?.conflateWayId)])
// SHow all relevant data - including (eventually) the way of which the geometry will be replaced
new ShowDataMultiLayer({
leafletMap: confirmationMap.leafletMap,
enablePopups: false,
zoomToFeatures: true,
features: new StaticFeatureSource(relevantFeatures, false),
allElements: o.state.allElements,
layers: o.state.filteredLayers
})
const theme = o.state.layoutToUse.id
const changes = o.state.changes
let confirm: () => Promise<string>
if (o.conflationSettings !== undefined) {
let replaceGeometryAction = new ReplaceGeometryAction(
o.state,
o.feature,
o.conflationSettings.conflateWayId,
{
theme: o.state.layoutToUse.id,
newTags: o.newTags.data
}
)
replaceGeometryAction.GetPreview().then(changePreview => {
new ShowDataLayer({
leafletMap: confirmationMap.leafletMap,
enablePopups: false,
zoomToFeatures: false,
features: changePreview,
allElements: o.state.allElements,
layerToShow: AllKnownLayers.sharedLayers.get("conflation")
})
})
confirm = async () => {
changes.applyAction (replaceGeometryAction)
return o.feature.properties.id
}
} else {
confirm = async () => {
const geom = o.feature.geometry
let coordinates: [number, number][]
if (geom.type === "LineString") {
coordinates = geom.coordinates
} else if (geom.type === "Polygon") {
coordinates = geom.coordinates[0]
}
const action = new CreateNewWayAction(o.newTags.data, coordinates.map(lngLat => ({
lat: lngLat[1],
lon: lngLat[0]
})), {theme})
return action.newElementId
}
}
const confirmButton = new SubtleButton(o.image(), o.message)
confirmButton.onClick(async () => {
{
if (isImported.data) {
return
}
o.originalTags.data["_imported"] = "yes"
o.originalTags.ping() // will set isImported as per its definition
const idToSelect = await confirm()
o.state.selectedElement.setData(o.state.allElements.ContainingFeatures.get(idToSelect))
}
})
const cancel = new SubtleButton(Svg.close_ui(), Translations.t.general.cancel).onClick(() => {
importClicked.setData(false)
})
return new Combine([confirmationMap, confirmButton, cancel]).SetClass("flex flex-col")
}
public static createConfirmPanelForPoint(
o: ImportButtonState,
isImported: UIEventSource<boolean>,
importClicked: UIEventSource<boolean>): BaseUIElement {
@ -239,39 +384,43 @@ export default class ImportButton extends Toggle {
}
o.originalTags.data["_imported"] = "yes"
o.originalTags.ping() // will set isImported as per its definition
const newElementAction = ImportButton.createAddActionForFeature(o.newTags.data, o.feature, o.state.layoutToUse.id)
const geometry = o.feature.geometry
const lat = geometry.coordinates[1]
const lon = geometry.coordinates[0];
const newElementAction = new CreateNewNodeAction(o.newTags.data, lat, lon, {
theme: o.state.layoutToUse.id,
changeType: "import"
})
await o.state.changes.applyAction(newElementAction)
o.state.selectedElement.setData(o.state.allElements.ContainingFeatures.get(
newElementAction.newElementId
))
console.log("Did set selected element to", o.state.allElements.ContainingFeatures.get(
newElementAction.newElementId
))
}
function cancel() {
importClicked.setData(false)
}
if (o.feature.geometry.type === "Point") {
const presetInfo = <PresetInfo>{
tags: o.newTags.data,
icon: o.image,
description: o.description,
layerToAddTo: o.targetLayer,
name: o.message,
title: o.message,
preciseInput: { snapToLayers: o.snapToLayers,
maxSnapDistance: o.snapToLayersMaxDist}
const presetInfo = <PresetInfo>{
tags: o.newTags.data,
icon: o.image,
description: o.description,
layerToAddTo: o.targetLayer,
name: o.message,
title: o.message,
preciseInput: {
snapToLayers: o.snapSettings?.snapToLayers,
maxSnapDistance: o.snapSettings?.snapToLayersMaxDist
}
const [lon, lat] = o.feature.geometry.coordinates
console.log("Creating an import dialog at location", lon, lat)
return new ConfirmLocationOfPoint(o.state, o.guiState.filterViewIsOpened, presetInfo, Translations.W(o.message), {
lon,
lat
}, confirm, cancel)
}
const [lon, lat] = o.feature.geometry.coordinates
return new ConfirmLocationOfPoint(o.state, o.guiState.filterViewIsOpened, presetInfo, Translations.W(o.message), {
lon,
lat
}, confirm, cancel)
}
@ -279,41 +428,4 @@ export default class ImportButton extends Toggle {
const type = feature.geometry.type
return type === "Point" || type === "LineString" || (type === "Polygon" && feature.geometry.coordinates.length === 1)
}
private static createAddActionForFeature(newTags: Tag[], feature: any, theme: string):
OsmChangeAction & { newElementId: string } {
const geometry = feature.geometry
const type = geometry.type
if (type === "Point") {
const lat = geometry.coordinates[1]
const lon = geometry.coordinates[0];
return new CreateNewNodeAction(newTags, lat, lon, {
theme,
changeType: "import"
})
}
if (type === "LineString") {
return new CreateNewWayAction(
newTags,
geometry.coordinates.map(coor => ({lon: coor[0], lat: coor[1]})),
{
theme
}
)
}
if (type === "Polygon") {
return new CreateNewWayAction(
newTags,
geometry.coordinates[0].map(coor => ({lon: coor[0], lat: coor[1]})),
{
theme
}
)
}
return undefined;
}
}

View file

@ -14,6 +14,8 @@ import Loc from "../../Models/Loc";
import {BBox} from "../../Logic/BBox";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import FilteredLayer from "../../Models/FilteredLayer";
import BaseLayer from "../../Models/BaseLayer";
import {OsmConnection} from "../../Logic/Osm/OsmConnection";
export default class LeftControls extends Combine {
@ -26,7 +28,9 @@ export default class LeftControls extends Combine {
featureSwitchEnableExport: UIEventSource<boolean>,
featureSwitchExportAsPdf: UIEventSource<boolean>,
filteredLayers: UIEventSource<FilteredLayer[]>,
featureSwitchFilter: UIEventSource<boolean>
featureSwitchFilter: UIEventSource<boolean>,
backgroundLayer: UIEventSource<BaseLayer>,
osmConnection: OsmConnection
},
guiState: {
downloadControlIsOpened: UIEventSource<boolean>,

View file

@ -4,17 +4,30 @@ import MapControlButton from "../MapControlButton";
import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler";
import Svg from "../../Svg";
import MapState from "../../Logic/State/MapState";
import ShowDataLayer from "../ShowDataLayer/ShowDataLayer";
import AllKnownLayers from "../../Customizations/AllKnownLayers";
export default class RightControls extends Combine {
constructor(state:MapState) {
const geolocatioHandler = new GeoLocationHandler(
state.currentGPSLocation,
state.leafletMap,
state.layoutToUse
)
new ShowDataLayer({
layerToShow: AllKnownLayers.sharedLayers.get("gps_location"),
leafletMap: state.leafletMap,
enablePopups: true,
features: geolocatioHandler.currentLocation
})
const geolocationButton = new Toggle(
new MapControlButton(
new GeoLocationHandler(
state.currentGPSLocation,
state.leafletMap,
state.layoutToUse
), {
geolocatioHandler
, {
dontStyle: true
}
),

View file

@ -8,11 +8,14 @@ import Toggle from "../Input/Toggle";
import Translations from "../i18n/Translations";
import BaseUIElement from "../BaseUIElement";
import LayerConfig from "../../Models/ThemeConfig/LayerConfig";
import MapState from "../../Logic/State/MapState";
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import Loc from "../../Models/Loc";
import BaseLayer from "../../Models/BaseLayer";
import FilteredLayer from "../../Models/FilteredLayer";
export default class ShareScreen extends Combine {
constructor(state: MapState) {
constructor(state: {layoutToUse: LayoutConfig, locationControl: UIEventSource<Loc>, backgroundLayer: UIEventSource<BaseLayer>, filteredLayers: UIEventSource<FilteredLayer[]>}) {
const layout = state?.layoutToUse;
const tr = Translations.t.general.sharescreen;

View file

@ -6,9 +6,6 @@ import FullWelcomePaneWithTabs from "./BigComponents/FullWelcomePaneWithTabs";
import MapControlButton from "./MapControlButton";
import Svg from "../Svg";
import Toggle from "./Input/Toggle";
import Hash from "../Logic/Web/Hash";
import {QueryParameters} from "../Logic/Web/QueryParameters";
import Constants from "../Models/Constants";
import UserBadge from "./BigComponents/UserBadge";
import SearchAndGo from "./BigComponents/SearchAndGo";
import Link from "./Base/Link";
@ -24,77 +21,7 @@ import Translations from "./i18n/Translations";
import SimpleAddUI from "./BigComponents/SimpleAddUI";
import StrayClickHandler from "../Logic/Actors/StrayClickHandler";
import Lazy from "./Base/Lazy";
export class DefaultGuiState {
public readonly welcomeMessageIsOpened : UIEventSource<boolean>;
public readonly downloadControlIsOpened: UIEventSource<boolean>;
public readonly filterViewIsOpened: UIEventSource<boolean>;
public readonly copyrightViewIsOpened: UIEventSource<boolean>;
public readonly welcomeMessageOpenedTab: UIEventSource<number>
public readonly allFullScreenStates: UIEventSource<boolean>[] = []
static state: DefaultGuiState;
constructor() {
this.welcomeMessageOpenedTab = UIEventSource.asFloat(QueryParameters.GetQueryParameter(
"tab",
"0",
`The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`
));
this.welcomeMessageIsOpened = QueryParameters.GetBooleanQueryParameter(
"welcome-control-toggle",
"false",
"Whether or not the welcome panel is shown"
)
this.downloadControlIsOpened = QueryParameters.GetBooleanQueryParameter(
"download-control-toggle",
"false",
"Whether or not the download panel is shown"
)
this.filterViewIsOpened = QueryParameters.GetBooleanQueryParameter(
"filter-toggle",
"false",
"Whether or not the filter view is shown"
)
this.copyrightViewIsOpened = QueryParameters.GetBooleanQueryParameter(
"copyright-toggle",
"false",
"Whether or not the copyright view is shown"
)
if(Hash.hash.data === "download"){
this.downloadControlIsOpened.setData(true)
}
if(Hash.hash.data === "filters"){
this.filterViewIsOpened.setData(true)
}
if(Hash.hash.data === "copyright"){
this.copyrightViewIsOpened.setData(true)
}
if(Hash.hash.data === "" || Hash.hash.data === undefined || Hash.hash.data === "welcome"){
this.welcomeMessageIsOpened.setData(true)
}
this.allFullScreenStates.push(this.downloadControlIsOpened, this.filterViewIsOpened, this.copyrightViewIsOpened, this.welcomeMessageIsOpened)
for (let i = 0; i < this.allFullScreenStates.length; i++){
const fullScreenState = this.allFullScreenStates[i];
for (let j = 0; j < this.allFullScreenStates.length; j++){
if(i == j){
continue
}
const otherState = this.allFullScreenStates[j];
fullScreenState.addCallbackAndRunD(isOpened => {
if(isOpened){
otherState.setData(false)
}
})
}
}
}
}
import {DefaultGuiState} from "./DefaultGuiState";
/**

74
UI/DefaultGuiState.ts Normal file
View file

@ -0,0 +1,74 @@
import {UIEventSource} from "../Logic/UIEventSource";
import {QueryParameters} from "../Logic/Web/QueryParameters";
import Constants from "../Models/Constants";
import Hash from "../Logic/Web/Hash";
export class DefaultGuiState {
public readonly welcomeMessageIsOpened: UIEventSource<boolean>;
public readonly downloadControlIsOpened: UIEventSource<boolean>;
public readonly filterViewIsOpened: UIEventSource<boolean>;
public readonly copyrightViewIsOpened: UIEventSource<boolean>;
public readonly welcomeMessageOpenedTab: UIEventSource<number>
public readonly allFullScreenStates: UIEventSource<boolean>[] = []
static state: DefaultGuiState;
constructor() {
this.welcomeMessageOpenedTab = UIEventSource.asFloat(QueryParameters.GetQueryParameter(
"tab",
"0",
`The tab that is shown in the welcome-message. 0 = the explanation of the theme,1 = OSM-credits, 2 = sharescreen, 3 = more themes, 4 = about mapcomplete (user must be logged in and have >${Constants.userJourney.mapCompleteHelpUnlock} changesets)`
));
this.welcomeMessageIsOpened = QueryParameters.GetBooleanQueryParameter(
"welcome-control-toggle",
"false",
"Whether or not the welcome panel is shown"
)
this.downloadControlIsOpened = QueryParameters.GetBooleanQueryParameter(
"download-control-toggle",
"false",
"Whether or not the download panel is shown"
)
this.filterViewIsOpened = QueryParameters.GetBooleanQueryParameter(
"filter-toggle",
"false",
"Whether or not the filter view is shown"
)
this.copyrightViewIsOpened = QueryParameters.GetBooleanQueryParameter(
"copyright-toggle",
"false",
"Whether or not the copyright view is shown"
)
if (Hash.hash.data === "download") {
this.downloadControlIsOpened.setData(true)
}
if (Hash.hash.data === "filters") {
this.filterViewIsOpened.setData(true)
}
if (Hash.hash.data === "copyright") {
this.copyrightViewIsOpened.setData(true)
}
if (Hash.hash.data === "" || Hash.hash.data === undefined || Hash.hash.data === "welcome") {
this.welcomeMessageIsOpened.setData(true)
}
this.allFullScreenStates.push(this.downloadControlIsOpened, this.filterViewIsOpened, this.copyrightViewIsOpened, this.welcomeMessageIsOpened)
for (let i = 0; i < this.allFullScreenStates.length; i++) {
const fullScreenState = this.allFullScreenStates[i];
for (let j = 0; j < this.allFullScreenStates.length; j++) {
if (i == j) {
continue
}
const otherState = this.allFullScreenStates[j];
fullScreenState.addCallbackAndRunD(isOpened => {
if (isOpened) {
otherState.setData(false)
}
})
}
}
}
}

View file

@ -1,9 +1,6 @@
import jsPDF from "jspdf";
import {SimpleMapScreenshoter} from "leaflet-simple-map-screenshoter";
import {UIEventSource} from "../Logic/UIEventSource";
import Minimap from "./Base/Minimap";
import Minimap, {MinimapObj} from "./Base/Minimap";
import Loc from "../Models/Loc";
import BaseLayer from "../Models/BaseLayer";
import {FixedUiElement} from "./Base/FixedUiElement";
@ -14,7 +11,6 @@ import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
import FeaturePipeline from "../Logic/FeatureSource/FeaturePipeline";
import ShowDataLayer from "./ShowDataLayer/ShowDataLayer";
import {BBox} from "../Logic/BBox";
import ShowOverlayLayer from "./ShowDataLayer/ShowOverlayLayer";
/**
* Creates screenshoter to take png screenshot
* Creates jspdf and downloads it
@ -63,14 +59,12 @@ export default class ExportPDF {
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(() => {
onFullyLoaded: _ => window.setTimeout(() => {
if (self._screenhotTaken) {
return;
}
try {
self.CreatePdf(leaflet)
self.CreatePdf(minimap)
.then(() => self.cleanup())
.catch(() => self.cleanup())
} catch (e) {
@ -112,20 +106,17 @@ export default class ExportPDF {
this._screenhotTaken = true;
}
private async CreatePdf(leaflet: L.Map) {
private async CreatePdf(minimap: MinimapObj) {
console.log("PDF creation started")
const t = Translations.t.general.pdf;
const layout = this._layout
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);
let doc = new jsPDF('landscape');
const image = (await screenshotter.takeScreen('image'))
const image = await minimap.TakeScreenshot()
// @ts-ignore
doc.addImage(image, 'PNG', 0, 0, this.mapW, this.mapH);

View file

@ -167,6 +167,9 @@ export default class LocationInput extends InputElement<Loc> implements MinimapO
installBounds(factor: number | BBox, showRange?: boolean): void {
this.map.installBounds(factor, showRange)
}
TakeScreenshot(): Promise<any> {
return this.map.TakeScreenshot()
}
protected InnerConstructElement(): HTMLElement {
try {

View file

@ -58,7 +58,6 @@ export default class FeatureInfoBox extends ScrollableFullScreen {
for (const groupName of allGroupNames) {
const questions = layerConfig.tagRenderings.filter(tr => tr.group === groupName)
const questionBox = new QuestionBox(tags, questions, layerConfig.units);
console.log("Groupname:", groupName)
questionBoxes.set(groupName, questionBox)
}
}

View file

@ -155,7 +155,6 @@ export default class ShowDataLayer {
continue
}
try {
if ((feat.geometry.type === "LineString" || feat.geometry.type === "MultiLineString")) {
const self = this;
const coords = L.GeoJSON.coordsToLatLngs(feat.geometry.coordinates)
@ -190,9 +189,10 @@ export default class ShowDataLayer {
if (options.zoomToFeatures ?? false) {
try {
mp.fitBounds(this.geoLayer.getBounds(), {animate: false})
const bounds = this.geoLayer.getBounds()
mp.fitBounds(bounds, {animate: false})
} catch (e) {
console.error(e)
console.debug("Invalid bounds",e)
}
}

View file

@ -20,7 +20,7 @@ import Histogram from "./BigComponents/Histogram";
import Loc from "../Models/Loc";
import {Utils} from "../Utils";
import LayerConfig from "../Models/ThemeConfig/LayerConfig";
import ImportButton, {ImportButtonSpecialViz} from "./BigComponents/ImportButton";
import {ImportButtonSpecialViz} from "./BigComponents/ImportButton";
import {Tag} from "../Logic/Tags/Tag";
import StaticFeatureSource from "../Logic/FeatureSource/Sources/StaticFeatureSource";
import ShowDataMultiLayer from "./ShowDataLayer/ShowDataMultiLayer";
@ -38,9 +38,9 @@ import {SubtleButton} from "./Base/SubtleButton";
import ChangeTagAction from "../Logic/Osm/Actions/ChangeTagAction";
import {And} from "../Logic/Tags/And";
import Toggle from "./Input/Toggle";
import {DefaultGuiState} from "./DefaultGUI";
import Img from "./Base/Img";
import FilteredLayer from "../Models/FilteredLayer";
import {DefaultGuiState} from "./DefaultGuiState";
export interface SpecialVisualization {
funcName: string,

View file

@ -8,7 +8,7 @@ import {Utils} from "../Utils";
import {VariableUiElement} from "./Base/VariableUIElement";
import Combine from "./Base/Combine";
import BaseUIElement from "./BaseUIElement";
import {DefaultGuiState} from "./DefaultGUI";
import {DefaultGuiState} from "./DefaultGuiState";
export class SubstitutedTranslation extends VariableUiElement {