forked from MapComplete/MapComplete
Refactoring: fix tests
This commit is contained in:
parent
a3242a3c7d
commit
670d2f0b32
4 changed files with 213 additions and 234 deletions
|
@ -1,153 +0,0 @@
|
||||||
import { UIEventSource } from "../../Logic/UIEventSource"
|
|
||||||
import BaseUIElement from "../BaseUIElement"
|
|
||||||
import Translations from "../i18n/Translations"
|
|
||||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
|
||||||
import NearbyImages, { NearbyImageOptions, P4CPicture, SelectOneNearbyImage } from "./NearbyImages"
|
|
||||||
import { SubstitutedTranslation } from "../SubstitutedTranslation"
|
|
||||||
import { Tag } from "../../Logic/Tags/Tag"
|
|
||||||
import ChangeTagAction from "../../Logic/Osm/Actions/ChangeTagAction"
|
|
||||||
import { And } from "../../Logic/Tags/And"
|
|
||||||
import { SaveButton } from "./SaveButton"
|
|
||||||
import Lazy from "../Base/Lazy"
|
|
||||||
import { CheckBox } from "../Input/Checkboxes"
|
|
||||||
import Slider from "../Input/Slider"
|
|
||||||
import AllImageProviders from "../../Logic/ImageProviders/AllImageProviders"
|
|
||||||
import Combine from "../Base/Combine"
|
|
||||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
|
||||||
import Toggle from "../Input/Toggle"
|
|
||||||
import Title from "../Base/Title"
|
|
||||||
import { MapillaryLinkVis } from "./MapillaryLinkVis"
|
|
||||||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
|
||||||
import { Feature } from "geojson"
|
|
||||||
|
|
||||||
export class NearbyImageVis implements SpecialVisualization {
|
|
||||||
args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [
|
|
||||||
{
|
|
||||||
name: "mode",
|
|
||||||
defaultValue: "expandable",
|
|
||||||
doc: "Indicates how this component is initialized. Options are: \n\n- `open`: always show and load the pictures\n- `collapsable`: show the pictures, but a user can collapse them\n- `expandable`: shown by default; but a user can collapse them.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "mapillary",
|
|
||||||
defaultValue: "true",
|
|
||||||
doc: "If 'true', includes a link to mapillary on this location.",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
docs =
|
|
||||||
"A component showing nearby images loaded from various online services such as Mapillary. In edit mode and when used on a feature, the user can select an image to add to the feature"
|
|
||||||
funcName = "nearby_images"
|
|
||||||
|
|
||||||
constr(
|
|
||||||
state: SpecialVisualizationState,
|
|
||||||
tagSource: UIEventSource<Record<string, string>>,
|
|
||||||
args: string[],
|
|
||||||
feature: Feature,
|
|
||||||
layer: LayerConfig
|
|
||||||
): BaseUIElement {
|
|
||||||
const t = Translations.t.image.nearbyPictures
|
|
||||||
const mode: "open" | "expandable" | "collapsable" = <any>args[0]
|
|
||||||
const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
|
|
||||||
const id: string = tagSource.data["id"]
|
|
||||||
const canBeEdited: boolean = !!id?.match("(node|way|relation)/-?[0-9]+")
|
|
||||||
const selectedImage = new UIEventSource<P4CPicture>(undefined)
|
|
||||||
|
|
||||||
let saveButton: BaseUIElement = undefined
|
|
||||||
if (canBeEdited) {
|
|
||||||
const confirmText: BaseUIElement = new SubstitutedTranslation(
|
|
||||||
t.confirm,
|
|
||||||
tagSource,
|
|
||||||
state
|
|
||||||
)
|
|
||||||
|
|
||||||
const onSave = async () => {
|
|
||||||
console.log("Selected a picture...", selectedImage.data)
|
|
||||||
const osmTags = selectedImage.data.osmTags
|
|
||||||
const tags: Tag[] = []
|
|
||||||
for (const key in osmTags) {
|
|
||||||
tags.push(new Tag(key, osmTags[key]))
|
|
||||||
}
|
|
||||||
await state?.changes?.applyAction(
|
|
||||||
new ChangeTagAction(id, new And(tags), tagSource.data, {
|
|
||||||
theme: state?.layout.id,
|
|
||||||
changeType: "link-image",
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
saveButton = new SaveButton(
|
|
||||||
selectedImage,
|
|
||||||
state.osmConnection,
|
|
||||||
confirmText,
|
|
||||||
t.noImageSelected
|
|
||||||
)
|
|
||||||
.onClick(onSave)
|
|
||||||
.SetClass("flex justify-end")
|
|
||||||
}
|
|
||||||
|
|
||||||
const nearby = new Lazy(() => {
|
|
||||||
const towardsCenter = new CheckBox(t.onlyTowards, false)
|
|
||||||
|
|
||||||
const maxSearchRadius = 100
|
|
||||||
const stepSize = 10
|
|
||||||
const defaultValue = Math.floor(maxSearchRadius / (2 * stepSize)) * stepSize
|
|
||||||
const fromOsmPreferences = state?.osmConnection
|
|
||||||
?.GetPreference("nearby-images-radius", "" + defaultValue)
|
|
||||||
.sync(
|
|
||||||
(s) => Number(s),
|
|
||||||
[],
|
|
||||||
(i) => "" + i
|
|
||||||
)
|
|
||||||
const radiusValue = new UIEventSource(fromOsmPreferences.data)
|
|
||||||
radiusValue.addCallbackAndRunD((v) => fromOsmPreferences.setData(v))
|
|
||||||
|
|
||||||
const radius = new Slider(stepSize, maxSearchRadius, {
|
|
||||||
value: radiusValue,
|
|
||||||
step: 10,
|
|
||||||
})
|
|
||||||
const alreadyInTheImage = AllImageProviders.LoadImagesFor(tagSource)
|
|
||||||
const options: NearbyImageOptions & { value } = {
|
|
||||||
lon,
|
|
||||||
lat,
|
|
||||||
searchRadius: maxSearchRadius,
|
|
||||||
shownRadius: radius.GetValue(),
|
|
||||||
value: selectedImage,
|
|
||||||
blacklist: alreadyInTheImage,
|
|
||||||
towardscenter: towardsCenter.GetValue(),
|
|
||||||
maxDaysOld: 365 * 3,
|
|
||||||
}
|
|
||||||
const slideshow = canBeEdited
|
|
||||||
? new SelectOneNearbyImage(options, state.indexedFeatures)
|
|
||||||
: new NearbyImages(options, state.indexedFeatures)
|
|
||||||
const controls = new Combine([
|
|
||||||
towardsCenter,
|
|
||||||
new Combine([
|
|
||||||
new VariableUiElement(
|
|
||||||
radius.GetValue().map((radius) => t.withinRadius.Subs({ radius }))
|
|
||||||
),
|
|
||||||
radius,
|
|
||||||
]).SetClass("flex justify-between"),
|
|
||||||
]).SetClass("flex flex-col")
|
|
||||||
return new Combine([
|
|
||||||
slideshow,
|
|
||||||
controls,
|
|
||||||
saveButton,
|
|
||||||
new MapillaryLinkVis().constr(state, tagSource, [], feature).SetClass("mt-6"),
|
|
||||||
])
|
|
||||||
})
|
|
||||||
|
|
||||||
let withEdit: BaseUIElement = nearby
|
|
||||||
if (canBeEdited) {
|
|
||||||
withEdit = new Combine([t.hasMatchingPicture, nearby]).SetClass("flex flex-col")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mode === "open") {
|
|
||||||
return withEdit
|
|
||||||
}
|
|
||||||
const toggleState = new UIEventSource<boolean>(mode === "collapsable")
|
|
||||||
return new Toggle(
|
|
||||||
new Combine([new Title(t.title), withEdit]),
|
|
||||||
new Title(t.browseNearby).onClick(() => toggleState.setData(true)),
|
|
||||||
toggleState
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
|
||||||
import TagRenderingConfig from "../../Models/ThemeConfig/TagRenderingConfig"
|
|
||||||
import { VariableUiElement } from "../Base/VariableUIElement"
|
|
||||||
import BaseUIElement from "../BaseUIElement"
|
|
||||||
import EditableTagRendering from "./EditableTagRendering"
|
|
||||||
import Combine from "../Base/Combine"
|
|
||||||
import { SpecialVisualization, SpecialVisualizationState } from "../SpecialVisualization"
|
|
||||||
|
|
||||||
export class StealViz implements SpecialVisualization {
|
|
||||||
funcName = "steal"
|
|
||||||
docs = "Shows a tagRendering from a different object as if this was the object itself"
|
|
||||||
args = [
|
|
||||||
{
|
|
||||||
name: "featureId",
|
|
||||||
doc: "The key of the attribute which contains the id of the feature from which to use the tags",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "tagRenderingId",
|
|
||||||
doc: "The layer-id and tagRenderingId to render. Can be multiple value if ';'-separated (in which case every value must also contain the layerId, e.g. `layerId.tagRendering0; layerId.tagRendering1`). Note: this can cause layer injection",
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
constr(state: SpecialVisualizationState, featureTags, args) {
|
|
||||||
const [featureIdKey, layerAndtagRenderingIds] = args
|
|
||||||
const tagRenderings: [LayerConfig, TagRenderingConfig][] = []
|
|
||||||
for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) {
|
|
||||||
const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".")
|
|
||||||
const layer = state.layout.layers.find((l) => l.id === layerId)
|
|
||||||
const tagRendering = layer.tagRenderings.find((tr) => tr.id === tagRenderingId)
|
|
||||||
tagRenderings.push([layer, tagRendering])
|
|
||||||
}
|
|
||||||
if (tagRenderings.length === 0) {
|
|
||||||
throw "Could not create stolen tagrenddering: tagRenderings not found"
|
|
||||||
}
|
|
||||||
return new VariableUiElement(
|
|
||||||
featureTags.map((tags) => {
|
|
||||||
const featureId = tags[featureIdKey]
|
|
||||||
if (featureId === undefined) {
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
const otherTags = state.featureProperties.getStore(featureId)
|
|
||||||
const elements: BaseUIElement[] = []
|
|
||||||
for (const [layer, tagRendering] of tagRenderings) {
|
|
||||||
const el = new EditableTagRendering(
|
|
||||||
otherTags,
|
|
||||||
tagRendering,
|
|
||||||
layer.units,
|
|
||||||
state,
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
elements.push(el)
|
|
||||||
}
|
|
||||||
if (elements.length === 1) {
|
|
||||||
return elements[0]
|
|
||||||
}
|
|
||||||
return new Combine(elements).SetClass("flex flex-col")
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
getLayerDependencies(args): string[] {
|
|
||||||
const [_, tagRenderingId] = args
|
|
||||||
if (tagRenderingId.indexOf(".") < 0) {
|
|
||||||
throw "Error: argument 'layerId.tagRenderingId' of special visualisation 'steal' should contain a dot"
|
|
||||||
}
|
|
||||||
const [layerId, __] = tagRenderingId.split(".")
|
|
||||||
return [layerId]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +1,7 @@
|
||||||
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
import { Store, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import BaseUIElement from "./BaseUIElement"
|
import BaseUIElement from "./BaseUIElement"
|
||||||
import { DefaultGuiState } from "./DefaultGuiState"
|
|
||||||
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
import LayoutConfig from "../Models/ThemeConfig/LayoutConfig"
|
||||||
import {
|
import { IndexedFeatureSource, WritableFeatureSource } from "../Logic/FeatureSource/FeatureSource"
|
||||||
FeatureSource,
|
|
||||||
IndexedFeatureSource,
|
|
||||||
WritableFeatureSource,
|
|
||||||
} from "../Logic/FeatureSource/FeatureSource"
|
|
||||||
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
import { OsmConnection } from "../Logic/Osm/OsmConnection"
|
||||||
import { Changes } from "../Logic/Osm/Changes"
|
import { Changes } from "../Logic/Osm/Changes"
|
||||||
import { MapProperties } from "../Models/MapProperties"
|
import { MapProperties } from "../Models/MapProperties"
|
||||||
|
@ -17,7 +12,6 @@ import { MangroveIdentity } from "../Logic/Web/MangroveReviews"
|
||||||
import { GeoIndexedStoreForLayer } from "../Logic/FeatureSource/Actors/GeoIndexedStore"
|
import { GeoIndexedStoreForLayer } from "../Logic/FeatureSource/Actors/GeoIndexedStore"
|
||||||
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||||
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
import FeatureSwitchState from "../Logic/State/FeatureSwitchState"
|
||||||
import SimpleFeatureSource from "../Logic/FeatureSource/Sources/SimpleFeatureSource"
|
|
||||||
import { MenuState } from "../Models/MenuState"
|
import { MenuState } from "../Models/MenuState"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,7 +9,6 @@ import {
|
||||||
SpecialVisualizationState,
|
SpecialVisualizationState,
|
||||||
} from "./SpecialVisualization"
|
} from "./SpecialVisualization"
|
||||||
import { HistogramViz } from "./Popup/HistogramViz"
|
import { HistogramViz } from "./Popup/HistogramViz"
|
||||||
import { StealViz } from "./Popup/StealViz"
|
|
||||||
import { MinimapViz } from "./Popup/MinimapViz"
|
import { MinimapViz } from "./Popup/MinimapViz"
|
||||||
import { ShareLinkViz } from "./Popup/ShareLinkViz"
|
import { ShareLinkViz } from "./Popup/ShareLinkViz"
|
||||||
import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
|
import { UploadToOsmViz } from "./Popup/UploadToOsmViz"
|
||||||
|
@ -20,7 +19,6 @@ import { PlantNetDetectionViz } from "./Popup/PlantNetDetectionViz"
|
||||||
import { ConflateButton, ImportPointButton, ImportWayButton } from "./Popup/ImportButton"
|
import { ConflateButton, ImportPointButton, ImportWayButton } from "./Popup/ImportButton"
|
||||||
import TagApplyButton from "./Popup/TagApplyButton"
|
import TagApplyButton from "./Popup/TagApplyButton"
|
||||||
import { CloseNoteButton } from "./Popup/CloseNoteButton"
|
import { CloseNoteButton } from "./Popup/CloseNoteButton"
|
||||||
import { NearbyImageVis } from "./Popup/NearbyImageVis"
|
|
||||||
import { MapillaryLinkVis } from "./Popup/MapillaryLinkVis"
|
import { MapillaryLinkVis } from "./Popup/MapillaryLinkVis"
|
||||||
import { Stores, UIEventSource } from "../Logic/UIEventSource"
|
import { Stores, UIEventSource } from "../Logic/UIEventSource"
|
||||||
import AllTagsPanel from "./Popup/AllTagsPanel.svelte"
|
import AllTagsPanel from "./Popup/AllTagsPanel.svelte"
|
||||||
|
@ -63,7 +61,218 @@ import AddNewPoint from "./Popup/AddNewPoint/AddNewPoint.svelte"
|
||||||
import UserProfile from "./BigComponents/UserProfile.svelte"
|
import UserProfile from "./BigComponents/UserProfile.svelte"
|
||||||
import LanguagePicker from "./LanguagePicker"
|
import LanguagePicker from "./LanguagePicker"
|
||||||
import Link from "./Base/Link"
|
import Link from "./Base/Link"
|
||||||
|
import LayerConfig from "../Models/ThemeConfig/LayerConfig"
|
||||||
|
import TagRenderingConfig from "../Models/ThemeConfig/TagRenderingConfig"
|
||||||
|
import EditableTagRendering from "./Popup/EditableTagRendering"
|
||||||
|
import NearbyImages, {
|
||||||
|
NearbyImageOptions,
|
||||||
|
P4CPicture,
|
||||||
|
SelectOneNearbyImage,
|
||||||
|
} from "./Popup/NearbyImages"
|
||||||
|
import { Tag } from "../Logic/Tags/Tag"
|
||||||
|
import ChangeTagAction from "../Logic/Osm/Actions/ChangeTagAction"
|
||||||
|
import { And } from "../Logic/Tags/And"
|
||||||
|
import { SaveButton } from "./Popup/SaveButton"
|
||||||
|
import Lazy from "./Base/Lazy"
|
||||||
|
import { CheckBox } from "./Input/Checkboxes"
|
||||||
|
import Slider from "./Input/Slider"
|
||||||
|
|
||||||
|
class NearbyImageVis implements SpecialVisualization {
|
||||||
|
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
|
||||||
|
args: { name: string; defaultValue?: string; doc: string; required?: boolean }[] = [
|
||||||
|
{
|
||||||
|
name: "mode",
|
||||||
|
defaultValue: "expandable",
|
||||||
|
doc: "Indicates how this component is initialized. Options are: \n\n- `open`: always show and load the pictures\n- `collapsable`: show the pictures, but a user can collapse them\n- `expandable`: shown by default; but a user can collapse them.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mapillary",
|
||||||
|
defaultValue: "true",
|
||||||
|
doc: "If 'true', includes a link to mapillary on this location.",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
docs =
|
||||||
|
"A component showing nearby images loaded from various online services such as Mapillary. In edit mode and when used on a feature, the user can select an image to add to the feature"
|
||||||
|
funcName = "nearby_images"
|
||||||
|
|
||||||
|
constr(
|
||||||
|
state: SpecialVisualizationState,
|
||||||
|
tagSource: UIEventSource<Record<string, string>>,
|
||||||
|
args: string[],
|
||||||
|
feature: Feature,
|
||||||
|
layer: LayerConfig
|
||||||
|
): BaseUIElement {
|
||||||
|
const t = Translations.t.image.nearbyPictures
|
||||||
|
const mode: "open" | "expandable" | "collapsable" = <any>args[0]
|
||||||
|
const [lon, lat] = GeoOperations.centerpointCoordinates(feature)
|
||||||
|
const id: string = tagSource.data["id"]
|
||||||
|
const canBeEdited: boolean = !!id?.match("(node|way|relation)/-?[0-9]+")
|
||||||
|
const selectedImage = new UIEventSource<P4CPicture>(undefined)
|
||||||
|
|
||||||
|
let saveButton: BaseUIElement = undefined
|
||||||
|
if (canBeEdited) {
|
||||||
|
const confirmText: BaseUIElement = new SubstitutedTranslation(
|
||||||
|
t.confirm,
|
||||||
|
tagSource,
|
||||||
|
state
|
||||||
|
)
|
||||||
|
|
||||||
|
const onSave = async () => {
|
||||||
|
console.log("Selected a picture...", selectedImage.data)
|
||||||
|
const osmTags = selectedImage.data.osmTags
|
||||||
|
const tags: Tag[] = []
|
||||||
|
for (const key in osmTags) {
|
||||||
|
tags.push(new Tag(key, osmTags[key]))
|
||||||
|
}
|
||||||
|
await state?.changes?.applyAction(
|
||||||
|
new ChangeTagAction(id, new And(tags), tagSource.data, {
|
||||||
|
theme: state?.layout.id,
|
||||||
|
changeType: "link-image",
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
saveButton = new SaveButton(
|
||||||
|
selectedImage,
|
||||||
|
state.osmConnection,
|
||||||
|
confirmText,
|
||||||
|
t.noImageSelected
|
||||||
|
)
|
||||||
|
.onClick(onSave)
|
||||||
|
.SetClass("flex justify-end")
|
||||||
|
}
|
||||||
|
|
||||||
|
const nearby = new Lazy(() => {
|
||||||
|
const towardsCenter = new CheckBox(t.onlyTowards, false)
|
||||||
|
|
||||||
|
const maxSearchRadius = 100
|
||||||
|
const stepSize = 10
|
||||||
|
const defaultValue = Math.floor(maxSearchRadius / (2 * stepSize)) * stepSize
|
||||||
|
const fromOsmPreferences = state?.osmConnection
|
||||||
|
?.GetPreference("nearby-images-radius", "" + defaultValue)
|
||||||
|
.sync(
|
||||||
|
(s) => Number(s),
|
||||||
|
[],
|
||||||
|
(i) => "" + i
|
||||||
|
)
|
||||||
|
const radiusValue = new UIEventSource(fromOsmPreferences.data)
|
||||||
|
radiusValue.addCallbackAndRunD((v) => fromOsmPreferences.setData(v))
|
||||||
|
|
||||||
|
const radius = new Slider(stepSize, maxSearchRadius, {
|
||||||
|
value: radiusValue,
|
||||||
|
step: 10,
|
||||||
|
})
|
||||||
|
const alreadyInTheImage = AllImageProviders.LoadImagesFor(tagSource)
|
||||||
|
const options: NearbyImageOptions & { value } = {
|
||||||
|
lon,
|
||||||
|
lat,
|
||||||
|
searchRadius: maxSearchRadius,
|
||||||
|
shownRadius: radius.GetValue(),
|
||||||
|
value: selectedImage,
|
||||||
|
blacklist: alreadyInTheImage,
|
||||||
|
towardscenter: towardsCenter.GetValue(),
|
||||||
|
maxDaysOld: 365 * 3,
|
||||||
|
}
|
||||||
|
const slideshow = canBeEdited
|
||||||
|
? new SelectOneNearbyImage(options, state.indexedFeatures)
|
||||||
|
: new NearbyImages(options, state.indexedFeatures)
|
||||||
|
const controls = new Combine([
|
||||||
|
towardsCenter,
|
||||||
|
new Combine([
|
||||||
|
new VariableUiElement(
|
||||||
|
radius.GetValue().map((radius) => t.withinRadius.Subs({ radius }))
|
||||||
|
),
|
||||||
|
radius,
|
||||||
|
]).SetClass("flex justify-between"),
|
||||||
|
]).SetClass("flex flex-col")
|
||||||
|
return new Combine([
|
||||||
|
slideshow,
|
||||||
|
controls,
|
||||||
|
saveButton,
|
||||||
|
new MapillaryLinkVis().constr(state, tagSource, [], feature).SetClass("mt-6"),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
let withEdit: BaseUIElement = nearby
|
||||||
|
if (canBeEdited) {
|
||||||
|
withEdit = new Combine([t.hasMatchingPicture, nearby]).SetClass("flex flex-col")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode === "open") {
|
||||||
|
return withEdit
|
||||||
|
}
|
||||||
|
const toggleState = new UIEventSource<boolean>(mode === "collapsable")
|
||||||
|
return new Toggle(
|
||||||
|
new Combine([new Title(t.title), withEdit]),
|
||||||
|
new Title(t.browseNearby).onClick(() => toggleState.setData(true)),
|
||||||
|
toggleState
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StealViz implements SpecialVisualization {
|
||||||
|
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
|
||||||
|
|
||||||
|
funcName = "steal"
|
||||||
|
docs = "Shows a tagRendering from a different object as if this was the object itself"
|
||||||
|
args = [
|
||||||
|
{
|
||||||
|
name: "featureId",
|
||||||
|
doc: "The key of the attribute which contains the id of the feature from which to use the tags",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tagRenderingId",
|
||||||
|
doc: "The layer-id and tagRenderingId to render. Can be multiple value if ';'-separated (in which case every value must also contain the layerId, e.g. `layerId.tagRendering0; layerId.tagRendering1`). Note: this can cause layer injection",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
constr(state: SpecialVisualizationState, featureTags, args) {
|
||||||
|
const [featureIdKey, layerAndtagRenderingIds] = args
|
||||||
|
const tagRenderings: [LayerConfig, TagRenderingConfig][] = []
|
||||||
|
for (const layerAndTagRenderingId of layerAndtagRenderingIds.split(";")) {
|
||||||
|
const [layerId, tagRenderingId] = layerAndTagRenderingId.trim().split(".")
|
||||||
|
const layer = state.layout.layers.find((l) => l.id === layerId)
|
||||||
|
const tagRendering = layer.tagRenderings.find((tr) => tr.id === tagRenderingId)
|
||||||
|
tagRenderings.push([layer, tagRendering])
|
||||||
|
}
|
||||||
|
if (tagRenderings.length === 0) {
|
||||||
|
throw "Could not create stolen tagrenddering: tagRenderings not found"
|
||||||
|
}
|
||||||
|
return new VariableUiElement(
|
||||||
|
featureTags.map((tags) => {
|
||||||
|
const featureId = tags[featureIdKey]
|
||||||
|
if (featureId === undefined) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
const otherTags = state.featureProperties.getStore(featureId)
|
||||||
|
const elements: BaseUIElement[] = []
|
||||||
|
for (const [layer, tagRendering] of tagRenderings) {
|
||||||
|
const el = new EditableTagRendering(
|
||||||
|
otherTags,
|
||||||
|
tagRendering,
|
||||||
|
layer.units,
|
||||||
|
state,
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
elements.push(el)
|
||||||
|
}
|
||||||
|
if (elements.length === 1) {
|
||||||
|
return elements[0]
|
||||||
|
}
|
||||||
|
return new Combine(elements).SetClass("flex flex-col")
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
getLayerDependencies(args): string[] {
|
||||||
|
const [_, tagRenderingId] = args
|
||||||
|
if (tagRenderingId.indexOf(".") < 0) {
|
||||||
|
throw "Error: argument 'layerId.tagRenderingId' of special visualisation 'steal' should contain a dot"
|
||||||
|
}
|
||||||
|
const [layerId, __] = tagRenderingId.split(".")
|
||||||
|
return [layerId]
|
||||||
|
}
|
||||||
|
}
|
||||||
export default class SpecialVisualizations {
|
export default class SpecialVisualizations {
|
||||||
public static specialVisualizations: SpecialVisualization[] = SpecialVisualizations.initList()
|
public static specialVisualizations: SpecialVisualization[] = SpecialVisualizations.initList()
|
||||||
|
|
||||||
|
@ -987,8 +1196,7 @@ export default class SpecialVisualizations {
|
||||||
constr(
|
constr(
|
||||||
state: SpecialVisualizationState,
|
state: SpecialVisualizationState,
|
||||||
tagSource: UIEventSource<Record<string, string>>,
|
tagSource: UIEventSource<Record<string, string>>,
|
||||||
args: string[],
|
args: string[]
|
||||||
feature: Feature
|
|
||||||
): BaseUIElement {
|
): BaseUIElement {
|
||||||
const [text, href] = args
|
const [text, href] = args
|
||||||
return new VariableUiElement(
|
return new VariableUiElement(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue