Skip to content

Source CursorPosition

Source CursorPosition

Cette page est générée automatiquement à partir du dépôt local au moment de la génération de la documentation.

Fichiers inclus

packages/common/src/lib/widgets/cursor-position/cursor-position.declaration.ts

packages/common/src/lib/widgets/cursor-position/cursor-position.declaration.ts
import { widgetFactorySvelte, type WidgetProps } from '$lib/api/managers/widget';
import { type CursorPositionConfig, cursorPositionConfigSchema } from './cursor-position.config';
import type { WidgetDeclaration } from '$lib/api/managers/widget/widget-declaration';
export const declaration = {
factory: () => import('./CursorPosition.svelte').then((CursorPosition) => widgetFactorySvelte(CursorPosition)),
schema: () => cursorPositionConfigSchema,
} satisfies WidgetDeclaration;
export type CursorPositionProps = WidgetProps<CursorPositionConfig>;

packages/common/src/lib/widgets/cursor-position/cursor-position.config.ts

packages/common/src/lib/widgets/cursor-position/cursor-position.config.ts
import { defineWidgetConfig } from '$lib/api/managers/configuration';
import { inToolbarSchemaFrom } from '$lib/api/managers/configuration/models/widget/widget-in-toolbar.schema';
import { i18nDataSchema, i18nSchemaFrom } from '$lib/api/managers/i18n';
import { z } from 'zod';
const cursorPositionProjectionOption = z.object({
wkid: z.number(),
label: i18nDataSchema,
unit: z.string().optional(),
precision: z.number().optional(),
dms: z.boolean().optional(),
xLabel: z.string().optional(),
yLabel: z.string().optional(),
key: z.string(),
});
export type CursorPositionProjectionOption = z.infer<typeof cursorPositionProjectionOption>;
export const LAMBERT_2008_OPTION = {
label: 'Lambert Belge 2008',
wkid: 3812,
unit: 'm',
key: 'lambert-belge-2008',
};
export const cursorPositionConfigSchema = defineWidgetConfig({
inToolbar: inToolbarSchemaFrom(false),
active: true,
i18n: i18nSchemaFrom({
'dropdown-label': {
fr: 'Coordonnées du pointeur en',
nl: 'NL - Coordonnées du pointeur en',
},
}),
config: z
.object({
defaultWkid: z.number().optional(),
options: cursorPositionProjectionOption.array().default([
{
label: 'Lambert Belge 1972',
wkid: 31370,
unit: 'm',
key: 'lambert-belge-1972',
},
LAMBERT_2008_OPTION,
{
label: 'WGS84 (DD)',
wkid: 4326,
precision: 5,
unit: '°',
xLabel: 'Long',
yLabel: 'Lat',
key: 'wgs84-dd',
},
{
label: 'WGS84 (DMS)',
wkid: 4326,
dms: true,
xLabel: 'Long',
yLabel: 'Lat',
key: 'wgs84-dms',
},
]),
})
.prefault({}),
});
export type CursorPositionConfig = z.infer<typeof cursorPositionConfigSchema>;

packages/common/src/lib/widgets/cursor-position/CursorPosition.svelte

