forked from MapComplete/MapComplete
		
	Better compass arrow
This commit is contained in:
		
							parent
							
								
									ba47d1bfad
								
							
						
					
					
						commit
						82409984dc
					
				
					 15 changed files with 219 additions and 114 deletions
				
			
		|  | @ -1,9 +1,39 @@ | ||||||
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
| <svg xmlns="http://www.w3.org/2000/svg" width="375px" height="375px" viewBox="0 0 375 375" version="1.1"> | <svg | ||||||
|     <g id="surface1"> |    width="375px" | ||||||
|         <path |    height="375px" | ||||||
|                 style="fill:#000000;" |    viewBox="0 0 375 375" | ||||||
|                 class="selectable" |    version="1.1" | ||||||
|               d="M 375 187.5 C 375 291.054688 291.054688 375 187.5 375 C 83.945312 375 0 291.054688 0 187.5 C 0 83.945312 83.945312 0 187.5 0 C 291.054688 0 375 83.945312 375 187.5 Z M 375 187.5 "/> |    id="svg1" | ||||||
|     </g> |    sodipodi:docname="circle.svg" | ||||||
|  |    inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg"> | ||||||
|  |   <defs | ||||||
|  |      id="defs1" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="namedview1" | ||||||
|  |      pagecolor="#505050" | ||||||
|  |      bordercolor="#eeeeee" | ||||||
|  |      borderopacity="1" | ||||||
|  |      inkscape:showpageshadow="0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pagecheckerboard="0" | ||||||
|  |      inkscape:deskcolor="#d1d1d1" | ||||||
|  |      inkscape:zoom="2.056" | ||||||
|  |      inkscape:cx="187.5" | ||||||
|  |      inkscape:cy="187.5" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="995" | ||||||
|  |      inkscape:window-x="0" | ||||||
|  |      inkscape:window-y="0" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:current-layer="svg1" /> | ||||||
|  |   <path | ||||||
|  |      style="fill:#000000" | ||||||
|  |      class="selectable" | ||||||
|  |      d="M 375,187.5 C 375,291.05469 291.05469,375 187.5,375 83.945312,375 0,291.05469 0,187.5 0,83.945312 83.945312,0 187.5,0 291.05469,0 375,83.945312 375,187.5 Z m 0,0" | ||||||
|  |      id="path1" /> | ||||||
| </svg> | </svg> | ||||||
|  |  | ||||||
| Before Width: | Height: | Size: 486 B After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										39
									
								
								assets/svg/compass_arrow.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								assets/svg/compass_arrow.svg
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | ||||||
|  | <?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||||||
|  | <svg | ||||||
|  |    width="375px" | ||||||
|  |    height="375px" | ||||||
|  |    viewBox="0 0 375 375" | ||||||
|  |    version="1.1" | ||||||
|  |    id="svg1" | ||||||
|  |    sodipodi:docname="compass_arrow.svg" | ||||||
|  |    inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)" | ||||||
|  |    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||||||
|  |    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||||||
|  |    xmlns="http://www.w3.org/2000/svg" | ||||||
|  |    xmlns:svg="http://www.w3.org/2000/svg"> | ||||||
|  |   <defs | ||||||
|  |      id="defs1" /> | ||||||
|  |   <sodipodi:namedview | ||||||
|  |      id="namedview1" | ||||||
|  |      pagecolor="#505050" | ||||||
|  |      bordercolor="#eeeeee" | ||||||
|  |      borderopacity="1" | ||||||
|  |      inkscape:showpageshadow="0" | ||||||
|  |      inkscape:pageopacity="0" | ||||||
|  |      inkscape:pagecheckerboard="0" | ||||||
|  |      inkscape:deskcolor="#d1d1d1" | ||||||
|  |      inkscape:zoom="1.0410569" | ||||||
|  |      inkscape:cx="33.139398" | ||||||
|  |      inkscape:cy="182.98711" | ||||||
|  |      inkscape:window-width="1920" | ||||||
|  |      inkscape:window-height="995" | ||||||
|  |      inkscape:window-x="0" | ||||||
|  |      inkscape:window-y="0" | ||||||
|  |      inkscape:window-maximized="1" | ||||||
|  |      inkscape:current-layer="svg1" /> | ||||||
|  |   <path | ||||||
|  |      id="rect2" | ||||||
|  |      style="fill:#000000;stroke:none;stroke-linecap:round;fill-opacity:1;stroke-opacity:1" | ||||||
|  |      d="M 16.835505,17.477497 79.869453,33.962116 V 80.511444 H 33.96212 Z" | ||||||
|  |      sodipodi:nodetypes="ccccc" /> | ||||||
|  | </svg> | ||||||
| After Width: | Height: | Size: 1.2 KiB | 
							
								
								
									
										2
									
								
								assets/svg/compass_arrow.svg.license
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								assets/svg/compass_arrow.svg.license
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,2 @@ | ||||||
|  | SPDX-FileCopyrightText: Pieter Vander Vennet | ||||||
|  | SPDX-License-Identifier: CC0 | ||||||
|  | @ -241,6 +241,14 @@ | ||||||
|     "authors": [], |     "authors": [], | ||||||
|     "sources": [] |     "sources": [] | ||||||
|   }, |   }, | ||||||
|  |   { | ||||||
|  |     "path": "compass_arrow.svg", | ||||||
|  |     "license": "CC0-1.0", | ||||||
|  |     "authors": [ | ||||||
|  |       "Pieter Vander Vennet" | ||||||
|  |     ], | ||||||
|  |     "sources": [] | ||||||
|  |   }, | ||||||
|   { |   { | ||||||
|     "path": "confirm.svg", |     "path": "confirm.svg", | ||||||
|     "license": "CC0-1.0", |     "license": "CC0-1.0", | ||||||
|  |  | ||||||
|  | @ -729,14 +729,6 @@ video { | ||||||
|   bottom: 0px; |   bottom: 0px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .top-1\/2 { |  | ||||||
|   top: 50%; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .left-1\/2 { |  | ||||||
|   left: 50%; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .right-4 { | .right-4 { | ||||||
|   right: 1rem; |   right: 1rem; | ||||||
| } | } | ||||||
|  | @ -1126,10 +1118,6 @@ video { | ||||||
|   height: 0px; |   height: 0px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .h-5 { |  | ||||||
|   height: 1.25rem; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .h-4 { | .h-4 { | ||||||
|   height: 1rem; |   height: 1rem; | ||||||
| } | } | ||||||
|  | @ -1150,6 +1138,10 @@ video { | ||||||
|   height: 2.75rem; |   height: 2.75rem; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .h-5 { | ||||||
|  |   height: 1.25rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .h-48 { | .h-48 { | ||||||
|   height: 12rem; |   height: 12rem; | ||||||
| } | } | ||||||
|  | @ -1240,10 +1232,6 @@ video { | ||||||
|   width: 0px; |   width: 0px; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .w-5 { |  | ||||||
|   width: 1.25rem; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .w-4 { | .w-4 { | ||||||
|   width: 1rem; |   width: 1rem; | ||||||
| } | } | ||||||
|  | @ -1272,6 +1260,10 @@ video { | ||||||
|   width: auto; |   width: auto; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .w-5 { | ||||||
|  |   width: 1.25rem; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| .w-10 { | .w-10 { | ||||||
|   width: 2.5rem; |   width: 2.5rem; | ||||||
| } | } | ||||||
|  | @ -1346,10 +1338,6 @@ video { | ||||||
|   cursor: pointer; |   cursor: pointer; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .cursor-wait { |  | ||||||
|   cursor: wait; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .resize { | .resize { | ||||||
|   resize: both; |   resize: both; | ||||||
| } | } | ||||||
|  | @ -1745,11 +1733,6 @@ video { | ||||||
|   background-color: rgb(255 255 255 / var(--tw-bg-opacity)); |   background-color: rgb(255 255 255 / var(--tw-bg-opacity)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .bg-red-500 { |  | ||||||
|   --tw-bg-opacity: 1; |  | ||||||
|   background-color: rgb(239 68 68 / var(--tw-bg-opacity)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| .bg-white\/50 { | .bg-white\/50 { | ||||||
|   background-color: rgb(255 255 255 / 0.5); |   background-color: rgb(255 255 255 / 0.5); | ||||||
| } | } | ||||||
|  | @ -2756,6 +2739,18 @@ a.link-underline { | ||||||
|   overflow: visible !important; |   overflow: visible !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .compass_arrow { | ||||||
|  |   width: calc( 2.5rem - 1px ) ; | ||||||
|  |   height: calc( 2.5rem - 1px ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (min-width: 640px) { | ||||||
|  |   .compass_arrow { | ||||||
|  |     width: calc( 2.75rem - 1px ) ; | ||||||
|  |     height: calc( 2.75rem - 1px ) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| @-webkit-keyframes glowing-drop-shadow { | @-webkit-keyframes glowing-drop-shadow { | ||||||
|   from { |   from { | ||||||
|     -webkit-filter: drop-shadow(5px 5px 60px rgb(128 128 128 / 0.6)); |     -webkit-filter: drop-shadow(5px 5px 60px rgb(128 128 128 / 0.6)); | ||||||
|  | @ -2863,6 +2858,10 @@ a.link-underline { | ||||||
|     margin: 0.5rem; |     margin: 0.5rem; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   .sm\:m-1 { | ||||||
|  |     margin: 0.25rem; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   .sm\:mx-1 { |   .sm\:mx-1 { | ||||||
|     margin-left: 0.25rem; |     margin-left: 0.25rem; | ||||||
|     margin-right: 0.25rem; |     margin-right: 0.25rem; | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| import { UIEventSource } from "../UIEventSource" | import { Stores, UIEventSource } from "../UIEventSource" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Exports the device orientation as UIEventSources and detects 'shakes' |  * Exports the device orientation as UIEventSources and detects 'shakes' | ||||||
|  | @ -33,8 +33,19 @@ export class Orientation { | ||||||
| 
 | 
 | ||||||
|     constructor() {} |     constructor() {} | ||||||
| 
 | 
 | ||||||
|     public fakeMeasurements() { |     public fakeMeasurements(rotateAlpha: boolean = true) { | ||||||
|  |         console.log("Starting fake measurements of orientation sensors", { | ||||||
|  |             alpha: this.alpha, | ||||||
|  |             beta: this.beta, | ||||||
|  |             gamma: this.gamma, | ||||||
|  |             absolute: this.absolute, | ||||||
|  |         }) | ||||||
|         this.alpha.setData(45) |         this.alpha.setData(45) | ||||||
|  |         if (rotateAlpha) { | ||||||
|  |             Stores.Chronic(25).addCallback((date) => | ||||||
|  |                 this.alpha.setData(-(date.getTime() / 10) % 360) | ||||||
|  |             ) | ||||||
|  |         } | ||||||
|         this.beta.setData(20) |         this.beta.setData(20) | ||||||
|         this.gamma.setData(30) |         this.gamma.setData(30) | ||||||
|         this.absolute.setData(true) |         this.absolute.setData(true) | ||||||
|  |  | ||||||
|  | @ -60,6 +60,7 @@ import { Imgur } from "../Logic/ImageProviders/Imgur" | ||||||
| import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSource" | import NearbyFeatureSource from "../Logic/FeatureSource/Sources/NearbyFeatureSource" | ||||||
| import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource" | import FavouritesFeatureSource from "../Logic/FeatureSource/Sources/FavouritesFeatureSource" | ||||||
| import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider" | import { ProvidedImage } from "../Logic/ImageProviders/ImageProvider" | ||||||
|  | import { GeolocationControlState } from "../UI/BigComponents/GeolocationControl" | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * |  * | ||||||
|  | @ -112,6 +113,8 @@ export default class ThemeViewState implements SpecialVisualizationState { | ||||||
|     readonly selectedLayer: UIEventSource<LayerConfig> |     readonly selectedLayer: UIEventSource<LayerConfig> | ||||||
|     readonly userRelatedState: UserRelatedState |     readonly userRelatedState: UserRelatedState | ||||||
|     readonly geolocation: GeoLocationHandler |     readonly geolocation: GeoLocationHandler | ||||||
|  |     readonly geolocationControl: GeolocationControlState | ||||||
|  | 
 | ||||||
|     readonly lastGeolocationRequestMoment: UIEventSource<Date> = new UIEventSource<Date>(undefined) |     readonly lastGeolocationRequestMoment: UIEventSource<Date> = new UIEventSource<Date>(undefined) | ||||||
| 
 | 
 | ||||||
|     readonly imageUploadManager: ImageUploadManager |     readonly imageUploadManager: ImageUploadManager | ||||||
|  | @ -191,6 +194,7 @@ export default class ThemeViewState implements SpecialVisualizationState { | ||||||
|             this.mapProperties, |             this.mapProperties, | ||||||
|             this.userRelatedState.gpsLocationHistoryRetentionTime |             this.userRelatedState.gpsLocationHistoryRetentionTime | ||||||
|         ) |         ) | ||||||
|  |         this.geolocationControl = new GeolocationControlState(this.geolocation, this.mapProperties) | ||||||
| 
 | 
 | ||||||
|         this.availableLayers = AvailableRasterLayers.layersAvailableAt(this.mapProperties.location) |         this.availableLayers = AvailableRasterLayers.layersAvailableAt(this.mapProperties.location) | ||||||
| 
 | 
 | ||||||
|  | @ -591,6 +595,13 @@ export default class ThemeViewState implements SpecialVisualizationState { | ||||||
|                 Translations.t.hotkeyDocumentation.selectAerial, |                 Translations.t.hotkeyDocumentation.selectAerial, | ||||||
|                 () => setLayerCategory("photo") |                 () => setLayerCategory("photo") | ||||||
|             ) |             ) | ||||||
|  |             Hotkeys.RegisterHotkey( | ||||||
|  |                 { nomod: "L" }, | ||||||
|  |                 Translations.t.hotkeyDocumentation.geolocate, | ||||||
|  |                 () => { | ||||||
|  |                     this.geolocationControl.handleClick() | ||||||
|  |                 } | ||||||
|  |             ) | ||||||
|             return true |             return true | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -12,11 +12,12 @@ | ||||||
|   export let arialabel: Translation = undefined  |   export let arialabel: Translation = undefined  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  |    | ||||||
| <button | <button | ||||||
|   on:click={(e) => dispatch("click", e)} |   on:click={(e) => dispatch("click", e)} | ||||||
|   on:keydown |   on:keydown | ||||||
|   use:ariaLabel={arialabel} |   use:ariaLabel={arialabel} | ||||||
|   class={twJoin("pointer-events-auto h-fit w-fit rounded-full", cls)} |   class={twJoin("relative pointer-events-auto h-fit w-fit rounded-full", cls)} | ||||||
| > | > | ||||||
|   <slot /> |   <slot /> | ||||||
| </button> | </button> | ||||||
|  |  | ||||||
							
								
								
									
										44
									
								
								src/UI/BigComponents/GeolocationControl.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/UI/BigComponents/GeolocationControl.svelte
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | ||||||
|  | <script lang="ts"> | ||||||
|  |   import Crosshair from "../../assets/svg/Crosshair.svelte" | ||||||
|  |   import Location_refused from "../../assets/svg/Location_refused.svelte" | ||||||
|  |   import { Store } from "../../Logic/UIEventSource.js" | ||||||
|  |   import type { GeolocationPermissionState } from "../../Logic/State/GeoLocationState.js" | ||||||
|  |   import ThemeViewState from "../../Models/ThemeViewState" | ||||||
|  |   import Location_locked from "../../assets/svg/Location_locked.svelte" | ||||||
|  |   import Location_unlocked from "../../assets/svg/Location_unlocked.svelte" | ||||||
|  |   import Location from "../../assets/svg/Location.svelte" | ||||||
|  | 
 | ||||||
|  |   export let state: ThemeViewState | ||||||
|  |   let geolocationstate = state.geolocation.geolocationState | ||||||
|  |   let geopermission: Store<GeolocationPermissionState> = state.geolocation.geolocationState.permission | ||||||
|  |   let allowMoving = geolocationstate.allowMoving | ||||||
|  |   let currentGPSLocation = state.geolocation.geolocationState.currentGPSLocation | ||||||
|  |   let geolocationControlState = state.geolocationControl | ||||||
|  |   let lastClickWasRecent = geolocationControlState.lastClickWithinThreeSecs | ||||||
|  | </script> | ||||||
|  | 
 | ||||||
|  | {#if !$allowMoving} | ||||||
|  |   <Location_locked class="h-8 w-8" /> | ||||||
|  | {:else if $currentGPSLocation !== undefined } | ||||||
|  |   <!-- If we have a location; this implies that the location access was granted --> | ||||||
|  |   {#if $lastClickWasRecent} | ||||||
|  |     <Location_unlocked class="h-8 w-8" /> | ||||||
|  |   {:else} | ||||||
|  |     <Location class="h-8 w-8" /> | ||||||
|  |   {/if} | ||||||
|  | {:else if $geopermission === "prompt"} | ||||||
|  |   <Location class="h-8 w-8" /> | ||||||
|  | {:else if $geopermission === "requested"} | ||||||
|  |   <!-- Even though disabled, when clicking we request the location again in case the contributor dismissed the location popup --> | ||||||
|  |   <Location | ||||||
|  |     class="h-8 w-8" | ||||||
|  |     style="animation: 3s linear 0s infinite normal none running spin;" | ||||||
|  |   /> | ||||||
|  | {:else if $geopermission === "denied"} | ||||||
|  |   <Location_refused class="h-8 w-8" /> | ||||||
|  | {:else} | ||||||
|  |   <Location | ||||||
|  |     class="h-8 w-8" | ||||||
|  |     style="animation: 3s linear 0s infinite normal none running spin;" | ||||||
|  |   /> | ||||||
|  | {/if} | ||||||
|  | @ -1,9 +1,5 @@ | ||||||
| import { VariableUiElement } from "../Base/VariableUIElement" |  | ||||||
| import Svg from "../../Svg" |  | ||||||
| import { Store, UIEventSource } from "../../Logic/UIEventSource" | import { Store, UIEventSource } from "../../Logic/UIEventSource" | ||||||
| import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler" | import GeoLocationHandler from "../../Logic/Actors/GeoLocationHandler" | ||||||
| import Hotkeys from "../Base/Hotkeys" |  | ||||||
| import Translations from "../i18n/Translations" |  | ||||||
| import Constants from "../../Models/Constants" | import Constants from "../../Models/Constants" | ||||||
| import { MapProperties } from "../../Models/MapProperties" | import { MapProperties } from "../../Models/MapProperties" | ||||||
| 
 | 
 | ||||||
|  | @ -11,11 +7,12 @@ import { MapProperties } from "../../Models/MapProperties" | ||||||
|  * Displays an icon depending on the state of the geolocation. |  * Displays an icon depending on the state of the geolocation. | ||||||
|  * Will set the 'lock' if clicked twice |  * Will set the 'lock' if clicked twice | ||||||
|  */ |  */ | ||||||
| export class GeolocationControl extends VariableUiElement { | export class GeolocationControlState { | ||||||
|     public readonly lastClick = new UIEventSource<Date>(undefined) |     public readonly lastClick = new UIEventSource<Date>(undefined) | ||||||
|  |     public readonly lastClickWithinThreeSecs: Store<boolean> | ||||||
|     private readonly _geolocationHandler: GeoLocationHandler |     private readonly _geolocationHandler: GeoLocationHandler | ||||||
|     private readonly _mapProperties: MapProperties |     private readonly _mapProperties: MapProperties | ||||||
|     private readonly _lastClickWithinThreeSecs: Store<boolean> | 
 | ||||||
|     constructor( |     constructor( | ||||||
|         geolocationHandler: GeoLocationHandler, |         geolocationHandler: GeoLocationHandler, | ||||||
|         state: MapProperties, |         state: MapProperties, | ||||||
|  | @ -41,60 +38,12 @@ export class GeolocationControl extends VariableUiElement { | ||||||
|                 return timeDiff <= Constants.zoomToLocationTimeout |                 return timeDiff <= Constants.zoomToLocationTimeout | ||||||
|             } |             } | ||||||
|         ) |         ) | ||||||
|         const geolocationState = geolocationHandler?.geolocationState |  | ||||||
|         super( |  | ||||||
|             geolocationState?.permission?.map( |  | ||||||
|                 (permission) => { |  | ||||||
|                     if (permission === "denied") { |  | ||||||
|                         return Svg.location_refused_svg() |  | ||||||
|                     } |  | ||||||
|                     if (!geolocationState.allowMoving.data) { |  | ||||||
|                         return Svg.location_locked_svg() |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     if (geolocationState.currentGPSLocation.data === undefined) { |  | ||||||
|                         if (permission === "prompt") { |  | ||||||
|                             return Svg.location_empty_svg() |  | ||||||
|                         } |  | ||||||
|                         // Position not yet found, but permission is either requested or granted: we spin to indicate activity
 |  | ||||||
|                         const icon = |  | ||||||
|                             !geolocationHandler.mapHasMoved.data || lastRequestWithinTimeout.data |  | ||||||
|                                 ? Svg.location_svg() |  | ||||||
|                                 : Svg.location_empty_svg() |  | ||||||
|                         return icon |  | ||||||
|                             .SetClass("cursor-wait") |  | ||||||
|                             .SetStyle("animation: spin 4s linear infinite;") |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     // We have a location, so we show a dot in the center
 |  | ||||||
| 
 |  | ||||||
|                     if (lastClickWithinThreeSecs.data) { |  | ||||||
|                         return Svg.location_unlocked_svg() |  | ||||||
|                     } |  | ||||||
| 
 |  | ||||||
|                     // We have a location, so we show a dot in the center
 |  | ||||||
|                     return Svg.location_svg() |  | ||||||
|                 }, |  | ||||||
|                 [ |  | ||||||
|                     geolocationState.currentGPSLocation, |  | ||||||
|                     geolocationState.allowMoving, |  | ||||||
|                     geolocationHandler.mapHasMoved, |  | ||||||
|                     lastClickWithinThreeSecs, |  | ||||||
|                     lastRequestWithinTimeout, |  | ||||||
|                 ] |  | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
|         this._geolocationHandler = geolocationHandler |         this._geolocationHandler = geolocationHandler | ||||||
|         this._mapProperties = state |         this._mapProperties = state | ||||||
| 
 | 
 | ||||||
|         this.lastClick = lastClick |         this.lastClick = lastClick | ||||||
|         this._lastClickWithinThreeSecs = lastClickWithinThreeSecs |         this.lastClickWithinThreeSecs = lastClickWithinThreeSecs | ||||||
| 
 |  | ||||||
|         this.onClick(() => this.handleClick()) |  | ||||||
|         Hotkeys.RegisterHotkey({ nomod: "L" }, Translations.t.hotkeyDocumentation.geolocate, () => { |  | ||||||
|             this.handleClick() |  | ||||||
|         }) |  | ||||||
| 
 | 
 | ||||||
|         lastClick.addCallbackAndRunD((_) => { |         lastClick.addCallbackAndRunD((_) => { | ||||||
|             window.setTimeout(() => { |             window.setTimeout(() => { | ||||||
|  | @ -148,7 +97,7 @@ export class GeolocationControl extends VariableUiElement { | ||||||
|             state.zoom.update((z) => z + 3) |             state.zoom.update((z) => z + 3) | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (this._lastClickWithinThreeSecs.data) { |         if (this.lastClickWithinThreeSecs.data) { | ||||||
|             geolocationState.allowMoving.setData(false) |             geolocationState.allowMoving.setData(false) | ||||||
|             lastClick.setData(undefined) |             lastClick.setData(undefined) | ||||||
|             return |             return | ||||||
|  |  | ||||||
|  | @ -6,7 +6,6 @@ | ||||||
|   import MapControlButton from "./Base/MapControlButton.svelte" |   import MapControlButton from "./Base/MapControlButton.svelte" | ||||||
|   import ToSvelte from "./Base/ToSvelte.svelte" |   import ToSvelte from "./Base/ToSvelte.svelte" | ||||||
|   import If from "./Base/If.svelte" |   import If from "./Base/If.svelte" | ||||||
|   import { GeolocationControl } from "./BigComponents/GeolocationControl" |  | ||||||
|   import type { Feature } from "geojson" |   import type { Feature } from "geojson" | ||||||
|   import SelectedElementView from "./BigComponents/SelectedElementView.svelte" |   import SelectedElementView from "./BigComponents/SelectedElementView.svelte" | ||||||
|   import LayerConfig from "../Models/ThemeConfig/LayerConfig" |   import LayerConfig from "../Models/ThemeConfig/LayerConfig" | ||||||
|  | @ -65,6 +64,8 @@ | ||||||
|   import ImageOperations from "./Image/ImageOperations.svelte" |   import ImageOperations from "./Image/ImageOperations.svelte" | ||||||
|   import VisualFeedbackPanel from "./BigComponents/VisualFeedbackPanel.svelte" |   import VisualFeedbackPanel from "./BigComponents/VisualFeedbackPanel.svelte" | ||||||
|   import { Orientation } from "../Logic/Web/Orientation" |   import { Orientation } from "../Logic/Web/Orientation" | ||||||
|  |   import GeolocationControl from "./BigComponents/GeolocationControl.svelte" | ||||||
|  |   import Compass_arrow from "../assets/svg/Compass_arrow.svelte" | ||||||
| 
 | 
 | ||||||
|   export let state: ThemeViewState |   export let state: ThemeViewState | ||||||
|   let layout = state.layout |   let layout = state.layout | ||||||
|  | @ -111,8 +112,6 @@ | ||||||
|   ) |   ) | ||||||
|   let previewedImage = state.previewedImage |   let previewedImage = state.previewedImage | ||||||
| 
 | 
 | ||||||
|   let geolocationControl = new GeolocationControl(state.geolocation, mapproperties, state.lastGeolocationRequestMoment) |  | ||||||
| 
 |  | ||||||
|   function forwardEventToMap(e: KeyboardEvent) { |   function forwardEventToMap(e: KeyboardEvent) { | ||||||
|     const mlmap = state.map.data |     const mlmap = state.map.data | ||||||
|     if (!mlmap) { |     if (!mlmap) { | ||||||
|  | @ -262,27 +261,20 @@ | ||||||
|         <Min class="h-8 w-8" /> |         <Min class="h-8 w-8" /> | ||||||
|       </MapControlButton> |       </MapControlButton> | ||||||
|       <If condition={featureSwitches.featureSwitchGeolocation}> |       <If condition={featureSwitches.featureSwitchGeolocation}> | ||||||
|         <div class="relative m-0.5 h-12 w-12 p-0 sm:p-1 md:m-1"> |         <div class="relative m-0.5 md:m-1"> | ||||||
|  |           <MapControlButton arialabel={Translations.t.general.labels.jumpToLocation} | ||||||
|  |                             on:click={() => state.geolocationControl.handleClick()} | ||||||
|  |                             on:keydown={forwardEventToMap} | ||||||
|  |           > | ||||||
|  |             <GeolocationControl {state} /> <!-- h-8 w-8 + p-0.5 sm:p-1 + 2px border => 9 sm: 10 in total--> | ||||||
|  |           </MapControlButton> | ||||||
|           {#if $compassLoaded} |           {#if $compassLoaded} | ||||||
|             <div class="absolute top-1/2 left-1/2 w-0 h-0"> |             <div class="absolute top-0 left-0 w-0 h-0 m-0.5 sm:m-1"> | ||||||
|               <div class="w-5 h-5" |               <Compass_arrow class="compass_arrow" style={`rotate: calc(${-$compass}deg + 225deg); transform-origin: 50% 50%;`} /> | ||||||
|                    style={`rotate: calc(${-$compass}deg + 225deg); transform-origin: 0% 0%; background: var(--button-background);`} /> |  | ||||||
|             </div> |             </div> | ||||||
|           {/if} |           {/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> |         </div> | ||||||
|  | 
 | ||||||
|       </If> |       </If> | ||||||
| 
 | 
 | ||||||
|     </div> |     </div> | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| <script> | <script> | ||||||
| export let color = "#000000" | export let color = "#000000" | ||||||
| </script> | </script> | ||||||
|  <svg {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave on:keydown xmlns="http://www.w3.org/2000/svg" width="375px" height="375px" viewBox="0 0 375 375" version="1.1">     <g id="surface1">         <path                 style="fill:{color};"                 class="selectable"               d="M 375 187.5 C 375 291.054688 291.054688 375 187.5 375 C 83.945312 375 0 291.054688 0 187.5 C 0 83.945312 83.945312 0 187.5 0 C 291.054688 0 375 83.945312 375 187.5 Z M 375 187.5 "/>     </g> </svg>  |  <svg {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave on:keydown    width="375px"    height="375px"    viewBox="0 0 375 375"    version="1.1"    id="svg1"    sodipodi:docname="circle.svg"    inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"    xmlns="http://www.w3.org/2000/svg"    xmlns:svg="http://www.w3.org/2000/svg">   <defs      id="defs1" />   <sodipodi:namedview      id="namedview1"      pagecolor="#505050"      bordercolor="#eeeeee"      borderopacity="1"      inkscape:showpageshadow="0"      inkscape:pageopacity="0"      inkscape:pagecheckerboard="0"      inkscape:deskcolor="#d1d1d1"      inkscape:zoom="2.056"      inkscape:cx="187.5"      inkscape:cy="187.5"      inkscape:window-width="1920"      inkscape:window-height="995"      inkscape:window-x="0"      inkscape:window-y="0"      inkscape:window-maximized="1"      inkscape:current-layer="svg1" />   <path      style="fill:{color}"      class="selectable"      d="M 375,187.5 C 375,291.05469 291.05469,375 187.5,375 83.945312,375 0,291.05469 0,187.5 0,83.945312 83.945312,0 187.5,0 291.05469,0 375,83.945312 375,187.5 Z m 0,0"      id="path1" /> </svg>  | ||||||
							
								
								
									
										4
									
								
								src/assets/svg/Compass_arrow.svelte
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/assets/svg/Compass_arrow.svelte
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,4 @@ | ||||||
|  | <script> | ||||||
|  | export let color = "#000000" | ||||||
|  | </script> | ||||||
|  |  <svg {...$$restProps} on:click on:mouseover on:mouseenter on:mouseleave on:keydown    width="375px"    height="375px"    viewBox="0 0 375 375"    version="1.1"    id="svg1"    sodipodi:docname="compass_arrow.svg"    inkscape:version="1.3.2 (1:1.3.2+202311252150+091e20ef0f)"    xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"    xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"    xmlns="http://www.w3.org/2000/svg"    xmlns:svg="http://www.w3.org/2000/svg">   <defs      id="defs1" />   <sodipodi:namedview      id="namedview1"      pagecolor="#505050"      bordercolor="#eeeeee"      borderopacity="1"      inkscape:showpageshadow="0"      inkscape:pageopacity="0"      inkscape:pagecheckerboard="0"      inkscape:deskcolor="#d1d1d1"      inkscape:zoom="1.0410569"      inkscape:cx="33.139398"      inkscape:cy="182.98711"      inkscape:window-width="1920"      inkscape:window-height="995"      inkscape:window-x="0"      inkscape:window-y="0"      inkscape:window-maximized="1"      inkscape:current-layer="svg1" />   <path      id="rect2"      style="fill:{color};stroke:none;stroke-linecap:round;fill-opacity:1;stroke-opacity:1"      d="M 16.835505,17.477497 79.869453,33.962116 V 80.511444 H 33.96212 Z"      sodipodi:nodetypes="ccccc" /> </svg>  | ||||||
|  | @ -590,6 +590,21 @@ a.link-underline { | ||||||
|     overflow: visible !important; |     overflow: visible !important; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | .compass_arrow { | ||||||
|  |     width: calc( 2.5rem - 1px ) ;  | ||||||
|  |     height: calc( 2.5rem - 1px ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @media (min-width: 640px) { | ||||||
|  |     .compass_arrow { | ||||||
|  |         width: calc( 2.75rem - 1px ) ; | ||||||
|  |         height: calc( 2.75rem - 1px ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| @-webkit-keyframes glowing-drop-shadow { | @-webkit-keyframes glowing-drop-shadow { | ||||||
|     from { |     from { | ||||||
|         filter: drop-shadow(5px 5px 60px rgb(128 128 128 / 0.6)); |         filter: drop-shadow(5px 5px 60px rgb(128 128 128 / 0.6)); | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
| <head> | <head> | ||||||
|     <meta charset="UTF-8"> |     <meta charset="UTF-8"> | ||||||
|     <!-- We disable 'user-scalable'. As we are working with a map, the user might zoom in using a popup, close the popup and _not_ be able to zoom out again. --> |     <!-- We disable 'user-scalable'. As we are working with a map, the user might zoom in using a popup, close the popup and _not_ be able to zoom out again. --> | ||||||
|     <meta content="width=device-width, initial-scale=1.0, user-scalable=no" name="viewport"> |     <meta content="width=device-width, initial-scale=1.0, user-scalable=yes" name="viewport"> | ||||||
|     <!-- CSP --> |     <!-- CSP --> | ||||||
|     <link href="./css/mobile.css" rel="stylesheet"/> |     <link href="./css/mobile.css" rel="stylesheet"/> | ||||||
|     <link href="./css/openinghourstable.css" rel="stylesheet"/> |     <link href="./css/openinghourstable.css" rel="stylesheet"/> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue