@local-logic/maps 0.0.2 → 0.0.4
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 +14 -0
- package/package.json +3 -3
- package/src/components/Map/Root/Layers/Google/index.tsx +97 -0
- package/src/components/Map/Root/Layers/Mapbox/index.tsx +74 -0
- package/src/components/Map/Root/Layers/Maptiler/index.tsx +74 -0
- package/src/components/Map/Root/Layers/index.tsx +32 -0
- package/src/components/Map/Root/Layers/types.ts +15 -0
- package/src/components/Map/Root/Layers/utils.ts +64 -0
- package/src/components/Map/Root/Markers/types.ts +10 -1
- package/src/components/Map/Root/index.tsx +13 -1
- package/src/components/Map/Root/types.ts +0 -10
- package/src/components/Map/index.stories.tsx +22 -103
- package/src/components/Map/storybook-data.ts +255 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# @local-logic/maps
|
|
2
2
|
|
|
3
|
+
## 0.0.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 892a059: LL22-5368: Updated storybook github action
|
|
8
|
+
- Updated dependencies [892a059]
|
|
9
|
+
- @local-logic/design-system@0.7.12
|
|
10
|
+
|
|
11
|
+
## 0.0.3
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- de9946a: LL22-5133: Added layer support to map package
|
|
16
|
+
|
|
3
17
|
## 0.0.2
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@local-logic/maps",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "This is a maps implementation allowing for the display of Local Logic data on a map.",
|
|
5
5
|
"author": "Local Logic",
|
|
6
6
|
"license": "ISC",
|
|
@@ -14,14 +14,14 @@
|
|
|
14
14
|
"scripts": {
|
|
15
15
|
"dev": "vite",
|
|
16
16
|
"build": "vite build",
|
|
17
|
+
"build:storybook": "storybook build",
|
|
17
18
|
"test": "vitest run",
|
|
18
19
|
"stats": "STATS=1 vite build",
|
|
19
20
|
"size": "yarn run build && size-limit",
|
|
20
21
|
"lint": "TIMING=1 eslint --ext .js,.jsx,.ts,.tsx .",
|
|
21
22
|
"check-types": "tsc --project ./tsconfig.json --noEmit",
|
|
22
23
|
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
|
|
23
|
-
"storybook
|
|
24
|
-
"storybook:build": "storybook build"
|
|
24
|
+
"storybook": "storybook dev -p 6006"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
27
|
"react": ">=18",
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import React, { useState, useEffect, useContext } from "react";
|
|
2
|
+
|
|
3
|
+
// Work inspired from:
|
|
4
|
+
// https://github.com/visgl/react-google-maps/blob/main/examples/geometry/src/components/polygon.tsx
|
|
5
|
+
// https://visgl.github.io/react-google-maps/examples/geometry
|
|
6
|
+
|
|
7
|
+
import { GoogleMapsContext } from "@vis.gl/react-google-maps";
|
|
8
|
+
|
|
9
|
+
import { getGooglePolygonFromLocalLogicGeometry } from "../utils";
|
|
10
|
+
|
|
11
|
+
import type { Props, Layer as LayerType } from "../types";
|
|
12
|
+
|
|
13
|
+
function getLayerPaint(type: LayerType["type"], color: string) {
|
|
14
|
+
switch (type) {
|
|
15
|
+
case "fill":
|
|
16
|
+
return {
|
|
17
|
+
fillColor: color,
|
|
18
|
+
fillOpacity: 0.25,
|
|
19
|
+
};
|
|
20
|
+
case "line":
|
|
21
|
+
return {
|
|
22
|
+
strokeColor: color,
|
|
23
|
+
strokeWeight: 2,
|
|
24
|
+
};
|
|
25
|
+
default:
|
|
26
|
+
return {};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default function GoogleLayers({ sources }: Props) {
|
|
31
|
+
const [map, setMap] = useState<google.maps.Map | null>(null);
|
|
32
|
+
const [polygonRefs, setPolygonRefs] = useState<google.maps.Polygon[]>([]);
|
|
33
|
+
const mapContext = useContext(GoogleMapsContext);
|
|
34
|
+
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (!mapContext) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
setMap(mapContext.map);
|
|
41
|
+
}, [mapContext]);
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
// Remove existing polygons
|
|
45
|
+
polygonRefs.forEach((polygonRef) => {
|
|
46
|
+
polygonRef?.setMap(null);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (!map || typeof sources === "undefined" || sources.length === 0) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Create new polygons
|
|
54
|
+
const newPolygons = sources.map((source) => {
|
|
55
|
+
const polygonOptions = {
|
|
56
|
+
paths: getGooglePolygonFromLocalLogicGeometry(source.geometry),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
if (Array.isArray(source.layer)) {
|
|
60
|
+
source.layer.forEach((layer) => {
|
|
61
|
+
const layerPaint = getLayerPaint(layer.type, layer.color);
|
|
62
|
+
Object.assign(polygonOptions, layerPaint);
|
|
63
|
+
});
|
|
64
|
+
} else {
|
|
65
|
+
const layerPaint = getLayerPaint(source.layer.type, source.layer.color);
|
|
66
|
+
Object.assign(polygonOptions, layerPaint);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const newPolygon = new google.maps.Polygon({
|
|
70
|
+
// Set default options otherwise the polygon remains visible (even if eg: we only want the outline)
|
|
71
|
+
// We then overrider the default options with the layer options
|
|
72
|
+
strokeWeight: 0,
|
|
73
|
+
fillOpacity: 0,
|
|
74
|
+
...polygonOptions,
|
|
75
|
+
});
|
|
76
|
+
newPolygon.setMap(map);
|
|
77
|
+
|
|
78
|
+
return newPolygon;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
setPolygonRefs(newPolygons);
|
|
82
|
+
// Set the map for each polygon
|
|
83
|
+
newPolygons.forEach((polygonRef) => {
|
|
84
|
+
polygonRef.setMap(map);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Clean up the polygons when the component unmounts or when sources change
|
|
88
|
+
// eslint-disable-next-line consistent-return
|
|
89
|
+
return () => {
|
|
90
|
+
newPolygons.forEach((polygonRef) => {
|
|
91
|
+
polygonRef?.setMap(null);
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
}, [map, sources]);
|
|
95
|
+
|
|
96
|
+
return <></>;
|
|
97
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
import { Source, Layer } from "react-map-gl/mapbox";
|
|
4
|
+
|
|
5
|
+
import { getFeatureCollectionFromLocalLogicGeometry } from "../utils";
|
|
6
|
+
|
|
7
|
+
import type { Props, Layer as LayerType } from "../types";
|
|
8
|
+
|
|
9
|
+
function getLayerPaint(type: LayerType["type"], color: string) {
|
|
10
|
+
switch (type) {
|
|
11
|
+
case "fill":
|
|
12
|
+
return {
|
|
13
|
+
"fill-color": color,
|
|
14
|
+
"fill-opacity": 0.15,
|
|
15
|
+
};
|
|
16
|
+
case "line":
|
|
17
|
+
return {
|
|
18
|
+
"line-color": color,
|
|
19
|
+
"line-width": 2,
|
|
20
|
+
};
|
|
21
|
+
default:
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default function MapboxLayers({ sources }: Props) {
|
|
27
|
+
const geometrySources = useMemo(() => {
|
|
28
|
+
if (!Array.isArray(sources) || sources.length === 0) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return sources.map((geometry) => ({
|
|
33
|
+
...geometry,
|
|
34
|
+
geoJson: geometry.geometry
|
|
35
|
+
? getFeatureCollectionFromLocalLogicGeometry(geometry.geometry)
|
|
36
|
+
: null,
|
|
37
|
+
}));
|
|
38
|
+
}, [sources]);
|
|
39
|
+
|
|
40
|
+
if (geometrySources?.length === 0) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
{geometrySources?.map((source) => (
|
|
47
|
+
<div key={source.key}>
|
|
48
|
+
{source.geoJson && (
|
|
49
|
+
<Source id={source.key} key={source.key} type="geojson" data={source.geoJson}>
|
|
50
|
+
{source.layer &&
|
|
51
|
+
(Array.isArray(source.layer) ? (
|
|
52
|
+
source.layer.map((layer, index) => (
|
|
53
|
+
<Layer
|
|
54
|
+
key={`${source.key}-${index}`}
|
|
55
|
+
{...{
|
|
56
|
+
...{ type: layer.type, paint: getLayerPaint(layer.type, layer.color) },
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
))
|
|
60
|
+
) : (
|
|
61
|
+
<Layer
|
|
62
|
+
{...{
|
|
63
|
+
type: source.layer.type,
|
|
64
|
+
paint: getLayerPaint(source.layer.type, source.layer.color),
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
))}
|
|
68
|
+
</Source>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
))}
|
|
72
|
+
</>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import React, { useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
import { Source, Layer } from "react-map-gl/maplibre";
|
|
4
|
+
|
|
5
|
+
import { getFeatureCollectionFromLocalLogicGeometry } from "../utils";
|
|
6
|
+
|
|
7
|
+
import type { Props, Layer as LayerType } from "../types";
|
|
8
|
+
|
|
9
|
+
function getLayerPaint(type: LayerType["type"], color: string) {
|
|
10
|
+
switch (type) {
|
|
11
|
+
case "fill":
|
|
12
|
+
return {
|
|
13
|
+
"fill-color": color,
|
|
14
|
+
"fill-opacity": 0.25,
|
|
15
|
+
};
|
|
16
|
+
case "line":
|
|
17
|
+
return {
|
|
18
|
+
"line-color": color,
|
|
19
|
+
"line-width": 2,
|
|
20
|
+
};
|
|
21
|
+
default:
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default function MaptilerLayers({ sources }: Props) {
|
|
27
|
+
const geometrySources = useMemo(() => {
|
|
28
|
+
if (!Array.isArray(sources) || sources.length === 0) {
|
|
29
|
+
return [];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return sources.map((geometry) => ({
|
|
33
|
+
...geometry,
|
|
34
|
+
geoJson: geometry.geometry
|
|
35
|
+
? getFeatureCollectionFromLocalLogicGeometry(geometry.geometry)
|
|
36
|
+
: null,
|
|
37
|
+
}));
|
|
38
|
+
}, [sources]);
|
|
39
|
+
|
|
40
|
+
if (geometrySources?.length === 0) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<>
|
|
46
|
+
{geometrySources?.map((source) => (
|
|
47
|
+
<div key={source.key}>
|
|
48
|
+
{source.geoJson && (
|
|
49
|
+
<Source id={source.key} key={source.key} type="geojson" data={source.geoJson}>
|
|
50
|
+
{source.layer &&
|
|
51
|
+
(Array.isArray(source.layer) ? (
|
|
52
|
+
source.layer.map((layer, index) => (
|
|
53
|
+
<Layer
|
|
54
|
+
key={`${source.key}-${index}`}
|
|
55
|
+
{...{
|
|
56
|
+
...{ type: layer.type, paint: getLayerPaint(layer.type, layer.color) },
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
|
+
))
|
|
60
|
+
) : (
|
|
61
|
+
<Layer
|
|
62
|
+
{...{
|
|
63
|
+
type: source.layer.type,
|
|
64
|
+
paint: getLayerPaint(source.layer.type, source.layer.color),
|
|
65
|
+
}}
|
|
66
|
+
/>
|
|
67
|
+
))}
|
|
68
|
+
</Source>
|
|
69
|
+
)}
|
|
70
|
+
</div>
|
|
71
|
+
))}
|
|
72
|
+
</>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React, { lazy, useMemo } from "react";
|
|
2
|
+
|
|
3
|
+
import type { Props } from "./types";
|
|
4
|
+
|
|
5
|
+
import { useRootElement } from "../context";
|
|
6
|
+
|
|
7
|
+
const MaptilerLayers = lazy(() => import("./Maptiler"));
|
|
8
|
+
const GoogleLayers = lazy(() => import("./Google"));
|
|
9
|
+
const MapboxLayers = lazy(() => import("./Mapbox"));
|
|
10
|
+
|
|
11
|
+
export function Layers(props: Props) {
|
|
12
|
+
const { mapProvider } = useRootElement();
|
|
13
|
+
|
|
14
|
+
const BaseLayers = useMemo(() => {
|
|
15
|
+
switch (mapProvider?.name) {
|
|
16
|
+
case "maptiler":
|
|
17
|
+
return MaptilerLayers;
|
|
18
|
+
case "google":
|
|
19
|
+
return GoogleLayers;
|
|
20
|
+
case "mapbox":
|
|
21
|
+
return MapboxLayers;
|
|
22
|
+
default:
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}, [mapProvider]);
|
|
26
|
+
|
|
27
|
+
if (!BaseLayers) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return <BaseLayers {...props} />;
|
|
32
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Layer = {
|
|
2
|
+
type: "fill" | "line";
|
|
3
|
+
color: string;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
export type Source = {
|
|
7
|
+
key: string;
|
|
8
|
+
layer: Layer | Layer[];
|
|
9
|
+
// Expected [lat, lng] format
|
|
10
|
+
geometry: number[][][][];
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type Props = {
|
|
14
|
+
sources?: Source[];
|
|
15
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { FeatureCollection, MultiPolygon } from "geojson";
|
|
2
|
+
|
|
3
|
+
type Geometry =
|
|
4
|
+
| number[][]
|
|
5
|
+
| number[][][]
|
|
6
|
+
| number[][][][]
|
|
7
|
+
| string[][]
|
|
8
|
+
| string[][][]
|
|
9
|
+
| string[][][][];
|
|
10
|
+
|
|
11
|
+
export function getFeatureCollectionFromLocalLogicGeometry(geometry: Geometry = []) {
|
|
12
|
+
/* Geometries need formatting before being added as a Source in the Map.
|
|
13
|
+
* Geometries from v3/schools have a format of [lat, lng]
|
|
14
|
+
* Geojson accepts polygons with a format of [lng, lat]
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const geometryLatLngFormat = (arr: object): object =>
|
|
18
|
+
Object.values(arr).map((a) => {
|
|
19
|
+
if (Array.isArray(a[0])) {
|
|
20
|
+
return geometryLatLngFormat(a);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return [a[1], a[0]];
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const finalCoordinates = geometryLatLngFormat(geometry);
|
|
27
|
+
|
|
28
|
+
const responseObject = {
|
|
29
|
+
type: "FeatureCollection",
|
|
30
|
+
features: [
|
|
31
|
+
{
|
|
32
|
+
type: "Feature",
|
|
33
|
+
geometry: {
|
|
34
|
+
type: "MultiPolygon",
|
|
35
|
+
coordinates: finalCoordinates,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
} as FeatureCollection<MultiPolygon>;
|
|
40
|
+
|
|
41
|
+
return responseObject;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function getGooglePolygonFromLocalLogicGeometry(geometry: Geometry = []) {
|
|
45
|
+
/* Geometries need formatting before being added as a Source in the Map.
|
|
46
|
+
* Geometries from v3/schools have a format of [lat, lng]
|
|
47
|
+
* Google Maps accepts polygons with a format of { lat: number, lng: number }
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
const geometryLatLngFormat = (arr: object): object =>
|
|
51
|
+
Object.values(arr).map((a) => {
|
|
52
|
+
if (Array.isArray(a[0])) {
|
|
53
|
+
return geometryLatLngFormat(a.flat());
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { lat: a[0], lng: a[1] };
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const finalCoordinates = geometryLatLngFormat(
|
|
60
|
+
geometry
|
|
61
|
+
) as google.maps.MVCArray<google.maps.LatLng>;
|
|
62
|
+
|
|
63
|
+
return finalCoordinates;
|
|
64
|
+
}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
2
|
import type { PointFeature, ClusterProperties } from "supercluster";
|
|
3
|
-
import type {
|
|
3
|
+
import type { Icon } from "@phosphor-icons/react";
|
|
4
|
+
import type { Coordinates } from "../types";
|
|
4
5
|
|
|
5
6
|
export type ClusterPoint = PointFeature<ClusterProperties & Marker>;
|
|
6
7
|
|
|
8
|
+
export type Marker = {
|
|
9
|
+
id: string;
|
|
10
|
+
latitude: Coordinates["latitude"];
|
|
11
|
+
longitude: Coordinates["longitude"];
|
|
12
|
+
name?: string;
|
|
13
|
+
icon?: Icon;
|
|
14
|
+
};
|
|
15
|
+
|
|
7
16
|
export type MarkerPoint = {
|
|
8
17
|
id: string;
|
|
9
18
|
latitude: number;
|
|
@@ -12,7 +12,19 @@ export function Root(props: RootProps) {
|
|
|
12
12
|
);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
// BASE MAP
|
|
15
16
|
export { BaseMap } from "./BaseMap";
|
|
17
|
+
|
|
18
|
+
// MARKERS
|
|
16
19
|
export { Markers } from "./Markers";
|
|
20
|
+
export type { MarkerProps, Marker, MarkerPoint } from "./Markers/types";
|
|
21
|
+
|
|
22
|
+
// POPUP
|
|
17
23
|
export { Popup } from "./Popup";
|
|
18
|
-
|
|
24
|
+
|
|
25
|
+
// LAYERS
|
|
26
|
+
export { Layers } from "./Layers";
|
|
27
|
+
export type { Source, Layer } from "./Layers/types";
|
|
28
|
+
|
|
29
|
+
// OTHER
|
|
30
|
+
export type { RootProps };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
-
import { Icon } from "@phosphor-icons/react";
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* We should try to keep the types "agnostic" but if we have to pick a side,
|
|
@@ -17,14 +16,6 @@ export type Coordinates = {
|
|
|
17
16
|
longitude: number;
|
|
18
17
|
};
|
|
19
18
|
|
|
20
|
-
export type Marker = {
|
|
21
|
-
id: string;
|
|
22
|
-
latitude: Coordinates["latitude"];
|
|
23
|
-
longitude: Coordinates["longitude"];
|
|
24
|
-
name?: string;
|
|
25
|
-
icon?: Icon;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
19
|
export type ZoomPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
|
|
29
20
|
|
|
30
21
|
export type RootProps = {
|
|
@@ -35,6 +26,5 @@ export type RootProps = {
|
|
|
35
26
|
pitch?: number;
|
|
36
27
|
bearing?: number;
|
|
37
28
|
cooperativeGestures?: boolean;
|
|
38
|
-
markers?: Marker[];
|
|
39
29
|
children?: ReactNode;
|
|
40
30
|
};
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
import React, { useState, useMemo } from "react";
|
|
2
2
|
import { StoryFn, Meta } from "@storybook/react";
|
|
3
3
|
import { mapDefaults as storybookMapDefaults } from "~/../.storybook/defaults";
|
|
4
|
-
import {
|
|
5
|
-
Storefront,
|
|
6
|
-
ShoppingCartSimple,
|
|
7
|
-
Brandy,
|
|
8
|
-
ForkKnife,
|
|
9
|
-
Coffee,
|
|
10
|
-
Baby,
|
|
11
|
-
Train,
|
|
12
|
-
Barbell,
|
|
13
|
-
GasPump,
|
|
14
|
-
Heartbeat,
|
|
15
|
-
} from "@phosphor-icons/react";
|
|
16
|
-
import type { RootProps, Marker } from "./Root/types";
|
|
17
4
|
import { defaultMapValues } from "./Root/constants";
|
|
18
|
-
import
|
|
5
|
+
import {
|
|
6
|
+
Root as MapRoot,
|
|
7
|
+
BaseMap,
|
|
8
|
+
Markers,
|
|
9
|
+
Popup,
|
|
10
|
+
Layers,
|
|
11
|
+
type RootProps,
|
|
12
|
+
type MarkerPoint,
|
|
13
|
+
} from "./Root";
|
|
14
|
+
import { themes, markerList, layerSources } from "./storybook-data";
|
|
19
15
|
|
|
20
16
|
export default {
|
|
21
17
|
title: "Map",
|
|
22
|
-
component:
|
|
18
|
+
component: MapRoot,
|
|
23
19
|
argTypes: storybookMapDefaults,
|
|
24
20
|
} as Meta<RootProps>;
|
|
25
21
|
|
|
@@ -32,88 +28,10 @@ const defaultValues = {
|
|
|
32
28
|
zoomPosition: "bottom-right" as RootProps["zoomPosition"],
|
|
33
29
|
};
|
|
34
30
|
|
|
35
|
-
const markerList = [
|
|
36
|
-
{
|
|
37
|
-
id: "marker-1",
|
|
38
|
-
name: "Marker 1",
|
|
39
|
-
latitude: 45.527399,
|
|
40
|
-
longitude: -73.598126,
|
|
41
|
-
icon: Storefront,
|
|
42
|
-
},
|
|
43
|
-
{
|
|
44
|
-
id: "marker-2",
|
|
45
|
-
name: "Marker 2",
|
|
46
|
-
latitude: 45.527302,
|
|
47
|
-
longitude: -73.597405,
|
|
48
|
-
icon: ShoppingCartSimple,
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
id: "marker-3",
|
|
52
|
-
name: "Marker 3",
|
|
53
|
-
latitude: 45.527302,
|
|
54
|
-
longitude: -73.597405,
|
|
55
|
-
icon: Brandy,
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
id: "marker-4",
|
|
59
|
-
name: "Marker 4",
|
|
60
|
-
latitude: 45.527302,
|
|
61
|
-
longitude: -73.597405,
|
|
62
|
-
icon: ForkKnife,
|
|
63
|
-
},
|
|
64
|
-
{
|
|
65
|
-
id: "marker-5",
|
|
66
|
-
name: "Marker 5",
|
|
67
|
-
latitude: 45.527302,
|
|
68
|
-
longitude: -73.597405,
|
|
69
|
-
icon: Coffee,
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
id: "marker-6",
|
|
73
|
-
name: "Marker 6",
|
|
74
|
-
latitude: 45.527302,
|
|
75
|
-
longitude: -73.597405,
|
|
76
|
-
icon: Baby,
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: "marker-7",
|
|
80
|
-
name: "Marker 7",
|
|
81
|
-
latitude: 45.527256,
|
|
82
|
-
longitude: -73.600229,
|
|
83
|
-
icon: Train,
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
id: "marker-8",
|
|
87
|
-
name: "Marker 8",
|
|
88
|
-
latitude: 45.527256,
|
|
89
|
-
longitude: -73.600229,
|
|
90
|
-
icon: Barbell,
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
id: "marker-9",
|
|
94
|
-
name: "Marker 9",
|
|
95
|
-
latitude: 45.526643,
|
|
96
|
-
longitude: -73.600293,
|
|
97
|
-
icon: GasPump,
|
|
98
|
-
},
|
|
99
|
-
{
|
|
100
|
-
id: "marker-10",
|
|
101
|
-
name: "Marker 10",
|
|
102
|
-
latitude: 45.527025,
|
|
103
|
-
longitude: -73.600897,
|
|
104
|
-
icon: Heartbeat,
|
|
105
|
-
},
|
|
106
|
-
] as Marker[];
|
|
107
|
-
|
|
108
|
-
const maptilerThemes = {
|
|
109
|
-
day: "600d69cb-288d-445e-9839-3dfe4d76b31a",
|
|
110
|
-
night: "dd191599-2a92-49fc-9a33-e12391753ad5",
|
|
111
|
-
};
|
|
112
|
-
|
|
113
31
|
const Template: StoryFn<RootProps> = (args) => {
|
|
114
|
-
const [activeMarker, setActiveMarker] = useState<
|
|
32
|
+
const [activeMarker, setActiveMarker] = useState<MarkerPoint | undefined>(undefined);
|
|
115
33
|
|
|
116
|
-
const handleMarkerClick = (markers:
|
|
34
|
+
const handleMarkerClick = (markers: MarkerPoint) => {
|
|
117
35
|
if (
|
|
118
36
|
activeMarker?.latitude === markers.latitude &&
|
|
119
37
|
activeMarker?.longitude === markers.longitude
|
|
@@ -168,19 +86,20 @@ const Template: StoryFn<RootProps> = (args) => {
|
|
|
168
86
|
|
|
169
87
|
return (
|
|
170
88
|
<div className="w-full h-[calc(100vh-30px)]">
|
|
171
|
-
<
|
|
172
|
-
<
|
|
173
|
-
<
|
|
89
|
+
<MapRoot {...args}>
|
|
90
|
+
<BaseMap>
|
|
91
|
+
<Layers sources={layerSources} />
|
|
92
|
+
<Markers markers={markerList} onClick={handleMarkerClick} />
|
|
174
93
|
|
|
175
|
-
<
|
|
94
|
+
<Popup
|
|
176
95
|
latitude={activeMarker?.latitude}
|
|
177
96
|
longitude={activeMarker?.longitude}
|
|
178
97
|
onClose={() => setActiveMarker(undefined)}
|
|
179
98
|
>
|
|
180
99
|
{popupContent}
|
|
181
|
-
</
|
|
182
|
-
</
|
|
183
|
-
</
|
|
100
|
+
</Popup>
|
|
101
|
+
</BaseMap>
|
|
102
|
+
</MapRoot>
|
|
184
103
|
</div>
|
|
185
104
|
);
|
|
186
105
|
};
|
|
@@ -190,7 +109,7 @@ Maptiler.args = {
|
|
|
190
109
|
mapProvider: {
|
|
191
110
|
name: "maptiler",
|
|
192
111
|
apiKey: import.meta.env.VITE_MAPTILER_KEY,
|
|
193
|
-
maptilerTheme:
|
|
112
|
+
maptilerTheme: themes.maptiler.day,
|
|
194
113
|
},
|
|
195
114
|
...defaultValues,
|
|
196
115
|
};
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Storefront,
|
|
3
|
+
ShoppingCartSimple,
|
|
4
|
+
Brandy,
|
|
5
|
+
ForkKnife,
|
|
6
|
+
Coffee,
|
|
7
|
+
Baby,
|
|
8
|
+
Train,
|
|
9
|
+
Barbell,
|
|
10
|
+
GasPump,
|
|
11
|
+
Heartbeat,
|
|
12
|
+
} from "@phosphor-icons/react";
|
|
13
|
+
|
|
14
|
+
import type { Marker, Source } from "./Root";
|
|
15
|
+
|
|
16
|
+
export const themes = {
|
|
17
|
+
maptiler: {
|
|
18
|
+
day: "600d69cb-288d-445e-9839-3dfe4d76b31a",
|
|
19
|
+
night: "dd191599-2a92-49fc-9a33-e12391753ad5",
|
|
20
|
+
},
|
|
21
|
+
mapbox: {
|
|
22
|
+
day: "",
|
|
23
|
+
night: "",
|
|
24
|
+
},
|
|
25
|
+
google: {
|
|
26
|
+
day: "",
|
|
27
|
+
night: "",
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const markerList = [
|
|
32
|
+
{
|
|
33
|
+
id: "marker-1",
|
|
34
|
+
name: "Marker 1",
|
|
35
|
+
latitude: 45.527399,
|
|
36
|
+
longitude: -73.598126,
|
|
37
|
+
icon: Storefront,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: "marker-2",
|
|
41
|
+
name: "Marker 2",
|
|
42
|
+
latitude: 45.527302,
|
|
43
|
+
longitude: -73.597405,
|
|
44
|
+
icon: ShoppingCartSimple,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "marker-3",
|
|
48
|
+
name: "Marker 3",
|
|
49
|
+
latitude: 45.527302,
|
|
50
|
+
longitude: -73.597405,
|
|
51
|
+
icon: Brandy,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: "marker-4",
|
|
55
|
+
name: "Marker 4",
|
|
56
|
+
latitude: 45.527302,
|
|
57
|
+
longitude: -73.597405,
|
|
58
|
+
icon: ForkKnife,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
id: "marker-5",
|
|
62
|
+
name: "Marker 5",
|
|
63
|
+
latitude: 45.527302,
|
|
64
|
+
longitude: -73.597405,
|
|
65
|
+
icon: Coffee,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: "marker-6",
|
|
69
|
+
name: "Marker 6",
|
|
70
|
+
latitude: 45.527302,
|
|
71
|
+
longitude: -73.597405,
|
|
72
|
+
icon: Baby,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
id: "marker-7",
|
|
76
|
+
name: "Marker 7",
|
|
77
|
+
latitude: 45.527256,
|
|
78
|
+
longitude: -73.600229,
|
|
79
|
+
icon: Train,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
id: "marker-8",
|
|
83
|
+
name: "Marker 8",
|
|
84
|
+
latitude: 45.527256,
|
|
85
|
+
longitude: -73.600229,
|
|
86
|
+
icon: Barbell,
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "marker-9",
|
|
90
|
+
name: "Marker 9",
|
|
91
|
+
latitude: 45.526643,
|
|
92
|
+
longitude: -73.600293,
|
|
93
|
+
icon: GasPump,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: "marker-10",
|
|
97
|
+
name: "Marker 10",
|
|
98
|
+
latitude: 45.527025,
|
|
99
|
+
longitude: -73.600897,
|
|
100
|
+
icon: Heartbeat,
|
|
101
|
+
},
|
|
102
|
+
] as Marker[];
|
|
103
|
+
|
|
104
|
+
export const layerSources: Source[] = [
|
|
105
|
+
{
|
|
106
|
+
key: "neighborhood",
|
|
107
|
+
layer: [
|
|
108
|
+
{
|
|
109
|
+
type: "fill",
|
|
110
|
+
color: "#008491",
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
type: "line",
|
|
114
|
+
color: "#008491",
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
geometry: [
|
|
118
|
+
[
|
|
119
|
+
[
|
|
120
|
+
[45.53006, -73.59634],
|
|
121
|
+
[45.52986, -73.59589],
|
|
122
|
+
[45.52982, -73.59582],
|
|
123
|
+
[45.52894, -73.59389],
|
|
124
|
+
[45.52864, -73.59321],
|
|
125
|
+
[45.52799, -73.59174],
|
|
126
|
+
[45.52626, -73.58795],
|
|
127
|
+
[45.52478, -73.58473],
|
|
128
|
+
[45.52396, -73.58292],
|
|
129
|
+
[45.52337, -73.58342],
|
|
130
|
+
[45.52332, -73.58347],
|
|
131
|
+
[45.52289, -73.58385],
|
|
132
|
+
[45.52242, -73.58426],
|
|
133
|
+
[45.52216, -73.58451],
|
|
134
|
+
[45.52164, -73.58499],
|
|
135
|
+
[45.5201, -73.58638],
|
|
136
|
+
[45.51835, -73.58796],
|
|
137
|
+
[45.51765, -73.58854],
|
|
138
|
+
[45.51753, -73.58864],
|
|
139
|
+
[45.51711, -73.58901],
|
|
140
|
+
[45.51695, -73.58915],
|
|
141
|
+
[45.51677, -73.58932],
|
|
142
|
+
[45.51679, -73.58938],
|
|
143
|
+
[45.51649, -73.58965],
|
|
144
|
+
[45.51639, -73.58973],
|
|
145
|
+
[45.51633, -73.58978],
|
|
146
|
+
[45.5163, -73.58981],
|
|
147
|
+
[45.51602, -73.59007],
|
|
148
|
+
[45.5158, -73.59027],
|
|
149
|
+
[45.51585, -73.59038],
|
|
150
|
+
[45.5159, -73.59049],
|
|
151
|
+
[45.51625, -73.59125],
|
|
152
|
+
[45.5163, -73.59136],
|
|
153
|
+
[45.51632, -73.5914],
|
|
154
|
+
[45.51652, -73.59185],
|
|
155
|
+
[45.51667, -73.5922],
|
|
156
|
+
[45.51682, -73.59253],
|
|
157
|
+
[45.51695, -73.59282],
|
|
158
|
+
[45.51704, -73.59302],
|
|
159
|
+
[45.51712, -73.5932],
|
|
160
|
+
[45.51721, -73.59339],
|
|
161
|
+
[45.51738, -73.59379],
|
|
162
|
+
[45.51742, -73.59387],
|
|
163
|
+
[45.51757, -73.59422],
|
|
164
|
+
[45.51797, -73.59513],
|
|
165
|
+
[45.5181, -73.59542],
|
|
166
|
+
[45.51861, -73.59655],
|
|
167
|
+
[45.51902, -73.59748],
|
|
168
|
+
[45.51917, -73.59781],
|
|
169
|
+
[45.51939, -73.59832],
|
|
170
|
+
[45.51944, -73.59843],
|
|
171
|
+
[45.51948, -73.59853],
|
|
172
|
+
[45.51963, -73.59887],
|
|
173
|
+
[45.52018, -73.6001],
|
|
174
|
+
[45.52076, -73.60143],
|
|
175
|
+
[45.52127, -73.60258],
|
|
176
|
+
[45.52138, -73.60283],
|
|
177
|
+
[45.52147, -73.60303],
|
|
178
|
+
[45.52206, -73.60435],
|
|
179
|
+
[45.52213, -73.60452],
|
|
180
|
+
[45.52228, -73.60485],
|
|
181
|
+
[45.52241, -73.60515],
|
|
182
|
+
[45.52245, -73.60523],
|
|
183
|
+
[45.52249, -73.60531],
|
|
184
|
+
[45.52252, -73.6054],
|
|
185
|
+
[45.52256, -73.60548],
|
|
186
|
+
[45.5226, -73.60556],
|
|
187
|
+
[45.52278, -73.60597],
|
|
188
|
+
[45.52285, -73.60614],
|
|
189
|
+
[45.52294, -73.60634],
|
|
190
|
+
[45.52309, -73.60667],
|
|
191
|
+
[45.52324, -73.607],
|
|
192
|
+
[45.52335, -73.60725],
|
|
193
|
+
[45.52349, -73.60758],
|
|
194
|
+
[45.52366, -73.60796],
|
|
195
|
+
[45.52376, -73.60819],
|
|
196
|
+
[45.52387, -73.60843],
|
|
197
|
+
[45.52463, -73.61015],
|
|
198
|
+
[45.52468, -73.61026],
|
|
199
|
+
[45.52468, -73.61026],
|
|
200
|
+
[45.525, -73.61098],
|
|
201
|
+
[45.52537, -73.61179],
|
|
202
|
+
[45.5256, -73.61233],
|
|
203
|
+
[45.52565, -73.61242],
|
|
204
|
+
[45.52566, -73.6124],
|
|
205
|
+
[45.5263, -73.61124],
|
|
206
|
+
[45.52644, -73.611],
|
|
207
|
+
[45.5277, -73.60871],
|
|
208
|
+
[45.52783, -73.60839],
|
|
209
|
+
[45.52804, -73.60786],
|
|
210
|
+
[45.52817, -73.60739],
|
|
211
|
+
[45.52822, -73.6072],
|
|
212
|
+
[45.52823, -73.60716],
|
|
213
|
+
[45.52825, -73.60704],
|
|
214
|
+
[45.52828, -73.60689],
|
|
215
|
+
[45.52829, -73.60685],
|
|
216
|
+
[45.52831, -73.60672],
|
|
217
|
+
[45.52831, -73.6067],
|
|
218
|
+
[45.52837, -73.60626],
|
|
219
|
+
[45.52838, -73.60619],
|
|
220
|
+
[45.52838, -73.60614],
|
|
221
|
+
[45.52839, -73.60576],
|
|
222
|
+
[45.52837, -73.60459],
|
|
223
|
+
[45.52837, -73.60457],
|
|
224
|
+
[45.52839, -73.6035],
|
|
225
|
+
[45.52842, -73.60238],
|
|
226
|
+
[45.52849, -73.60167],
|
|
227
|
+
[45.52849, -73.60167],
|
|
228
|
+
[45.5285, -73.60159],
|
|
229
|
+
[45.5285, -73.60159],
|
|
230
|
+
[45.52854, -73.60122],
|
|
231
|
+
[45.52857, -73.60103],
|
|
232
|
+
[45.52871, -73.60014],
|
|
233
|
+
[45.52873, -73.6],
|
|
234
|
+
[45.52873, -73.6],
|
|
235
|
+
[45.52878, -73.59978],
|
|
236
|
+
[45.52878, -73.59977],
|
|
237
|
+
[45.5289, -73.59929],
|
|
238
|
+
[45.52905, -73.5988],
|
|
239
|
+
[45.5291, -73.59861],
|
|
240
|
+
[45.52916, -73.59844],
|
|
241
|
+
[45.52916, -73.59844],
|
|
242
|
+
[45.5293, -73.59807],
|
|
243
|
+
[45.52931, -73.59803],
|
|
244
|
+
[45.52934, -73.59796],
|
|
245
|
+
[45.52956, -73.5974],
|
|
246
|
+
[45.52966, -73.59715],
|
|
247
|
+
[45.52985, -73.59678],
|
|
248
|
+
[45.53004, -73.5964],
|
|
249
|
+
[45.53007, -73.59635],
|
|
250
|
+
[45.53006, -73.59634],
|
|
251
|
+
],
|
|
252
|
+
],
|
|
253
|
+
],
|
|
254
|
+
},
|
|
255
|
+
];
|