Add UI flow to generate flyers

This commit is contained in:
pietervdvn 2022-09-17 03:24:01 +02:00
parent bc86db2815
commit 9c961d32b3
10 changed files with 814 additions and 624 deletions

View file

@ -678,6 +678,18 @@ export class UIEventSource<T> extends Store<T> {
public map<J>(f: (t: T) => J, extraSources: Store<any>[] = []): Store<J> {
return new MappedStore(this, f, extraSources, this._callbacks, f(this.data))
}
/**
* Monoidal map which results in a read-only store. 'undefined' is passed 'as is'
* Given a function 'f', will construct a new UIEventSource where the contents will always be "f(this.data)'
*/
public mapD<J>(f: (t: T) => J, extraSources: Store<any>[] = []): Store<J | undefined> {
return new MappedStore(this, t => {
if(t === undefined){
return undefined
}
return f(t)
}, extraSources, this._callbacks, this.data === undefined ? undefined : f(this.data))
}
/**
* Two way sync with functions in both directions

View file

@ -108,4 +108,11 @@ export class QueryParameters {
history.replaceState(null, "", "?" + parts.join("&") + Hash.Current())
}
}
static ClearAll() {
for (const name in QueryParameters.knownSources) {
QueryParameters.knownSources[name].setData("")
}
QueryParameters._wasInitialized.clear()
}
}

View file

@ -10,7 +10,7 @@ import Combine from "../Base/Combine"
import Locale from "../i18n/Locale"
export default class SearchAndGo extends Combine {
constructor(state: { leafletMap: UIEventSource<any>; selectedElement: UIEventSource<any> }) {
constructor(state: { leafletMap: UIEventSource<any>; selectedElement?: UIEventSource<any> }) {
const goButton = Svg.search_ui().SetClass("w-8 h-8 full-rounded border-black float-right")
const placeholder = new UIEventSource<Translation>(Translations.t.general.search.search)
@ -63,7 +63,7 @@ export default class SearchAndGo extends Combine {
[bb[0], bb[2]],
[bb[1], bb[3]],
]
state.selectedElement.setData(undefined)
state.selectedElement?.setData(undefined)
Hash.hash.setData(poi.osm_type + "/" + poi.osm_id)
state.leafletMap.data.fitBounds(bounds)
placeholder.setData(Translations.t.general.search.search)

View file

@ -3,11 +3,12 @@ import { UIEventSource } from "../../Logic/UIEventSource"
import { Utils } from "../../Utils"
import BaseUIElement from "../BaseUIElement"
import InputElementMap from "./InputElementMap"
import Translations from "../i18n/Translations";
export class CheckBox extends InputElementMap<number[], boolean> {
constructor(el: BaseUIElement, defaultValue?: boolean) {
constructor(el: (BaseUIElement | string), defaultValue?: boolean) {
super(
new CheckBoxes([el]),
new CheckBoxes([Translations.T(el)]),
(x0, x1) => x0 === x1,
(t) => t.length > 0,
(x) => (x ? [0] : [])

View file

@ -18,6 +18,7 @@ import * as matchpoint from "../../assets/layers/matchpoint/matchpoint.json"
import LayoutConfig from "../../Models/ThemeConfig/LayoutConfig";
import FilteredLayer from "../../Models/FilteredLayer";
import {ElementStorage} from "../../Logic/ElementStorage";
import AvailableBaseLayers from "../../Logic/Actors/AvailableBaseLayers";
export default class LocationInput
extends BaseUIElement
@ -56,16 +57,16 @@ export default class LocationInput
readonly allElements: ElementStorage
}
constructor(options: {
constructor(options?: {
minZoom?: number
mapBackground?: UIEventSource<BaseLayer>
snapTo?: UIEventSource<{ feature: any }[]>
maxSnapDistance?: number
snappedPointTags?: any
requiresSnapping?: boolean
centerLocation: UIEventSource<Loc>
centerLocation?: UIEventSource<Loc>
bounds?: UIEventSource<BBox>
state: {
state?: {
readonly filteredLayers: Store<FilteredLayer[]>;
readonly backgroundLayer: UIEventSource<BaseLayer>;
readonly layoutToUse: LayoutConfig;
@ -74,15 +75,17 @@ export default class LocationInput
}
}) {
super()
this._snapTo = options.snapTo?.map((features) =>
this._snapTo = options?.snapTo?.map((features) =>
features?.filter((feat) => feat.feature.geometry.type !== "Point")
)
this._maxSnapDistance = options.maxSnapDistance
this._centerLocation = options.centerLocation
this._snappedPointTags = options.snappedPointTags
this._bounds = options.bounds
this._minZoom = options.minZoom
this._state = options.state
this._maxSnapDistance = options?.maxSnapDistance
this._centerLocation = options?.centerLocation ?? new UIEventSource<Loc>({
lat: 0, lon: 0, zoom: 0
})
this._snappedPointTags = options?.snappedPointTags
this._bounds = options?.bounds
this._minZoom = options?.minZoom
this._state = options?.state
if (this._snapTo === undefined) {
this._value = this._centerLocation
} else {
@ -102,7 +105,7 @@ export default class LocationInput
this._matching_layer = LocationInput.matchLayer
}
this._snappedPoint = options.centerLocation.map(
this._snappedPoint = this._centerLocation.map(
(loc) => {
if (loc === undefined) {
return undefined
@ -139,17 +142,17 @@ export default class LocationInput
}
if (min === undefined || min.properties.dist * 1000 > self._maxSnapDistance) {
if (options.requiresSnapping) {
if (options?.requiresSnapping) {
return undefined
} else {
return {
type: "Feature",
properties: options.snappedPointTags ?? min.properties,
properties: options?.snappedPointTags ?? min.properties,
geometry: {type: "Point", coordinates: [loc.lon, loc.lat]},
}
}
}
min.properties = options.snappedPointTags ?? min.properties
min.properties = options?.snappedPointTags ?? min.properties
self.snappedOnto.setData(matchedWay)
return min
},
@ -165,7 +168,7 @@ export default class LocationInput
}
})
}
this.mapBackground = options.mapBackground ?? this._state?.backgroundLayer
this.mapBackground = options?.mapBackground ?? this._state?.backgroundLayer ?? new UIEventSource<BaseLayer>(AvailableBaseLayers.osmCarto)
this.SetClass("block h-full")
this.clickLocation = new UIEventSource<Loc>(undefined)

View file

@ -12,6 +12,8 @@ import Translations from "../UI/i18n/Translations";
import {Utils} from "../Utils";
import Locale from "../UI/i18n/Locale";
import Constants from "../Models/Constants";
import {QueryParameters} from "../Logic/Web/QueryParameters";
import Hash from "../Logic/Web/Hash";
class SvgToPdfInternals {
private readonly doc: jsPDF;
@ -497,6 +499,7 @@ export interface SvgToPdfOptions {
disableMaps?: false | true
textSubstitutions?: Record<string, string>,
beforePage?: (i: number) => void,
overrideLocation?: {lat: number, lon: number}
}
@ -505,7 +508,6 @@ export class SvgToPdfPage {
private images: Record<string, HTMLImageElement> = {}
private rects: Record<string, SVGRectElement> = {}
public readonly _svgRoot: SVGSVGElement;
public readonly _usedTranslations: Set<string> = new Set<string>()
public readonly currentState: Store<string>
private readonly importedTranslations: Record<string, string> = {}
private readonly layerTranslations: Record<string, Record<string, any>> = {}
@ -566,12 +568,7 @@ export class SvgToPdfPage {
if (element.tagName === "tspan" && element.childElementCount == 0) {
const specialValues = element.textContent.split(" ").filter(t => t.startsWith("$"))
for (let specialValue of specialValues) {
const translationMatch = specialValue.match(/\$([a-zA-Z0-9._-]+)(.*)/)
if (translationMatch !== null) {
this._usedTranslations.add(translationMatch[1])
}
const importMatch = element.textContent.match(/\$import ([a-zA-Z-_0-9.? ]+) as ([a-zA-Z0-9]+)/)
if (importMatch !== null) {
const [, pathRaw, as] = importMatch
this.importedTranslations[as] = pathRaw
@ -672,11 +669,15 @@ export class SvgToPdfPage {
}
const zoom = Number(params["zoom"] ?? params["z"] ?? 14);
Hash.hash.setData(undefined)
history.replaceState(null, "", "")
const state = new FeaturePipelineState(layout)
state.locationControl.addCallbackAndRunD(l => console.trace("Location is",l))
state.locationControl.setData({
zoom,
lat: Number(params["lat"] ?? 51.05016),
lon: Number(params["lon"] ?? 3.717842)
lat: this.options?.overrideLocation?.lat ?? Number(params["lat"] ?? 51.05016),
lon: this.options?.overrideLocation?.lon ?? Number(params["lon"] ?? 3.717842)
})
const fl = state.filteredLayers.data
@ -738,12 +739,16 @@ export class SvgToPdfPage {
textElement.parentElement.removeChild(textElement)
}
public async Prepare(language: string) {
public async PrepareLanguage(language: string){
// Always fetch the remote data - it's cached anyway
this.layerTranslations[language] = await Utils.downloadJsonCached("https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/langs/layers/" + language + ".json", 24 * 60 * 60 * 1000)
const shared_questions = await Utils.downloadJsonCached("https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/langs/shared-questions/" + language + ".json", 24 * 60 * 60 * 1000)
this.layerTranslations[language]["shared-questions"] = shared_questions["shared_questions"]
}
public async Prepare() {
if (this._isPrepared) {
return
}
@ -778,9 +783,18 @@ export class SvgToPdfPage {
export class SvgToPdf {
public static readonly templates : Record<string, {pages: string[], description: string | Translation}>= {
flyer_a4:{pages: ["/assets/templates/MapComplete-flyer.svg","/assets/templates/MapComplete-flyer.back.svg"], description: Translations.t.flyer.description}
}
private readonly _pages: SvgToPdfPage[]
constructor(pages: string[], options?: SvgToPdfOptions) {
options = options ?? <SvgToPdfOptions>{}
options.textSubstitutions = options.textSubstitutions ?? {}
const mapCount = "" + Array.from(AllKnownLayouts.allKnownLayouts.values()).filter(th => !th.hideFromOverview).length;
options.textSubstitutions["mapCount"] = mapCount
this._pages = pages.map(page => new SvgToPdfPage(page, options))
}
@ -791,8 +805,10 @@ export class SvgToPdf {
const height = SvgToPdfInternals.attrNumber(firstPage, "height")
const mode = width > height ? "landscape" : "portrait"
await this.Prepare()
for (const page of this._pages) {
await page.Prepare(language)
await page.Prepare()
await page.PrepareLanguage(language)
}
Locale.language.setData(language)
@ -815,4 +831,10 @@ export class SvgToPdf {
}
public async Prepare(): Promise<SvgToPdf> {
for (const page of this._pages) {
await page.Prepare()
}
return this
}
}

View file

@ -26,9 +26,9 @@
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="1.0430996"
inkscape:cx="836.4494"
inkscape:cy="155.30636"
inkscape:zoom="1.9704628"
inkscape:cx="1058.3808"
inkscape:cy="146.15856"
inkscape:window-width="1920"
inkscape:window-height="1007"
inkscape:window-x="0"
@ -335,14 +335,14 @@
<rect
x="28.759503"
y="661.40117"
width="411.91488"
height="202.28339"
width="301.84133"
height="222.3756"
id="rect17153" />
<rect
x="28.759503"
y="661.40117"
width="439.98073"
height="339.17915"
width="286.60455"
height="141.05191"
id="rect21432" />
<rect
x="28.759502"
@ -365,8 +365,8 @@
<rect
x="28.759502"
y="661.40118"
width="417.32852"
height="149.75414"
width="225.97206"
height="175.28144"
id="rect3239" />
<rect
x="28.759502"
@ -392,6 +392,24 @@
width="266.88498"
height="79.149891"
id="rect5917" />
<rect
x="28.759503"
y="661.40117"
width="286.60455"
height="141.05191"
id="rect5203" />
<rect
x="28.759503"
y="661.40117"
width="327.77911"
height="79.260959"
id="rect23050" />
<rect
x="28.759503"
y="661.40117"
width="296.10439"
height="80.904815"
id="rect28360" />
</defs>
<g
inkscape:groupmode="layer"
@ -429,14 +447,14 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect21432-8);display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264848;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"><tspan
x="28.759766"
y="697.7954"
id="tspan8486"><tspan
id="tspan43984"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8484">$map(theme:aed,z:14,lat:</tspan></tspan><tspan
id="tspan43982">$map(theme:aed,z:14,lat:</tspan></tspan><tspan
x="28.759766"
y="747.7954"
id="tspan8490"><tspan
id="tspan43988"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8488">51.2098,lon:3.2284)</tspan></tspan></text>
id="tspan43986">51.2098,lon:3.2284)</tspan></tspan></text>
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,1.3325782,-88.396258)"
@ -444,75 +462,87 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect13433);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="28.759766"
y="697.7954"
id="tspan8494"><tspan
id="tspan43992"><tspan
style="font-size:16px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8492">$flyer.toerisme_vlaanderen</tspan></tspan></text>
id="tspan43990">$flyer.toerisme_vlaanderen</tspan></tspan></text>
<rect
style="fill:#deadff;fill-opacity:1;stroke:#000000;stroke-width:0.0270132;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="fill:#deadff;fill-opacity:1;stroke:#000000;stroke-width:0.0182753;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11121"
width="196.84476"
height="80.141121"
x="5.3551202"
y="122.6297" />
width="90.0849"
height="80.149857"
x="5.3507514"
y="122.62533" />
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,3.1668997,-43.500981)"
id="text17151"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect17153);fill:#000000;fill-opacity:1;stroke:none"><tspan
style="font-style:normal;font-weight:normal;font-size:40px;line-height:0.25;font-family:sans-serif;white-space:pre;fill:#000000;fill-opacity:1;stroke:none;shape-inside:url(#rect17153)"><tspan
x="28.759766"
y="697.7954"
id="tspan8498"><tspan
y="677.7954"
id="tspan43996"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8496">$map(theme:toerisme_vlaanderen,layers:none</tspan></tspan><tspan
id="tspan43994">$map(theme:toerisme_vlaandere</tspan></tspan><tspan
x="28.759766"
y="747.7954"
id="tspan8502"><tspan
y="691.20604"
id="tspan44002"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8500">,layer-charging_station_ebikes:force,lat:</tspan></tspan><tspan
id="tspan43998">n,layers:none</tspan><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44000">,layer-</tspan></tspan><tspan
x="28.759766"
y="797.7954"
id="tspan8506"><tspan
y="704.61669"
id="tspan44006"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8504">51.02403,lon:5.1, z:10)</tspan></tspan></text>
id="tspan44004">charging_station_ebikes:force,lat:</tspan></tspan><tspan
x="28.759766"
y="718.02733"
id="tspan44012"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44008">50.8552</tspan><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44010">,lon:4.3156, z:10)</tspan></tspan></text>
<rect
style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:0.0178908;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:0.0161075;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11459"
width="93.812988"
height="73.760445"
x="101.18607"
y="57.089542" />
width="93.815002"
height="59.787514"
x="101.18518"
y="57.08865" />
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,101.8274,-113.37049)"
id="text21430"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect21432);fill:#000000;fill-opacity:1;stroke:none"><tspan
style="font-style:normal;font-weight:normal;font-size:40px;line-height:0.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect21432);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="28.759766"
y="697.7954"
id="tspan8512"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8508">$map(theme:cyclofix,z:14,lat:</tspan><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8510">51.05016,lon:</tspan></tspan><tspan
y="677.7954"
id="tspan44016"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44014">$map(theme:cyclofix,z:14,lat:51.05016,lon:</tspan></tspan><tspan
x="28.759766"
y="747.7954"
id="tspan8516"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8514">3.717842,layers:none,layer-</tspan></tspan><tspan
y="692.05876"
id="tspan44020"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44018">3.717842,layers:none,layer-</tspan></tspan><tspan
x="28.759766"
y="797.7954"
id="tspan8520"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8518">bike_repair_station:true,layer-</tspan></tspan><tspan
y="706.32213"
id="tspan44024"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44022">bike_repair_station:true,layer-</tspan></tspan><tspan
x="28.759766"
y="847.7954"
id="tspan8524"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8522">drinking_water:true,layer-bike_cafe:true,layer-</tspan></tspan><tspan
y="720.5855"
id="tspan44028"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44026">drinking_water:true,layer-</tspan></tspan><tspan
x="28.759766"
y="897.7954"
id="tspan8528"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8526">bicycle_tube_vending_machine: true)</tspan></tspan></text>
y="734.84886"
id="tspan44032"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44030">bike_cafe:true,layer-</tspan></tspan><tspan
x="28.759766"
y="749.11223"
id="tspan44036"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44034">bicycle_tube_vending_machine: true)</tspan></tspan></text>
<rect
style="fill:#733034;fill-opacity:1;stroke:#000000;stroke-width:0.0661458;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11543"
@ -534,14 +564,14 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;white-space:pre;shape-inside:url(#rect20457);display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264848;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"><tspan
x="28.759766"
y="697.7954"
id="tspan8532"><tspan
id="tspan44040"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8530">$map(theme:artwork,z:15,lat:51.2098,lon:</tspan></tspan><tspan
id="tspan44038">$map(theme:artwork,z:15,lat:51.2098,lon:</tspan></tspan><tspan
x="28.759766"
y="747.7954"
id="tspan8536"><tspan
id="tspan44044"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8534">3.2284,background:AGIV)</tspan></tspan></text>
id="tspan44042">3.2284,background:AGIV)</tspan></tspan></text>
<rect
style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:0.0700743;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect11647"
@ -553,17 +583,22 @@
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,210.02275,-141.45522)"
id="text3237"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3239);display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264848;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"><tspan
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264848;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;shape-inside:url(#rect3239)"><tspan
x="28.759766"
y="697.7954"
id="tspan8540"><tspan
id="tspan44048"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8538">$map(theme:cyclestreets,z:12,lat:51.2098,lon:</tspan></tspan><tspan
id="tspan44046">$map(theme:cyclestreets,</tspan></tspan><tspan
x="28.759766"
y="747.7954"
id="tspan8544"><tspan
id="tspan44052"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8542">3.2284)</tspan></tspan></text>
id="tspan44050">z:15,lat:51.02802,lon:</tspan></tspan><tspan
x="28.759766"
y="797.7954"
id="tspan44056"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44054">4.48029, scaling:3)</tspan></tspan></text>
<g
id="g1367"
transform="matrix(1,0,0.20502864,-1,-20.554711,213.09746)">
@ -596,14 +631,14 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect890);display:inline;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:0.264848;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"><tspan
x="28.759766"
y="697.7954"
id="tspan8548"><tspan
id="tspan44060"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8546">$map(theme:benches,z:14,lat:51.2098,lon:</tspan></tspan><tspan
id="tspan44058">$map(theme:benches,z:14,lat:51.2098,lon:</tspan></tspan><tspan
x="28.759766"
y="747.7954"
id="tspan8552"><tspan
id="tspan44064"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8550">3.2284, layers:none, layer-bench:force)</tspan></tspan></text>
id="tspan44062">3.2284, layers:none, layer-bench:force)</tspan></tspan></text>
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,205.99418,0.58092297)"
@ -611,9 +646,9 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect6468);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="28.759766"
y="697.7954"
id="tspan8556"><tspan
id="tspan44068"><tspan
style="font-size:16px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8554">$flyer.aerial</tspan></tspan></text>
id="tspan44066">$flyer.aerial</tspan></tspan></text>
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,-1.7998979,-153.42245)"
@ -621,9 +656,9 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect3512);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="28.759766"
y="697.7954"
id="tspan8560"><tspan
id="tspan44072"><tspan
style="font-size:18.6667px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8558">$flyer.examples</tspan></tspan></text>
id="tspan44070">$flyer.examples</tspan></tspan></text>
<g
id="path15616"
transform="matrix(-1,0,0,1,497.66957,-0.86523396)">
@ -691,9 +726,103 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect5917);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="28.759766"
y="697.7954"
id="tspan8564"><tspan
id="tspan44076"><tspan
style="font-size:16px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan8562">$flyer.lines_too</tspan></tspan></text>
id="tspan44074">$flyer.lines_too</tspan></tspan></text>
<rect
style="fill:#cccccc;fill-opacity:1;stroke:#000000;stroke-width:0.0161075;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5197"
width="93.815002"
height="59.787514"
x="101.83195"
y="143.0887" />
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,102.47417,-27.370445)"
id="text5201"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:0.25;font-family:sans-serif;white-space:pre;fill:#000000;fill-opacity:1;stroke:none;shape-inside:url(#rect5203)"><tspan
x="28.759766"
y="677.7954"
id="tspan44080"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44078">$map(theme:onwheels,z:18,lat:50.86622,lon:</tspan></tspan><tspan
x="28.759766"
y="692.05876"
id="tspan44086"><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44082">4.35012</tspan><tspan
style="font-size:13.3333px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44084">,layer-governments:false)</tspan></tspan></text>
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,99.365194,-43.160062)"
id="text23036"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:0.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect23050);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="28.759766"
y="677.7954"
id="tspan44090"><tspan
style="font-size:16px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44088">$flyer.onwheels</tspan></tspan></text>
<g
id="g23048"
transform="matrix(0.99953426,0.03051675,0.2354499,-0.99327745,75.052107,241.32304)">
<path
style="color:#000000;fill:#000000;stroke-width:1.35478;-inkscape-stroke:none"
d="m 10.773987,88.413041 c -6.7214066,3.665424 -8.0818381,7.903356 -7.7053042,11.206038 0.3765338,3.302671 2.4528904,5.665201 2.4528904,5.665201 l 0.2698975,-0.2355 c 0,0 -2.0036724,-2.29509 -2.3655708,-5.469396 -0.2226277,-1.952726 0.1624065,-4.239546 2.0370665,-6.553174 1.1727415,-1.447349 2.9284401,-2.905188 5.4830146,-4.298289 z"
id="path23038"
sodipodi:nodetypes="csccsscc" />
<g
id="g23046"
transform="matrix(1.3547788,0,0,1.3547788,-1.268197,-38.166165)">
<g
id="g23044">
<path
style="color:#000000;fill:#000000;fill-rule:evenodd;stroke-width:0.181901;stroke-linejoin:round;-inkscape-stroke:none"
d="m 5.9062068,93.870487 3.351582,-0.495843 -2.2319045,2.549032 C 7.1413596,95.074353 6.6865692,94.246503 5.9062068,93.870487 Z"
id="path23040" />
<path
style="color:#000000;fill:#000000;fill-rule:evenodd;stroke-linejoin:round;-inkscape-stroke:none"
d="M 9.2441406,93.285156 5.8925781,93.78125 c -0.088278,0.01373 -0.1059275,0.133203 -0.025391,0.171875 0.7457822,0.359354 1.1784769,1.149068 1.0683594,1.958984 -0.011715,0.0889 0.098674,0.139328 0.1582031,0.07227 l 2.2324219,-2.550781 c 0.053217,-0.06373 2.437e-4,-0.159586 -0.082031,-0.148438 z"
id="path23042"
sodipodi:nodetypes="ccccccsc" />
</g>
</g>
</g>
<text
xml:space="preserve"
transform="matrix(0.26458333,0,0,0.26458333,99.091208,-57.205081)"
id="text28358"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:0.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect28360);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="28.759766"
y="677.7954"
id="tspan44094"><tspan
style="font-size:16px;-inkscape-font-specification:'sans-serif, Normal'"
id="tspan44092">$flyer.cyclofix</tspan></tspan></text>
<g
id="g29134"
transform="matrix(-1,0,-0.20502864,1,211.57633,16.855536)">
<path
style="color:#000000;fill:#000000;stroke-width:1.35478;-inkscape-stroke:none"
d="m 10.773987,88.413041 c -6.7214066,3.665424 -8.0818381,7.903356 -7.7053042,11.206038 0.3765338,3.302671 2.4528904,5.665201 2.4528904,5.665201 l 0.2698975,-0.2355 c 0,0 -2.0036724,-2.29509 -2.3655708,-5.469396 -0.2226277,-1.952726 0.1624065,-4.239546 2.0370665,-6.553174 1.1727415,-1.447349 2.9284401,-2.905188 5.4830146,-4.298289 z"
id="path29124"
sodipodi:nodetypes="csccsscc" />
<g
id="g29132"
transform="matrix(1.3547788,0,0,1.3547788,-1.268197,-38.166165)">
<g
id="g29130">
<path
style="color:#000000;fill:#000000;fill-rule:evenodd;stroke-width:0.181901;stroke-linejoin:round;-inkscape-stroke:none"
d="m 5.9062068,93.870487 3.351582,-0.495843 -2.2319045,2.549032 C 7.1413596,95.074353 6.6865692,94.246503 5.9062068,93.870487 Z"
id="path29126" />
<path
style="color:#000000;fill:#000000;fill-rule:evenodd;stroke-linejoin:round;-inkscape-stroke:none"
d="M 9.2441406,93.285156 5.8925781,93.78125 c -0.088278,0.01373 -0.1059275,0.133203 -0.025391,0.171875 0.7457822,0.359354 1.1784769,1.149068 1.0683594,1.958984 -0.011715,0.0889 0.098674,0.139328 0.1582031,0.07227 l 2.2324219,-2.550781 c 0.053217,-0.06373 2.437e-4,-0.159586 -0.082031,-0.148438 z"
id="path29128"
sodipodi:nodetypes="ccccccsc" />
</g>
</g>
</g>
</g>
<g
inkscape:label="Layer 1"
@ -728,9 +857,9 @@
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;white-space:pre;shape-inside:url(#rect135032);fill:#000000;fill-opacity:1;stroke:none"><tspan
x="8.7285156"
y="42.098132"
id="tspan8568"><tspan
id="tspan44098"><tspan
style="font-weight:bold;font-size:34.6667px;-inkscape-font-specification:'sans-serif, Bold'"
id="tspan8566">$flyer.title</tspan></tspan></text>
id="tspan44096">$flyer.title</tspan></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.5833px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 54 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -728,12 +728,8 @@ video {
margin: 0.25rem;
}
.m-0 {
margin: 0px;
}
.m-auto {
margin: auto;
.m-2 {
margin: 0.5rem;
}
.m-4 {
@ -744,14 +740,14 @@ video {
margin: 1.25rem;
}
.m-2 {
margin: 0.5rem;
}
.m-0\.5 {
margin: 0.125rem;
}
.m-0 {
margin: 0px;
}
.m-3 {
margin: 0.75rem;
}
@ -764,21 +760,6 @@ video {
margin: 1px;
}
.mx-4 {
margin-left: 1rem;
margin-right: 1rem;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
}
.my-auto {
margin-top: auto;
margin-bottom: auto;
}
.my-2 {
margin-top: 0.5rem;
margin-bottom: 0.5rem;
@ -794,26 +775,6 @@ video {
margin-bottom: 0.75rem;
}
.mt-20 {
margin-top: 5rem;
}
.mr-4 {
margin-right: 1rem;
}
.ml-2 {
margin-left: 0.5rem;
}
.mt-3 {
margin-top: 0.75rem;
}
.mr-1 {
margin-right: 0.25rem;
}
.ml-3 {
margin-left: 0.75rem;
}
@ -842,6 +803,10 @@ video {
margin-top: 1.5rem;
}
.mr-1 {
margin-right: 0.25rem;
}
.mr-2 {
margin-right: 0.5rem;
}
@ -858,14 +823,26 @@ video {
margin-bottom: 6rem;
}
.mr-4 {
margin-right: 1rem;
}
.mb-2 {
margin-bottom: 0.5rem;
}
.ml-2 {
margin-left: 0.5rem;
}
.ml-12 {
margin-left: 3rem;
}
.mt-3 {
margin-top: 0.75rem;
}
.mb-10 {
margin-bottom: 2.5rem;
}
@ -967,22 +944,6 @@ video {
height: min-content;
}
.h-16 {
height: 4rem;
}
.h-12 {
height: 3rem;
}
.h-20 {
height: 5rem;
}
.h-4 {
height: 1rem;
}
.h-64 {
height: 16rem;
}
@ -991,10 +952,18 @@ video {
height: 2.5rem;
}
.h-12 {
height: 3rem;
}
.h-8 {
height: 2rem;
}
.h-4 {
height: 1rem;
}
.h-1\/2 {
height: 50%;
}
@ -1019,6 +988,10 @@ video {
height: 24rem;
}
.h-16 {
height: 4rem;
}
.h-0 {
height: 0px;
}
@ -1031,10 +1004,6 @@ video {
height: 12rem;
}
.max-h-4 {
max-height: 1rem;
}
.max-h-7 {
max-height: 1.75rem;
}
@ -1047,32 +1016,20 @@ video {
max-height: 8rem;
}
.max-h-8 {
max-height: 2rem;
.max-h-4 {
max-height: 1rem;
}
.min-h-screen {
min-height: 100vh;
.max-h-8 {
max-height: 2rem;
}
.w-full {
width: 100%;
}
.w-12 {
width: 3rem;
}
.w-0 {
width: 0px;
}
.w-20 {
width: 5rem;
}
.w-4 {
width: 1rem;
.w-96 {
width: 24rem;
}
.w-24 {
@ -1091,10 +1048,22 @@ video {
width: 2.5rem;
}
.w-12 {
width: 3rem;
}
.w-8 {
width: 2rem;
}
.w-4 {
width: 1rem;
}
.w-0 {
width: 0px;
}
.w-screen {
width: 100vw;
}
@ -1130,10 +1099,6 @@ video {
min-width: min-content;
}
.max-w-screen-md {
max-width: 768px;
}
.max-w-full {
max-width: 100%;
}
@ -1251,10 +1216,6 @@ video {
align-content: flex-start;
}
.items-start {
align-items: flex-start;
}
.items-end {
align-items: flex-end;
}
@ -1352,24 +1313,24 @@ video {
border-radius: 9999px;
}
.rounded {
border-radius: 0.25rem;
}
.rounded-lg {
border-radius: 0.5rem;
.rounded-xl {
border-radius: 0.75rem;
}
.rounded-3xl {
border-radius: 1.5rem;
}
.rounded {
border-radius: 0.25rem;
}
.rounded-md {
border-radius: 0.375rem;
}
.rounded-xl {
border-radius: 0.75rem;
.rounded-lg {
border-radius: 0.5rem;
}
.rounded-sm {
@ -1381,14 +1342,14 @@ video {
border-bottom-left-radius: 0.25rem;
}
.border {
border-width: 1px;
}
.border-2 {
border-width: 2px;
}
.border {
border-width: 1px;
}
.border-4 {
border-width: 4px;
}
@ -1405,13 +1366,9 @@ video {
border-bottom-width: 1px;
}
.border-gray-600 {
.border-black {
--tw-border-opacity: 1;
border-color: rgb(75 85 99 / var(--tw-border-opacity));
}
.border-transparent {
border-color: transparent;
border-color: rgb(0 0 0 / var(--tw-border-opacity));
}
.border-gray-500 {
@ -1419,11 +1376,6 @@ video {
border-color: rgb(107 114 128 / var(--tw-border-opacity));
}
.border-black {
--tw-border-opacity: 1;
border-color: rgb(0 0 0 / var(--tw-border-opacity));
}
.border-gray-400 {
--tw-border-opacity: 1;
border-color: rgb(156 163 175 / var(--tw-border-opacity));
@ -1458,15 +1410,6 @@ video {
background-color: rgb(255 255 255 / var(--tw-bg-opacity));
}
.bg-indigo-100 {
--tw-bg-opacity: 1;
background-color: rgb(224 231 255 / var(--tw-bg-opacity));
}
.bg-transparent {
background-color: transparent;
}
.bg-gray-200 {
--tw-bg-opacity: 1;
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
@ -1482,6 +1425,11 @@ video {
background-color: rgb(156 163 175 / var(--tw-bg-opacity));
}
.bg-indigo-100 {
--tw-bg-opacity: 1;
background-color: rgb(224 231 255 / var(--tw-bg-opacity));
}
.bg-black {
--tw-bg-opacity: 1;
background-color: rgb(0 0 0 / var(--tw-bg-opacity));
@ -1507,22 +1455,10 @@ video {
background-color: rgb(254 202 202 / var(--tw-bg-opacity));
}
.object-cover {
object-fit: cover;
}
.p-3 {
padding: 0.75rem;
}
.p-1 {
padding: 0.25rem;
}
.p-0 {
padding: 0px;
}
.p-4 {
padding: 1rem;
}
@ -1531,25 +1467,18 @@ video {
padding: 0.5rem;
}
.p-1 {
padding: 0.25rem;
}
.p-0 {
padding: 0px;
}
.p-0\.5 {
padding: 0.125rem;
}
.px-10 {
padding-left: 2.5rem;
padding-right: 2.5rem;
}
.py-6 {
padding-top: 1.5rem;
padding-bottom: 1.5rem;
}
.px-1 {
padding-left: 0.25rem;
padding-right: 0.25rem;
}
.px-0 {
padding-left: 0px;
padding-right: 0px;
@ -1560,16 +1489,8 @@ video {
padding-right: 1rem;
}
.pt-4 {
padding-top: 1rem;
}
.pr-4 {
padding-right: 1rem;
}
.pt-5 {
padding-top: 1.25rem;
.pl-4 {
padding-left: 1rem;
}
.pl-1 {
@ -1584,10 +1505,6 @@ video {
padding-bottom: 3rem;
}
.pl-4 {
padding-left: 1rem;
}
.pl-2 {
padding-left: 0.5rem;
}
@ -1624,6 +1541,10 @@ video {
padding-right: 0.75rem;
}
.pr-4 {
padding-right: 1rem;
}
.pl-3 {
padding-left: 0.75rem;
}
@ -1661,11 +1582,6 @@ video {
line-height: 1.75rem;
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
@ -1681,6 +1597,11 @@ video {
line-height: 2.5rem;
}
.text-sm {
font-size: 0.875rem;
line-height: 1.25rem;
}
.text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
@ -1691,18 +1612,6 @@ video {
line-height: 1.5rem;
}
.font-light {
font-weight: 300;
}
.font-medium {
font-weight: 500;
}
.font-semibold {
font-weight: 600;
}
.font-bold {
font-weight: 700;
}
@ -1711,6 +1620,10 @@ video {
font-weight: 800;
}
.font-semibold {
font-weight: 600;
}
.uppercase {
text-transform: uppercase;
}
@ -1732,16 +1645,16 @@ video {
letter-spacing: -0.025em;
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-gray-900 {
--tw-text-opacity: 1;
color: rgb(17 24 39 / var(--tw-text-opacity));
}
.text-gray-700 {
--tw-text-opacity: 1;
color: rgb(55 65 81 / var(--tw-text-opacity));
}
.text-gray-800 {
--tw-text-opacity: 1;
color: rgb(31 41 55 / var(--tw-text-opacity));
@ -1752,11 +1665,6 @@ video {
color: rgb(107 114 128 / var(--tw-text-opacity));
}
.text-white {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.text-green-600 {
--tw-text-opacity: 1;
color: rgb(22 163 74 / var(--tw-text-opacity));
@ -1772,25 +1680,20 @@ video {
text-decoration-line: line-through;
}
.opacity-0 {
opacity: 0;
}
.opacity-50 {
opacity: 0.5;
}
.opacity-0 {
opacity: 0;
}
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.outline-none {
outline: 2px solid transparent;
outline-offset: 2px;
}
.outline {
outline-style: solid;
}
@ -2612,31 +2515,11 @@ input {
margin-left: 1.5rem;
}
.hover\:border-blue-700:hover {
--tw-border-opacity: 1;
border-color: rgb(29 78 216 / var(--tw-border-opacity));
}
.hover\:bg-indigo-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(199 210 254 / var(--tw-bg-opacity));
}
.hover\:bg-blue-600:hover {
--tw-bg-opacity: 1;
background-color: rgb(37 99 235 / var(--tw-bg-opacity));
}
.hover\:text-white:hover {
--tw-text-opacity: 1;
color: rgb(255 255 255 / var(--tw-text-opacity));
}
.hover\:text-blue-600:hover {
--tw-text-opacity: 1;
color: rgb(37 99 235 / var(--tw-text-opacity));
}
.hover\:text-blue-800:hover {
--tw-text-opacity: 1;
color: rgb(30 64 175 / var(--tw-text-opacity));
@ -2657,39 +2540,12 @@ input {
color: var(--unsubtle-detail-color-contrast);
}
.focus\:text-gray-600:focus {
--tw-text-opacity: 1;
color: rgb(75 85 99 / var(--tw-text-opacity));
}
.focus\:outline-none:focus {
outline: 2px solid transparent;
outline-offset: 2px;
}
@media (min-width: 640px) {
.sm\:m-0 {
margin: 0px;
}
.sm\:mx-0 {
margin-left: 0px;
margin-right: 0px;
}
.sm\:mx-auto {
margin-left: auto;
margin-right: auto;
}
.sm\:mr-10 {
margin-right: 2.5rem;
}
.sm\:ml-2 {
margin-left: 0.5rem;
}
.sm\:mr-2 {
margin-right: 0.5rem;
}
@ -2702,34 +2558,18 @@ input {
display: flex;
}
.sm\:h-32 {
height: 8rem;
}
.sm\:h-8 {
height: 2rem;
}
.sm\:h-24 {
height: 6rem;
}
.sm\:w-auto {
width: auto;
}
.sm\:w-32 {
width: 8rem;
}
.sm\:w-8 {
width: 2rem;
}
.sm\:w-24 {
width: 6rem;
}
.sm\:w-auto {
width: auto;
}
.sm\:max-w-sm {
max-width: 24rem;
}
@ -2786,10 +2626,6 @@ input {
padding-left: 0.5rem;
}
.sm\:pt-0 {
padding-top: 0px;
}
.sm\:pt-1 {
padding-top: 0.25rem;
}
@ -2798,11 +2634,6 @@ input {
text-align: center;
}
.sm\:text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
}
.sm\:text-xl {
font-size: 1.25rem;
line-height: 1.75rem;
@ -2832,11 +2663,6 @@ input {
margin: 0.5rem;
}
.md\:mx-auto {
margin-left: auto;
margin-right: auto;
}
.md\:mt-5 {
margin-top: 1.25rem;
}
@ -2865,11 +2691,6 @@ input {
height: 3rem;
}
.md\:w-max {
width: -webkit-max-content;
width: max-content;
}
.md\:w-2\/6 {
width: 33.333333%;
}
@ -2878,6 +2699,11 @@ input {
width: auto;
}
.md\:w-max {
width: -webkit-max-content;
width: max-content;
}
.md\:grid-flow-row {
grid-auto-flow: row;
}
@ -2922,11 +2748,6 @@ input {
padding-bottom: 0px;
}
.md\:text-base {
font-size: 1rem;
line-height: 1.5rem;
}
.md\:text-2xl {
font-size: 1.5rem;
line-height: 2rem;

215
test.ts
View file

@ -1,11 +1,29 @@
import MinimapImplementation from "./UI/Base/MinimapImplementation";
import {Utils} from "./Utils";
import {SvgToPdf, SvgToPdfOptions} from "./Utils/svgToPdf";
import {AllKnownLayouts} from "./Customizations/AllKnownLayouts";
import LayerConfig from "./Models/ThemeConfig/LayerConfig";
import Constants from "./Models/Constants";
import {And} from "./Logic/Tags/And";
import {Tag} from "./Logic/Tags/Tag";
import {FlowPanelFactory, FlowStep} from "./UI/ImportFlow/FlowStep";
import Title from "./UI/Base/Title";
import Combine from "./UI/Base/Combine";
import {ImmutableStore, Store, UIEventSource} from "./Logic/UIEventSource";
import {RadioButton} from "./UI/Input/RadioButton";
import {InputElement} from "./UI/Input/InputElement";
import {FixedInputElement} from "./UI/Input/FixedInputElement";
import List from "./UI/Base/List";
import {VariableUiElement} from "./UI/Base/VariableUIElement";
import BaseUIElement from "./UI/BaseUIElement";
import LeftIndex from "./UI/Base/LeftIndex";
import {SvgToPdf, SvgToPdfOptions} from "./Utils/svgToPdf";
import Img from "./UI/Base/Img";
import Toggle from "./UI/Input/Toggle";
import CheckBoxes, {CheckBox} from "./UI/Input/Checkboxes";
import Loading from "./UI/Base/Loading";
import Minimap from "./UI/Base/Minimap";
import {FixedUiElement} from "./UI/Base/FixedUiElement";
import SearchAndGo from "./UI/BigComponents/SearchAndGo";
MinimapImplementation.initialize()
@ -22,12 +40,9 @@ async function main() {
{
// Dirty hack!
// Make the charging-station layer simpler to allow querying it by overpass
const chargingStationLayer: LayerConfig = AllKnownLayouts.allKnownLayouts.get("toerisme_vlaanderen").layers.find(l => l.id === "charging_station")
chargingStationLayer.filters = []
const bikechargingStationLayer : LayerConfig = AllKnownLayouts.allKnownLayouts.get("toerisme_vlaanderen").layers.find(l => l.id === "charging_station_ebikes")
bikechargingStationLayer.source.osmTags = new And([new Tag("amenity","charging_station"), new Tag("bicycle","yes")])
Constants.defaultOverpassUrls.splice(0,1) // remove overpass-api.de for this run
const bikechargingStationLayer: LayerConfig = AllKnownLayouts.allKnownLayouts.get("toerisme_vlaanderen").layers.find(l => l.id === "charging_station_ebikes")
bikechargingStationLayer.source.osmTags = new And([new Tag("amenity", "charging_station"), new Tag("bicycle", "yes")])
Constants.defaultOverpassUrls.splice(0, 1) // remove overpass-api.de for this run
}
@ -36,15 +51,191 @@ async function main() {
const options = <SvgToPdfOptions>{
getFreeDiv: createElement,
textSubstitutions: {
mapCount: "" + Array.from(AllKnownLayouts.allKnownLayouts.values()).filter(th => !th.hideFromOverview).length
},
disableMaps: false
}
const front = await new SvgToPdf([svg, svgBack], options)
const front = await new SvgToPdf([svg, svgBack], options)
await front.ConvertSvg("Flyer-nl.pdf", "nl")
await front.ConvertSvg("Flyer-en.pdf", "en")
}
main().then(() => console.log("Done!"))
class SelectTemplate extends Combine implements FlowStep<string[]> {
readonly IsValid: Store<boolean>;
readonly Value: Store<string[]>;
constructor() {
const elements: InputElement<{ pages: string[] }>[] = []
for (const templateName in SvgToPdf.templates) {
const template = SvgToPdf.templates[templateName]
elements.push(new FixedInputElement(template.description, new UIEventSource(template)))
}
const radio = new RadioButton(elements, {selectFirstAsDefault: true})
const loaded: Store<{ success: string[] } | { error: any }> = radio.GetValue().bind(template => {
if (template === undefined) {
return undefined
}
const urls = template.pages.map(p => SelectTemplate.ToUrl(p))
const dloadAll: Promise<string[]> = Promise.all(urls.map(url => Utils.download(url)))
return UIEventSource.FromPromiseWithErr(dloadAll)
})
const preview = new VariableUiElement(
loaded.map(pages => {
if (pages === undefined) {
return new Loading()
}
if (pages["err"] !== undefined) {
return new FixedUiElement("Loading preview failed: " + pages["err"]).SetClass("alert")
}
const els: BaseUIElement[] = []
for (const pageSrc of pages["success"]) {
const el = new Img(pageSrc, true)
.SetClass("w-96 m-2 border-black border-2")
els.push(el)
}
return new Combine(els).SetClass("flex border border-subtle rounded-xl");
})
)
super([
new Title("Select template"),
radio,
new Title("Preview"),
preview
]);
this.Value = loaded.map(l => l === undefined ? undefined : l["success"])
this.IsValid = this.Value.map(v => v !== undefined)
}
public static ToUrl(spec: string) {
if (spec.startsWith("http")) {
return spec
}
return window.location.protocol + "//" + window.location.host + "/" + spec
}
}
class SelectPdfOptions extends Combine implements FlowStep<{ pages: string[], options: SvgToPdfOptions }> {
readonly IsValid: Store<boolean>;
readonly Value: Store<{ pages: string[], options: SvgToPdfOptions }>;
constructor(pages: string[], getFreeDiv: () => string) {
const dummy = new CheckBox("Don't add data to the map (to quickly preview the PDF)", false)
const overrideMapLocation = new CheckBox("Override map location: use a selected location instead of the location set in the template", false)
const locationInput = Minimap.createMiniMap().SetClass("block w-full")
const searchField = new SearchAndGo( {leafletMap: locationInput.leafletMap})
const selectLocation =
new Combine([
new Toggle(new Combine([new Title("Select override location"), searchField]).SetClass("flex"), undefined, overrideMapLocation.GetValue()),
new Toggle(locationInput.SetStyle("height: 20rem"), undefined, overrideMapLocation.GetValue()).SetStyle("height: 20rem")
]).SetClass("block").SetStyle("height: 25rem")
super([new Title("Select options"),
dummy,
overrideMapLocation,
selectLocation
]);
this.Value = dummy.GetValue().map((disableMaps) => {
return {
pages,
options: <SvgToPdfOptions>{
disableMaps,
getFreeDiv,
overrideLocation: overrideMapLocation.GetValue().data ? locationInput.location.data : undefined
}
}
}, [overrideMapLocation.GetValue(), locationInput.location])
this.IsValid = new ImmutableStore(true)
}
}
class PreparePdf extends Combine implements FlowStep<{ svgToPdf: SvgToPdf, languages: string[] }> {
readonly IsValid: Store<boolean>;
readonly Value: Store<{ svgToPdf: SvgToPdf, languages: string[] }>;
constructor(pages: string[], options: SvgToPdfOptions) {
const svgToPdf = new SvgToPdf(pages, options)
const languageOptions = [
new FixedInputElement("Nederlands", "nl"),
new FixedInputElement("English", "en")
]
const languages = new CheckBoxes(languageOptions)
const isPrepared = UIEventSource.FromPromiseWithErr(svgToPdf.Prepare())
super([
new Title("Select languages..."),
languages,
new Toggle(
new Loading("Preparing maps..."),
undefined,
isPrepared.map(p => p === undefined)
)
]);
this.Value = isPrepared.map(isPrepped => {
if (isPrepped === undefined) {
return undefined
}
if (isPrepped["success"] !== undefined) {
const svgToPdf = isPrepped["success"]
const langs = languages.GetValue().data.map(i => languageOptions[i].GetValue().data)
return {svgToPdf, languages: langs}
}
return undefined;
}, [languages.GetValue()])
this.IsValid = this.Value.map(v => v !== undefined)
}
}
class SavePdf extends Combine {
constructor(svgToPdf: SvgToPdf, languages: string[]) {
super([
new Title("Generating your pdfs..."),
new List(languages.map(lng => new Toggle(
lng + " is done!",
new Loading("Creating pdf for " + lng),
UIEventSource.FromPromiseWithErr(svgToPdf.ConvertSvg("Template" + "_" + lng + ".pdf", lng).then(() => true))
.map(x => x !== undefined && x["success"] === true)
)))
]);
}
}
const {flow, furthestStep, titles} = FlowPanelFactory.start(
new Title("Select template"), new SelectTemplate()
).then(new Title("Select options"), (pages) => new SelectPdfOptions(pages, createElement))
.then("Generate maps...", ({pages, options}) => new PreparePdf(pages, options))
.finish("Generating...", ({svgToPdf, languages}) => new SavePdf(svgToPdf, languages))
const toc = new List(
titles.map(
(title, i) =>
new VariableUiElement(
furthestStep.map((currentStep) => {
if (i > currentStep) {
return new Combine([title]).SetClass("subtle")
}
if (i == currentStep) {
return new Combine([title]).SetClass("font-bold")
}
if (i < currentStep) {
return title
}
})
)
),
true
)
const leftContents: BaseUIElement[] = [
toc
].map((el) => el?.SetClass("pl-4"))
new LeftIndex(leftContents, flow).AttachTo("maindiv")
// main().then(() => console.log("Done!"))