Refactoring: fix GPX-track view

This commit is contained in:
Pieter Vander Vennet 2023-04-20 18:58:31 +02:00
parent 4172af6a72
commit c6e12fdd6b
23 changed files with 217 additions and 347 deletions

View file

@ -5,7 +5,6 @@ import Img from "../Base/Img"
import { FixedUiElement } from "../Base/FixedUiElement"
import Combine from "../Base/Combine"
import Link from "../Base/Link"
import { SubstitutedTranslation } from "../SubstitutedTranslation"
import { Utils } from "../../Utils"
import StaticFeatureSource from "../../Logic/FeatureSource/Sources/StaticFeatureSource"
import { VariableUiElement } from "../Base/VariableUIElement"
@ -25,6 +24,7 @@ import { MapLibreAdaptor } from "../Map/MapLibreAdaptor"
import ShowDataLayer from "../Map/ShowDataLayer"
import SvelteUIElement from "../Base/SvelteUIElement"
import MaplibreMap from "../Map/MaplibreMap.svelte"
import SpecialVisualizations from "../SpecialVisualizations"
export interface AutoAction extends SpecialVisualization {
supportsAutoAction: boolean
@ -148,19 +148,22 @@ class ApplyButton extends UIElement {
const featureTags = this.state.featureProperties.getStore(targetFeatureId)
const rendering = this.tagRenderingConfig.GetRenderValue(featureTags.data).txt
const specialRenderings = Utils.NoNull(
SubstitutedTranslation.ExtractSpecialComponents(rendering).map((x) => x.special)
).filter((v) => v.func["supportsAutoAction"] === true)
SpecialVisualizations.constructSpecification(rendering)
).filter((v) => typeof v !== "string" && v.func["supportsAutoAction"] === true)
if (specialRenderings.length == 0) {
console.warn(
"AutoApply: feature " +
targetFeatureId +
" got a rendering without supported auto actions:",
targetFeatureId +
" got a rendering without supported auto actions:",
rendering
)
}
for (const specialRendering of specialRenderings) {
if (typeof specialRendering === "string") {
continue
}
const action = <AutoAction>specialRendering.func
await action.applyActionOn(this.state, featureTags, specialRendering.args)
}
@ -225,7 +228,7 @@ export default class AutoApplyButton implements SpecialVisualization {
"To effectively use this button, you'll need some ingredients:",
new List([
"A target layer with features for which an action is defined in a tag rendering. The following special visualisations support an autoAction: " +
supportedActions.join(", "),
supportedActions.join(", "),
"A host feature to place the auto-action on. This can be a big outline (such as a city). Another good option for this is the layer ",
new Link("current_view", "./BuiltinLayers.md#current_view"),
"Then, use a calculated tag on the host feature to determine the overlapping object ids",
@ -245,7 +248,7 @@ export default class AutoApplyButton implements SpecialVisualization {
!(
state.featureSwitchIsTesting.data ||
state.osmConnection._oauth_config.url ===
OsmConnection.oauth_configs["osm-test"].url
OsmConnection.oauth_configs["osm-test"].url
)
) {
const t = Translations.t.general.add.import

View file

@ -5,16 +5,26 @@ import Combine from "../Base/Combine"
import { GeoOperations } from "../../Logic/GeoOperations"
import { Utils } from "../../Utils"
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
import { UIEventSource } from "../../Logic/UIEventSource"
import { Store, UIEventSource } from "../../Logic/UIEventSource"
import { Feature, LineString } from "geojson"
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
export class ExportAsGpxViz implements SpecialVisualization {
funcName = "export_as_gpx"
docs = "Exports the selected feature as GPX-file"
args = []
constr(state: SpecialVisualizationState, tagSource: UIEventSource<Record<string, string>>) {
constr(
state: SpecialVisualizationState,
tagSource: UIEventSource<Record<string, string>>,
argument: string[],
feature: Feature,
layer: LayerConfig
) {
const t = Translations.t.general.download
if (feature.geometry.type !== "LineString") {
return undefined
}
return new SubtleButton(
Svg.download_ui(),
new Combine([
@ -24,10 +34,8 @@ export class ExportAsGpxViz implements SpecialVisualization {
).onClick(() => {
console.log("Exporting as GPX!")
const tags = tagSource.data
const feature = state.indexedFeatures.featuresById.data.get(tags.id)
const layer = state?.layout?.getMatchingLayer(tags)
const gpx = GeoOperations.AsGpx(feature, { layer })
const title = layer.title?.GetRenderValue(tags)?.Subs(tags)?.txt ?? "gpx_track"
const gpx = GeoOperations.toGpx(<Feature<LineString>>feature, title)
Utils.offerContentsAsDownloadableFile(gpx, title + "_mapcomplete_export.gpx", {
mimetype: "{gpx=application/gpx+xml}",
})

View file

@ -9,9 +9,7 @@ import InputElementMap from "../Input/InputElementMap"
import { SaveButton } from "./SaveButton"
import { VariableUiElement } from "../Base/VariableUIElement"
import Translations from "../i18n/Translations"
import { FixedUiElement } from "../Base/FixedUiElement"
import { Translation } from "../i18n/Translation"
import Constants from "../../Models/Constants"
import { SubstitutedTranslation } from "../SubstitutedTranslation"
import { TagsFilter } from "../../Logic/Tags/TagsFilter"
import { Tag } from "../../Logic/Tags/Tag"
@ -19,7 +17,6 @@ import { And } from "../../Logic/Tags/And"
import { TagUtils, UploadableTag } from "../../Logic/Tags/TagUtils"
import BaseUIElement from "../BaseUIElement"
import { DropDown } from "../Input/DropDown"
import InputElementWrapper from "../Input/InputElementWrapper"
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
import TagRenderingConfig, { Mapping } from "../../Models/ThemeConfig/TagRenderingConfig"
import { Unit } from "../../Models/Unit"
@ -626,25 +623,11 @@ export default class TagRenderingQuestion extends Combine {
}
})
let inputTagsFilter: InputElement<UploadableTag> = new InputElementMap(
return new InputElementMap(
input,
(a, b) => a === b || (a?.shadows(b) ?? false),
pickString,
toString
)
if (freeform.inline) {
inputTagsFilter.SetClass("w-48-imp")
inputTagsFilter = new InputElementWrapper(
inputTagsFilter,
configuration.render,
freeform.key,
tags,
state
)
inputTagsFilter.SetClass("block")
}
return inputTagsFilter
}
}

View file

@ -5,6 +5,7 @@ import { GeoLocationPointProperties } from "../../Logic/State/GeoLocationState"
import UploadTraceToOsmUI from "../BigComponents/UploadTraceToOsmUI"
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
import { UIEventSource } from "../../Logic/UIEventSource"
import { GeoOperations } from "../../Logic/GeoOperations"
/**
* Wrapper around 'UploadTraceToOsmUI'
@ -20,38 +21,8 @@ export class UploadToOsmViz implements SpecialVisualization {
featureTags: UIEventSource<Record<string, string>>,
args: string[]
) {
function getTrace(title: string) {
title = title?.trim()
if (title === undefined || title === "") {
title = "Uploaded with MapComplete"
}
title = Utils.EncodeXmlValue(title)
const userLocations = <Feature<Point, GeoLocationPointProperties>[]>(
state.historicalUserLocations.features.data
)
const trackPoints: string[] = []
for (const l of userLocations) {
let trkpt = ` <trkpt lat="${l.geometry.coordinates[1]}" lon="${l.geometry.coordinates[0]}">`
trkpt += ` <time>${l.properties.date}</time>`
if (l.properties.altitude !== null && l.properties.altitude !== undefined) {
trkpt += ` <ele>${l.properties.altitude}</ele>`
}
trkpt += " </trkpt>"
trackPoints.push(trkpt)
}
const header =
'<gpx version="1.1" creator="MapComplete track uploader" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">'
return (
header +
"\n<name>" +
title +
"</name>\n<trk><trkseg>\n" +
trackPoints.join("\n") +
"\n</trkseg></trk></gpx>"
)
}
return new UploadTraceToOsmUI(getTrace, state, {
const locations = state.historicalUserLocations.features.data
return new UploadTraceToOsmUI((title) => GeoOperations.toGpx(locations, title), state, {
whenUploaded: async () => {
state.historicalUserLocations.features.setData([])
},