@geops/rvf-mobility-web-component 0.1.11 → 0.1.12

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.
Files changed (61) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/docutils.js +9 -9
  3. package/index.js +222 -169
  4. package/package.json +2 -2
  5. package/scripts/build.mjs +3 -2
  6. package/scripts/dev.mjs +1 -0
  7. package/src/BaseLayer/BaseLayer.tsx +20 -12
  8. package/src/FloatingMenu/FloatingMenu.tsx +42 -0
  9. package/src/FloatingMenu/index.tsx +1 -0
  10. package/src/RealtimeLayer/RealtimeLayer.tsx +1 -2
  11. package/src/RvfCheckbox/RvfCheckbox.tsx +24 -0
  12. package/src/RvfCheckbox/index.tsx +1 -0
  13. package/src/RvfExportMenu/RvfExportMenu.tsx +14 -6
  14. package/src/RvfFloatingMenu/RvfFloatingMenu.tsx +44 -0
  15. package/src/RvfFloatingMenu/index.tsx +1 -0
  16. package/src/{LayerTree/LayerTree.tsx → RvfLayerTree/RvfLayerTree.tsx} +10 -13
  17. package/src/RvfLayerTree/TreeItem/TreeItem.tsx +120 -0
  18. package/src/RvfLayerTree/index.tsx +1 -0
  19. package/src/{LayerTree → RvfLayerTree}/layersTreeReducer.ts +0 -4
  20. package/src/RvfLineNetworkPlanLayer/RvfLineNetworkPlanLayer.tsx +42 -0
  21. package/src/RvfLineNetworkPlanLayer/index.tsx +1 -0
  22. package/src/RvfMobilityMap/RvfMobilityMap.tsx +28 -23
  23. package/src/RvfRadioButton/RvfRadioButton.tsx +16 -0
  24. package/src/RvfRadioButton/index.tsx +1 -0
  25. package/src/RvfSelect/RvfSelect.tsx +22 -0
  26. package/src/RvfSelect/index.tsx +1 -0
  27. package/src/RvfSellingPointsLayer/RvfSellingPointsLayer.tsx +41 -0
  28. package/src/RvfSellingPointsLayer/index.tsx +1 -0
  29. package/src/RvfSharedMobilityLayerGroup/RvfSharedMobilityLayerGroup.tsx +17 -5
  30. package/src/RvfSingleClickListener/RvfSingleClickListener.tsx +10 -1
  31. package/src/RvfTarifZonenLayer/RvfTarifZonenLayer.tsx +41 -0
  32. package/src/RvfTarifZonenLayer/index.tsx +1 -0
  33. package/src/RvfTopics/RvfTopics.tsx +47 -0
  34. package/src/RvfTopics/index.tsx +1 -0
  35. package/src/icons/ArrowDown/ArrowDown.tsx +22 -0
  36. package/src/icons/ArrowDown/down-open.svg +7 -0
  37. package/src/icons/ArrowDown/index.tsx +1 -0
  38. package/src/icons/ArrowUp/ArrowUp.tsx +22 -0
  39. package/src/icons/ArrowUp/index.tsx +1 -0
  40. package/src/icons/ArrowUp/up-open.svg +7 -0
  41. package/src/icons/Bicycle/verkehrstraeger-rad-2px-white.svg +19 -0
  42. package/src/icons/Car/verkehrstraeger-auto-2px-white.svg +14 -0
  43. package/src/icons/CargoBicycle/verkehrstraeger-lastenrad-2px-white.svg +27 -0
  44. package/src/icons/DownOpen/DownOpen.tsx +24 -0
  45. package/src/icons/DownOpen/down-open.svg +7 -0
  46. package/src/icons/DownOpen/index.tsx +1 -0
  47. package/src/icons/Ok/ok-grey.svg +7 -0
  48. package/src/icons/Ok/ok.svg +4 -0
  49. package/src/icons/Scooter/scooter.svg +10 -0
  50. package/src/utils/createMobiDataBwWfsLayer.ts +3 -3
  51. package/src/utils/createSharedMobilityLayer.ts +165 -0
  52. package/src/utils/exportPdf.ts +9 -29
  53. package/tailwind.config.mjs +19 -38
  54. package/src/LayerTree/TreeItem/TreeItem.tsx +0 -145
  55. package/src/LayerTree/TreeItemContainer/TreeItemContainer.tsx +0 -16
  56. package/src/LayerTree/TreeItemContainer/index.tsx +0 -1
  57. package/src/LayerTree/index.tsx +0 -1
  58. package/src/TopicMenu/TopicMenu.tsx +0 -143
  59. package/src/TopicMenu/index.tsx +0 -1
  60. /package/src/{LayerTree → RvfLayerTree}/TreeItem/index.tsx +0 -0
  61. /package/src/{LayerTree → RvfLayerTree}/layersTreeContext.ts +0 -0
