@open-pioneer/selection 1.4.0 → 1.5.0-dev.20260910103330
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +47 -29
- package/README.md +28 -9
- package/_virtual/hooks.js +1 -1
- package/_virtual/source-info.js +1 -1
- package/api.d.ts +27 -2
- package/i18n/de.yaml +0 -6
- package/i18n/en.yaml +0 -6
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/interactions/ExtentSelectionInteraction.d.ts +12 -0
- package/interactions/ExtentSelectionInteraction.js +57 -0
- package/interactions/ExtentSelectionInteraction.js.map +1 -0
- package/model/SelectionViewModel.d.ts +30 -0
- package/model/SelectionViewModel.js +270 -0
- package/model/SelectionViewModel.js.map +1 -0
- package/model/SelectionViewModelFactory.d.ts +21 -0
- package/model/SelectionViewModelFactory.js +43 -0
- package/model/SelectionViewModelFactory.js.map +1 -0
- package/model/index.d.ts +1 -0
- package/model/index.js +2 -0
- package/model/index.js.map +1 -0
- package/package.json +34 -15
- package/services.d.ts +2 -7
- package/services.js +2 -17
- package/services.js.map +1 -1
- package/{VectorSelectionSource.d.ts → sources/VectorSelectionSource.d.ts} +3 -7
- package/{VectorSelectionSource.js → sources/VectorSelectionSource.js} +12 -9
- package/sources/VectorSelectionSource.js.map +1 -0
- package/sources/VectorSelectionSourceFactory.d.ts +7 -0
- package/sources/VectorSelectionSourceFactory.js +19 -0
- package/sources/VectorSelectionSourceFactory.js.map +1 -0
- package/{Selection.d.ts → ui/Selection.d.ts} +1 -1
- package/ui/Selection.js +97 -0
- package/ui/Selection.js.map +1 -0
- package/ui/SelectionSourceItem.d.ts +7 -0
- package/ui/SelectionSourceItem.js +38 -0
- package/ui/SelectionSourceItem.js.map +1 -0
- package/ui/useSelectionSourceId.d.ts +9 -0
- package/ui/useSelectionSourceId.js +23 -0
- package/ui/useSelectionSourceId.js.map +1 -0
- package/ui/useSelectionViewModel.d.ts +11 -0
- package/ui/useSelectionViewModel.js +43 -0
- package/ui/useSelectionViewModel.js.map +1 -0
- package/ui/useSourceStatus.d.ts +8 -0
- package/ui/useSourceStatus.js +27 -0
- package/ui/useSourceStatus.js.map +1 -0
- package/DragController.d.ts +0 -33
- package/DragController.js +0 -175
- package/DragController.js.map +0 -1
- package/Selection.js +0 -232
- package/Selection.js.map +0 -1
- package/SelectionController.d.ts +0 -20
- package/SelectionController.js +0 -58
- package/SelectionController.js.map +0 -1
- package/VectorSelectionSource.js.map +0 -1
- /package/{SelectionTooltipContent.d.ts → ui/SelectionTooltipContent.d.ts} +0 -0
- /package/{SelectionTooltipContent.js → ui/SelectionTooltipContent.js} +0 -0
- /package/{SelectionTooltipContent.js.map → ui/SelectionTooltipContent.js.map} +0 -0
- /package/{selection.css → ui/selection.css} +0 -0
- /package/{selection.css.map → ui/selection.css.map} +0 -0
package/ui/Selection.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { createListCollection, VStack, Select, Portal } from '@chakra-ui/react';
|
|
3
|
+
import { useMapModelValue } from '@open-pioneer/map';
|
|
4
|
+
import { useCommonComponentProps } from '@open-pioneer/react-utils';
|
|
5
|
+
import { useReactiveSnapshot } from '@open-pioneer/reactivity';
|
|
6
|
+
import { useIntl } from '../_virtual/hooks.js';
|
|
7
|
+
import { useMemo } from 'react';
|
|
8
|
+
import { SelectionSourceItem } from './SelectionSourceItem.js';
|
|
9
|
+
import { useSelectionSourceId } from './useSelectionSourceId.js';
|
|
10
|
+
import { useSelectionViewModel } from './useSelectionViewModel.js';
|
|
11
|
+
import { useSourceStatus } from './useSourceStatus.js';
|
|
12
|
+
|
|
13
|
+
const Selection = (props) => {
|
|
14
|
+
const { sources, onSelectionComplete, onSelectionSourceChanged } = props;
|
|
15
|
+
const map = useMapModelValue(props);
|
|
16
|
+
const viewModel = useSelectionViewModel(
|
|
17
|
+
map,
|
|
18
|
+
sources,
|
|
19
|
+
onSelectionComplete,
|
|
20
|
+
onSelectionSourceChanged
|
|
21
|
+
);
|
|
22
|
+
return viewModel && /* @__PURE__ */ jsx(SelectionReady, { viewModel, ...props });
|
|
23
|
+
};
|
|
24
|
+
function SelectionReady(props) {
|
|
25
|
+
const { viewModel } = props;
|
|
26
|
+
const { containerProps } = useCommonComponentProps("selection", props);
|
|
27
|
+
const intl = useIntl();
|
|
28
|
+
const sources = useReactiveSnapshot(() => viewModel.sources, [viewModel]);
|
|
29
|
+
const currentSource = useReactiveSnapshot(() => viewModel.currentSource, [viewModel]);
|
|
30
|
+
const ariaMessage = useReactiveSnapshot(() => viewModel.ariaMessage, [viewModel]);
|
|
31
|
+
const getSourceId = useSelectionSourceId();
|
|
32
|
+
const sourceOptionsCollection = useMemo(
|
|
33
|
+
() => createListCollection({
|
|
34
|
+
items: sources,
|
|
35
|
+
isItemDisabled: () => {
|
|
36
|
+
return false;
|
|
37
|
+
},
|
|
38
|
+
itemToString: (item) => item.label,
|
|
39
|
+
itemToValue: (item) => getSourceId(item)
|
|
40
|
+
}),
|
|
41
|
+
[sources, getSourceId]
|
|
42
|
+
);
|
|
43
|
+
let triggerItem;
|
|
44
|
+
if (currentSource) {
|
|
45
|
+
triggerItem = /* @__PURE__ */ jsx(SelectionSourceItem, { source: currentSource });
|
|
46
|
+
} else {
|
|
47
|
+
triggerItem = null;
|
|
48
|
+
}
|
|
49
|
+
return /* @__PURE__ */ jsx(VStack, { ...containerProps, gap: 2, children: /* @__PURE__ */ jsxs(
|
|
50
|
+
Select.Root,
|
|
51
|
+
{
|
|
52
|
+
className: "selection-source",
|
|
53
|
+
collection: sourceOptionsCollection,
|
|
54
|
+
value: currentSource ? [getSourceId(currentSource)] : [],
|
|
55
|
+
onValueChange: (details) => {
|
|
56
|
+
const source = details.items[0];
|
|
57
|
+
if (source) {
|
|
58
|
+
viewModel.currentSource = source;
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
lazyMount: true,
|
|
62
|
+
unmountOnExit: true,
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ jsx(Select.Label, { children: intl.formatMessage({ id: "selectSource" }) }),
|
|
65
|
+
/* @__PURE__ */ jsxs(Select.Control, { children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Select.Trigger, { "aria-description": ariaMessage, children: /* @__PURE__ */ jsx(
|
|
67
|
+
Select.ValueText,
|
|
68
|
+
{
|
|
69
|
+
placeholder: intl.formatMessage({ id: "selectionPlaceholder" }),
|
|
70
|
+
children: triggerItem
|
|
71
|
+
}
|
|
72
|
+
) }),
|
|
73
|
+
/* @__PURE__ */ jsx(Select.IndicatorGroup, { children: /* @__PURE__ */ jsx(Select.Indicator, {}) })
|
|
74
|
+
] }),
|
|
75
|
+
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, { children: /* @__PURE__ */ jsx(Select.Content, { className: "selection-source-options", children: sourceOptionsCollection.items.map((item) => /* @__PURE__ */ jsx(SelectionSourceItemContent, { source: item }, getSourceId(item))) }) }) })
|
|
76
|
+
]
|
|
77
|
+
}
|
|
78
|
+
) });
|
|
79
|
+
}
|
|
80
|
+
function SelectionSourceItemContent(props) {
|
|
81
|
+
const { source } = props;
|
|
82
|
+
const isDisabled = useSourceStatus(source).kind === "unavailable";
|
|
83
|
+
return /* @__PURE__ */ jsx(
|
|
84
|
+
Select.Item,
|
|
85
|
+
{
|
|
86
|
+
className: "selection-source-option",
|
|
87
|
+
item: source,
|
|
88
|
+
justifyContent: "flex-start",
|
|
89
|
+
pointerEvents: "auto",
|
|
90
|
+
"aria-disabled": isDisabled ? "true" : void 0,
|
|
91
|
+
children: /* @__PURE__ */ jsx(SelectionSourceItem, { source })
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { Selection };
|
|
97
|
+
//# sourceMappingURL=Selection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Selection.js","sources":["Selection.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { createListCollection, Portal, Select, VStack } from \"@chakra-ui/react\";\nimport { MapModelProps, useMapModelValue } from \"@open-pioneer/map\";\nimport { CommonComponentProps, useCommonComponentProps } from \"@open-pioneer/react-utils\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { FC, useMemo } from \"react\";\nimport { SelectionResult, SelectionSource } from \"../api\";\nimport { SelectionViewModel } from \"../model\";\nimport { SelectionSourceItem } from \"./SelectionSourceItem\";\nimport { useSelectionSourceId } from \"./useSelectionSourceId\";\nimport { useSelectionViewModel } from \"./useSelectionViewModel\";\nimport { useSourceStatus } from \"./useSourceStatus\";\n\n/**\n * Properties supported by the {@link Selection} component.\n */\nexport interface SelectionProps extends CommonComponentProps, MapModelProps {\n /**\n * Array of selection sources available for spatial selection.\n */\n sources: SelectionSource[];\n\n /**\n * This handler is called whenever the user has successfully selected\n * some items.\n */\n onSelectionComplete?(event: SelectionCompleteEvent): void;\n\n /**\n * This handler is called whenever the user has changed the selected source\n */\n onSelectionSourceChanged?(event: SelectionSourceChangedEvent): void;\n}\n\nexport interface SelectionCompleteEvent {\n /** The source that returned the {@link results}. */\n source: SelectionSource;\n\n /** Results selected by the user. */\n results: SelectionResult[];\n}\n\nexport interface SelectionSourceChangedEvent {\n /** The new selected source */\n source: SelectionSource | undefined;\n}\n\n/**\n * A component that allows the user to perform a spatial selection on a given set of {@link SelectionSource}.\n */\nexport const Selection: FC<SelectionProps> = (props) => {\n const { sources, onSelectionComplete, onSelectionSourceChanged } = props;\n const map = useMapModelValue(props);\n const viewModel = useSelectionViewModel(\n map,\n sources,\n onSelectionComplete,\n onSelectionSourceChanged\n );\n return viewModel && <SelectionReady viewModel={viewModel} {...props} />;\n};\n\nfunction SelectionReady(props: CommonComponentProps & { viewModel: SelectionViewModel }) {\n const { viewModel } = props;\n const { containerProps } = useCommonComponentProps(\"selection\", props);\n const intl = useIntl();\n\n // Subscribe to relevant view model state.\n const sources = useReactiveSnapshot(() => viewModel.sources, [viewModel]);\n const currentSource = useReactiveSnapshot(() => viewModel.currentSource, [viewModel]);\n const ariaMessage = useReactiveSnapshot(() => viewModel.ariaMessage, [viewModel]);\n\n // Translate sources array to a collection for chakra's select control.\n const getSourceId = useSelectionSourceId();\n const sourceOptionsCollection = useMemo(\n () =>\n createListCollection({\n items: sources,\n isItemDisabled: () => {\n return false;\n },\n itemToString: (item) => item.label,\n itemToValue: (item) => getSourceId(item)\n }),\n [sources, getSourceId]\n );\n\n let triggerItem;\n if (currentSource) {\n triggerItem = <SelectionSourceItem source={currentSource} />;\n } else {\n triggerItem = null;\n }\n\n return (\n <VStack {...containerProps} gap={2}>\n <Select.Root\n className=\"selection-source\"\n collection={sourceOptionsCollection}\n value={currentSource ? [getSourceId(currentSource)] : []}\n onValueChange={(details) => {\n const source = details.items[0];\n if (source) {\n viewModel.currentSource = source;\n }\n }}\n lazyMount={true}\n unmountOnExit={true}\n >\n <Select.Label>{intl.formatMessage({ id: \"selectSource\" })}</Select.Label>\n\n <Select.Control>\n <Select.Trigger aria-description={ariaMessage}>\n <Select.ValueText\n placeholder={intl.formatMessage({ id: \"selectionPlaceholder\" })}\n >\n {triggerItem}\n </Select.ValueText>\n </Select.Trigger>\n <Select.IndicatorGroup>\n <Select.Indicator />\n </Select.IndicatorGroup>\n </Select.Control>\n\n <Portal>\n <Select.Positioner>\n <Select.Content className=\"selection-source-options\">\n {sourceOptionsCollection.items.map((item) => (\n <SelectionSourceItemContent source={item} key={getSourceId(item)} />\n ))}\n </Select.Content>\n </Select.Positioner>\n </Portal>\n </Select.Root>\n </VStack>\n );\n}\n\n/**\n * Renders a dropdown item in the menu.\n */\nfunction SelectionSourceItemContent(props: { source: SelectionSource }) {\n const { source } = props;\n const isDisabled = useSourceStatus(source).kind === \"unavailable\";\n return (\n <Select.Item\n className=\"selection-source-option\"\n item={source}\n justifyContent=\"flex-start\"\n // Override pointer-events: none rule for disabled items; we want to show the tooltip on hover\n pointerEvents=\"auto\"\n aria-disabled={isDisabled ? \"true\" : undefined}\n >\n <SelectionSourceItem source={source} />\n </Select.Item>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { Flex, Box, chakra, Icon } from '@chakra-ui/react';
|
|
3
|
+
import { Tooltip } from '@open-pioneer/chakra-snippets/tooltip';
|
|
4
|
+
import { useReactiveSnapshot } from '@open-pioneer/reactivity';
|
|
5
|
+
import { LuTriangleAlert } from 'react-icons/lu';
|
|
6
|
+
import { useSourceStatus } from './useSourceStatus.js';
|
|
7
|
+
|
|
8
|
+
function SelectionSourceItem(props) {
|
|
9
|
+
const { source } = props;
|
|
10
|
+
const label = useReactiveSnapshot(() => source?.label, [source]);
|
|
11
|
+
const status = useSourceStatus(source);
|
|
12
|
+
const isAvailable = status.kind === "available";
|
|
13
|
+
const clazz = isAvailable ? "selection-source-value" : "selection-source-value selection-source-value--disabled";
|
|
14
|
+
return /* @__PURE__ */ jsxs(Flex, { className: clazz, direction: "row", alignItems: "center", grow: 1, children: [
|
|
15
|
+
label,
|
|
16
|
+
status.kind === "unavailable" && /* @__PURE__ */ jsx(Box, { ml: 2, children: /* @__PURE__ */ jsx(
|
|
17
|
+
Tooltip,
|
|
18
|
+
{
|
|
19
|
+
content: status.reason,
|
|
20
|
+
positioning: { placement: "right" },
|
|
21
|
+
openDelay: 500,
|
|
22
|
+
children: /* @__PURE__ */ jsx(chakra.span, { children: /* @__PURE__ */ jsx(
|
|
23
|
+
Icon,
|
|
24
|
+
{
|
|
25
|
+
color: "red",
|
|
26
|
+
className: "warning-icon",
|
|
27
|
+
"aria-label": status.reason,
|
|
28
|
+
"aria-hidden": void 0,
|
|
29
|
+
children: /* @__PURE__ */ jsx(LuTriangleAlert, {})
|
|
30
|
+
}
|
|
31
|
+
) })
|
|
32
|
+
}
|
|
33
|
+
) })
|
|
34
|
+
] });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export { SelectionSourceItem };
|
|
38
|
+
//# sourceMappingURL=SelectionSourceItem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SelectionSourceItem.js","sources":["SelectionSourceItem.tsx"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { Box, chakra, Flex, Icon } from \"@chakra-ui/react\";\nimport { Tooltip } from \"@open-pioneer/chakra-snippets/tooltip\";\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport { LuTriangleAlert } from \"react-icons/lu\";\nimport { SelectionSource } from \"../api\";\nimport { useSourceStatus } from \"./useSourceStatus\";\n\n/**\n * Renders a selection source in the dropdown menu (option or current selection).\n */\nexport function SelectionSourceItem(props: { source: SelectionSource | undefined }) {\n const { source } = props;\n const label = useReactiveSnapshot(() => source?.label, [source]);\n const status = useSourceStatus(source);\n const isAvailable = status.kind === \"available\";\n const clazz = isAvailable\n ? \"selection-source-value\"\n : \"selection-source-value selection-source-value--disabled\";\n\n return (\n <Flex className={clazz} direction=\"row\" alignItems=\"center\" grow={1}>\n {label}\n {status.kind === \"unavailable\" && (\n <Box ml={2}>\n <Tooltip\n content={status.reason}\n positioning={{ placement: \"right\" }}\n openDelay={500}\n >\n <chakra.span>\n <Icon\n color=\"red\"\n className=\"warning-icon\"\n aria-label={status.reason}\n aria-hidden={undefined} // Overwrite icon default so the label gets read\n >\n <LuTriangleAlert />\n </Icon>\n </chakra.span>\n </Tooltip>\n </Box>\n )}\n </Flex>\n );\n}\n"],"names":[],"mappings":";;;;;;;AAaO,SAAS,oBAAoB,KAAA,EAAgD;AAChF,EAAA,MAAM,EAAE,QAAO,GAAI,KAAA;AACnB,EAAA,MAAM,QAAQ,mBAAA,CAAoB,MAAM,QAAQ,KAAA,EAAO,CAAC,MAAM,CAAC,CAAA;AAC/D,EAAA,MAAM,MAAA,GAAS,gBAAgB,MAAM,CAAA;AACrC,EAAA,MAAM,WAAA,GAAc,OAAO,IAAA,KAAS,WAAA;AACpC,EAAA,MAAM,KAAA,GAAQ,cACR,wBAAA,GACA,yDAAA;AAEN,EAAA,uBACI,IAAA,CAAC,QAAK,SAAA,EAAW,KAAA,EAAO,WAAU,KAAA,EAAM,UAAA,EAAW,QAAA,EAAS,IAAA,EAAM,CAAA,EAC7D,QAAA,EAAA;AAAA,IAAA,KAAA;AAAA,IACA,OAAO,IAAA,KAAS,aAAA,oBACb,GAAA,CAAC,GAAA,EAAA,EAAI,IAAI,CAAA,EACL,QAAA,kBAAA,GAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACG,SAAS,MAAA,CAAO,MAAA;AAAA,QAChB,WAAA,EAAa,EAAE,SAAA,EAAW,OAAA,EAAQ;AAAA,QAClC,SAAA,EAAW,GAAA;AAAA,QAEX,QAAA,kBAAA,GAAA,CAAC,MAAA,CAAO,IAAA,EAAP,EACG,QAAA,kBAAA,GAAA;AAAA,UAAC,IAAA;AAAA,UAAA;AAAA,YACG,KAAA,EAAM,KAAA;AAAA,YACN,SAAA,EAAU,cAAA;AAAA,YACV,cAAY,MAAA,CAAO,MAAA;AAAA,YACnB,aAAA,EAAa,MAAA;AAAA,YAEb,8BAAC,eAAA,EAAA,EAAgB;AAAA;AAAA,SACrB,EACJ;AAAA;AAAA,KACJ,EACJ;AAAA,GAAA,EAER,CAAA;AAER;;;;"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SelectionSource } from "../api";
|
|
2
|
+
export type GetSelectionSourceId = (selectionSource: SelectionSource) => string;
|
|
3
|
+
/**
|
|
4
|
+
* Assigns unique IDs to selection sources.
|
|
5
|
+
*
|
|
6
|
+
* Sources that define their own {@link SelectionSource.id} keep that id;
|
|
7
|
+
* for all other sources an id is generated.
|
|
8
|
+
*/
|
|
9
|
+
export declare function useSelectionSourceId(): GetSelectionSourceId;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { useRef, useCallback } from 'react';
|
|
2
|
+
|
|
3
|
+
const GENERATED_ID_PREFIX = "__anon_source_";
|
|
4
|
+
function useSelectionSourceId() {
|
|
5
|
+
const sourceIds = useRef(void 0);
|
|
6
|
+
const counter = useRef(0);
|
|
7
|
+
if (!sourceIds.current) {
|
|
8
|
+
sourceIds.current = /* @__PURE__ */ new WeakMap();
|
|
9
|
+
}
|
|
10
|
+
return useCallback((source) => {
|
|
11
|
+
if (source.id != null) {
|
|
12
|
+
return source.id;
|
|
13
|
+
}
|
|
14
|
+
const ids = sourceIds.current;
|
|
15
|
+
if (!ids.has(source)) {
|
|
16
|
+
ids.set(source, `${GENERATED_ID_PREFIX}${counter.current++}`);
|
|
17
|
+
}
|
|
18
|
+
return ids.get(source);
|
|
19
|
+
}, []);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { useSelectionSourceId };
|
|
23
|
+
//# sourceMappingURL=useSelectionSourceId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSelectionSourceId.js","sources":["useSelectionSourceId.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useCallback, useRef } from \"react\";\nimport { SelectionSource } from \"../api\";\n\nexport type GetSelectionSourceId = (selectionSource: SelectionSource) => string;\n\nconst GENERATED_ID_PREFIX = \"__anon_source_\";\n\n/**\n * Assigns unique IDs to selection sources.\n *\n * Sources that define their own {@link SelectionSource.id} keep that id;\n * for all other sources an id is generated.\n */\nexport function useSelectionSourceId(): GetSelectionSourceId {\n const sourceIds = useRef<WeakMap<SelectionSource, string>>(undefined);\n const counter = useRef(0);\n // oxlint-disable-next-line react/refs\n if (!sourceIds.current) {\n sourceIds.current = new WeakMap();\n }\n\n return useCallback((source: SelectionSource) => {\n if (source.id != null) {\n return source.id;\n }\n\n // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion\n const ids = sourceIds.current!;\n if (!ids.has(source)) {\n ids.set(source, `${GENERATED_ID_PREFIX}${counter.current++}`);\n }\n // oxlint-disable-next-line @typescript-eslint/no-non-null-assertion\n return ids.get(source)!;\n }, []);\n}\n"],"names":[],"mappings":";;AAQA,MAAM,mBAAA,GAAsB,gBAAA;AAQrB,SAAS,oBAAA,GAA6C;AACzD,EAAA,MAAM,SAAA,GAAY,OAAyC,MAAS,CAAA;AACpE,EAAA,MAAM,OAAA,GAAU,OAAO,CAAC,CAAA;AAExB,EAAA,IAAI,CAAC,UAAU,OAAA,EAAS;AACpB,IAAA,SAAA,CAAU,OAAA,uBAAc,OAAA,EAAQ;AAAA,EACpC;AAEA,EAAA,OAAO,WAAA,CAAY,CAAC,MAAA,KAA4B;AAC5C,IAAA,IAAI,MAAA,CAAO,MAAM,IAAA,EAAM;AACnB,MAAA,OAAO,MAAA,CAAO,EAAA;AAAA,IAClB;AAGA,IAAA,MAAM,MAAM,SAAA,CAAU,OAAA;AACtB,IAAA,IAAI,CAAC,GAAA,CAAI,GAAA,CAAI,MAAM,CAAA,EAAG;AAClB,MAAA,GAAA,CAAI,IAAI,MAAA,EAAQ,CAAA,EAAG,mBAAmB,CAAA,EAAG,OAAA,CAAQ,SAAS,CAAA,CAAE,CAAA;AAAA,IAChE;AAEA,IAAA,OAAO,GAAA,CAAI,IAAI,MAAM,CAAA;AAAA,EACzB,CAAA,EAAG,EAAE,CAAA;AACT;;;;"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MapModel } from "@open-pioneer/map";
|
|
2
|
+
import { SelectionSource } from "../api";
|
|
3
|
+
import { SelectionViewModel } from "../model";
|
|
4
|
+
import { SelectionCompleteEvent, SelectionSourceChangedEvent } from "./Selection";
|
|
5
|
+
/**
|
|
6
|
+
* Initializes the (internal) view model used by the selection component.
|
|
7
|
+
*
|
|
8
|
+
* The view model contains the primary widget state.
|
|
9
|
+
* It is a long lived instance that is updated in place when relevant react props are changed.
|
|
10
|
+
*/
|
|
11
|
+
export declare function useSelectionViewModel(map: MapModel, sources: SelectionSource[], onSelectionComplete: ((event: SelectionCompleteEvent) => void) | undefined, onSelectionSourceChanged: ((event: SelectionSourceChangedEvent) => void) | undefined): SelectionViewModel | undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { watchValue } from '@conterra/reactivity-core';
|
|
2
|
+
import { useService } from '../_virtual/hooks.js';
|
|
3
|
+
import { useEffectEvent, useState, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
function useSelectionViewModel(map, sources, onSelectionComplete, onSelectionSourceChanged) {
|
|
6
|
+
const viewModelFactory = useService("selection.ViewModelFactory");
|
|
7
|
+
const onComplete = useEffectEvent((source, results) => {
|
|
8
|
+
onSelectionComplete?.({ source, results });
|
|
9
|
+
});
|
|
10
|
+
const onChange = useEffectEvent((source) => {
|
|
11
|
+
onSelectionSourceChanged?.({ source });
|
|
12
|
+
});
|
|
13
|
+
const [viewModel, setViewModel] = useState();
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const vm = viewModelFactory.createViewModel({
|
|
16
|
+
map,
|
|
17
|
+
onSelectionComplete: onComplete
|
|
18
|
+
});
|
|
19
|
+
setViewModel(vm);
|
|
20
|
+
return () => {
|
|
21
|
+
setViewModel(void 0);
|
|
22
|
+
vm.destroy();
|
|
23
|
+
};
|
|
24
|
+
}, [viewModelFactory, map]);
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (viewModel) {
|
|
27
|
+
viewModel.sources = sources;
|
|
28
|
+
}
|
|
29
|
+
}, [viewModel, sources]);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!viewModel) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const handle = watchValue(() => viewModel.currentSource, onChange, {
|
|
35
|
+
immediate: true
|
|
36
|
+
});
|
|
37
|
+
return () => handle.destroy();
|
|
38
|
+
}, [viewModel]);
|
|
39
|
+
return viewModel;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { useSelectionViewModel };
|
|
43
|
+
//# sourceMappingURL=useSelectionViewModel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSelectionViewModel.js","sources":["useSelectionViewModel.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { watchValue } from \"@conterra/reactivity-core\";\nimport { MapModel } from \"@open-pioneer/map\";\nimport { useService } from \"open-pioneer:react-hooks\";\nimport { useEffect, useEffectEvent, useState } from \"react\";\nimport { SelectionResult, SelectionSource } from \"../api\";\nimport { SelectionViewModel } from \"../model\";\nimport { SelectionViewModelFactory } from \"../services\";\nimport { SelectionCompleteEvent, SelectionSourceChangedEvent } from \"./Selection\";\n\n/**\n * Initializes the (internal) view model used by the selection component.\n *\n * The view model contains the primary widget state.\n * It is a long lived instance that is updated in place when relevant react props are changed.\n */\nexport function useSelectionViewModel(\n map: MapModel,\n sources: SelectionSource[],\n onSelectionComplete: ((event: SelectionCompleteEvent) => void) | undefined,\n onSelectionSourceChanged: ((event: SelectionSourceChangedEvent) => void) | undefined\n): SelectionViewModel | undefined {\n const viewModelFactory = useService<SelectionViewModelFactory>(\"selection.ViewModelFactory\");\n const onComplete = useEffectEvent((source: SelectionSource, results: SelectionResult[]) => {\n onSelectionComplete?.({ source, results });\n });\n const onChange = useEffectEvent((source: SelectionSource | undefined) => {\n onSelectionSourceChanged?.({ source });\n });\n\n // Construct view model\n const [viewModel, setViewModel] = useState<SelectionViewModel>();\n useEffect(() => {\n const vm = viewModelFactory.createViewModel({\n map,\n onSelectionComplete: onComplete\n });\n\n setViewModel(vm);\n return () => {\n setViewModel(undefined);\n vm.destroy();\n };\n }, [viewModelFactory, map]);\n\n // Sync sources --> view model\n useEffect(() => {\n if (viewModel) {\n viewModel.sources = sources;\n }\n }, [viewModel, sources]);\n\n // Sync current source --> react callbacks\n useEffect(() => {\n if (!viewModel) {\n return;\n }\n\n const handle = watchValue(() => viewModel.currentSource, onChange, {\n immediate: true\n });\n return () => handle.destroy();\n }, [viewModel]);\n\n return viewModel;\n}\n"],"names":[],"mappings":";;;;AAkBO,SAAS,qBAAA,CACZ,GAAA,EACA,OAAA,EACA,mBAAA,EACA,wBAAA,EAC8B;AAC9B,EAAA,MAAM,gBAAA,GAAmB,WAAsC,4BAA4B,CAAA;AAC3F,EAAA,MAAM,UAAA,GAAa,cAAA,CAAe,CAAC,MAAA,EAAyB,OAAA,KAA+B;AACvF,IAAA,mBAAA,GAAsB,EAAE,MAAA,EAAQ,OAAA,EAAS,CAAA;AAAA,EAC7C,CAAC,CAAA;AACD,EAAA,MAAM,QAAA,GAAW,cAAA,CAAe,CAAC,MAAA,KAAwC;AACrE,IAAA,wBAAA,GAA2B,EAAE,QAAQ,CAAA;AAAA,EACzC,CAAC,CAAA;AAGD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,QAAA,EAA6B;AAC/D,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,MAAM,EAAA,GAAK,iBAAiB,eAAA,CAAgB;AAAA,MACxC,GAAA;AAAA,MACA,mBAAA,EAAqB;AAAA,KACxB,CAAA;AAED,IAAA,YAAA,CAAa,EAAE,CAAA;AACf,IAAA,OAAO,MAAM;AACT,MAAA,YAAA,CAAa,MAAS,CAAA;AACtB,MAAA,EAAA,CAAG,OAAA,EAAQ;AAAA,IACf,CAAA;AAAA,EACJ,CAAA,EAAG,CAAC,gBAAA,EAAkB,GAAG,CAAC,CAAA;AAG1B,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,IAAI,SAAA,EAAW;AACX,MAAA,SAAA,CAAU,OAAA,GAAU,OAAA;AAAA,IACxB;AAAA,EACJ,CAAA,EAAG,CAAC,SAAA,EAAW,OAAO,CAAC,CAAA;AAGvB,EAAA,SAAA,CAAU,MAAM;AACZ,IAAA,IAAI,CAAC,SAAA,EAAW;AACZ,MAAA;AAAA,IACJ;AAEA,IAAA,MAAM,MAAA,GAAS,UAAA,CAAW,MAAM,SAAA,CAAU,eAAe,QAAA,EAAU;AAAA,MAC/D,SAAA,EAAW;AAAA,KACd,CAAA;AACD,IAAA,OAAO,MAAM,OAAO,OAAA,EAAQ;AAAA,EAChC,CAAA,EAAG,CAAC,SAAS,CAAC,CAAA;AAEd,EAAA,OAAO,SAAA;AACX;;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useReactiveSnapshot } from '@open-pioneer/reactivity';
|
|
2
|
+
import { useIntl } from '../_virtual/hooks.js';
|
|
3
|
+
import { getSourceStatus } from '../model/SelectionViewModel.js';
|
|
4
|
+
|
|
5
|
+
function useSourceStatus(source) {
|
|
6
|
+
const intl = useIntl();
|
|
7
|
+
const sourceStatus = useReactiveSnapshot(() => {
|
|
8
|
+
if (!source) {
|
|
9
|
+
return {
|
|
10
|
+
kind: "unavailable",
|
|
11
|
+
reason: intl.formatMessage({ id: "sourceNotAvailable" })
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
const status = getSourceStatus(source);
|
|
15
|
+
if (status.kind === "available") {
|
|
16
|
+
return status;
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
kind: "unavailable",
|
|
20
|
+
reason: status.reason ?? intl.formatMessage({ id: "sourceNotAvailable" })
|
|
21
|
+
};
|
|
22
|
+
}, [source, intl]);
|
|
23
|
+
return sourceStatus;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { useSourceStatus };
|
|
27
|
+
//# sourceMappingURL=useSourceStatus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useSourceStatus.js","sources":["useSourceStatus.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { useReactiveSnapshot } from \"@open-pioneer/reactivity\";\nimport { useIntl } from \"open-pioneer:react-hooks\";\nimport { SelectionSource } from \"../api\";\nimport { getSourceStatus } from \"../model\";\n\nexport type SimpleStatus =\n | {\n kind: \"available\";\n }\n | {\n kind: \"unavailable\";\n reason: string;\n };\n\nexport function useSourceStatus(source: SelectionSource | undefined): SimpleStatus {\n const intl = useIntl();\n const sourceStatus = useReactiveSnapshot((): SimpleStatus => {\n if (!source) {\n return {\n kind: \"unavailable\",\n reason: intl.formatMessage({ id: \"sourceNotAvailable\" })\n };\n }\n\n const status = getSourceStatus(source);\n if (status.kind === \"available\") {\n return status;\n }\n return {\n kind: \"unavailable\",\n reason: status.reason ?? intl.formatMessage({ id: \"sourceNotAvailable\" })\n };\n }, [source, intl]);\n return sourceStatus;\n}\n"],"names":[],"mappings":";;;;AAiBO,SAAS,gBAAgB,MAAA,EAAmD;AAC/E,EAAA,MAAM,OAAO,OAAA,EAAQ;AACrB,EAAA,MAAM,YAAA,GAAe,oBAAoB,MAAoB;AACzD,IAAA,IAAI,CAAC,MAAA,EAAQ;AACT,MAAA,OAAO;AAAA,QACH,IAAA,EAAM,aAAA;AAAA,QACN,QAAQ,IAAA,CAAK,aAAA,CAAc,EAAE,EAAA,EAAI,sBAAsB;AAAA,OAC3D;AAAA,IACJ;AAEA,IAAA,MAAM,MAAA,GAAS,gBAAgB,MAAM,CAAA;AACrC,IAAA,IAAI,MAAA,CAAO,SAAS,WAAA,EAAa;AAC7B,MAAA,OAAO,MAAA;AAAA,IACX;AACA,IAAA,OAAO;AAAA,MACH,IAAA,EAAM,aAAA;AAAA,MACN,MAAA,EAAQ,OAAO,MAAA,IAAU,IAAA,CAAK,cAAc,EAAE,EAAA,EAAI,sBAAsB;AAAA,KAC5E;AAAA,EACJ,CAAA,EAAG,CAAC,MAAA,EAAQ,IAAI,CAAC,CAAA;AACjB,EAAA,OAAO,YAAA;AACX;;;;"}
|
package/DragController.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { Resource } from "@open-pioneer/core";
|
|
2
|
-
import { MapModel } from "@open-pioneer/map";
|
|
3
|
-
import Geometry from "ol/geom/Geometry";
|
|
4
|
-
import PointerInteraction from "ol/interaction/Pointer";
|
|
5
|
-
import OlMap from "ol/Map";
|
|
6
|
-
interface InteractionResource extends Resource {
|
|
7
|
-
interaction: PointerInteraction;
|
|
8
|
-
}
|
|
9
|
-
export declare class DragController {
|
|
10
|
-
#private;
|
|
11
|
-
constructor(map: MapModel, tooltipMessage: string, tooltipDisabledMessage: string, onExtentSelected: (geometry: Geometry) => void);
|
|
12
|
-
initViewport(olMap: OlMap): HTMLElement;
|
|
13
|
-
/**
|
|
14
|
-
* Method for destroying the controller when it is no longer needed
|
|
15
|
-
*/
|
|
16
|
-
destroy(): void;
|
|
17
|
-
/**
|
|
18
|
-
* The current tooltip text shown to the user.
|
|
19
|
-
*/
|
|
20
|
-
get tooltipText(): string;
|
|
21
|
-
setActive(isActive: boolean): void;
|
|
22
|
-
/**
|
|
23
|
-
* Method for testing purposes only
|
|
24
|
-
* @returns InteractionResource of class DragBox
|
|
25
|
-
*/
|
|
26
|
-
getDragboxInteraction(): InteractionResource | undefined;
|
|
27
|
-
/**
|
|
28
|
-
* Method for testing purposes only
|
|
29
|
-
* @returns InteractionResource of class DragPan
|
|
30
|
-
*/
|
|
31
|
-
getDragPanInteraction(): InteractionResource | undefined;
|
|
32
|
-
}
|
|
33
|
-
export {};
|
package/DragController.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
import { reactive, watch } from '@conterra/reactivity-core';
|
|
2
|
-
import { mouseActionButton } from 'ol/events/condition.js';
|
|
3
|
-
import { DragBox, DragPan } from 'ol/interaction.js';
|
|
4
|
-
import { createElement } from 'react';
|
|
5
|
-
import { SelectionTooltipContent } from './SelectionTooltipContent.js';
|
|
6
|
-
|
|
7
|
-
const ACTIVE_CLASS = "selection-active";
|
|
8
|
-
const INACTIVE_CLASS = "selection-inactive";
|
|
9
|
-
class DragController {
|
|
10
|
-
#tooltip;
|
|
11
|
-
#interactionResources = [];
|
|
12
|
-
#olMap;
|
|
13
|
-
#isActive = reactive(true);
|
|
14
|
-
#tooltipMessage;
|
|
15
|
-
#tooltipDisabledMessage;
|
|
16
|
-
#tooltipSync;
|
|
17
|
-
constructor(map, tooltipMessage, tooltipDisabledMessage, onExtentSelected) {
|
|
18
|
-
this.#olMap = map.olMap;
|
|
19
|
-
const viewPort = this.initViewport(this.#olMap);
|
|
20
|
-
this.#interactionResources.push(
|
|
21
|
-
this.#createDragBox(this.#olMap, onExtentSelected, viewPort, this.#interactionResources)
|
|
22
|
-
);
|
|
23
|
-
this.#interactionResources.push(
|
|
24
|
-
this.#createDrag(this.#olMap, viewPort, this.#interactionResources)
|
|
25
|
-
);
|
|
26
|
-
this.#tooltip = this.#createHelpTooltip(map, tooltipMessage);
|
|
27
|
-
this.#tooltipMessage = tooltipMessage;
|
|
28
|
-
this.#tooltipDisabledMessage = tooltipDisabledMessage;
|
|
29
|
-
this.#tooltipSync = watch(
|
|
30
|
-
() => [this.#isActive.value, this.tooltipText],
|
|
31
|
-
([isActive, tooltipText]) => {
|
|
32
|
-
const tooltipContent = createElement(SelectionTooltipContent, {
|
|
33
|
-
content: tooltipText
|
|
34
|
-
});
|
|
35
|
-
this.#tooltip.setContent(tooltipContent);
|
|
36
|
-
viewPort.classList.toggle(ACTIVE_CLASS, isActive);
|
|
37
|
-
viewPort.classList.toggle(INACTIVE_CLASS, !isActive);
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
immediate: true
|
|
41
|
-
}
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
initViewport(olMap) {
|
|
45
|
-
const viewPort = olMap.getViewport();
|
|
46
|
-
viewPort.classList.add(ACTIVE_CLASS);
|
|
47
|
-
viewPort.oncontextmenu = (e) => {
|
|
48
|
-
e.preventDefault();
|
|
49
|
-
return false;
|
|
50
|
-
};
|
|
51
|
-
return viewPort;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Method for destroying the controller when it is no longer needed
|
|
55
|
-
*/
|
|
56
|
-
destroy() {
|
|
57
|
-
this.#tooltipSync?.destroy();
|
|
58
|
-
this.#tooltipSync = void 0;
|
|
59
|
-
this.#tooltip.destroy();
|
|
60
|
-
this.#interactionResources.forEach((interaction) => {
|
|
61
|
-
interaction.destroy();
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* The current tooltip text shown to the user.
|
|
66
|
-
*/
|
|
67
|
-
get tooltipText() {
|
|
68
|
-
const isActive = this.#isActive.value;
|
|
69
|
-
return isActive ? this.#tooltipMessage : this.#tooltipDisabledMessage;
|
|
70
|
-
}
|
|
71
|
-
setActive(isActive) {
|
|
72
|
-
if (this.#isActive.value === isActive) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
if (isActive) {
|
|
76
|
-
this.#interactionResources.forEach(
|
|
77
|
-
(interaction) => this.#olMap.addInteraction(interaction.interaction)
|
|
78
|
-
);
|
|
79
|
-
this.#isActive.value = true;
|
|
80
|
-
} else {
|
|
81
|
-
this.#interactionResources.forEach(
|
|
82
|
-
(interaction) => this.#olMap.removeInteraction(interaction.interaction)
|
|
83
|
-
);
|
|
84
|
-
this.#isActive.value = false;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Method to create a simple extent-selection
|
|
89
|
-
*/
|
|
90
|
-
#createDragBox(olMap, onExtentSelected, viewPort, interactionResources) {
|
|
91
|
-
const dragBox = new DragBox({
|
|
92
|
-
className: "selection-drag-box",
|
|
93
|
-
condition: mouseActionButton
|
|
94
|
-
});
|
|
95
|
-
olMap.addInteraction(dragBox);
|
|
96
|
-
dragBox.on("boxend", function() {
|
|
97
|
-
onExtentSelected(dragBox.getGeometry());
|
|
98
|
-
});
|
|
99
|
-
const interactionResource = {
|
|
100
|
-
interaction: dragBox,
|
|
101
|
-
destroy() {
|
|
102
|
-
olMap.removeInteraction(dragBox);
|
|
103
|
-
interactionResources.splice(interactionResources.indexOf(this));
|
|
104
|
-
dragBox.dispose();
|
|
105
|
-
viewPort.classList.remove(ACTIVE_CLASS);
|
|
106
|
-
viewPort.classList.remove(INACTIVE_CLASS);
|
|
107
|
-
viewPort.oncontextmenu = null;
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
return interactionResource;
|
|
111
|
-
}
|
|
112
|
-
/**
|
|
113
|
-
* Method to activate pan with right-mouse-click
|
|
114
|
-
*/
|
|
115
|
-
#createDrag(olMap, viewPort, interactionResources) {
|
|
116
|
-
const condition = function(mapBrowserEvent) {
|
|
117
|
-
const originalEvent = mapBrowserEvent.originalEvent;
|
|
118
|
-
return "button" in originalEvent && originalEvent.button == 2;
|
|
119
|
-
};
|
|
120
|
-
const drag = new DragPan({
|
|
121
|
-
condition
|
|
122
|
-
});
|
|
123
|
-
olMap.addInteraction(drag);
|
|
124
|
-
const interactionResource = {
|
|
125
|
-
interaction: drag,
|
|
126
|
-
destroy() {
|
|
127
|
-
olMap.removeInteraction(drag);
|
|
128
|
-
interactionResources.splice(interactionResources.indexOf(this));
|
|
129
|
-
drag.dispose();
|
|
130
|
-
viewPort.classList.remove(ACTIVE_CLASS);
|
|
131
|
-
viewPort.classList.remove(INACTIVE_CLASS);
|
|
132
|
-
viewPort.oncontextmenu = null;
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
return interactionResource;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Method to generate a tooltip on the mouse cursor
|
|
139
|
-
*/
|
|
140
|
-
#createHelpTooltip(map, message) {
|
|
141
|
-
const tooltipContent = createElement(SelectionTooltipContent, {
|
|
142
|
-
content: message
|
|
143
|
-
});
|
|
144
|
-
const tooltipOverlay = map.overlays.add({
|
|
145
|
-
content: tooltipContent,
|
|
146
|
-
position: "follow-pointer",
|
|
147
|
-
offset: [15, 0],
|
|
148
|
-
positioning: "center-left",
|
|
149
|
-
ariaRole: "tooltip",
|
|
150
|
-
className: "selection-tooltip printing-hide"
|
|
151
|
-
});
|
|
152
|
-
return tooltipOverlay;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Method for testing purposes only
|
|
156
|
-
* @returns InteractionResource of class DragBox
|
|
157
|
-
*/
|
|
158
|
-
getDragboxInteraction() {
|
|
159
|
-
return this.#interactionResources.find(
|
|
160
|
-
(interactionResource) => interactionResource.interaction instanceof DragBox
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Method for testing purposes only
|
|
165
|
-
* @returns InteractionResource of class DragPan
|
|
166
|
-
*/
|
|
167
|
-
getDragPanInteraction() {
|
|
168
|
-
return this.#interactionResources.find(
|
|
169
|
-
(interactionResource) => interactionResource.interaction instanceof DragPan
|
|
170
|
-
);
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
export { DragController };
|
|
175
|
-
//# sourceMappingURL=DragController.js.map
|
package/DragController.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DragController.js","sources":["DragController.ts"],"sourcesContent":["// SPDX-FileCopyrightText: 2023-2025 Open Pioneer project (https://github.com/open-pioneer)\n// SPDX-License-Identifier: Apache-2.0\n\nimport { reactive, watch } from \"@conterra/reactivity-core\";\nimport { Resource } from \"@open-pioneer/core\";\nimport { MapModel, Overlay } from \"@open-pioneer/map\";\nimport { MapBrowserEvent } from \"ol\";\nimport { mouseActionButton } from \"ol/events/condition\";\nimport Geometry from \"ol/geom/Geometry\";\nimport { DragBox, DragPan } from \"ol/interaction\";\nimport PointerInteraction from \"ol/interaction/Pointer\";\nimport OlMap from \"ol/Map\";\nimport { createElement } from \"react\";\nimport { SelectionTooltipContent } from \"./SelectionTooltipContent\";\n\ninterface InteractionResource extends Resource {\n interaction: PointerInteraction;\n}\n\nconst ACTIVE_CLASS = \"selection-active\";\nconst INACTIVE_CLASS = \"selection-inactive\";\n\nexport class DragController {\n #tooltip: Overlay;\n #interactionResources: InteractionResource[] = [];\n #olMap: OlMap;\n #isActive = reactive(true);\n #tooltipMessage: string;\n #tooltipDisabledMessage: string;\n #tooltipSync: Resource | undefined;\n\n constructor(\n map: MapModel,\n tooltipMessage: string,\n tooltipDisabledMessage: string,\n onExtentSelected: (geometry: Geometry) => void\n ) {\n this.#olMap = map.olMap;\n const viewPort = this.initViewport(this.#olMap);\n this.#interactionResources.push(\n this.#createDragBox(this.#olMap, onExtentSelected, viewPort, this.#interactionResources)\n );\n this.#interactionResources.push(\n this.#createDrag(this.#olMap, viewPort, this.#interactionResources)\n );\n\n this.#tooltip = this.#createHelpTooltip(map, tooltipMessage);\n this.#tooltipMessage = tooltipMessage;\n this.#tooltipDisabledMessage = tooltipDisabledMessage;\n\n this.#tooltipSync = watch(\n () => [this.#isActive.value, this.tooltipText],\n ([isActive, tooltipText]) => {\n const tooltipContent = createElement(SelectionTooltipContent, {\n content: tooltipText\n });\n this.#tooltip.setContent(tooltipContent);\n viewPort.classList.toggle(ACTIVE_CLASS, isActive);\n viewPort.classList.toggle(INACTIVE_CLASS, !isActive);\n },\n {\n immediate: true\n }\n );\n }\n\n initViewport(olMap: OlMap) {\n const viewPort = olMap.getViewport();\n viewPort.classList.add(ACTIVE_CLASS);\n\n viewPort.oncontextmenu = (e) => {\n e.preventDefault();\n return false;\n };\n return viewPort;\n }\n\n /**\n * Method for destroying the controller when it is no longer needed\n */\n destroy() {\n this.#tooltipSync?.destroy();\n this.#tooltipSync = undefined;\n\n this.#tooltip.destroy();\n this.#interactionResources.forEach((interaction) => {\n interaction.destroy();\n });\n }\n\n /**\n * The current tooltip text shown to the user.\n */\n get tooltipText(): string {\n const isActive = this.#isActive.value;\n return isActive ? this.#tooltipMessage : this.#tooltipDisabledMessage;\n }\n\n setActive(isActive: boolean) {\n if (this.#isActive.value === isActive) {\n return;\n }\n\n if (isActive) {\n this.#interactionResources.forEach((interaction) =>\n this.#olMap.addInteraction(interaction.interaction)\n );\n this.#isActive.value = true;\n } else {\n this.#interactionResources.forEach((interaction) =>\n this.#olMap.removeInteraction(interaction.interaction)\n );\n this.#isActive.value = false;\n }\n }\n\n /**\n * Method to create a simple extent-selection\n */\n #createDragBox(\n olMap: OlMap,\n onExtentSelected: (geometry: Geometry) => void,\n viewPort: HTMLElement,\n interactionResources: InteractionResource[]\n ): InteractionResource {\n const dragBox = new DragBox({\n className: \"selection-drag-box\",\n condition: mouseActionButton\n });\n\n olMap.addInteraction(dragBox);\n dragBox.on(\"boxend\", function () {\n onExtentSelected(dragBox.getGeometry());\n });\n\n const interactionResource: InteractionResource = {\n interaction: dragBox,\n destroy() {\n olMap.removeInteraction(dragBox);\n interactionResources.splice(interactionResources.indexOf(this));\n dragBox.dispose();\n viewPort.classList.remove(ACTIVE_CLASS);\n viewPort.classList.remove(INACTIVE_CLASS);\n viewPort.oncontextmenu = null;\n }\n };\n return interactionResource;\n }\n\n /**\n * Method to activate pan with right-mouse-click\n */\n #createDrag(\n olMap: OlMap,\n viewPort: HTMLElement,\n interactionResources: InteractionResource[]\n ): InteractionResource {\n const condition = function (mapBrowserEvent: MapBrowserEvent) {\n const originalEvent = mapBrowserEvent.originalEvent;\n return \"button\" in originalEvent && originalEvent.button == 2;\n };\n const drag = new DragPan({\n condition: condition\n });\n\n olMap.addInteraction(drag);\n\n const interactionResource: InteractionResource = {\n interaction: drag,\n destroy() {\n olMap.removeInteraction(drag);\n interactionResources.splice(interactionResources.indexOf(this));\n drag.dispose();\n viewPort.classList.remove(ACTIVE_CLASS);\n viewPort.classList.remove(INACTIVE_CLASS);\n viewPort.oncontextmenu = null;\n }\n };\n\n return interactionResource;\n }\n\n /**\n * Method to generate a tooltip on the mouse cursor\n */\n #createHelpTooltip(map: MapModel, message: string): Overlay {\n const tooltipContent = createElement(SelectionTooltipContent, {\n content: message\n });\n const tooltipOverlay = map.overlays.add({\n content: tooltipContent,\n position: \"follow-pointer\",\n offset: [15, 0],\n positioning: \"center-left\",\n ariaRole: \"tooltip\",\n className: \"selection-tooltip printing-hide\"\n });\n\n return tooltipOverlay;\n }\n\n /**\n * Method for testing purposes only\n * @returns InteractionResource of class DragBox\n */\n getDragboxInteraction() {\n return this.#interactionResources.find(\n (interactionResource) => interactionResource.interaction instanceof DragBox\n );\n }\n\n /**\n * Method for testing purposes only\n * @returns InteractionResource of class DragPan\n */\n getDragPanInteraction() {\n return this.#interactionResources.find(\n (interactionResource) => interactionResource.interaction instanceof DragPan\n );\n }\n}\n"],"names":[],"mappings":"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"}
|