@any-routing/leaflet-engine 1.0.0-rc.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.
@@ -0,0 +1,137 @@
1
+ import type {
2
+ AnyRouting,
3
+ AnyRoutingDataProvider,
4
+ AnyRoutingDataResponse,
5
+ AnyRoutingProjectorEventMap,
6
+ InternalWaypoint,
7
+ } from '@any-routing/core';
8
+ import type { Feature, Geometry } from 'geojson';
9
+ import type { LatLngExpression, Layer, LeafletMouseEvent, Map, Marker } from 'leaflet';
10
+
11
+ export type WaypointDragEvent = {
12
+ waypoint: InternalWaypoint;
13
+ };
14
+
15
+ export type RouteClickEvent = {
16
+ routeId: number;
17
+ };
18
+
19
+ export type RoutesProjectedEvent = {
20
+ routesShapeGeojson: AnyRoutingDataResponse['routesShapeGeojson'];
21
+ };
22
+
23
+ export type WaypointsProjectedEvent = {
24
+ waypoints: InternalWaypoint[];
25
+ };
26
+
27
+ export type WaypointDragEndEvent = {
28
+ waypoint: InternalWaypoint;
29
+ };
30
+
31
+ export type WaypointAddedEvent = {
32
+ waypoint: InternalWaypoint;
33
+ };
34
+
35
+ export interface LeafletProjectorEventMap {
36
+ previewStarted: Record<string, never>;
37
+ previewFinished: { data: AnyRoutingDataResponse };
38
+ previewError: { error: Error };
39
+ waypointDrag: WaypointDragEvent;
40
+ waypointDragCommit: WaypointDragEvent;
41
+ waypointDragEnd: WaypointDragEndEvent;
42
+ waypointAdded: WaypointAddedEvent;
43
+ routesProjected: RoutesProjectedEvent;
44
+ waypointsProjected: WaypointsProjectedEvent;
45
+ routeClick: RouteClickEvent;
46
+ routeHighlight: AnyRoutingProjectorEventMap['routeHighlight'];
47
+ viewStateChanged: AnyRoutingProjectorEventMap['viewStateChanged'];
48
+ }
49
+
50
+ export type MarkerFactoryContext = {
51
+ waypoint?: InternalWaypoint;
52
+ routeHover?: Feature<Geometry, RouteFeatureProperties>;
53
+ };
54
+
55
+ export type LeafletMarkerFactory = (
56
+ ctx: MarkerFactoryContext,
57
+ ) => Marker;
58
+
59
+ export type LeafletProjectorOptions = {
60
+ map: Map;
61
+
62
+ editable?: boolean;
63
+
64
+ maxWaypoints?: number;
65
+
66
+ canAddWaypoints?: boolean;
67
+
68
+ canDragWaypoints?: boolean;
69
+
70
+ canSelectRoute?: boolean;
71
+
72
+ hoverEnabled?: boolean;
73
+
74
+ routesWhileDragging?: boolean;
75
+
76
+ waypointDragCommitDebounceTime?: number;
77
+
78
+ previewDataProvider?: AnyRoutingDataProvider;
79
+
80
+ markerFactory: LeafletMarkerFactory;
81
+
82
+ /**
83
+ * Optional custom route style.
84
+ */
85
+ routeStyle?: LeafletRouteStyle;
86
+
87
+ /**
88
+ * Optional selected route style.
89
+ */
90
+ selectedRouteStyle?: LeafletRouteStyle;
91
+
92
+ /**
93
+ * Optional style for the route casing rendered underneath each route.
94
+ */
95
+ routeOutlineStyle?: LeafletRouteStyle;
96
+
97
+ /**
98
+ * Optional z-index for selected routes.
99
+ */
100
+ selectedRouteZIndex?: number;
101
+
102
+ /**
103
+ * Optional z-index for regular routes.
104
+ */
105
+ routeZIndex?: number;
106
+ };
107
+
108
+ export type LeafletRouteStyle = {
109
+ color?: string;
110
+
111
+ weight?: number;
112
+
113
+ opacity?: number;
114
+
115
+ dashArray?: string;
116
+
117
+ lineCap?: 'butt' | 'round' | 'square';
118
+
119
+ lineJoin?: 'miter' | 'round' | 'bevel';
120
+
121
+ className?: string;
122
+ };
123
+
124
+ export type RouteFeatureProperties = {
125
+ routeId: number;
126
+
127
+ waypoint: number;
128
+
129
+ selected?: boolean;
130
+
131
+ offset?: number;
132
+ };
133
+
134
+ export type LeafletRouteFeature = Feature<
135
+ Geometry,
136
+ RouteFeatureProperties
137
+ >;
@@ -0,0 +1,164 @@
1
+ type DebounceOptions = {
2
+ leading?: boolean;
3
+ maxWait?: number;
4
+ trailing?: boolean;
5
+ };
6
+
7
+ type DebouncedFunction<T extends (...args: any[]) => any> = ((
8
+ ...args: Parameters<T>
9
+ ) => ReturnType<T> | undefined) & {
10
+ cancel: () => void;
11
+ flush: () => ReturnType<T> | undefined;
12
+ };
13
+
14
+ export function debounce<T extends (...args: any[]) => any>(
15
+ func: T,
16
+ wait = 0,
17
+ options: DebounceOptions = {},
18
+ ): DebouncedFunction<T> {
19
+ if (typeof func !== 'function') {
20
+ throw new TypeError('Expected a function');
21
+ }
22
+
23
+ const delay = Number(wait) || 0;
24
+
25
+ const leading = options.leading ?? false;
26
+ const trailing = options.trailing ?? true;
27
+ const maxing = options.maxWait !== undefined;
28
+ const maxWait = maxing
29
+ ? Math.max(Number(options.maxWait) || 0, delay)
30
+ : undefined;
31
+
32
+ let lastArgs: Parameters<T> | undefined;
33
+ let lastThis: ThisParameterType<T> | undefined;
34
+
35
+ let timerId: ReturnType<typeof setTimeout> | undefined;
36
+ let lastCallTime: number | undefined;
37
+ let lastInvokeTime = 0;
38
+
39
+ let result: ReturnType<T> | undefined;
40
+
41
+ const invoke = (time: number): ReturnType<T> | undefined => {
42
+ const args = lastArgs!;
43
+ const thisArg = lastThis;
44
+
45
+ lastArgs = undefined;
46
+ lastThis = undefined;
47
+ lastInvokeTime = time;
48
+
49
+ result = func.apply(thisArg, args);
50
+
51
+ return result;
52
+ };
53
+
54
+ const startTimer = (time: number): void => {
55
+ timerId = setTimeout(timerExpired, time);
56
+ };
57
+
58
+ const leadingEdge = (time: number): ReturnType<T> | undefined => {
59
+ lastInvokeTime = time;
60
+ startTimer(delay);
61
+
62
+ return leading ? invoke(time) : result;
63
+ };
64
+
65
+ const remainingWait = (time: number): number => {
66
+ const timeSinceLastCall = time - (lastCallTime ?? 0);
67
+ const timeSinceLastInvoke = time - lastInvokeTime;
68
+
69
+ const remaining = delay - timeSinceLastCall;
70
+
71
+ return maxing
72
+ ? Math.min(remaining, maxWait! - timeSinceLastInvoke)
73
+ : remaining;
74
+ };
75
+
76
+ const shouldInvoke = (time: number): boolean => {
77
+ const timeSinceLastCall = time - (lastCallTime ?? 0);
78
+ const timeSinceLastInvoke = time - lastInvokeTime;
79
+
80
+ return (
81
+ lastCallTime === undefined ||
82
+ timeSinceLastCall >= delay ||
83
+ timeSinceLastCall < 0 ||
84
+ (maxing && timeSinceLastInvoke >= maxWait!)
85
+ );
86
+ };
87
+
88
+ const trailingEdge = (time: number): ReturnType<T> | undefined => {
89
+ timerId = undefined;
90
+
91
+ if (trailing && lastArgs) {
92
+ return invoke(time);
93
+ }
94
+
95
+ lastArgs = undefined;
96
+ lastThis = undefined;
97
+
98
+ return result;
99
+ };
100
+
101
+ const timerExpired = (): void => {
102
+ const time = Date.now();
103
+
104
+ if (shouldInvoke(time)) {
105
+ trailingEdge(time);
106
+ return;
107
+ }
108
+
109
+ startTimer(remainingWait(time));
110
+ };
111
+
112
+ const cancel = (): void => {
113
+ if (timerId !== undefined) {
114
+ clearTimeout(timerId);
115
+ }
116
+
117
+ lastInvokeTime = 0;
118
+ lastArgs = undefined;
119
+ lastThis = undefined;
120
+ lastCallTime = undefined;
121
+ timerId = undefined;
122
+ };
123
+
124
+ const flush = (): ReturnType<T> | undefined => {
125
+ return timerId === undefined
126
+ ? result
127
+ : trailingEdge(Date.now());
128
+ };
129
+
130
+ const debounced = function (
131
+ this: ThisParameterType<T>,
132
+ ...args: Parameters<T>
133
+ ): ReturnType<T> | undefined {
134
+ const time = Date.now();
135
+ const isInvoking = shouldInvoke(time);
136
+
137
+ lastArgs = args;
138
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
139
+ lastThis = this;
140
+ lastCallTime = time;
141
+
142
+ if (isInvoking) {
143
+ if (timerId === undefined) {
144
+ return leadingEdge(time);
145
+ }
146
+
147
+ if (maxing) {
148
+ startTimer(delay);
149
+ return invoke(time);
150
+ }
151
+ }
152
+
153
+ if (timerId === undefined) {
154
+ startTimer(delay);
155
+ }
156
+
157
+ return result;
158
+ } as DebouncedFunction<T>;
159
+
160
+ debounced.cancel = cancel;
161
+ debounced.flush = flush;
162
+
163
+ return debounced;
164
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "module": "commonjs",
5
+ "forceConsistentCasingInFileNames": true,
6
+ "strict": true,
7
+ "importHelpers": true,
8
+ "noImplicitOverride": true,
9
+ "noImplicitReturns": true,
10
+ "noFallthroughCasesInSwitch": true,
11
+ "noPropertyAccessFromIndexSignature": true
12
+ },
13
+ "files": [],
14
+ "include": [],
15
+ "references": [
16
+ {
17
+ "path": "./tsconfig.lib.json"
18
+ },
19
+ {
20
+ "path": "./tsconfig.spec.json"
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../../../dist/out-tsc",
5
+ "declaration": true,
6
+ "types": ["node", "vite/client"]
7
+ },
8
+ "include": ["src/**/*.ts"],
9
+ "exclude": [
10
+ "vite.config.ts",
11
+ "vite.config.mts",
12
+ "vitest.config.ts",
13
+ "vitest.config.mts",
14
+ "src/**/*.test.ts",
15
+ "src/**/*.spec.ts",
16
+ "src/**/*.test.tsx",
17
+ "src/**/*.spec.tsx",
18
+ "src/**/*.test.js",
19
+ "src/**/*.spec.js",
20
+ "src/**/*.test.jsx",
21
+ "src/**/*.spec.jsx"
22
+ ]
23
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../../../dist/out-tsc",
5
+ "types": ["vitest/globals", "vitest/importMeta", "vite/client", "node", "vitest"]
6
+ },
7
+ "include": [
8
+ "vite.config.ts",
9
+ "vite.config.mts",
10
+ "vitest.config.ts",
11
+ "vitest.config.mts",
12
+ "src/**/*.test.ts",
13
+ "src/**/*.spec.ts",
14
+ "src/**/*.test.tsx",
15
+ "src/**/*.spec.tsx",
16
+ "src/**/*.test.js",
17
+ "src/**/*.spec.js",
18
+ "src/**/*.test.jsx",
19
+ "src/**/*.spec.jsx",
20
+ "src/**/*.d.ts"
21
+ ]
22
+ }
@@ -0,0 +1,59 @@
1
+ /// <reference types='vitest' />
2
+ import { defineConfig } from 'vite';
3
+ import dts from 'vite-plugin-dts';
4
+ import * as path from 'path';
5
+ import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
6
+ import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
7
+
8
+ export default defineConfig(() => ({
9
+ root: import.meta.dirname,
10
+ cacheDir: '../../../../node_modules/.vite/libs/line-loader/libs/leaflet-engine',
11
+ plugins: [
12
+ nxViteTsPaths(),
13
+ nxCopyAssetsPlugin(['*.md']),
14
+ dts({
15
+ entryRoot: 'src',
16
+ tsconfigPath: path.join(import.meta.dirname, 'tsconfig.lib.json'),
17
+ pathsToAliases: false,
18
+ }),
19
+ ],
20
+ // Uncomment this if you are using workers.
21
+ // worker: {
22
+ // plugins: () => [ nxViteTsPaths() ],
23
+ // },
24
+ // Configuration for building your library.
25
+ // See: https://vite.dev/guide/build.html#library-mode
26
+ build: {
27
+ outDir: '../../dist/libs/line-loader/libs/leaflet-engine',
28
+ emptyOutDir: true,
29
+ reportCompressedSize: true,
30
+ commonjsOptions: {
31
+ transformMixedEsModules: true,
32
+ },
33
+ lib: {
34
+ // Could also be a dictionary or array of multiple entry points.
35
+ entry: 'src/index.ts',
36
+ name: 'leaflet-engine',
37
+ fileName: 'index',
38
+ // Change this to the formats you want to support.
39
+ // Don't forget to update your package.json as well.
40
+ formats: ['es' as const],
41
+ },
42
+ rolldownOptions: {
43
+ // External packages that should not be bundled into your library.
44
+ external: [],
45
+ },
46
+ },
47
+ test: {
48
+ name: 'leaflet-engine',
49
+ watch: false,
50
+ globals: true,
51
+ environment: 'node',
52
+ include: ['{src,tests}/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
53
+ reporters: ['default'],
54
+ coverage: {
55
+ reportsDirectory: '../../../../coverage/libs/line-loader/libs/leaflet-engine',
56
+ provider: 'v8' as const,
57
+ },
58
+ },
59
+ }));