package/package.json CHANGED
@@ -2,14 +2,14 @@
2
2
  "name": "@geops/rvf-mobility-web-component",
3
3
  "license": "UNLICENSED",
4
4
  "description": "Web components for rvf in the domains of mobility and logistics.",
5
- "version": "0.1.11",
5
+ "version": "0.1.12",
6
6
  "homepage": "https://rvf-mobility-web-component-geops.vercel.app/",
7
7
  "type": "module",
8
8
  "main": "index.js",
9
9
  "dependencies": {
10
10
  "jspdf": "^2.5.2",
11
11
  "maplibre-gl": "^4.7.1",
12
- "mobility-toolbox-js": "3.1.0-beta.2",
12
+ "mobility-toolbox-js": "3.1.0",
13
13
  "ol": "^10.3.1",
14
14
  "preact": "^10.25.1",
15
15
  "preact-custom-element": "^4.3.0",
package/scripts/build.mjs CHANGED
@@ -3,13 +3,14 @@ import * as esbuild from "esbuild";
3
3
  import { sassPlugin } from "esbuild-sass-plugin";
4
4
 
5
5
  await esbuild.build({
6
- entryPoints: ["./src/index.js"],
7
6
  bundle: true,
8
- minify: true,
7
+ entryPoints: ["./src/index.js"],
9
8
  external: ["mapbox-gl"],
10
9
  loader: {
11
10
  ".png": "dataurl",
11
+ ".svg": "dataurl",
12
12
  },
13
+ minify: true,
13
14
  outfile: "index.js",
14
15
  plugins: [sassPlugin({ type: "css-text" })],
15
16
  sourcemap: false,
package/scripts/dev.mjs CHANGED
@@ -8,6 +8,7 @@ const ctx = await esbuild.context({
8
8
  external: ["mapbox-gl"],
9
9
  loader: {
10
10
  ".png": "dataurl",
11
+ ".svg": "dataurl",
11
12
  },
12
13
  outfile: "index.js",
13
14
  plugins: [sassPlugin({ type: "css-text" })],
@@ -1,34 +1,42 @@
1
1
  import { MaplibreLayer } from "mobility-toolbox-js/ol";
2
2
  import { MaplibreLayerOptions } from "mobility-toolbox-js/ol/layers/MaplibreLayer";
3
- import { Layer } from "ol/layer";
4
3
  import { memo } from "preact/compat";
5
- import { useEffect } from "preact/hooks";
4
+ import { useEffect, useMemo } from "preact/hooks";
6
5
 
7
6
  import useMapContext from "../utils/hooks/useMapContext";
8
7
 
9
- function BaseLayer(props: MaplibreLayerOptions) {
8
+ export type BaseLayerProps = MaplibreLayerOptions;
9
+
10
+ function BaseLayer(props: BaseLayerProps) {
10
11
  const { apikey, baselayer, map, mapsurl, setBaseLayer } = useMapContext();
11
- useEffect(() => {
12
- if (!map || !baselayer || !apikey) {
12
+
13
+ const layer = useMemo(() => {
14
+ if (!baselayer || !apikey) {
13
15
  return;
14
16
  }
15
- const layer = new MaplibreLayer({
17
+ return new MaplibreLayer({
16
18
  apiKey: apikey,
17
19
  style: baselayer,
18
20
  url: mapsurl,
21
+ zIndex: 0,
19
22
  ...(props || {}),
20
23
  });
21
- const baseLayer = layer as unknown as Layer;
24
+ }, [baselayer, apikey, props, mapsurl]);
22
25
 
23
- // TODO: find why the setZIndex is not found
24
- baseLayer.setZIndex(0);
25
- map.addLayer(baseLayer);
26
+ useEffect(() => {
26
27
  setBaseLayer(layer);
28
+ }, [layer, setBaseLayer]);
29
+
30
+ useEffect(() => {
31
+ if (!map || !layer) {
32
+ return;
33
+ }
34
+ map.addLayer(layer);
27
35
 
28
36
  return () => {
29
- map?.removeLayer(baseLayer);
37
+ map.removeLayer(layer);
30
38
  };
31
- }, [map, baselayer, apikey, setBaseLayer, props, mapsurl]);
39
+ }, [map, layer]);
32
40
 
33
41
  return null;
34
42
  }
@@ -0,0 +1,42 @@
1
+ import { useState } from "preact/hooks";
2
+
3
+ import ArrowDown from "../icons/ArrowDown";
4
+ import ArrowUp from "../icons/ArrowUp";
5
+ import Topics from "../RvfTopics";
6
+ import useMapContext from "../utils/hooks/useMapContext";
7
+
8
+ function FloatingMenu() {
9
+ const { map } = useMapContext();
10
+ const [isCollapsed, setIsCollapsed] = useState(true);
11
+
12
+ if (!map) {
13
+ return null;
14
+ }
15
+
16
+ return (
17
+ <div className="pointer-events-none absolute bottom-8 left-2 top-2 z-10 flex flex-col overflow-hidden rounded-lg">
18
+ <div
19
+ className="pointer-events-auto max-h-full rounded-lg border bg-white shadow-lg medium:w-largeMenu large:w-mediumMenu"
20
+
21
+ // className="flex-column absolute left-2 top-2 z-10 max-h-80 rounded-lg bg-white px-2 py-1.5 shadow-lg medium:w-largeMenu large:w-mediumMenu"
22
+ >
23
+ <button
24
+ className="flex w-full items-center justify-between px-2 py-1.5 "
25
+ onClick={() => {
26
+ return setIsCollapsed(!isCollapsed);
27
+ }}
28
+ >
29
+ <span>Kartendaten</span>
30
+ {isCollapsed ? <ArrowDown /> : <ArrowUp />}
31
+ </button>
32
+ {!isCollapsed && (
33
+ <div className="flex h-[calc(100%-39px)] w-full flex-1 overflow-y-auto">
34
+ <Topics />
35
+ </div>
36
+ )}
37
+ </div>
38
+ </div>
39
+ );
40
+ }
41
+
42
+ export default FloatingMenu;
@@ -0,0 +1 @@
1
+ export { default } from "./FloatingMenu";
@@ -50,6 +50,7 @@ function RealtimeLayer(props: RealtimeLayerProps) {
50
50
  : undefined,
51
51
  tenant,
52
52
  url: realtimeurl,
53
+ zIndex: 1,
53
54
  ...props,
54
55
  styleOptions: {
55
56
  getDelayColor: getDelayColorForVehicle,
@@ -61,8 +62,6 @@ function RealtimeLayer(props: RealtimeLayerProps) {
61
62
  },
62
63
  });
63
64
 
64
- layer.setZIndex(1);
65
-
66
65
  return layer;
67
66
  }, [apikey, mots, realtimeurl, tenant, props]);
68
67
 
@@ -0,0 +1,24 @@
1
+ import type { JSX } from "preact";
2
+
3
+ import { memo } from "preact/compat";
4
+
5
+ // @ts-expect-error - required for htm to resolve the JSX pragma
6
+ import ok from "../icons/Ok/ok-grey.svg";
7
+
8
+ export type RvfCheckboxProps = {} & JSX.InputHTMLAttributes<HTMLInputElement>;
9
+
10
+ function RvfCheckbox({ className, ...props }: RvfCheckboxProps) {
11
+ return (
12
+ <input
13
+ className={`box-border size-[20px] cursor-pointer appearance-none rounded border-2 border-grey bg-white bg-contain bg-center text-grey disabled:cursor-default disabled:border-lightgrey ${className}`}
14
+ style={{
15
+ backgroundImage:
16
+ props.checked && !props.disabled ? `url('` + ok + `')` : "",
17
+ }}
18
+ {...props}
19
+ type="checkbox"
20
+ />
21
+ );
22
+ }
23
+
24
+ export default memo(RvfCheckbox);
@@ -0,0 +1 @@
1
+ export { default } from "./RvfCheckbox";
@@ -4,7 +4,9 @@ import { memo, useId, useState } from "preact/compat";
4
4
 
5
5
  import Cancel from "../icons/Cancel";
6
6
  import RvfButton from "../RvfButton";
7
+ import RvfCheckbox from "../RvfCheckbox";
7
8
  import RvfIconButton from "../RvfIconButton";
9
+ import RvfSelect from "../RvfSelect";
8
10
  import exportPdf from "../utils/exportPdf";
9
11
  import useMapContext from "../utils/hooks/useMapContext";
10
12
  import useRvfContext from "../utils/hooks/useRvfContext";
@@ -39,31 +41,37 @@ function RvfExportMenu({ ...props }: RvfExportMenuButtonProps) {
39
41
  </div>
40
42
  {/* <!-- Content --> */}
41
43
  <div className="flex flex-1 flex-col gap-2">
42
- <div className={"flex gap-2"}>
43
- <input
44
+ <div className={"flex items-center gap-2"}>
45
+ {/* <input
44
46
  checked={useMaxExtent}
45
47
  id={checkboxId}
46
48
  onChange={() => {
47
49
  setUseMaxExtent(!useMaxExtent);
48
50
  }}
49
51
  type="checkbox"
52
+ /> */}
53
+ <RvfCheckbox
54
+ checked={useMaxExtent}
55
+ id={checkboxId}
56
+ onChange={() => {
57
+ return setUseMaxExtent(!useMaxExtent);
58
+ }}
50
59
  />
51
60
  <label htmlFor={checkboxId}>Ganze Region exportieren</label>
52
61
  </div>
53
- <div className={"flex gap-2"}>
62
+ <div className={"flex items-center gap-2"}>
54
63
  <label htmlFor={selectId}>Format:</label>
55
- <select
64
+ <RvfSelect
56
65
  className={"w-24"}
57
66
  id={selectId}
58
67
  onChange={(evt) => {
59
68
  setFormat((evt.target as HTMLSelectElement).value);
60
69
  }}
61
- value={format}
62
70
  >
63
71
  {formats.map((format) => {
64
72
  return <option key={format}>{format}</option>;
65
73
  })}
66
- </select>
74
+ </RvfSelect>
67
75
  </div>
68
76
  </div>
69
77
  {/* <!-- Footer --> */}
@@ -0,0 +1,44 @@
1
+ import type { JSX, PreactDOMAttributes } from "preact";
2
+
3
+ import ArrowDown from "../icons/ArrowDown";
4
+ import ArrowUp from "../icons/ArrowUp";
5
+ import useMapContext from "../utils/hooks/useMapContext";
6
+
7
+ export type RvfFloatingMenuProps = {
8
+ isOpen: boolean;
9
+ onClick: () => void;
10
+ } & JSX.HTMLAttributes<HTMLDivElement> &
11
+ PreactDOMAttributes;
12
+
13
+ function RvfFloatingMenu({
14
+ children,
15
+ isOpen,
16
+ onClick,
17
+ title,
18
+ }: RvfFloatingMenuProps) {
19
+ const { map } = useMapContext();
20
+
21
+ if (!map) {
22
+ return null;
23
+ }
24
+
25
+ return (
26
+ <div className="pointer-events-none absolute bottom-8 left-2 top-2 z-10 flex flex-col overflow-hidden rounded-lg">
27
+ <div className="pointer-events-auto max-h-full rounded-lg border bg-white shadow-lg medium:w-largeMenu large:w-mediumMenu">
28
+ <button
29
+ className="flex w-full items-center justify-between px-2 py-1.5 "
30
+ onClick={onClick}
31
+ >
32
+ {title} {isOpen ? <ArrowDown /> : <ArrowUp />}
33
+ </button>
34
+ {!isOpen && (
35
+ <div className="flex h-[calc(100%-39px)] w-full flex-1 overflow-y-auto">
36
+ {children}
37
+ </div>
38
+ )}
39
+ </div>
40
+ </div>
41
+ );
42
+ }
43
+
44
+ export default RvfFloatingMenu;
@@ -0,0 +1 @@
1
+ export { default } from "./RvfFloatingMenu";
@@ -1,3 +1,5 @@
1
+ import { JSX, PreactDOMAttributes } from "preact";
2
+ import { memo } from "preact/compat";
1
3
  import { useEffect, useReducer } from "preact/hooks";
2
4
 
3
5
  import {
@@ -6,24 +8,23 @@ import {
6
8
  } from "./layersTreeContext";
7
9
  import layersTreeReducer from "./layersTreeReducer";
8
10
  import TreeItem, { TreeItemProps } from "./TreeItem/TreeItem";
9
- import TreeItemContainer from "./TreeItemContainer";
10
11
 
11
- export interface LayerTreeProps {
12
+ export type RvfLayerTreeProps = {
12
13
  layers: TreeItemProps[];
13
- }
14
+ } & JSX.HTMLAttributes<HTMLDivElement> &
15
+ PreactDOMAttributes;
14
16
 
15
- function LayerTree({ layers }: LayerTreeProps) {
17
+ function RvfLayerTree({ layers, ...props }: RvfLayerTreeProps) {
16
18
  const [tree, dispatch] = useReducer(layersTreeReducer, layers);
17
19
 
18
20
  useEffect(() => {
19
21
  dispatch({ payload: layers, type: "INIT" });
20
- console.log("INIT", layers);
21
22
  }, [layers]);
22
23
 
23
24
  const renderedLayers = layers.map((item, idx) => {
24
25
  return (
25
- <div className="border-b border-grey" key={idx}>
26
- <TreeItem {...item} />
26
+ <div className="w-full" key={idx}>
27
+ <TreeItem className="w-full" {...item} />
27
28
  </div>
28
29
  );
29
30
  });
@@ -31,14 +32,10 @@ function LayerTree({ layers }: LayerTreeProps) {
31
32
  return (
32
33
  <LayersTreeContext.Provider value={tree}>
33
34
  <LayersTreeDispatchContext.Provider value={dispatch}>
34
- <div className="flex flex-col">
35
- <TreeItemContainer selectionType={tree[0]?.selectionType}>
36
- {renderedLayers}
37
- </TreeItemContainer>
38
- </div>
35
+ <div {...props}>{renderedLayers}</div>
39
36
  </LayersTreeDispatchContext.Provider>
40
37
  </LayersTreeContext.Provider>
41
38
  );
42
39
  }
43
40
 
44
- export default LayerTree;
41
+ export default memo(RvfLayerTree);
@@ -0,0 +1,120 @@
1
+ import type { JSX, PreactDOMAttributes } from "preact";
2
+
3
+ import BaseLayer from "ol/layer/Base";
4
+ import {
5
+ SVGProps,
6
+ useContext,
7
+ useEffect,
8
+ useId,
9
+ useState,
10
+ } from "preact/compat";
11
+
12
+ import ArrowDown from "../../icons/ArrowDown";
13
+ import ArrowUp from "../../icons/ArrowUp";
14
+ import RvfCheckbox from "../../RvfCheckbox";
15
+ import RvfRadioButton from "../../RvfRadioButton";
16
+ import { LayersTreeDispatchContext } from "../layersTreeContext";
17
+
18
+ export enum SelectionType {
19
+ CHECKBOX = "checkbox",
20
+ RADIO = "radio",
21
+ }
22
+
23
+ export type TreeItemProps = {
24
+ childItems: TreeItemProps[];
25
+ Icon?: (props: SVGProps<SVGSVGElement>) => preact.JSX.Element;
26
+ id: string;
27
+ isCollapsedOnControlClick?: boolean;
28
+ isControlChecked?: boolean;
29
+ layer?: BaseLayer;
30
+ onIconClick?: () => void;
31
+ selectionType: SelectionType;
32
+ title: string;
33
+ } & JSX.HTMLAttributes<HTMLButtonElement> &
34
+ PreactDOMAttributes;
35
+
36
+ function TreeItem({
37
+ childItems,
38
+ isCollapsedOnControlClick,
39
+ isControlChecked,
40
+ layer,
41
+ selectionType,
42
+ title,
43
+ }: TreeItemProps) {
44
+ const [isContainerVisible, setIsContainerVisible] = useState(true);
45
+ const dispatch = useContext(LayersTreeDispatchContext);
46
+ const inputId = useId();
47
+ const buttonId = useId();
48
+
49
+ useEffect(() => {
50
+ if (isCollapsedOnControlClick) {
51
+ setIsContainerVisible(isControlChecked);
52
+ }
53
+ }, [isControlChecked, isCollapsedOnControlClick, layer]);
54
+
55
+ const handleItemClick = () => {
56
+ setIsContainerVisible(!isContainerVisible);
57
+
58
+ if (isCollapsedOnControlClick && !isContainerVisible) {
59
+ dispatch({
60
+ payload: {
61
+ ...this["props"],
62
+ isControlChecked: true,
63
+ },
64
+ type: "SELECT_ITEM",
65
+ });
66
+ }
67
+ };
68
+
69
+ const handleSelectionChange = (event) => {
70
+ dispatch({
71
+ payload: {
72
+ ...this["props"],
73
+ isControlChecked: event.target.checked,
74
+ },
75
+ type: "SELECT_ITEM",
76
+ });
77
+ };
78
+
79
+ const renderedLayers = childItems.map((item, idx) => {
80
+ return <TreeItem key={idx} {...item} />;
81
+ });
82
+
83
+ return (
84
+ <div>
85
+ <div className="flex items-center gap-2 border-b py-2">
86
+ {selectionType === SelectionType.RADIO ? (
87
+ <RvfRadioButton
88
+ checked={isControlChecked}
89
+ id={inputId}
90
+ onChange={handleSelectionChange}
91
+ />
92
+ ) : (
93
+ <RvfCheckbox
94
+ checked={isControlChecked}
95
+ id={inputId}
96
+ onChange={handleSelectionChange}
97
+ />
98
+ )}
99
+ <label
100
+ className={`cursor-pointer`}
101
+ htmlFor={childItems.length > 0 ? buttonId : inputId}
102
+ >
103
+ {title}
104
+ </label>
105
+ {childItems.length > 0 && (
106
+ <button
107
+ className={`flex cursor-pointer items-center gap-2 font-normal`}
108
+ id={buttonId}
109
+ onClick={handleItemClick}
110
+ >
111
+ {isContainerVisible ? <ArrowUp /> : <ArrowDown />}
112
+ </button>
113
+ )}
114
+ </div>
115
+ {isContainerVisible && <div className="pl-6">{renderedLayers}</div>}
116
+ </div>
117
+ );
118
+ }
119
+
120
+ export default TreeItem;
@@ -0,0 +1 @@
1
+ export { default } from "./RvfLayerTree";
@@ -10,8 +10,6 @@ const initTree = (tree) => {
10
10
  initializedTree.childItems = tree;
11
11
  mapNode(initializedTree.childItems, initializedTree);
12
12
 
13
- console.log("initializedTree", initializedTree);
14
-
15
13
  return initializedTree;
16
14
  };
17
15
 
@@ -146,8 +144,6 @@ function layersTreeReducer(state = ROOT, action) {
146
144
  return initTree(action.payload);
147
145
  case "SELECT_ITEM":
148
146
  return setNewControlCheckedStatus(state, action.payload);
149
- case "SELECT_RADIO_ITEM":
150
- return setNewControlCheckedStatus(state, action.payload);
151
147
  default:
152
148
  return state;
153
149
  }
@@ -0,0 +1,42 @@
1
+ import { MaplibreStyleLayer } from "mobility-toolbox-js/ol";
2
+ import { MaplibreStyleLayerOptions } from "mobility-toolbox-js/ol/layers/MaplibreStyleLayer";
3
+ import { memo } from "preact/compat";
4
+ import { useEffect, useMemo } from "preact/hooks";
5
+
6
+ import useMapContext from "../utils/hooks/useMapContext";
7
+
8
+ function RvfLineNetworkPlanLayer(props: MaplibreStyleLayerOptions) {
9
+ const { baseLayer, map } = useMapContext();
10
+
11
+ const layer = useMemo(() => {
12
+ if (!baseLayer) {
13
+ return null;
14
+ }
15
+ return new MaplibreStyleLayer({
16
+ layersFilter: ({ metadata, source }) => {
17
+ return (
18
+ metadata?.["rvf.filter"] === "netowrk_plans" ||
19
+ source === "network_plans"
20
+ );
21
+ },
22
+ maplibreLayer: baseLayer,
23
+ minZoom: 10,
24
+ ...(props || {}),
25
+ });
26
+ }, [baseLayer, props]);
27
+
28
+ useEffect(() => {
29
+ if (!map || !layer) {
30
+ return;
31
+ }
32
+
33
+ map.addLayer(layer);
34
+ return () => {
35
+ map.removeLayer(layer);
36
+ };
37
+ }, [map, layer]);
38
+
39
+ return null; // <RegisterForSelectFeaturesOnClick />;
40
+ }
41
+
42
+ export default memo(RvfLineNetworkPlanLayer);
@@ -0,0 +1 @@
1
+ export { default } from "./RvfLineNetworkPlanLayer";
@@ -16,8 +16,6 @@ import { useEffect, useMemo, useRef, useState } from "preact/hooks";
16
16
  import BaseLayer from "../BaseLayer";
17
17
  import Copyright from "../Copyright";
18
18
  import GeolocationButton from "../GeolocationButton";
19
- import Cancel from "../icons/Cancel";
20
- import Menu from "../icons/Menu";
21
19
  import Map from "../Map";
22
20
  import { MobilityMapProps } from "../MobilityMap/MobilityMap";
23
21
  import NotificationLayer from "../NotificationLayer";
@@ -27,11 +25,15 @@ import RouteSchedule from "../RouteSchedule";
27
25
  import RvfExportMenu from "../RvfExportMenu";
28
26
  import RvfExportMenuButton from "../RvfExportMenuButton";
29
27
  import RvfFeatureDetails from "../RvfFeatureDetails";
28
+ import RvfFloatingMenu from "../RvfFloatingMenu";
30
29
  // Notificationurl example: https://mobility-web-component-tmp.vercel.app/geops-mobility?notificationurl=https%3A%2F%2Fmoco.geops.io%2Fapi%2Fv1%2Fexport%2Fnotification%2F%3Fsso_config%3Dsob&geolocation=false&realtime=false&search=false&notificationat=2024-01-25T22%3A59%3A00Z
31
- import RvfIconButton from "../RvfIconButton";
30
+ import RvfLineNetworkPlanLayer from "../RvfLineNetworkPlanLayer";
32
31
  import Modal from "../RvfModal";
33
32
  import RvfPoisLayer from "../RvfPoisLayer";
33
+ import RvfSellingPointsLayer from "../RvfSellingPointsLayer";
34
34
  import RvfSharedMobilityLayerGroup from "../RvfSharedMobilityLayerGroup";
35
+ import RvfTarifZonenLayer from "../RvfTarifZonenLayer";
36
+ import Topics from "../RvfTopics";
35
37
  import RvfZoomButtons from "../RvfZoomButtons";
36
38
  import ScaleLine from "../ScaleLine";
37
39
  import Search from "../Search";
@@ -40,7 +42,6 @@ import Station from "../Station";
40
42
  import StationsLayer from "../StationsLayer";
41
43
  // @ts-expect-error bad type definition
42
44
  import tailwind from "../style.css";
43
- import TopicMenu from "../TopicMenu";
44
45
  import { RVF_EXTENT_3857 } from "../utils/constants";
45
46
  import { I18nContext } from "../utils/hooks/useI18n";
46
47
  import { MapContext } from "../utils/hooks/useMapContext";
@@ -57,6 +58,7 @@ const bbox = RVF_EXTENT_3857.join(",");
57
58
 
58
59
  const baseLayerProps = {
59
60
  mapLibreOptions: {
61
+ maxCanvasSize: [20000, 20000], // remove 4096 limitations
60
62
  preserveDrawingBuffer: true,
61
63
  },
62
64
  };
@@ -98,7 +100,7 @@ function RvfMobilityMap({
98
100
  const [isExportMenuOpen, setIsExportMenuOpen] = useState<boolean>(false);
99
101
  const [selectedFeature, setSelectedFeature] = useState<Feature>();
100
102
  const [selectedFeatures, setSelectedFeatures] = useState<Feature[]>();
101
- const [isLayerTreeOpen, setIsLayerTreeOpen] = useState(false);
103
+ const [isLayerTreeOpen, setIsLayerTreeOpen] = useState<boolean>(false);
102
104
 
103
105
  // TODO: this should be removed. The parent application should be responsible to do this
104
106
  // or we should find something that fit more usecases
@@ -226,13 +228,15 @@ function RvfMobilityMap({
226
228
  const rvfContextValue = useMemo(() => {
227
229
  return {
228
230
  isExportMenuOpen,
231
+ isLayerTreeOpen,
229
232
  selectedFeature,
230
233
  selectedFeatures,
231
234
  setIsExportMenuOpen,
235
+ setIsLayerTreeOpen,
232
236
  setSelectedFeature,
233
237
  setSelectedFeatures,
234
238
  };
235
- }, [isExportMenuOpen, selectedFeature, selectedFeatures]);
239
+ }, [isExportMenuOpen, selectedFeature, selectedFeatures, isLayerTreeOpen]);
236
240
 
237
241
  return (
238
242
  <I18nContext.Provider value={i18n}>
@@ -243,47 +247,48 @@ function RvfMobilityMap({
243
247
  <div
244
248
  className="relative size-full border font-sans @container/main"
245
249
  ref={eventNodeRef}
250
+ style={{ fontSize: 16 }}
246
251
  >
247
252
  <div className="relative flex size-full flex-col @lg/main:flex-row-reverse">
248
253
  <Map className="relative flex-1 overflow-visible ">
254
+ <RvfFloatingMenu
255
+ isOpen={isLayerTreeOpen}
256
+ onClick={() => {
257
+ setIsLayerTreeOpen(!isLayerTreeOpen);
258
+ }}
259
+ title="Kartendaten"
260
+ >
261
+ <Topics className={"w-full px-2"} />
262
+ </RvfFloatingMenu>
249
263
  <BaseLayer {...baseLayerProps} isNotInLayerTree />
250
264
  <SingleClickListener />
251
265
 
252
- {realtime === "true" && <RealtimeLayer title="Realtime data" />}
266
+ {realtime === "true" && <RealtimeLayer title="Echtzeit" />}
253
267
  {tenant && <StationsLayer />}
254
268
  {notification === "true" && <NotificationLayer />}
255
- {/* <RvfLnpLayer />
256
- <RvfVerkaufStellenLayer />
257
- <RvfTarifZonenLayer /> */}
269
+ <RvfSellingPointsLayer title="Verkaufsstellen" />
270
+ <RvfLineNetworkPlanLayer title="Liniennetz" />
271
+ <RvfTarifZonenLayer title="Tarifzonen" />
258
272
  <RvfPoisLayer title="POIs" />
259
-
260
273
  <RvfSharedMobilityLayerGroup title="Shared Mobility" />
261
274
 
262
- <div className="absolute left-2 top-2 z-10">
263
- <RvfIconButton
264
- onClick={() => {
265
- return setIsLayerTreeOpen(!isLayerTreeOpen);
266
- }}
267
- selected={isLayerTreeOpen}
268
- >
269
- {isLayerTreeOpen ? <Cancel /> : <Menu />}
270
- </RvfIconButton>
271
- {isLayerTreeOpen && <TopicMenu map={map} />}
272
- </div>
273
275
  <div className="absolute inset-x-2 bottom-2 z-10 flex items-end justify-between gap-2 text-[10px]">
274
276
  <ScaleLine className="bg-slate-50/70" />
275
277
  <Copyright className="bg-slate-50/70" />
276
278
  </div>
279
+
277
280
  <div className="absolute right-2 top-2 z-10 flex flex-col gap-2">
278
281
  {geolocation === "true" && <GeolocationButton />}
282
+ <RvfExportMenuButton />
279
283
  </div>
284
+
280
285
  {search === "true" && (
281
286
  <div className="absolute left-2 right-12 top-2 z-10 flex max-h-[90%] min-w-64 max-w-96 flex-col">
282
287
  <Search />
283
288
  </div>
284
289
  )}
290
+
285
291
  <div className="absolute bottom-10 right-2 z-10 flex flex-col justify-between gap-2">
286
- <RvfExportMenuButton />
287
292
  <RvfZoomButtons />
288
293
  </div>
289
294
  </Map>