packages/common/src/lib/widgets/cursor-position/CursorPosition.svelte
<script lang="ts">
import { getI18n } from '$lib/api/managers/i18n';
import { Projections } from '$lib/api/managers/projection';
import { getMapManager } from '$lib/api/map';
import { type CardinalLabels, formatDms, parseDms } from '$lib/api/utils/format.utils';
import { ApiSelect, type ApiSelectItem } from '$lib/components/api-select';
import { onDestroy, tick } from 'svelte';
import { type CursorPositionProjectionOption, LAMBERT_2008_OPTION } from './cursor-position.config';
import type { ApiPoint } from '$lib/api/geometry';
import { cn } from '$lib/components/shadcn/utils';
import type { CursorPositionProps } from './cursor-position.declaration';
type ResultFormat = {
x: string;
y: string;
xLabel: string;
yLabel: string;
unit: string;
};
const { fullConfig }: CursorPositionProps = $props();
const mapManager = getMapManager();
const zoom = mapManager.tools.zoom;
const transform = mapManager.tools.transform;
const i18n = getI18n(fullConfig.i18n);
const defaultWkid = fullConfig.config.defaultWkid;
const defaultOption = defaultWkid
? fullConfig.config.options.find((x) => x.wkid === defaultWkid)
: fullConfig.config.options[0];
let selectedProjection = $state<CursorPositionProjectionOption>(defaultOption ?? LAMBERT_2008_OPTION);
const options: ApiSelectItem<CursorPositionProjectionOption>[] = $derived(
fullConfig.config.options.map((o) => ({
value: o,
label: i18n.translate(o.label),
})),
);
$effect(() => {
if (selectedProjection) {
editMode = false;
}
});
const isWGS84 = $derived.by(() => {
return selectedProjection.wkid === Projections.WGS_1984.wkid;
});
const cardinalLabels: CardinalLabels = $derived.by(() => {
return {
north: i18n('common.cardinal-north'),
south: i18n('common.cardinal-south'),
west: i18n('common.cardinal-west'),
east: i18n('common.cardinal-east'),
};
});
let point = $state<ApiPoint | null>(null);
let editMode = $state<boolean>(false);
let xCoordValue = $state<number | string>(0);
let yCoordValue = $state<number | string>(0);
let xCoordInput = $state<HTMLInputElement | undefined>();
let yCoordInput = $state<HTMLInputElement | undefined>();
const formated = $derived.by(() => {
if (point) {
if (!selectedProjection) {
return {
x: point.x.toFixed(0),
y: point.y.toFixed(0),
xLabel: 'x',
yLabel: 'y',
unit: '',
} satisfies ResultFormat;
}
const projected = transform.transformPoint(point, selectedProjection.wkid);
if (selectedProjection.dms) {
return {
x: formatDms(projected.x, 'X', cardinalLabels),
y: formatDms(projected.y, 'Y', cardinalLabels),
xLabel: selectedProjection.xLabel ?? 'Long',
yLabel: selectedProjection.yLabel ?? 'Lat',
unit: '',
} satisfies ResultFormat;
}
return {
x: projected.x.toFixed(selectedProjection.precision ?? 0),
y: projected.y.toFixed(selectedProjection.precision ?? 0),
xLabel: selectedProjection.xLabel ?? 'x',
yLabel: selectedProjection.yLabel ?? 'y',
unit: selectedProjection.unit ?? '',
} satisfies ResultFormat;
}
return null;
});
function validate(event: KeyboardEvent) {
if (event.key === 'Enter' && formated) {
let xCoord: string | number = xCoordValue;
let yCoord: string | number = yCoordValue;
if (selectedProjection.dms) {
const { x, y } = parseDms(`${xCoordValue}`, `${yCoordValue}`);
xCoord = x;
yCoord = y;
}
zoom.zoomToPoint({
x: Number(xCoord),
y: Number(yCoord),
wkid: selectedProjection.wkid,
});
editMode = false;
}
}
function activateEditMode(inputClick: HTMLInputElement | undefined) {
editMode = true;
if (!formated) return;
xCoordValue = formated.x;
yCoordValue = formated.y;
tick().then(() => inputClick?.focus());
}
const unsub = mapManager.tools.events.on('hover', (p) => (point = p));
onDestroy(() => {
unsub();
});
</script>
<div
class="gv-bg-black/40 gv-text-white gv-flex gv-items-center gv-h-5 gv-gap-1 gv-px-1 gv-py-0.5 gv-text-sm gv-leading-3"
>
<span>{i18n('dropdown-label')}</span>
<ApiSelect
bind:value={selectedProjection}
{options}
getKey={(p) => p.key}
class="gv-h-5 gv-bg-transparent gv-w-[12rem] gv-border-none"
contentClass="gv-bg-black/40 gv-text-white"
dataTestId="CursorPosition-ProjectionSelect"
/>
{#if formated}
<span>
{formated.xLabel} =
<input
onkeydown={validate}
bind:this={xCoordInput}
bind:value={xCoordValue}
class={cn(editMode ? 'gv-visible' : 'gv-hidden', 'gv-bg-black/50 focus:gv-outline-none gv-m-0')}
type={isWGS84 ? 'text' : 'number'}
data-test-id="CursorPosition-XInput"
/>
<button class={cn(editMode ? 'gv-hidden' : 'gv-visible', '')} onclick={() => activateEditMode(xCoordInput)}>
{formated.x}
</button>
<span class="gv-mr-3">{formated.unit}</span>
{formated.yLabel} =
<input
onkeydown={validate}
bind:this={yCoordInput}
bind:value={yCoordValue}
class={cn(editMode ? 'gv-visible' : 'gv-hidden', 'gv-bg-black/50 focus:gv-outline-none gv-m-0')}
type={isWGS84 ? 'text' : 'number'}
data-test-id="CursorPosition-YInput"
/>
<button class={cn(editMode ? 'gv-hidden' : 'gv-visible', '')} onclick={() => activateEditMode(yCoordInput)}>
{formated.y}
</button>
{formated.unit}
</span>
{/if}
</div>
<style>
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type='number'] {
-moz-appearance: textfield;
}
</style>

packages/common/src/lib/widgets/cursor-position/index.ts

packages/common/src/lib/widgets/cursor-position/index.ts
export * from './cursor-position.config';
export * as CursorPosition from './CursorPosition.svelte';
export * from './cursor-position.declaration';

Aller plus loin