Improve 'slopes' input, add compass indicator
This commit is contained in:
parent
b7175384f9
commit
7a3cb9fbdd
17 changed files with 268 additions and 108 deletions
|
@ -281,11 +281,17 @@
|
|||
"openTheMap": "Open the map",
|
||||
"openTheMapAtGeolocation": "Zoom to your location",
|
||||
"opening_hours": {
|
||||
"all_days_from": "Opened every day {ranges}",
|
||||
"closed_permanently": "Closed for an unknown duration",
|
||||
"closed_until": "Closed until {date}",
|
||||
"error": "Could not parse the opening hours",
|
||||
"error_loading": "Error: could not visualize these opening hours.",
|
||||
"friday": "On friday {ranges}",
|
||||
"loadingCountry": "Determining country…",
|
||||
"monday": "On monday {ranges}",
|
||||
"not_all_rules_parsed": "These opening hours are complicated. The following rules are ignored in the input element:",
|
||||
"on_weekdays": "Opened on weekdays {ranges}",
|
||||
"on_weekends": "Opened on weekends {ranges}",
|
||||
"openTill": "till",
|
||||
"open_24_7": "Open around the clock",
|
||||
"open_during_ph": "During a public holiday, this is",
|
||||
|
@ -293,7 +299,15 @@
|
|||
"ph_closed": "closed",
|
||||
"ph_not_known": " ",
|
||||
"ph_open": "open",
|
||||
"ph_open_as_usual": "open, as usual"
|
||||
"ph_open_as_usual": "open, as usual",
|
||||
"ranges": "from {starttime} till {endtime}",
|
||||
"rangescombined": "{range0} and {range1}",
|
||||
"saturday": "On saturday {ranges}",
|
||||
"sunday": "On sunday {ranges}",
|
||||
"thursday": "On thursday {ranges}",
|
||||
"tuesday": "On tuesday {ranges}",
|
||||
"unknown": "The opening hours are unkown",
|
||||
"wednesday": "On wednesday {ranges}"
|
||||
},
|
||||
"osmLinkTooltip": "Browse this object on OpenStreetMap for history and more editing options",
|
||||
"pdf": {
|
||||
|
|
|
@ -551,6 +551,9 @@ export class OsmConnection {
|
|||
|
||||
private UpdateCapabilities(): void {
|
||||
const self = this
|
||||
if (this.fakeUser) {
|
||||
return
|
||||
}
|
||||
this.FetchCapabilities().then(({ api, gpx }) => {
|
||||
self.apiIsOnline.setData(api)
|
||||
self.gpxServiceIsOnline.setData(gpx)
|
||||
|
|
80
src/Logic/Web/Orientation.ts
Normal file
80
src/Logic/Web/Orientation.ts
Normal file
|
@ -0,0 +1,80 @@
|
|||
import { UIEventSource } from "../UIEventSource"
|
||||
|
||||
/**
|
||||
* Exports the device orientation as UIEventSources and detects 'shakes'
|
||||
*/
|
||||
export class Orientation {
|
||||
public static singleton = new Orientation()
|
||||
|
||||
public gotMeasurement: UIEventSource<boolean> = new UIEventSource<boolean>(false)
|
||||
/**
|
||||
* The direction wrt to the magnetic north, with clockwise = positive.
|
||||
* 0 degrees is pointing towards the north
|
||||
* 90° is east,
|
||||
* 180° is south
|
||||
* 270° is west
|
||||
*
|
||||
* Note that this is the opposite of what the DeviceOrientationEvent uses!
|
||||
* */
|
||||
public alpha: UIEventSource<number> = new UIEventSource<number>(undefined)
|
||||
public beta: UIEventSource<number> = new UIEventSource<number>(undefined)
|
||||
public gamma: UIEventSource<number> = new UIEventSource<number>(undefined)
|
||||
/**
|
||||
* Indicates if 'alpha' is with the actual magnetic field or just mimicks that
|
||||
*/
|
||||
public absolute: UIEventSource<boolean> = new UIEventSource<boolean>(undefined)
|
||||
/**
|
||||
* A derivate of beta and gamma
|
||||
* An arrow pointing up, rotated with this amount should more or less point towards the sky
|
||||
* Used in the slope input
|
||||
*/
|
||||
public arrowDirection: UIEventSource<number> = new UIEventSource(undefined)
|
||||
private _measurementsStarted = false
|
||||
|
||||
constructor() {
|
||||
this.fakeMeasurements()
|
||||
}
|
||||
|
||||
public fakeMeasurements() {
|
||||
this.alpha.setData(45)
|
||||
this.beta.setData(20)
|
||||
this.gamma.setData(30)
|
||||
this.absolute.setData(true)
|
||||
this.gotMeasurement.setData(true)
|
||||
}
|
||||
|
||||
public startMeasurements() {
|
||||
if (this._measurementsStarted) {
|
||||
return
|
||||
}
|
||||
this._measurementsStarted = true
|
||||
console.log("Starting device orientation listener")
|
||||
try {
|
||||
window.addEventListener("deviceorientationabsolute", (e: DeviceOrientationEvent) =>
|
||||
this.update(e)
|
||||
)
|
||||
} catch (e) {
|
||||
console.log("Could not init device orientation api due to", e)
|
||||
}
|
||||
}
|
||||
|
||||
private update(event: DeviceOrientationEvent) {
|
||||
this.gotMeasurement.setData(true)
|
||||
// IF the phone is lying flat, then:
|
||||
// alpha is the compass direction (but not absolute)
|
||||
// beta is tilt if you would lift the phone towards you
|
||||
// gamma is rotation if you rotate the phone along the long axis
|
||||
|
||||
// Note: the event uses _counterclockwise_ = positive for alpha
|
||||
// However, we use _clockwise_ = positive throughout the application, so we use '-' here!
|
||||
this.alpha.setData(Math.floor(360 - event.alpha))
|
||||
this.beta.setData(Math.floor(event.beta))
|
||||
this.gamma.setData(Math.floor(event.gamma))
|
||||
this.absolute.setData(event.absolute)
|
||||
if (this.beta.data < 0) {
|
||||
this.arrowDirection.setData(this.gamma.data + 180)
|
||||
} else {
|
||||
this.arrowDirection.setData(-this.gamma.data)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -518,6 +518,13 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
|||
if (this.selectedElement.data !== undefined) {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
this.guistate.menuIsOpened.data ||
|
||||
this.guistate.themeIsOpened.data ||
|
||||
this.previewedImage.data !== undefined
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.selectClosestAtCenter(0)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* A round button with an icon and possible a small text, which hovers above the map
|
||||
*/
|
||||
const dispatch = createEventDispatcher()
|
||||
export let cls = ""
|
||||
export let cls = "m-0.5 p-0.5 sm:p-1 md:m-1"
|
||||
export let arialabel: Translation = undefined
|
||||
</script>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
|||
on:click={(e) => dispatch("click", e)}
|
||||
on:keydown
|
||||
use:ariaLabel={arialabel}
|
||||
class={twJoin("pointer-events-auto m-0.5 h-fit w-fit rounded-full p-0.5 sm:p-1 md:m-1", cls)}
|
||||
class={twJoin("pointer-events-auto h-fit w-fit rounded-full", cls)}
|
||||
>
|
||||
<slot />
|
||||
</button>
|
||||
|
|
|
@ -92,9 +92,9 @@ export class GeolocationControl extends VariableUiElement {
|
|||
this._lastClickWithinThreeSecs = lastClickWithinThreeSecs
|
||||
|
||||
this.onClick(() => this.handleClick())
|
||||
Hotkeys.RegisterHotkey({ nomod: "L" }, Translations.t.hotkeyDocumentation.geolocate, () =>
|
||||
Hotkeys.RegisterHotkey({ nomod: "L" }, Translations.t.hotkeyDocumentation.geolocate, () => {
|
||||
this.handleClick()
|
||||
)
|
||||
})
|
||||
|
||||
lastClick.addCallbackAndRunD((_) => {
|
||||
window.setTimeout(() => {
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||
import TagRenderingAnswer from "../Popup/TagRendering/TagRenderingAnswer.svelte"
|
||||
import { GeoOperations } from "../../Logic/GeoOperations"
|
||||
import { Store } from "../../Logic/UIEventSource"
|
||||
|
||||
export let state: SpecialVisualizationState
|
||||
export let feature: Feature
|
||||
|
@ -16,11 +18,22 @@
|
|||
state.selectedLayer.setData(layer)
|
||||
state.selectedElement.setData(feature)
|
||||
}
|
||||
|
||||
let bearingAndDist: Store<{ bearing: number, dist: number }> = state.mapProperties.location.map(l => {
|
||||
let fcenter = GeoOperations.centerpointCoordinates(feature)
|
||||
let mapCenter = [l.lon, l.lat]
|
||||
|
||||
let bearing = Math.round(GeoOperations.bearing(fcenter, mapCenter))
|
||||
let dist = Math.round(GeoOperations.distanceBetween(fcenter, mapCenter))
|
||||
return { bearing, dist }
|
||||
},
|
||||
)
|
||||
</script>
|
||||
|
||||
<button class="cursor-pointer small" on:click={() => select()}>
|
||||
<button class="cursor-pointer small flex" on:click={() => select()}>
|
||||
{#if i !== undefined}
|
||||
<span class="font-bold">{i + 1}.</span>
|
||||
{/if}
|
||||
<TagRenderingAnswer config={layer.title} {layer} selectedElement={feature} {state} {tags} />
|
||||
<span class="flex">{$bearingAndDist.dist}m {$bearingAndDist.bearing}°</span>
|
||||
</button>
|
||||
|
|
22
src/UI/Debug/OrientationDebugPanel.svelte
Normal file
22
src/UI/Debug/OrientationDebugPanel.svelte
Normal file
|
@ -0,0 +1,22 @@
|
|||
<script lang="ts">
|
||||
import { Orientation } from "../../Logic/Web/Orientation"
|
||||
|
||||
const o = Orientation.singleton
|
||||
let alpha = o.alpha
|
||||
let beta = o.beta
|
||||
let gamma = o.gamma
|
||||
let absolute = o.absolute
|
||||
let gotMeasurement = o.gotMeasurement
|
||||
o.startMeasurements()
|
||||
</script>
|
||||
{#if !$gotMeasurement}
|
||||
No device orientation data available
|
||||
{:else}
|
||||
Device orientation data:
|
||||
<ol>
|
||||
<li>Alpha: {$alpha}</li>
|
||||
<li>Beta: {$beta}</li>
|
||||
<li>Gamma: {$gamma}</li>
|
||||
<li>Absolute?: {$absolute}</li>
|
||||
</ol>
|
||||
{/if}
|
|
@ -1,112 +1,92 @@
|
|||
<script lang="ts">
|
||||
import { UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import { ArrowUpIcon } from "@babeard/svelte-heroicons/mini"
|
||||
import { ImmutableStore, UIEventSource } from "../../../Logic/UIEventSource"
|
||||
import Translations from "../../i18n/Translations"
|
||||
import Tr from "../../Base/Tr.svelte"
|
||||
import { Orientation } from "../../../Logic/Web/Orientation"
|
||||
import type { Feature } from "geojson"
|
||||
import { GeoOperations } from "../../../Logic/GeoOperations"
|
||||
import If from "../../Base/If.svelte"
|
||||
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
|
||||
export let value: UIEventSource<string>
|
||||
export let value: UIEventSource<string> = new UIEventSource<string>(undefined)
|
||||
export let mode: "degrees" | "percentage" = "percentage"
|
||||
|
||||
export let preview: UIEventSource<string> = new UIEventSource<string>(undefined)
|
||||
export let feature: Feature = undefined
|
||||
export let state: SpecialVisualizationState = undefined
|
||||
|
||||
let previewMode: "degrees" | "percentage" = mode
|
||||
|
||||
function oppMode(m: "degrees" | "percentage"): "percentage" | "degrees" {
|
||||
if (m === "degrees") {
|
||||
return "percentage"
|
||||
}
|
||||
return "degrees"
|
||||
let featureBearing: number = 45
|
||||
if (feature?.geometry?.type === "LineString") {
|
||||
/* Bearing between -180 and + 180, positive is clockwise*/
|
||||
featureBearing = Math.round(GeoOperations.bearing(
|
||||
feature.geometry.coordinates[0],
|
||||
feature.geometry.coordinates.at(-1),
|
||||
))
|
||||
}
|
||||
|
||||
let previewDegrees: UIEventSource<string> = new UIEventSource<string>(undefined)
|
||||
let previewPercentage: UIEventSource<string> = new UIEventSource<string>(undefined)
|
||||
|
||||
|
||||
function degreesToPercentage(beta: number): string {
|
||||
const perc = Math.tan(beta * Math.PI / 180) * 100
|
||||
const rounded = Math.round(perc / 5) * 5
|
||||
const rounded = Math.round(perc / 2.5) * 2.5
|
||||
return rounded + "%"
|
||||
}
|
||||
|
||||
export let safetyMargin: number = 10
|
||||
if (safetyMargin < 5) {
|
||||
throw "Safetymargin should be at least 5, it is " + JSON.stringify(safetyMargin)
|
||||
}
|
||||
const orientation = Orientation.singleton
|
||||
orientation.startMeasurements()
|
||||
const alpha = orientation.alpha
|
||||
const beta = orientation.beta
|
||||
|
||||
let alpha = new UIEventSource<number>(undefined)
|
||||
let beta = new UIEventSource<number>(undefined)
|
||||
let gamma = new UIEventSource<number>(45)
|
||||
let abs = new UIEventSource<number>(undefined)
|
||||
let gotMeasurement = orientation.gotMeasurement
|
||||
|
||||
let gotMeasurement = new UIEventSource(false)
|
||||
let arrowDirection: number = undefined
|
||||
|
||||
|
||||
function handleOrientation(event) {
|
||||
gotMeasurement.setData(true)
|
||||
// IF the phone is lying flat, then:
|
||||
// alpha is the compass direction (but not absolute)
|
||||
// beta is tilt if you would lift the phone towards you
|
||||
// gamma is rotation if you rotate the phone along the long axis
|
||||
|
||||
alpha.setData(Math.floor(event.alpha))
|
||||
beta.setData(Math.floor(event.beta))
|
||||
gamma.setData(Math.floor(event.gamma))
|
||||
abs.setData((event.absolute))
|
||||
if (beta.data < 0) {
|
||||
arrowDirection = gamma.data + 180
|
||||
} else {
|
||||
arrowDirection = -gamma.data
|
||||
let valuesign = alpha.map(phoneBearing => {
|
||||
if (featureBearing === undefined) {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
// are we going _with_ or _against_ the direction of the feature?
|
||||
|
||||
console.log("Starting device orientation listener")
|
||||
try {
|
||||
window.addEventListener("deviceorientation", e => handleOrientation(e))
|
||||
} catch (e) {
|
||||
console.log("Could not init device orientation api due to", e)
|
||||
}
|
||||
if (featureBearing < 0) {
|
||||
featureBearing += 360
|
||||
}
|
||||
let relativeAngle = Math.abs(featureBearing - phoneBearing) % 360
|
||||
|
||||
if (relativeAngle < 90 || relativeAngle > 270) {
|
||||
return 1
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
|
||||
beta.map(beta => {
|
||||
if (-safetyMargin < arrowDirection && arrowDirection < safetyMargin) {
|
||||
if (mode === "degrees") {
|
||||
value.setData("" + beta + "°")
|
||||
} else {
|
||||
value.setData(degreesToPercentage(beta))
|
||||
}
|
||||
|
||||
if (previewMode === "degrees") {
|
||||
preview.setData("" + beta + "°")
|
||||
} else {
|
||||
preview.setData(degreesToPercentage(beta))
|
||||
}
|
||||
// As one moves forward on a way, a positive incline gets higher, and a negative incline gets lower.
|
||||
let valueSign = valuesign.data
|
||||
|
||||
if (mode === "degrees") {
|
||||
value.setData(valueSign * beta + "°")
|
||||
} else {
|
||||
value.setData(undefined)
|
||||
value.setData(degreesToPercentage(valueSign * beta))
|
||||
}
|
||||
}, [beta])
|
||||
|
||||
previewDegrees.setData(beta + "°")
|
||||
previewPercentage.setData(degreesToPercentage(beta))
|
||||
|
||||
}, [valuesign, beta])
|
||||
|
||||
</script>
|
||||
{#if $gotMeasurement}
|
||||
<div class="flex flex-col m-2">
|
||||
<div class="flex w-full">
|
||||
|
||||
<div class="shrink-0 relative w-32 h-32 p-0 m-0 overflow-hidden"
|
||||
style="border-radius: 9999px; background: greenyellow">
|
||||
<div class="absolute top-0 left-0 w-16 h-16 interactive"
|
||||
style={`transform: rotate( ${-safetyMargin}deg ); transform-origin: 100% 100%`} />
|
||||
<div class="absolute top-0 left-0 w-16 h-16 interactive"
|
||||
style={`transform: rotate( ${90+safetyMargin}deg ); transform-origin: 100% 100%`} />
|
||||
<div class="absolute top-0 mt-8 left-0 w-32 h-32 interactive" />
|
||||
<div class="absolute w-30 h-30 top-0 left-0 rounded-full">
|
||||
<ArrowUpIcon class="" style={`transform: rotate( ${arrowDirection}deg )`} />
|
||||
<div class="font-bold w-full flex justify-around items-center text-5xl">
|
||||
<div>
|
||||
{$previewDegrees}
|
||||
</div>
|
||||
<div>
|
||||
{$previewPercentage}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="font-bold w-full flex justify-center items-center">
|
||||
{#if $value}
|
||||
<div class="text-5xl" on:click={() => {previewMode = oppMode(previewMode)}}>
|
||||
{$preview}
|
||||
</div>
|
||||
{:else}
|
||||
<Tr cls="alert" t={Translations.t.validation.slope.inputIncorrect} />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
@ -114,5 +94,16 @@
|
|||
<div>
|
||||
<Tr t={Translations.t.validation.slope.inputExplanation} />
|
||||
</div>
|
||||
|
||||
<If condition={state?.featureSwitchIsTesting ?? new ImmutableStore(true)}>
|
||||
<span class="subtle">
|
||||
Way: {featureBearing}°, compass: {$alpha}°, diff: {(featureBearing - $alpha)}
|
||||
{#if $valuesign === 1}
|
||||
Forward
|
||||
{:else}
|
||||
Backward
|
||||
{/if}
|
||||
</span>
|
||||
</If>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
import InputHelpers from "./InputHelpers"
|
||||
import ToSvelte from "../Base/ToSvelte.svelte"
|
||||
import type { Feature } from "geojson"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
import ImageHelper from "./Helpers/ImageHelper.svelte"
|
||||
import TranslationInput from "./Helpers/TranslationInput.svelte"
|
||||
import TagInput from "./Helpers/TagInput.svelte"
|
||||
|
@ -19,17 +18,16 @@
|
|||
import ColorInput from "./Helpers/ColorInput.svelte"
|
||||
import OpeningHoursInput from "./Helpers/OpeningHoursInput.svelte"
|
||||
import SlopeInput from "./Helpers/SlopeInput.svelte"
|
||||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
||||
|
||||
export let type: ValidatorType
|
||||
export let value: UIEventSource<string | object>
|
||||
|
||||
export let feature: Feature
|
||||
export let args: (string | number | boolean)[] = undefined
|
||||
export let state: SpecialVisualizationState
|
||||
|
||||
let properties = { feature, args: args ?? [] }
|
||||
let dispatch = createEventDispatcher<{
|
||||
selected
|
||||
}>()
|
||||
</script>
|
||||
|
||||
{#if type === "translation"}
|
||||
|
@ -49,7 +47,7 @@
|
|||
{:else if type === "opening_hours"}
|
||||
<OpeningHoursInput {value} />
|
||||
{:else if type === "slope"}
|
||||
<SlopeInput {value} />
|
||||
<SlopeInput {value} {feature} {state} />
|
||||
{:else if type === "wikidata"}
|
||||
<ToSvelte construct={() => InputHelpers.constructWikidataHelper(value, properties)} />
|
||||
{/if}
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
import NatValidator from "./NatValidator"
|
||||
import FloatValidator from "./FloatValidator"
|
||||
|
||||
export default class SlopeValidator extends NatValidator {
|
||||
export default class SlopeValidator extends FloatValidator {
|
||||
constructor() {
|
||||
super("slope", "Validates that the slope is a valid number")
|
||||
super(
|
||||
"slope",
|
||||
"Validates that the slope is a valid number." +
|
||||
"The accompanying input element uses the gyroscope and the compass to determine the correct incline. The sign of the incline will be set automatically. The bearing of the way is compared to the bearing of the compass, as such, the device knows if it is measuring in the forward or backward direction."
|
||||
)
|
||||
}
|
||||
isValid(str: string): boolean {
|
||||
if (str.endsWith("%") || str.endsWith("°")) {
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
const canvas = _map.getCanvas()
|
||||
ariaLabel(canvas, Translations.t.general.visualFeedback.navigation)
|
||||
canvas.role="application"
|
||||
canvas.tabIndex = 0
|
||||
})
|
||||
map.set(_map)
|
||||
})
|
||||
|
|
|
@ -9,12 +9,14 @@
|
|||
import type { Feature } from "geojson"
|
||||
import { Unit } from "../../../Models/Unit"
|
||||
import InputHelpers from "../../InputElement/InputHelpers"
|
||||
import type { SpecialVisualizationState } from "../../SpecialVisualization"
|
||||
|
||||
export let value: UIEventSource<string>
|
||||
export let config: TagRenderingConfig
|
||||
export let tags: UIEventSource<Record<string, string>>
|
||||
|
||||
export let feature: Feature = undefined
|
||||
export let state: SpecialVisualizationState
|
||||
export let unit: Unit | undefined
|
||||
|
||||
let placeholder = config.freeform?.placeholder
|
||||
|
@ -70,6 +72,7 @@
|
|||
{feature}
|
||||
type={config.freeform.type}
|
||||
{value}
|
||||
{state}
|
||||
on:submit
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -254,6 +254,7 @@
|
|||
{tags}
|
||||
{feedback}
|
||||
{unit}
|
||||
{state}
|
||||
feature={selectedElement}
|
||||
value={freeformInput}
|
||||
on:submit={onSave}
|
||||
|
@ -296,6 +297,7 @@
|
|||
{tags}
|
||||
{feedback}
|
||||
{unit}
|
||||
{state}
|
||||
feature={selectedElement}
|
||||
value={freeformInput}
|
||||
on:selected={() => (selectedMapping = config.mappings?.length)}
|
||||
|
@ -338,6 +340,7 @@
|
|||
{tags}
|
||||
{feedback}
|
||||
{unit}
|
||||
{state}
|
||||
feature={selectedElement}
|
||||
value={freeformInput}
|
||||
on:submit={onSave}
|
||||
|
|
|
@ -83,6 +83,7 @@ import NearbyImagesCollapsed from "./Image/NearbyImagesCollapsed.svelte"
|
|||
import MoveWizard from "./Popup/MoveWizard.svelte"
|
||||
import { Unit } from "../Models/Unit"
|
||||
import Link from "./Base/Link.svelte"
|
||||
import OrientationDebugPanel from "./Debug/OrientationDebugPanel.svelte"
|
||||
|
||||
class NearbyImageVis implements SpecialVisualization {
|
||||
// Class must be in SpecialVisualisations due to weird cyclical import that breaks the tests
|
||||
|
@ -1536,10 +1537,13 @@ export default class SpecialVisualizations {
|
|||
)).geolocation.currentUserLocation.features.map(
|
||||
(features) => features[0]?.properties
|
||||
)
|
||||
return new SvelteUIElement(AllTagsPanel, {
|
||||
state,
|
||||
tags,
|
||||
})
|
||||
return new Combine([
|
||||
new SvelteUIElement(OrientationDebugPanel, {}),
|
||||
new SvelteUIElement(AllTagsPanel, {
|
||||
state,
|
||||
tags,
|
||||
}),
|
||||
])
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
|
@ -2,10 +2,9 @@
|
|||
// Testing grounds
|
||||
import { UIEventSource } from "../Logic/UIEventSource"
|
||||
import SlopeInput from "./InputElement/Helpers/SlopeInput.svelte"
|
||||
import OrientationDebugPanel from "./Debug/OrientationDebugPanel.svelte"
|
||||
let value: UIEventSource<string> = new UIEventSource(undefined)
|
||||
</script>
|
||||
|
||||
<div class="w-full flex flex-col">
|
||||
<div>Value: {$value}</div>
|
||||
</div>
|
||||
<SlopeInput {value}></SlopeInput>
|
||||
<OrientationDebugPanel/>
|
||||
<SlopeInput />
|
||||
|
|
|
@ -64,12 +64,15 @@
|
|||
import Favourites from "./Favourites/Favourites.svelte"
|
||||
import ImageOperations from "./Image/ImageOperations.svelte"
|
||||
import VisualFeedbackPanel from "./BigComponents/VisualFeedbackPanel.svelte"
|
||||
import { Orientation } from "../Logic/Web/Orientation"
|
||||
|
||||
export let state: ThemeViewState
|
||||
let layout = state.layout
|
||||
let maplibremap: UIEventSource<MlMap> = state.map
|
||||
let selectedElement: UIEventSource<Feature> = new UIEventSource<Feature>(undefined)
|
||||
|
||||
let compass = Orientation.singleton.alpha
|
||||
let compassLoaded = Orientation.singleton.gotMeasurement
|
||||
state.selectedElement.addCallback(selected => {
|
||||
if (!selected) {
|
||||
selectedElement.setData(selected)
|
||||
|
@ -258,15 +261,29 @@
|
|||
<Min class="h-8 w-8" />
|
||||
</MapControlButton>
|
||||
<If condition={featureSwitches.featureSwitchGeolocation}>
|
||||
<MapControlButton arialabel={Translations.t.general.labels.jumpToLocation}
|
||||
on:click={() => geolocationControl.handleClick()}
|
||||
on:keydown={forwardEventToMap}
|
||||
>
|
||||
<ToSvelte
|
||||
construct={geolocationControl.SetClass("block w-8 h-8")}
|
||||
/>
|
||||
</MapControlButton>
|
||||
<div class="relative m-0.5 h-12 w-12 p-0 sm:p-1 md:m-1">
|
||||
{#if $compassLoaded}
|
||||
<div class="absolute top-1/2 left-1/2 w-0 h-0">
|
||||
<div class="w-5 h-5"
|
||||
style={`rotate: calc(${-$compass}deg + 225deg); transform-origin: 0% 0%; background: var(--button-background);`} />
|
||||
</div>
|
||||
{/if}
|
||||
<div class="absolute top-0 left-0 p-0.5 md:p-1">
|
||||
|
||||
<MapControlButton arialabel={Translations.t.general.labels.jumpToLocation}
|
||||
cls="m-0 p-0.5 sm:p-1"
|
||||
on:click={() => geolocationControl.handleClick()}
|
||||
on:keydown={forwardEventToMap}
|
||||
>
|
||||
<ToSvelte
|
||||
construct={geolocationControl.SetClass("block w-8 h-8")}
|
||||
/>
|
||||
</MapControlButton>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</If>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue