terra-draw-route-snap-mode 0.0.1

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 (87) hide show
  1. package/.vscode/settings.json +3 -0
  2. package/CNAME +1 -0
  3. package/LICENSE.txt +8 -0
  4. package/README.md +66 -0
  5. package/demo/assets/favicon.ico +0 -0
  6. package/demo/assets/icons/android-chrome-192x192.png +0 -0
  7. package/demo/assets/icons/android-chrome-512x512.png +0 -0
  8. package/demo/assets/icons/apple-touch-icon.png +0 -0
  9. package/demo/assets/icons/favicon-16x16.png +0 -0
  10. package/demo/assets/icons/favicon-32x32.png +0 -0
  11. package/demo/assets/icons/mstile-150x150.png +0 -0
  12. package/demo/assets/imgs/geolocation.png +0 -0
  13. package/demo/assets/imgs/github.png +0 -0
  14. package/demo/assets/imgs/logo.png +0 -0
  15. package/demo/components/app.tsx +18 -0
  16. package/demo/components/geojson-tab/GeoJSONTab.tsx +42 -0
  17. package/demo/components/geojson-tab/style.module.css +30 -0
  18. package/demo/components/geojson-tab/useDownloadJSON.ts +34 -0
  19. package/demo/components/header/Header.tsx +25 -0
  20. package/demo/components/header/style.module.css +78 -0
  21. package/demo/components/info-tab/InfoTab.tsx +101 -0
  22. package/demo/components/info-tab/style.module.css +42 -0
  23. package/demo/components/map-button/ClearButton.tsx +24 -0
  24. package/demo/components/map-button/MapButton.tsx +41 -0
  25. package/demo/components/map-button/style.module.css +42 -0
  26. package/demo/components/map-buttons/MapButtons.tsx +28 -0
  27. package/demo/components/map-buttons/style.module.css +17 -0
  28. package/demo/declaration.d.ts +9 -0
  29. package/demo/index.html +23 -0
  30. package/demo/index.tsx +12 -0
  31. package/demo/manifest.json +21 -0
  32. package/demo/package-lock.json +18900 -0
  33. package/demo/package.json +50 -0
  34. package/demo/public/network.json +216459 -0
  35. package/demo/routes/home/colors.ts +31 -0
  36. package/demo/routes/home/index.tsx +101 -0
  37. package/demo/routes/home/setup-draw.ts +67 -0
  38. package/demo/routes/home/setup-leaflet.ts +41 -0
  39. package/demo/routes/home/setup-routing.ts +21 -0
  40. package/demo/routes/home/style.module.css +94 -0
  41. package/demo/size-plugin.json +1 -0
  42. package/demo/style/index.css +20 -0
  43. package/demo/sw.js +4 -0
  44. package/demo/template.html +30 -0
  45. package/demo/tsconfig.json +7 -0
  46. package/demo/utils/casing.ts +7 -0
  47. package/demo/utils/dates.ts +10 -0
  48. package/demo/utils/geo.ts +4 -0
  49. package/demo/vite.config.js +10 -0
  50. package/dist/kdbush/geokdbush.d.ts +3 -0
  51. package/dist/kdbush/kdbush.d.ts +16 -0
  52. package/dist/kdbush/tinyqueue.d.ts +11 -0
  53. package/dist/routing.d.ts +37 -0
  54. package/dist/terra-draw-route-snap-mode.cjs +2 -0
  55. package/dist/terra-draw-route-snap-mode.cjs.map +1 -0
  56. package/dist/terra-draw-route-snap-mode.d.ts +75 -0
  57. package/dist/terra-draw-route-snap-mode.modern.js +2 -0
  58. package/dist/terra-draw-route-snap-mode.modern.js.map +1 -0
  59. package/dist/terra-draw-route-snap-mode.module.js +2 -0
  60. package/dist/terra-draw-route-snap-mode.module.js.map +1 -0
  61. package/dist/terra-draw-route-snap-mode.umd.js +2 -0
  62. package/dist/terra-draw-route-snap-mode.umd.js.map +1 -0
  63. package/docs/assets/favicon-r77Z2In5.ico +0 -0
  64. package/docs/assets/index-5ax2eNro.js +4 -0
  65. package/docs/assets/index-CEAM8jr3.css +1 -0
  66. package/docs/assets/index-Cfqr5nmq.js +4 -0
  67. package/docs/assets/index-CpmDVghy.css +1 -0
  68. package/docs/assets/index-D8NK55L4.js +4 -0
  69. package/docs/assets/index-DJYewHY6.js +4 -0
  70. package/docs/assets/index-DT3pkFX6.js +4 -0
  71. package/docs/assets/index-DZ8OkOfD.js +4 -0
  72. package/docs/assets/index-DjN8PkFw.js +4 -0
  73. package/docs/assets/index-iILsBcOs.js +4 -0
  74. package/docs/assets/logo-DQvm3LRv.png +0 -0
  75. package/docs/index.html +24 -0
  76. package/docs/network.json +216459 -0
  77. package/eslint.config.mjs +54 -0
  78. package/jest.config.js +5 -0
  79. package/package.json +97 -0
  80. package/src/kdbush/geokdbush.ts +183 -0
  81. package/src/kdbush/kdbush.ts +189 -0
  82. package/src/kdbush/tinyqueue.ts +108 -0
  83. package/src/routing.spec.ts +91 -0
  84. package/src/routing.ts +115 -0
  85. package/src/terra-draw-route-snap-mode.ts +462 -0
  86. package/src/terra-draw-route-snap.mode.spec.ts +24 -0
  87. package/tsconfig.json +12 -0
@@ -0,0 +1,3 @@
1
+ {
2
+ "typescript.tsdk": "node_modules/typescript/lib"
3
+ }
package/CNAME ADDED
@@ -0,0 +1 @@
1
+ terradraw.io
package/LICENSE.txt ADDED
@@ -0,0 +1,8 @@
1
+ The MIT License (MIT)
2
+ Copyright © 2025 James Milner
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Terra Draw Route Snapping Mode
2
+
3
+
4
+ This repository is for the `TerraDrawRouteSnappingMode` module. `TerraDrawRouteSnappingMode` is designed to help with the scenario where you want to be able to create a multi-stop route on a map, snapping the route against a predefined route network. This is achieved by client side routing on a FeatureCollection<LineString> where the LineStrings have identical coordinates.
5
+
6
+ ## Install
7
+
8
+ ```shell
9
+ npm install terra-draw-route-snap-mode
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ We can import `TerraDrawRouteSnapMode` in this way:
15
+
16
+ ```typescript
17
+ import { TerraDrawRouteSnapMode } from terra-draw-route-snap-mode
18
+ ```
19
+
20
+ We can construct `TerraDrawRouteSnapMode` like so:
21
+
22
+ ```typescript
23
+ new TerraDrawRouteSnapMode({
24
+ routing,
25
+ maxPoints: 5,
26
+ styles: {
27
+ lineStringColor: '#990000',
28
+ routePointColor: '#990000'
29
+ }
30
+ }),
31
+ ```
32
+
33
+ Where routing is of type:
34
+
35
+ ```typescript
36
+ export interface RoutingInterface {
37
+ getRoute: (startCoord: Position, endCoord: Position) => Feature<LineString> | null;
38
+ getClosestNetworkCoordinate: (coordinate: Position) => Position | null;
39
+ }
40
+ ```
41
+
42
+ You could construct the `routing` like so:
43
+
44
+ ```typescript
45
+ import { Routing } from "../../../src/terra-draw-route-snap-mode";
46
+ import { FeatureCollection, LineString } from "geojson";
47
+ import { TerraRoute, createCheapRuler } from 'terra-route';
48
+
49
+ // Initialise the TerraRoute instance with the default distance
50
+ const terraRoute = new TerraRoute()
51
+
52
+ // Construct the route network ready to call `getRoute` on terraRoute later in the TerraDrawRouteSnapMode instance
53
+ terraRoute.buildRouteGraph(network)
54
+
55
+ const terraRouting = new Routing({
56
+ network,
57
+ useCache: true,
58
+ routeFinder: terraRoute
59
+ })
60
+ ```
61
+
62
+ If you want to see the faster CheapRuler implementation from the `terra-route` package, please see the demo folder in the `setup-routing.ts` file for an examples. CheapRuler is a reasonable distance metric to use for network graphs of less than 500km size that are not located on or near the poles.
63
+
64
+ ## License
65
+
66
+ MIT
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,18 @@
1
+ import { h } from "preact";
2
+ // import { Route, Router, CustomHistory } from "preact-router";
3
+ // import { createHashHistory } from "history";
4
+ import Header from "./header/Header";
5
+
6
+ // Code-splitting is automated for `routes` directory
7
+ import Home from "../routes/home";
8
+
9
+ console.log('App.tsx');
10
+
11
+ const App = () => (
12
+ <div id="app">
13
+ <Header />
14
+ <Home />
15
+ </div>
16
+ );
17
+
18
+ export default App;
@@ -0,0 +1,42 @@
1
+ import { h } from "preact";
2
+ import style from "./style.module.css";
3
+ import { useMemo } from "preact/hooks";
4
+ import { GeoJSONStoreFeatures } from "../../node_modules/terra-draw/dist/store/store";
5
+ import { useDownloadJSON } from "./useDownloadJSON";
6
+ import { fileDate } from "../../utils/dates";
7
+
8
+ const GeoJSONTab = ({ features }: { features: GeoJSONStoreFeatures[] }) => {
9
+ // Create a FeatureCollection when features changes
10
+ const featureCollection = useMemo(
11
+ () => ({
12
+ type: "FeatureCollection",
13
+ features,
14
+ }),
15
+ [features]
16
+ );
17
+
18
+ // Turn it into a string so it can be rendered,
19
+ // again only when features change
20
+ const featureCollectionString = useMemo(() => {
21
+ return JSON.stringify(featureCollection, null, 4);
22
+ }, [featureCollection]);
23
+
24
+ const downloadJSON = useDownloadJSON();
25
+
26
+ // Download to a file called terradraw.geojson
27
+ const downloadGeoJSON = () =>
28
+ downloadJSON(featureCollection, `terradraw_${fileDate()}.geojson`);
29
+
30
+ return (
31
+ <div class={style.container}>
32
+ <textarea class={style.geojson} readonly>
33
+ {featureCollectionString}
34
+ </textarea>
35
+ <button class={style.download} onClick={downloadGeoJSON}>
36
+ Download GeoJSON
37
+ </button>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export default GeoJSONTab;
@@ -0,0 +1,30 @@
1
+ .geojson {
2
+ resize: none;
3
+ width: 100%;
4
+ flex-grow: 1;
5
+ height: calc(100vh - 193px);
6
+ /** accomidate the 3px margin top for the download button **/
7
+ }
8
+
9
+ .container {
10
+ padding: 20px;
11
+ display: flex;
12
+ flex-grow: 1;
13
+ flex-direction: column;
14
+ }
15
+
16
+ .download {
17
+ padding: 10px;
18
+ font-weight: bold;
19
+ background: #00d088;
20
+ color: white;
21
+ border: 0;
22
+ border: 2px solid rgba(0, 0, 0, 0.2);
23
+ margin-top: 3px;
24
+ }
25
+
26
+ .download:hover {
27
+ background: #00d088c4;
28
+ border: 2px solid rgba(0, 0, 0, 0.2);
29
+ cursor: pointer;
30
+ }
@@ -0,0 +1,34 @@
1
+ import { useCallback } from "preact/hooks";
2
+
3
+ export function useDownloadJSON() {
4
+ const downloadJSON = useCallback(
5
+ (json: Record<string, any>, filename: string) => {
6
+ // Turn the JSON object into a string
7
+ const data = JSON.stringify(json, null, 4);
8
+
9
+ // Pass the string to a Blob and turn it
10
+ // into an ObjectURL
11
+ const blob = new Blob([data], { type: "text/plain" });
12
+ const jsonObjectUrl = URL.createObjectURL(blob);
13
+
14
+ // Create an anchor element, set it's
15
+ // href to be the Object URL we have created
16
+ // and set the download property to be the file name
17
+ // we want to set
18
+ const anchorEl = document.createElement("a");
19
+ anchorEl.href = jsonObjectUrl;
20
+ anchorEl.download = filename;
21
+
22
+ // There is no need to actually attach the DOM
23
+ // element but we do need to click on it
24
+ anchorEl.click();
25
+
26
+ // We don't want to keep a reference to the file
27
+ // any longer so we release it manually
28
+ URL.revokeObjectURL(jsonObjectUrl);
29
+ },
30
+ []
31
+ );
32
+
33
+ return downloadJSON;
34
+ }
@@ -0,0 +1,25 @@
1
+ import { h } from "preact";
2
+ import { Link } from "preact-router/match";
3
+ import style from "./style.module.css";
4
+ import logo from "../../assets/imgs/logo.png";
5
+ import github from "../../assets/imgs/github.png";
6
+
7
+ const Header = () => (
8
+ <header class={style.header}>
9
+ <div class={style.nav}>
10
+ <img class={style.logo} src={logo} />
11
+ <nav>
12
+ <Link activeClassName={style.active} href="/">
13
+ Home
14
+ </Link>
15
+ </nav>
16
+ </div>
17
+ <div class={style.github}>
18
+ <a href="https://www.github.com/JamesLMilner/terra-draw">
19
+ <img src={github} />
20
+ </a>
21
+ </div>
22
+ </header>
23
+ );
24
+
25
+ export default Header;
@@ -0,0 +1,78 @@
1
+ .header {
2
+ width: 100%;
3
+ height: 70px;
4
+ padding: 0;
5
+ background: #fdfdfd;
6
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
7
+ z-index: 50;
8
+ display: flex;
9
+ color: #565656;
10
+ display: flex;
11
+ justify-content: space-between;
12
+ }
13
+
14
+ .header .nav {
15
+ width: 100%;
16
+ display: flex;
17
+ }
18
+
19
+ .github {
20
+ display: flex;
21
+ justify-items: center;
22
+ align-items: center;
23
+ margin-right: 20px;
24
+ }
25
+
26
+ .logo {
27
+ height: 35px;
28
+ display: flex;
29
+ align-self: center;
30
+ padding-left: 20px;
31
+ }
32
+
33
+ .header h1 {
34
+ float: left;
35
+ margin: 0;
36
+ padding: 0 15px;
37
+ font-size: 24px;
38
+ line-height: 70px;
39
+ font-weight: 400;
40
+ color: #fdfdfd;
41
+ }
42
+
43
+ .header nav {
44
+ font-size: 100%;
45
+ margin-left: 20px;
46
+ }
47
+
48
+ .header nav a {
49
+ display: inline-block;
50
+ height: 70px;
51
+ line-height: 70px;
52
+ padding: 0 15px;
53
+ min-width: 50px;
54
+ text-align: center;
55
+ background: fdfdfd;
56
+ text-decoration: none;
57
+ color: #565656;
58
+ will-change: background-color;
59
+ }
60
+
61
+ .header nav a:hover,
62
+ .header nav a:active {
63
+ border-bottom: solid 5px #00d088;
64
+ }
65
+
66
+ .header nav a.active {
67
+ border-bottom: solid 5px #00d088;
68
+ }
69
+
70
+ @media screen and (max-width: 500px) {
71
+ .logo {
72
+ display: none;
73
+ }
74
+
75
+ .header nav {
76
+ margin-left: 0px;
77
+ }
78
+ }
@@ -0,0 +1,101 @@
1
+ import { h } from "preact";
2
+ import style from "./style.module.css";
3
+ import { getHHMMSS } from "../../utils/dates";
4
+ import { area, length } from "../../utils/geo";
5
+ import { useMemo } from "preact/hooks";
6
+ import { GeoJSONStoreFeatures } from "../../node_modules/terra-draw/dist/store/store";
7
+
8
+ const InfoTab = ({
9
+ selected,
10
+ features,
11
+ }: {
12
+ selected: undefined | GeoJSONStoreFeatures;
13
+ features: GeoJSONStoreFeatures[];
14
+ }) => {
15
+ const { points, lines, polygons } = useMemo(() => {
16
+ const points: GeoJSONStoreFeatures[] = [];
17
+ const lines: GeoJSONStoreFeatures[] = [];
18
+ const polygons: GeoJSONStoreFeatures[] = [];
19
+ features.forEach((f) => {
20
+ if (f.geometry.type === "Point") {
21
+ points.push(f);
22
+ }
23
+ if (f.geometry.type === "LineString") {
24
+ lines.push(f);
25
+ }
26
+ if (f.geometry.type === "Polygon") {
27
+ polygons.push(f);
28
+ }
29
+ });
30
+
31
+ return { points, lines, polygons };
32
+ }, [features]);
33
+
34
+ return (
35
+ <div class={style.container}>
36
+ <div class={style.all}>
37
+ <h3 class={style.header}> All Features </h3>
38
+ <span class={style.row}>
39
+ <span class={style.type}>Total</span> {features.length}
40
+ </span>
41
+ <span class={style.row}>
42
+ <span class={style.type}>Polygons:</span>
43
+ {polygons.length}
44
+ </span>
45
+ <span class={style.row}>
46
+ <span class={style.type}>LineStrings:</span>
47
+ {lines.length}
48
+ </span>
49
+ <span class={style.row}>
50
+ <span class={style.type}>Points:</span>
51
+ {points.length}
52
+ </span>
53
+ </div>
54
+ <div class={style.current}>
55
+ <h3 class={style.header}> Selected Feature </h3>
56
+ <span class={style.row}>
57
+ <span class={style.type}>ID</span>
58
+ {selected ? (selected.id as string).slice(0, 8) + "..." : "N/A"}
59
+ </span>
60
+ <span class={style.row}>
61
+ <span class={style.type}>Geometry Type</span>
62
+ {selected ? selected.geometry.type : "N/A"}
63
+ </span>
64
+ <span class={style.row}>
65
+ <span class={style.type}>Created</span>
66
+ {selected
67
+ ? getHHMMSS(selected.properties.createdAt as number)
68
+ : "N/A"}
69
+ </span>
70
+ <span class={style.row}>
71
+ <span class={style.type}>Updated</span>
72
+ {selected
73
+ ? getHHMMSS(selected.properties.updatedAt as number)
74
+ : "N/A"}
75
+ </span>
76
+ <span class={style.row}>
77
+ <span class={style.type}>Coordinates</span>
78
+ {selected && selected.geometry.type === "Polygon"
79
+ ? selected.geometry.coordinates[0].length
80
+ : selected && selected.geometry.type === "LineString"
81
+ ? selected.geometry.coordinates.length
82
+ : "N/A"}
83
+ </span>
84
+ <span class={style.row}>
85
+ <span class={style.type}>Area (m2)</span>
86
+ {selected && selected.geometry.type === "Polygon"
87
+ ? area(selected).toFixed(2)
88
+ : "N/A"}
89
+ </span>
90
+ <span class={style.row}>
91
+ <span class={style.type}>Length (km)</span>
92
+ {selected && selected.geometry.type === "LineString"
93
+ ? length(selected).toFixed(2)
94
+ : "N/A"}
95
+ </span>
96
+ </div>
97
+ </div>
98
+ );
99
+ };
100
+
101
+ export default InfoTab;
@@ -0,0 +1,42 @@
1
+ .current,
2
+ .all {
3
+ display: flex;
4
+ flex-direction: column;
5
+ border-radius: 20px;
6
+ border: solid 3px #565656;
7
+ padding: 20px;
8
+ margin-bottom: 20px;
9
+ }
10
+
11
+ .header {
12
+ margin-top: 0;
13
+ font-weight: bolder;
14
+ font-size: 20px;
15
+ text-transform: capitalize;
16
+ }
17
+
18
+ .type {
19
+ display: inline-block;
20
+ width: 150px;
21
+ }
22
+
23
+ button:hover {
24
+ background: white;
25
+ border: solid 3px #222222;
26
+ }
27
+
28
+ .container {
29
+ width: 100%;
30
+ padding: 20px;
31
+ }
32
+
33
+ .row {
34
+ width: 100%;
35
+ display: flex;
36
+ justify-content: space-between;
37
+ border-bottom: 1px solid #d9d9d9;
38
+ margin-bottom: 10px;
39
+ white-space: nowrap;
40
+ overflow: hidden;
41
+ text-overflow: ellipsis;
42
+ }
@@ -0,0 +1,24 @@
1
+ import { h } from "preact";
2
+ import style from "./style.module.css";
3
+
4
+ const ClearButton = ({
5
+ label,
6
+ onClick,
7
+ }: {
8
+ onClick: () => void;
9
+ label?: string;
10
+ }) => {
11
+ return (
12
+ <button
13
+ id={'clear'}
14
+ class={style.button}
15
+ onClick={() => {
16
+ onClick()
17
+ }}
18
+ >
19
+ {label}
20
+ </button>
21
+ );
22
+ };
23
+
24
+ export default ClearButton;
@@ -0,0 +1,41 @@
1
+ import { h } from "preact";
2
+ import style from "./style.module.css";
3
+ import { titleCase } from "../../utils/casing";
4
+
5
+ const MapButton = ({
6
+ mode,
7
+ currentMode,
8
+ changeMode,
9
+ label,
10
+ hiddenOnTouch,
11
+ }: {
12
+ mode: string;
13
+ currentMode: string;
14
+ changeMode: (mode: string) => void;
15
+ label?: string;
16
+ hiddenOnTouch?: boolean;
17
+ }) => {
18
+ let classes = style.button;
19
+
20
+ if (hiddenOnTouch) {
21
+ classes = `${style.hiddenOnMobile} ${classes}`;
22
+ }
23
+
24
+ if (currentMode === mode) {
25
+ classes = `${style.active} ${classes}`;
26
+ }
27
+
28
+ return (
29
+ <button
30
+ id={mode}
31
+ class={classes}
32
+ onClick={() => {
33
+ changeMode(mode);
34
+ }}
35
+ >
36
+ {label ? label : titleCase(mode)}
37
+ </button>
38
+ );
39
+ };
40
+
41
+ export default MapButton;
@@ -0,0 +1,42 @@
1
+ .button {
2
+ padding: 10px;
3
+ width: 115px;
4
+ background: #fdfdfd;
5
+ border: solid 1px #ebebeb;
6
+ cursor: pointer;
7
+ border-radius: 10px;
8
+ font-weight: bold;
9
+ font-size: 16px;
10
+ color: #565656;
11
+ margin: 4px;
12
+ margin-top: 8px;
13
+ border: solid 3px #565656;
14
+ }
15
+
16
+ .button:hover {
17
+ background: white;
18
+ border: solid 3px #222222;
19
+ }
20
+
21
+ .active {
22
+ color: #02cf87;
23
+ transition: color 0.5s;
24
+ }
25
+
26
+ .hiddenOnMobile {
27
+ }
28
+
29
+ @media screen and (max-width: 900px) {
30
+ .expanded,
31
+ .collapsed {
32
+ display: none;
33
+ }
34
+
35
+ .button {
36
+ padding: 9px;
37
+ }
38
+
39
+ .hiddenOnMobile {
40
+ display: none;
41
+ }
42
+ }
@@ -0,0 +1,28 @@
1
+ import MapButton from "../map-button/MapButton";
2
+ import ClearButton from "../map-button/ClearButton";
3
+ import { h } from "preact";
4
+ import style from "./style.module.css";
5
+
6
+ const MapButtons = ({
7
+ mode,
8
+ onClear,
9
+ changeMode,
10
+ }: {
11
+ mode: string;
12
+ changeMode: (mode: string) => void;
13
+ onClear: () => void;
14
+ }) => {
15
+ return (
16
+ <div class={style.buttons}>
17
+ <MapButton
18
+ label={"Route Snap"}
19
+ mode={"routesnap"}
20
+ currentMode={mode}
21
+ changeMode={changeMode}
22
+ />
23
+ <ClearButton onClick={onClear} label='Clear' />
24
+ </div>
25
+ );
26
+ };
27
+
28
+ export default MapButtons;
@@ -0,0 +1,17 @@
1
+ .buttons {
2
+ position: relative;
3
+ top: 0;
4
+ z-index: 1000;
5
+ margin: auto;
6
+ display: flex;
7
+ justify-content: center;
8
+ flex-wrap: wrap;
9
+ }
10
+
11
+ @media screen and (max-width: 900px) {
12
+ .buttons {
13
+ width: 85%;
14
+ margin: auto;
15
+ margin-left: 45px;
16
+ }
17
+ }
@@ -0,0 +1,9 @@
1
+ declare module "*.css" {
2
+ const mapping: Record<string, string>;
3
+ export default mapping;
4
+ }
5
+
6
+ declare module "*.png" {
7
+ const mapping: string;
8
+ export default mapping;
9
+ }
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <link rel="icon" type="image/svg+xml" href="/src/assets/favicon.ico" />
7
+ <meta name="viewport" content="width=device-width,initial-scale=1" />
8
+ <meta name="mobile-web-app-capable" content="yes" />
9
+ <meta name="apple-mobile-web-app-capable" content="yes" />
10
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
12
+ <link href="https://fonts.googleapis.com/css2?family=Open+Sans&display=swap" rel="stylesheet" />
13
+ <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.3/dist/leaflet.css"
14
+ integrity="sha256-kLaT2GOSpHechhsozzB+flnD+zUyjE2LlfWPgU04xyI=" crossorigin="" />
15
+ <title>Terra Draw - route snap mode</title>
16
+ </head>
17
+
18
+ <body>
19
+ <div id="app"></div>
20
+ <script prerender type="module" src="index.tsx"></script>
21
+ </body>
22
+
23
+ </html>