@d3-maps/core 0.1.1-next.0 → 0.3.0
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/dist/index.css +1 -0
- package/dist/index.d.ts +189 -99
- package/dist/index.iife.js +1 -1
- package/dist/index.js +71 -64
- package/package.json +3 -2
package/dist/index.css
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,55 @@
|
|
|
1
|
-
import { GeoPath, GeoProjection } from "d3-geo";
|
|
1
|
+
import { ExtendedFeature, ExtendedFeatureCollection, GeoGeometryObjects, GeoPath, GeoPermissibleObjects, GeoProjection } from "d3-geo";
|
|
2
|
+
import { mesh } from "topojson-client";
|
|
2
3
|
import { D3ZoomEvent, D3ZoomEvent as D3ZoomEvent$1, ZoomBehavior, ZoomBehavior as ZoomBehavior$1, ZoomTransform, ZoomTransform as ZoomTransform$1 } from "d3-zoom";
|
|
3
4
|
|
|
5
|
+
//#region src/lib/mapObject.d.ts
|
|
6
|
+
type MapObject = GeoGeometryObjects | ExtendedFeature;
|
|
7
|
+
type MapObjectFocusEventType = 'focus' | 'blur';
|
|
8
|
+
type MapObjectMouseEventType = 'mouseenter' | 'mouseleave' | 'mousedown' | 'mouseup';
|
|
9
|
+
type MapObjectEventType = MapObjectFocusEventType | MapObjectMouseEventType;
|
|
10
|
+
type MapObjectEvent<E> = E extends MapObjectFocusEventType ? FocusEvent : MouseEvent;
|
|
11
|
+
/**
|
|
12
|
+
* Supported interaction states for map objects.
|
|
13
|
+
*/
|
|
14
|
+
declare const mapObjectState: readonly ["default", "hover", "active"];
|
|
15
|
+
type MapObjectState = typeof mapObjectState[number];
|
|
16
|
+
type MapObjectStyles<TStyle> = Partial<Record<MapObjectState, TStyle>>;
|
|
17
|
+
/**
|
|
18
|
+
* Maps DOM event names to interaction state updates.
|
|
19
|
+
*/
|
|
20
|
+
declare function getObjectStateUpdate(event: MapObjectEventType): MapObjectState;
|
|
21
|
+
/**
|
|
22
|
+
* Resolves a style value for the current state (falls back to `default`).
|
|
23
|
+
*/
|
|
24
|
+
declare function resolveObjectStyle<TStyle>(state: MapObjectState, styles?: MapObjectStyles<TStyle>): TStyle | undefined;
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/lib/feature.d.ts
|
|
27
|
+
/**
|
|
28
|
+
* A GeoJSON Feature used by d3-maps.
|
|
29
|
+
*
|
|
30
|
+
* This type allows extra top-level fields to be attached in `dataTransformer` (e.g. choropleth colors).
|
|
31
|
+
*/
|
|
32
|
+
type MapFeature = (ExtendedFeature & Record<string, unknown>) | ExtendedFeature;
|
|
33
|
+
/**
|
|
34
|
+
* Shared props contract for a single rendered feature.
|
|
35
|
+
*/
|
|
36
|
+
interface MapFeatureProps<TStyle = unknown> {
|
|
37
|
+
data: MapFeature;
|
|
38
|
+
styles?: MapObjectStyles<TStyle>;
|
|
39
|
+
fill?: string;
|
|
40
|
+
stroke?: string;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Resolves a stable key for a feature.
|
|
44
|
+
*
|
|
45
|
+
* Checks:
|
|
46
|
+
* 1) `feature[idKey]`
|
|
47
|
+
* 2) `feature.properties[idKey]`
|
|
48
|
+
* 3) fallback to the list index
|
|
49
|
+
*/
|
|
50
|
+
declare function getFeatureKey(feature: MapFeature, idKey: string | undefined, index: number): string | number;
|
|
51
|
+
//#endregion
|
|
4
52
|
//#region ../../node_modules/.pnpm/@types+geojson@7946.0.16/node_modules/@types/geojson/index.d.ts
|
|
5
|
-
|
|
6
53
|
/**
|
|
7
54
|
* The valid values for the "type" property of GeoJSON geometry objects.
|
|
8
55
|
* https://tools.ietf.org/html/rfc7946#section-1.4
|
|
@@ -183,53 +230,6 @@ interface FeatureCollection<G extends Geometry | null = Geometry, P$1 = GeoJsonP
|
|
|
183
230
|
features: Array<Feature<G, P$1>>;
|
|
184
231
|
}
|
|
185
232
|
//#endregion
|
|
186
|
-
//#region src/lib/mapObject.d.ts
|
|
187
|
-
type MapObject = Point$1 | Feature;
|
|
188
|
-
type MapObjectFocusEventType = 'focus' | 'blur';
|
|
189
|
-
type MapObjectMouseEventType = 'mouseenter' | 'mouseleave' | 'mousedown' | 'mouseup';
|
|
190
|
-
type MapObjectEventType = MapObjectFocusEventType | MapObjectMouseEventType;
|
|
191
|
-
type MapObjectEvent<E> = E extends MapObjectFocusEventType ? FocusEvent : MouseEvent;
|
|
192
|
-
/**
|
|
193
|
-
* Supported interaction states for map objects.
|
|
194
|
-
*/
|
|
195
|
-
declare const mapObjectState: readonly ["default", "hover", "active"];
|
|
196
|
-
type MapObjectState = typeof mapObjectState[number];
|
|
197
|
-
type MapObjectStyles<TStyle> = Partial<Record<MapObjectState, TStyle>>;
|
|
198
|
-
/**
|
|
199
|
-
* Maps DOM event names to interaction state updates.
|
|
200
|
-
*/
|
|
201
|
-
declare function getObjectStateUpdate(event: MapObjectEventType): MapObjectState;
|
|
202
|
-
/**
|
|
203
|
-
* Resolves a style value for the current state (falls back to `default`).
|
|
204
|
-
*/
|
|
205
|
-
declare function resolveObjectStyle<TStyle>(state: MapObjectState, styles?: MapObjectStyles<TStyle>): TStyle | undefined;
|
|
206
|
-
//#endregion
|
|
207
|
-
//#region src/lib/feature.d.ts
|
|
208
|
-
/**
|
|
209
|
-
* A GeoJSON Feature used by d3-maps.
|
|
210
|
-
*
|
|
211
|
-
* This type allows extra top-level fields to be attached in `dataTransformer` (e.g. choropleth colors).
|
|
212
|
-
*/
|
|
213
|
-
type MapFeature = (Feature & Record<string, unknown>) | Feature;
|
|
214
|
-
/**
|
|
215
|
-
* Shared props contract for a single rendered feature.
|
|
216
|
-
*/
|
|
217
|
-
interface MapFeatureProps<TStyle = unknown> {
|
|
218
|
-
data: MapFeature;
|
|
219
|
-
styles?: MapObjectStyles<TStyle>;
|
|
220
|
-
fill?: string;
|
|
221
|
-
stroke?: string;
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Resolves a stable key for a feature.
|
|
225
|
-
*
|
|
226
|
-
* Checks:
|
|
227
|
-
* 1) `feature[idKey]`
|
|
228
|
-
* 2) `feature.properties[idKey]`
|
|
229
|
-
* 3) fallback to the list index
|
|
230
|
-
*/
|
|
231
|
-
declare function getFeatureKey(feature: MapFeature, idKey: string | undefined, index: number): string | number;
|
|
232
|
-
//#endregion
|
|
233
233
|
//#region ../../node_modules/.pnpm/@types+topojson-specification@1.0.5/node_modules/@types/topojson-specification/index.d.ts
|
|
234
234
|
// ---------------------------------------------------------------
|
|
235
235
|
// TopoJSON Format Specification
|
|
@@ -316,19 +316,120 @@ interface NullObject extends GeometryObjectA {
|
|
|
316
316
|
type: null;
|
|
317
317
|
}
|
|
318
318
|
//#endregion
|
|
319
|
+
//#region src/lib/utils.d.ts
|
|
320
|
+
declare function isString(value: unknown): value is string;
|
|
321
|
+
declare function isDefined<T>(value: T | null | undefined): value is T;
|
|
322
|
+
declare const isNullish: (value: unknown) => value is null | undefined;
|
|
323
|
+
declare const isNumber: (value: unknown) => value is number;
|
|
324
|
+
declare function isStringOrNumber(value: unknown): value is string | number;
|
|
325
|
+
declare function isFunction(value: unknown): value is (...args: unknown[]) => unknown;
|
|
326
|
+
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
327
|
+
declare function makeTransform(x: number, y: number, k?: number): string;
|
|
328
|
+
type AnyFn = (...args: any) => any;
|
|
329
|
+
/**
|
|
330
|
+
* Extracts a union of parameter tuples from a (possibly overloaded) function type.
|
|
331
|
+
*
|
|
332
|
+
* TypeScript's built-in `Parameters<F>` only captures the *last* overload, which breaks typing
|
|
333
|
+
* for overloaded getter/setter APIs (common in d3), where the setter overload might not be last.
|
|
334
|
+
*
|
|
335
|
+
* Notes:
|
|
336
|
+
* - This helper supports up to 5 overload signatures (adjust if needed).
|
|
337
|
+
* - Getter overloads like `(): T` are filtered out later via `Exclude<..., []>` when we build
|
|
338
|
+
* setter-only config types.
|
|
339
|
+
*/
|
|
340
|
+
type OverloadedArgs<F> = F extends {
|
|
341
|
+
(...a: infer A1): any;
|
|
342
|
+
(...a: infer A2): any;
|
|
343
|
+
(...a: infer A3): any;
|
|
344
|
+
(...a: infer A4): any;
|
|
345
|
+
(...a: infer A5): any;
|
|
346
|
+
} ? A1 | A2 | A3 | A4 | A5 : F extends {
|
|
347
|
+
(...a: infer A1): any;
|
|
348
|
+
(...a: infer A2): any;
|
|
349
|
+
(...a: infer A3): any;
|
|
350
|
+
(...a: infer A4): any;
|
|
351
|
+
} ? A1 | A2 | A3 | A4 : F extends {
|
|
352
|
+
(...a: infer A1): any;
|
|
353
|
+
(...a: infer A2): any;
|
|
354
|
+
(...a: infer A3): any;
|
|
355
|
+
} ? A1 | A2 | A3 : F extends {
|
|
356
|
+
(...a: infer A1): any;
|
|
357
|
+
(...a: infer A2): any;
|
|
358
|
+
} ? A1 | A2 : F extends ((...a: infer A1) => any) ? A1 : never;
|
|
359
|
+
/**
|
|
360
|
+
* Removes 0-arg overloads (getters), leaving only setter-style overload argument tuples.
|
|
361
|
+
*/
|
|
362
|
+
type SetterArgs<F> = Exclude<OverloadedArgs<F>, []>;
|
|
363
|
+
/**
|
|
364
|
+
* True if the function has at least one overload that accepts arguments (i.e. a setter overload).
|
|
365
|
+
*/
|
|
366
|
+
type HasArgs<F> = [SetterArgs<F>] extends [never] ? false : true;
|
|
367
|
+
type OwnKeys<T> = T extends AnyFn ? Exclude<keyof T, keyof CallableFunction> : keyof T;
|
|
368
|
+
/**
|
|
369
|
+
* Converts method parameters to modifiers values
|
|
370
|
+
* - single non-array arg: `arg` | `[arg]`
|
|
371
|
+
* - multiple args/single array wrapped with array
|
|
372
|
+
*/
|
|
373
|
+
type ModifierArgs<P$1 extends unknown[]> = P$1 extends [infer Only] ? Only extends readonly unknown[] ? [Only] : Only | [Only] : P$1;
|
|
374
|
+
/**
|
|
375
|
+
* Maps methods with args to modifiers
|
|
376
|
+
*
|
|
377
|
+
* @example
|
|
378
|
+
* type X = {
|
|
379
|
+
* a: string; // not a function - will be ignored
|
|
380
|
+
* b(): void; // has no arguments - will be ignored
|
|
381
|
+
* c(x: number): void;
|
|
382
|
+
* d(x: number, y: string): void;
|
|
383
|
+
* e(xs: string[]): void;
|
|
384
|
+
* }
|
|
385
|
+
*
|
|
386
|
+
* type R = MethodsToModifiers<X>
|
|
387
|
+
* {
|
|
388
|
+
* c: number | [number];
|
|
389
|
+
* d: [number, string];
|
|
390
|
+
* e: [string[]]; // forced wrapper (arg is array)
|
|
391
|
+
* }
|
|
392
|
+
*/
|
|
393
|
+
type MethodsToModifiers<T extends object> = { [K in OwnKeys<T> as Extract<T[K], AnyFn> extends never ? never : HasArgs<Extract<T[K], AnyFn>> extends true ? K : never]?: ModifierArgs<Extract<SetterArgs<Extract<T[K], AnyFn>>, unknown[]>> };
|
|
394
|
+
/**
|
|
395
|
+
* Invokes `target` methods with arguments from `modifiers`.
|
|
396
|
+
*
|
|
397
|
+
* modifiers: `{ [methodName]: args[] | arg }`
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* class X {
|
|
401
|
+
* a(x: number) {}
|
|
402
|
+
* b(x: number, y: string) {}
|
|
403
|
+
* c(x: string[]) {}
|
|
404
|
+
* d() {}
|
|
405
|
+
* e = 'foo'
|
|
406
|
+
* }
|
|
407
|
+
*
|
|
408
|
+
* applyModifiers(new X(), {
|
|
409
|
+
* a: 1, // ok (single arg as-is)
|
|
410
|
+
* a: [1], // ok (single arg wrapped)
|
|
411
|
+
* b: [1, 'foo'], // ok (tuple for 2 args)
|
|
412
|
+
* c: [['foo', 'bar']], // ok (array-arg must be wrapped)
|
|
413
|
+
* c: ['foo', 'bar'], // error (single array-arg must be wrapped into array)
|
|
414
|
+
* d: [], // error (d has no args, excluded)
|
|
415
|
+
* e: 'foo' // error (e is not a function, excluded)
|
|
416
|
+
* })
|
|
417
|
+
*/
|
|
418
|
+
declare function applyModifiers<T extends object>(target: T, modifiers?: MethodsToModifiers<T>): void;
|
|
419
|
+
//#endregion
|
|
319
420
|
//#region src/lib/map.d.ts
|
|
320
|
-
type
|
|
421
|
+
type MapMesh = ReturnType<typeof mesh>;
|
|
422
|
+
type MapData = ExtendedFeatureCollection | Topology;
|
|
321
423
|
type DataTransformer = (features: MapFeature[]) => MapFeature[];
|
|
322
424
|
/**
|
|
323
|
-
*
|
|
425
|
+
* Extra projection method calls to apply before rendering.
|
|
426
|
+
*
|
|
427
|
+
* Use projection method names as keys and method arguments as values.
|
|
428
|
+
* Example: `{ center: [[0, 20]], rotate: [[0, 0, 0]], scale: 160 }`
|
|
324
429
|
*
|
|
325
|
-
* d3-
|
|
430
|
+
* @see https://d3js.org/d3-geo/projection
|
|
326
431
|
*/
|
|
327
|
-
interface ProjectionConfig {
|
|
328
|
-
center?: [number, number];
|
|
329
|
-
rotate?: [number, number, number];
|
|
330
|
-
scale?: number;
|
|
331
|
-
}
|
|
432
|
+
interface ProjectionConfig extends Omit<MethodsToModifiers<GeoProjection>, 'invert' | 'stream'> {}
|
|
332
433
|
/**
|
|
333
434
|
* Input configuration for creating a map context.
|
|
334
435
|
*
|
|
@@ -344,6 +445,9 @@ interface MapConfig {
|
|
|
344
445
|
* Example: `geoEqualEarth`.
|
|
345
446
|
*/
|
|
346
447
|
projection?: () => GeoProjection;
|
|
448
|
+
/**
|
|
449
|
+
* Projection method arguments passed to the created projection
|
|
450
|
+
*/
|
|
347
451
|
projectionConfig?: ProjectionConfig;
|
|
348
452
|
/**
|
|
349
453
|
* TopoJSON or GeoJSON input.
|
|
@@ -366,8 +470,10 @@ interface MapContext {
|
|
|
366
470
|
height: number;
|
|
367
471
|
projection?: GeoProjection;
|
|
368
472
|
features: MapFeature[];
|
|
473
|
+
mesh?: MapMesh;
|
|
369
474
|
path: GeoPath;
|
|
370
|
-
renderPath: (feature:
|
|
475
|
+
renderPath: (feature: MapFeature) => ReturnType<GeoPath>;
|
|
476
|
+
renderMesh: () => ReturnType<GeoPath>;
|
|
371
477
|
}
|
|
372
478
|
/**
|
|
373
479
|
* Creates a configured projection and fits it to the provided GeoJSON (if present).
|
|
@@ -383,7 +489,7 @@ declare function makeProjection({
|
|
|
383
489
|
height: number;
|
|
384
490
|
config?: ProjectionConfig;
|
|
385
491
|
projection: () => GeoProjection;
|
|
386
|
-
geoJson?:
|
|
492
|
+
geoJson?: GeoPermissibleObjects;
|
|
387
493
|
}): GeoProjection;
|
|
388
494
|
/**
|
|
389
495
|
* Normalizes input map data to GeoJSON features.
|
|
@@ -391,8 +497,12 @@ declare function makeProjection({
|
|
|
391
497
|
* - TopoJSON is converted via `topojson-client`.
|
|
392
498
|
* - If provided, `dataTransformer` is applied to the feature array.
|
|
393
499
|
*/
|
|
394
|
-
declare function makeFeatures(geoData: MapData, dataTransformer?: DataTransformer): [features: MapFeature[], geoJson:
|
|
500
|
+
declare function makeFeatures(geoData: MapData, dataTransformer?: DataTransformer): [features: MapFeature[], geoJson: ExtendedFeatureCollection];
|
|
395
501
|
declare const makePathFn: (mapProjection: GeoProjection) => GeoPath;
|
|
502
|
+
/**
|
|
503
|
+
* Returns a TopoJSON mesh when topology data is provided.
|
|
504
|
+
*/
|
|
505
|
+
declare function makeMesh(geoData: MapData): MapMesh | undefined;
|
|
396
506
|
/**
|
|
397
507
|
* Creates a full {@link MapContext} from a {@link MapConfig}.
|
|
398
508
|
*/
|
|
@@ -409,6 +519,7 @@ declare function makeMapContext({
|
|
|
409
519
|
* Type guard for TopoJSON topology inputs.
|
|
410
520
|
*/
|
|
411
521
|
declare function isTopology(data: MapData): data is Topology;
|
|
522
|
+
declare function getTopoObject(geoData: Topology): GeometryObject;
|
|
412
523
|
//#endregion
|
|
413
524
|
//#region src/lib/marker.d.ts
|
|
414
525
|
type MapMarkerCoordinates = [number, number];
|
|
@@ -426,41 +537,24 @@ interface MapMarkerProps<TStyle = unknown> {
|
|
|
426
537
|
*/
|
|
427
538
|
declare function getMarkerTransform(context: MapContext | undefined, coordinates: MapMarkerCoordinates, fallback?: string): string;
|
|
428
539
|
//#endregion
|
|
429
|
-
//#region src/lib/utils.d.ts
|
|
430
|
-
declare function isString(value: unknown): value is string;
|
|
431
|
-
declare function isDefined<T>(value: T | null | undefined): value is T;
|
|
432
|
-
declare const isNullish: (value: unknown) => value is null | undefined;
|
|
433
|
-
declare const isNumber: (value: unknown) => value is number;
|
|
434
|
-
declare const isStringOrNumber: (value: unknown) => value is string | number;
|
|
435
|
-
declare function isFunction(value: unknown): value is (...args: unknown[]) => unknown;
|
|
436
|
-
declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
437
|
-
declare function get<T>(url: string): Promise<T>;
|
|
438
|
-
declare const makeTransform: (x: number, y: number, k?: number) => string;
|
|
439
|
-
//#endregion
|
|
440
540
|
//#region src/lib/zoom.d.ts
|
|
441
541
|
type Extent = [[number, number], [number, number]];
|
|
442
|
-
interface
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
type ZoomBehaviorMethodArgs<TElement extends Element, TDatum, TMethod extends ZoomBehaviorMethodName<TElement, TDatum>> = ZoomBehavior$1<TElement, TDatum>[TMethod] extends ((...args: infer TArgs) => unknown) ? TArgs : never;
|
|
454
|
-
type ZoomBehaviorSingleArg<TElement extends Element, TDatum, TMethod extends ZoomBehaviorMethodName<TElement, TDatum>> = ZoomBehaviorMethodArgs<TElement, TDatum, TMethod> extends [infer TArg] ? TArg : never;
|
|
455
|
-
type ZoomModifierValue<TElement extends Element, TDatum, TMethod extends ZoomBehaviorMethodName<TElement, TDatum>> = ZoomBehaviorMethodArgs<TElement, TDatum, TMethod> | ZoomBehaviorSingleArg<TElement, TDatum, TMethod>;
|
|
456
|
-
type ZoomModifiers<TElement extends Element = SVGSVGElement, TDatum = unknown> = Partial<{ [K in ZoomBehaviorMethodName<TElement, TDatum>]: ZoomModifierValue<TElement, TDatum, K> }>;
|
|
457
|
-
interface ZoomProps<TElement extends Element = SVGSVGElement, TDatum = unknown> {
|
|
542
|
+
interface DefaultZoomBehavior extends ZoomBehavior$1<SVGSVGElement, unknown> {}
|
|
543
|
+
/**
|
|
544
|
+
* Extra zoom method calls to apply before rendering.
|
|
545
|
+
*
|
|
546
|
+
* Use zoom method names as keys and method arguments as values.
|
|
547
|
+
* Example: `{ scaleExtent: [[2, 9]], translateExtent: [[[0, 0], [10, 10]]] }`
|
|
548
|
+
*
|
|
549
|
+
* @see https://d3js.org/d3-zoom
|
|
550
|
+
*/
|
|
551
|
+
interface ZoomModifiers extends MethodsToModifiers<DefaultZoomBehavior> {}
|
|
552
|
+
interface ZoomProps {
|
|
458
553
|
center?: [number, number];
|
|
459
554
|
zoom?: number;
|
|
460
555
|
minZoom?: number;
|
|
461
556
|
maxZoom?: number;
|
|
462
|
-
|
|
463
|
-
modifiers?: ZoomModifiers<TElement, TDatum>;
|
|
557
|
+
config?: ZoomModifiers;
|
|
464
558
|
}
|
|
465
559
|
interface ZoomEvent extends D3ZoomEvent$1<SVGSVGElement, unknown> {}
|
|
466
560
|
interface ZoomEvents {
|
|
@@ -468,7 +562,7 @@ interface ZoomEvents {
|
|
|
468
562
|
onZoom?: (event: ZoomEvent) => void;
|
|
469
563
|
onZoomEnd?: (event: ZoomEvent) => void;
|
|
470
564
|
}
|
|
471
|
-
interface ZoomBehaviorOptions
|
|
565
|
+
interface ZoomBehaviorOptions extends ZoomProps, ZoomEvents {}
|
|
472
566
|
type ZoomScaleSource = number | ZoomTransform$1 | {
|
|
473
567
|
transform: ZoomTransform$1;
|
|
474
568
|
};
|
|
@@ -478,24 +572,20 @@ declare const ZOOM_DEFAULTS: {
|
|
|
478
572
|
zoom: number;
|
|
479
573
|
minZoom: number;
|
|
480
574
|
maxZoom: number;
|
|
481
|
-
extent: Extent;
|
|
482
575
|
};
|
|
483
576
|
interface ApplyZoomOptions {
|
|
484
577
|
element: ZoomTargetElement | null | undefined;
|
|
485
|
-
behavior:
|
|
578
|
+
behavior: DefaultZoomBehavior;
|
|
486
579
|
center?: [number, number];
|
|
487
580
|
zoom?: number;
|
|
488
581
|
}
|
|
489
582
|
interface SetupZoomOptions extends ApplyZoomOptions {}
|
|
490
|
-
declare function
|
|
491
|
-
declare function
|
|
492
|
-
declare function
|
|
493
|
-
declare function createZoomBehavior<TElement extends Element = SVGSVGElement, TDatum = unknown>(context?: MapContext, options?: ZoomBehaviorOptions<TElement, TDatum>): ZoomBehavior$1<TElement, TDatum>;
|
|
494
|
-
declare function attachZoomBehavior(element: ZoomTargetElement | null | undefined, behavior: ZoomBehavior$1<SVGSVGElement, unknown>): void;
|
|
495
|
-
declare function applyZoomBehaviorTransform(element: ZoomTargetElement | null | undefined, behavior: ZoomBehavior$1<SVGSVGElement, unknown>, transform: ZoomTransform$1): void;
|
|
583
|
+
declare function createZoomBehavior(context?: MapContext, options?: ZoomBehaviorOptions): DefaultZoomBehavior;
|
|
584
|
+
declare function attachZoomBehavior(element: ZoomTargetElement | null | undefined, behavior: DefaultZoomBehavior): void;
|
|
585
|
+
declare function applyZoomBehaviorTransform(element: ZoomTargetElement | null | undefined, behavior: DefaultZoomBehavior, transform: ZoomTransform$1): void;
|
|
496
586
|
declare function applyZoomTransform(options: ApplyZoomOptions): void;
|
|
497
587
|
declare function setupZoom(options: SetupZoomOptions): void;
|
|
498
588
|
declare function getZoomScale(source: ZoomScaleSource): number;
|
|
499
589
|
declare function getInverseZoomScale(source: ZoomScaleSource, fallback?: number): number;
|
|
500
590
|
//#endregion
|
|
501
|
-
export { ApplyZoomOptions, type D3ZoomEvent, DataTransformer, Extent, MapConfig, MapContext, MapData, MapFeature, MapFeatureProps, MapMarkerCoordinates, MapMarkerProps, MapObject, MapObjectEvent, MapObjectEventType, MapObjectFocusEventType, MapObjectMouseEventType, MapObjectState, MapObjectStyles,
|
|
591
|
+
export { AnyFn, ApplyZoomOptions, type D3ZoomEvent, DataTransformer, DefaultZoomBehavior, Extent, HasArgs, MapConfig, MapContext, MapData, MapFeature, MapFeatureProps, MapMarkerCoordinates, MapMarkerProps, MapMesh, MapObject, MapObjectEvent, MapObjectEventType, MapObjectFocusEventType, MapObjectMouseEventType, MapObjectState, MapObjectStyles, MethodsToModifiers, ModifierArgs, OverloadedArgs, OwnKeys, ProjectionConfig, SetterArgs, SetupZoomOptions, ZOOM_DEFAULTS, type ZoomBehavior, ZoomBehaviorOptions, ZoomEvent, ZoomEvents, ZoomModifiers, ZoomProps, ZoomScaleSource, ZoomTargetElement, type ZoomTransform, applyModifiers, applyZoomBehaviorTransform, applyZoomTransform, attachZoomBehavior, createZoomBehavior, getFeatureKey, getInverseZoomScale, getMarkerTransform, getObjectStateUpdate, getTopoObject, getZoomScale, isDefined, isFunction, isNullish, isNumber, isPlainObject, isString, isStringOrNumber, isTopology, makeFeatures, makeMapContext, makeMesh, makePathFn, makeProjection, makeTransform, mapObjectState, resolveObjectStyle, setupZoom };
|
package/dist/index.iife.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(e,t,n,r,i){function a(e){return typeof e==`string`}function o(e){return e!==`undefined`}let s=e=>e==null,c=e=>Number.isFinite(e)
|
|
1
|
+
(function(e,t,n,r,i){function a(e){return typeof e==`string`}function o(e){return e!==`undefined`}let s=e=>e==null,c=e=>Number.isFinite(e);function l(e){return a(e)||c(e)}function u(e){return typeof e==`function`}function d(e){if(Object.prototype.toString.call(e)!==`[object Object]`)return!1;let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype}function f(e,t,n){return`translate(${e}, ${t}) scale(${n??1})`}function p(e,t){if(t)for(let n of Object.keys(t)){let r=t[n];if(!o(r))continue;let i=e[n];if(!u(i))continue;let a=Array.isArray(r)?r:[r];i.apply(e,a)}}function m(e,t=`id`,n){let r=e[t];if(l(r))return r;let i=e.properties?.[t];return l(i)?i:n}function h({width:e,height:t,config:n,projection:r,geoJson:i}){let a=r();return i?n?.fitSize||a.fitSize([e,t],i):n?.translate||a.translate([e/2,t/2]),p(a,n),a}function g(e,t){let r;if(b(e)){let t=(0,n.feature)(e,x(e));r=t.type===`FeatureCollection`?t:{type:`FeatureCollection`,features:[t]}}else r=e;return[t?t(r.features):r.features,r]}let _=e=>(0,t.geoPath)().projection(e);function v(e){if(b(e))return(0,n.mesh)(e,x(e))}function y({width:e=600,height:n,aspectRatio:r=16/9,data:i,dataTransformer:a,projection:o=t.geoEqualEarth,projectionConfig:s}){let[c,l]=g(i,a),u=v(i),d=n||e/r,f=h({width:e,height:d,projection:o,config:s,geoJson:l}),p=_(f);return{width:e,height:d,projection:f,features:c,mesh:u,path:p,renderPath:e=>p(e),renderMesh:()=>u?p(u):null}}function b(e){return e?.type===`Topology`}function x(e){let t=Object.keys(e.objects)[0];return e.objects[t]}let S=[`default`,`hover`,`active`];function C(e){switch(e){case`focus`:case`mouseenter`:case`mouseup`:return`hover`;case`blur`:case`mouseleave`:return`default`;case`mousedown`:return`active`;default:return`default`}}function w(e,t){return t?.[e]??t?.default}function T(e,t,n=`translate(0, 0)`){let r=e?.projection;if(!r)return n;let i=r(t);return i?f(...i):n}let E={center:[0,0],zoom:1,minZoom:1,maxZoom:8};function D(e,t={}){let n=(0,i.zoom)(),r=t.minZoom??E.minZoom,a=t.maxZoom??E.maxZoom,o=[[0,0],[e?.width??0,e?.height??0]];return n.scaleExtent([r,a]).translateExtent(o),t.onZoomStart&&n.on(`start`,t.onZoomStart),t.onZoom&&n.on(`zoom`,t.onZoom),t.onZoomEnd&&n.on(`end`,t.onZoomEnd),p(n,t.config),n}function O(e,t){let n=F(e);n&&(0,r.select)(n).call(t)}function k(e,t,n){let i=F(e);i&&(0,r.select)(i).call(t.transform,n)}function A(e){let t=e.center??E.center,n=e.zoom??E.zoom;k(e.element,e.behavior,i.zoomIdentity.translate(...t).scale(n))}function j(e){O(e.element,e.behavior),A(e)}function M(e){return c(e)?e:P(e)?e.k:e?.transform?.k??1}function N(e,t=1){let n=M(e);return!c(n)||n===0?t:1/n}function P(e){return!!(e&&c(e.k)&&c(e.x)&&c(e.y))}function F(e){return e?e instanceof SVGSVGElement?e:e.closest(`svg`):null}e.ZOOM_DEFAULTS=E,e.applyModifiers=p,e.applyZoomBehaviorTransform=k,e.applyZoomTransform=A,e.attachZoomBehavior=O,e.createZoomBehavior=D,e.getFeatureKey=m,e.getInverseZoomScale=N,e.getMarkerTransform=T,e.getObjectStateUpdate=C,e.getTopoObject=x,e.getZoomScale=M,e.isDefined=o,e.isFunction=u,e.isNullish=s,e.isNumber=c,e.isPlainObject=d,e.isString=a,e.isStringOrNumber=l,e.isTopology=b,e.makeFeatures=g,e.makeMapContext=y,e.makeMesh=v,e.makePathFn=_,e.makeProjection=h,e.makeTransform=f,e.mapObjectState=S,e.resolveObjectStyle=w,e.setupZoom=j})(this.D3Maps=this.D3Maps||{},d3,topojson,d3,d3);
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { geoEqualEarth, geoPath } from "d3-geo";
|
|
2
|
-
import { feature } from "topojson-client";
|
|
2
|
+
import { feature, mesh } from "topojson-client";
|
|
3
3
|
import { select } from "d3-selection";
|
|
4
4
|
import { zoom, zoomIdentity } from "d3-zoom";
|
|
5
5
|
|
|
@@ -12,7 +12,9 @@ function isDefined(value) {
|
|
|
12
12
|
}
|
|
13
13
|
const isNullish = (value) => value == null;
|
|
14
14
|
const isNumber = (value) => Number.isFinite(value);
|
|
15
|
-
|
|
15
|
+
function isStringOrNumber(value) {
|
|
16
|
+
return isString(value) || isNumber(value);
|
|
17
|
+
}
|
|
16
18
|
function isFunction(value) {
|
|
17
19
|
return typeof value === "function";
|
|
18
20
|
}
|
|
@@ -21,10 +23,44 @@ function isPlainObject(value) {
|
|
|
21
23
|
const prototype = Object.getPrototypeOf(value);
|
|
22
24
|
return prototype === null || prototype === Object.prototype;
|
|
23
25
|
}
|
|
24
|
-
|
|
25
|
-
return (
|
|
26
|
+
function makeTransform(x, y, k) {
|
|
27
|
+
return `translate(${x}, ${y}) scale(${k ?? 1})`;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Invokes `target` methods with arguments from `modifiers`.
|
|
31
|
+
*
|
|
32
|
+
* modifiers: `{ [methodName]: args[] | arg }`
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* class X {
|
|
36
|
+
* a(x: number) {}
|
|
37
|
+
* b(x: number, y: string) {}
|
|
38
|
+
* c(x: string[]) {}
|
|
39
|
+
* d() {}
|
|
40
|
+
* e = 'foo'
|
|
41
|
+
* }
|
|
42
|
+
*
|
|
43
|
+
* applyModifiers(new X(), {
|
|
44
|
+
* a: 1, // ok (single arg as-is)
|
|
45
|
+
* a: [1], // ok (single arg wrapped)
|
|
46
|
+
* b: [1, 'foo'], // ok (tuple for 2 args)
|
|
47
|
+
* c: [['foo', 'bar']], // ok (array-arg must be wrapped)
|
|
48
|
+
* c: ['foo', 'bar'], // error (single array-arg must be wrapped into array)
|
|
49
|
+
* d: [], // error (d has no args, excluded)
|
|
50
|
+
* e: 'foo' // error (e is not a function, excluded)
|
|
51
|
+
* })
|
|
52
|
+
*/
|
|
53
|
+
function applyModifiers(target, modifiers) {
|
|
54
|
+
if (!modifiers) return;
|
|
55
|
+
for (const methodName of Object.keys(modifiers)) {
|
|
56
|
+
const methodArgs = modifiers[methodName];
|
|
57
|
+
if (!isDefined(methodArgs)) continue;
|
|
58
|
+
const fn = target[methodName];
|
|
59
|
+
if (!isFunction(fn)) continue;
|
|
60
|
+
const normalizedArgs = Array.isArray(methodArgs) ? methodArgs : [methodArgs];
|
|
61
|
+
fn.apply(target, normalizedArgs);
|
|
62
|
+
}
|
|
26
63
|
}
|
|
27
|
-
const makeTransform = (x, y, k) => `translate(${x}, ${y}) scale(${k ?? 1})`;
|
|
28
64
|
|
|
29
65
|
//#endregion
|
|
30
66
|
//#region src/lib/feature.ts
|
|
@@ -51,21 +87,10 @@ function getFeatureKey(feature$1, idKey = "id", index) {
|
|
|
51
87
|
*/
|
|
52
88
|
function makeProjection({ width, height, config, projection, geoJson }) {
|
|
53
89
|
const mapProjection = projection();
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (config?.rotate) {
|
|
59
|
-
const [rx, ry, rz] = config.rotate;
|
|
60
|
-
if (isNumber(rx) && isNumber(ry)) mapProjection.rotate([
|
|
61
|
-
rx,
|
|
62
|
-
ry,
|
|
63
|
-
isNumber(rz) ? rz : 0
|
|
64
|
-
]);
|
|
65
|
-
}
|
|
66
|
-
if (config && isNumber(config.scale)) mapProjection.scale(config.scale);
|
|
67
|
-
if (geoJson) mapProjection.fitSize([width, height], geoJson);
|
|
68
|
-
else mapProjection.translate([width / 2, height / 2]);
|
|
90
|
+
if (!geoJson) {
|
|
91
|
+
if (!config?.translate) mapProjection.translate([width / 2, height / 2]);
|
|
92
|
+
} else if (!config?.fitSize) mapProjection.fitSize([width, height], geoJson);
|
|
93
|
+
applyModifiers(mapProjection, config);
|
|
69
94
|
return mapProjection;
|
|
70
95
|
}
|
|
71
96
|
/**
|
|
@@ -77,27 +102,28 @@ function makeProjection({ width, height, config, projection, geoJson }) {
|
|
|
77
102
|
function makeFeatures(geoData, dataTransformer) {
|
|
78
103
|
let geoJson;
|
|
79
104
|
if (isTopology(geoData)) {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
const topoObject = geoData.objects[objectKey];
|
|
83
|
-
const normalizedGeoJson = feature(geoData, topoObject);
|
|
84
|
-
geoJson = normalizedGeoJson.type === "FeatureCollection" ? normalizedGeoJson : {
|
|
85
|
-
type: "FeatureCollection",
|
|
86
|
-
features: [normalizedGeoJson]
|
|
87
|
-
};
|
|
88
|
-
} else geoJson = {
|
|
105
|
+
const normalizedGeoJson = feature(geoData, getTopoObject(geoData));
|
|
106
|
+
geoJson = normalizedGeoJson.type === "FeatureCollection" ? normalizedGeoJson : {
|
|
89
107
|
type: "FeatureCollection",
|
|
90
|
-
features: []
|
|
108
|
+
features: [normalizedGeoJson]
|
|
91
109
|
};
|
|
92
110
|
} else geoJson = geoData;
|
|
93
111
|
return [dataTransformer ? dataTransformer(geoJson.features) : geoJson.features, geoJson];
|
|
94
112
|
}
|
|
95
113
|
const makePathFn = (mapProjection) => geoPath().projection(mapProjection);
|
|
96
114
|
/**
|
|
115
|
+
* Returns a TopoJSON mesh when topology data is provided.
|
|
116
|
+
*/
|
|
117
|
+
function makeMesh(geoData) {
|
|
118
|
+
if (!isTopology(geoData)) return void 0;
|
|
119
|
+
return mesh(geoData, getTopoObject(geoData));
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
97
122
|
* Creates a full {@link MapContext} from a {@link MapConfig}.
|
|
98
123
|
*/
|
|
99
124
|
function makeMapContext({ width = 600, height: passedHeight, aspectRatio = 16 / 9, data, dataTransformer, projection: providedProjection = geoEqualEarth, projectionConfig }) {
|
|
100
125
|
const [features, geoJson] = makeFeatures(data, dataTransformer);
|
|
126
|
+
const mapMesh = makeMesh(data);
|
|
101
127
|
const height = passedHeight || width / aspectRatio;
|
|
102
128
|
const projection = makeProjection({
|
|
103
129
|
width,
|
|
@@ -112,8 +138,10 @@ function makeMapContext({ width = 600, height: passedHeight, aspectRatio = 16 /
|
|
|
112
138
|
height,
|
|
113
139
|
projection,
|
|
114
140
|
features,
|
|
141
|
+
mesh: mapMesh,
|
|
115
142
|
path: pathFn,
|
|
116
|
-
renderPath: (feature$1) => pathFn(feature$1)
|
|
143
|
+
renderPath: (feature$1) => pathFn(feature$1),
|
|
144
|
+
renderMesh: () => mapMesh ? pathFn(mapMesh) : null
|
|
117
145
|
};
|
|
118
146
|
}
|
|
119
147
|
/**
|
|
@@ -122,6 +150,10 @@ function makeMapContext({ width = 600, height: passedHeight, aspectRatio = 16 /
|
|
|
122
150
|
function isTopology(data) {
|
|
123
151
|
return data?.type === "Topology";
|
|
124
152
|
}
|
|
153
|
+
function getTopoObject(geoData) {
|
|
154
|
+
const objectKey = Object.keys(geoData.objects)[0];
|
|
155
|
+
return geoData.objects[objectKey];
|
|
156
|
+
}
|
|
125
157
|
|
|
126
158
|
//#endregion
|
|
127
159
|
//#region src/lib/mapObject.ts
|
|
@@ -175,33 +207,18 @@ const ZOOM_DEFAULTS = {
|
|
|
175
207
|
center: [0, 0],
|
|
176
208
|
zoom: 1,
|
|
177
209
|
minZoom: 1,
|
|
178
|
-
maxZoom: 8
|
|
179
|
-
extent: [[0, 0], [0, 0]]
|
|
210
|
+
maxZoom: 8
|
|
180
211
|
};
|
|
181
|
-
function getDefaultTranslateExtent(context) {
|
|
182
|
-
return [[0, 0], [context?.width ?? 0, context?.height ?? 0]];
|
|
183
|
-
}
|
|
184
|
-
function createZoomTransform(center, zoomLevel) {
|
|
185
|
-
return zoomIdentity.translate(...center).scale(zoomLevel);
|
|
186
|
-
}
|
|
187
|
-
function createZoomConfig(options) {
|
|
188
|
-
return {
|
|
189
|
-
scaleExtent: [options.minZoom ?? ZOOM_DEFAULTS.minZoom, options.maxZoom ?? ZOOM_DEFAULTS.maxZoom],
|
|
190
|
-
translateExtent: options.translateExtent ?? ZOOM_DEFAULTS.extent
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
212
|
function createZoomBehavior(context, options = {}) {
|
|
194
213
|
const behavior = zoom();
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
});
|
|
200
|
-
behavior.scaleExtent(config.scaleExtent).translateExtent(config.translateExtent);
|
|
214
|
+
const minZoom = options.minZoom ?? ZOOM_DEFAULTS.minZoom;
|
|
215
|
+
const maxZoom = options.maxZoom ?? ZOOM_DEFAULTS.maxZoom;
|
|
216
|
+
const translateExtent = [[0, 0], [context?.width ?? 0, context?.height ?? 0]];
|
|
217
|
+
behavior.scaleExtent([minZoom, maxZoom]).translateExtent(translateExtent);
|
|
201
218
|
if (options.onZoomStart) behavior.on("start", options.onZoomStart);
|
|
202
219
|
if (options.onZoom) behavior.on("zoom", options.onZoom);
|
|
203
220
|
if (options.onZoomEnd) behavior.on("end", options.onZoomEnd);
|
|
204
|
-
|
|
221
|
+
applyModifiers(behavior, options.config);
|
|
205
222
|
return behavior;
|
|
206
223
|
}
|
|
207
224
|
function attachZoomBehavior(element, behavior) {
|
|
@@ -217,7 +234,7 @@ function applyZoomBehaviorTransform(element, behavior, transform) {
|
|
|
217
234
|
function applyZoomTransform(options) {
|
|
218
235
|
const center = options.center ?? ZOOM_DEFAULTS.center;
|
|
219
236
|
const zoom$1 = options.zoom ?? ZOOM_DEFAULTS.zoom;
|
|
220
|
-
applyZoomBehaviorTransform(options.element, options.behavior,
|
|
237
|
+
applyZoomBehaviorTransform(options.element, options.behavior, zoomIdentity.translate(...center).scale(zoom$1));
|
|
221
238
|
}
|
|
222
239
|
function setupZoom(options) {
|
|
223
240
|
attachZoomBehavior(options.element, options.behavior);
|
|
@@ -236,16 +253,6 @@ function getInverseZoomScale(source, fallback = 1) {
|
|
|
236
253
|
function isZoomTransform(value) {
|
|
237
254
|
return Boolean(value && isNumber(value.k) && isNumber(value.x) && isNumber(value.y));
|
|
238
255
|
}
|
|
239
|
-
function applyZoomModifiers(behavior, modifiers) {
|
|
240
|
-
if (!modifiers) return;
|
|
241
|
-
for (const [methodName, methodArgs] of Object.entries(modifiers)) {
|
|
242
|
-
if (!methodName || methodArgs === void 0) continue;
|
|
243
|
-
const modifier = behavior[methodName];
|
|
244
|
-
if (typeof modifier !== "function") continue;
|
|
245
|
-
const normalizedArgs = Array.isArray(methodArgs) ? methodArgs : [methodArgs];
|
|
246
|
-
modifier.apply(behavior, normalizedArgs);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
256
|
function getSvgElement(element) {
|
|
250
257
|
if (!element) return null;
|
|
251
258
|
if (element instanceof SVGSVGElement) return element;
|
|
@@ -253,4 +260,4 @@ function getSvgElement(element) {
|
|
|
253
260
|
}
|
|
254
261
|
|
|
255
262
|
//#endregion
|
|
256
|
-
export { ZOOM_DEFAULTS, applyZoomBehaviorTransform, applyZoomTransform, attachZoomBehavior, createZoomBehavior,
|
|
263
|
+
export { ZOOM_DEFAULTS, applyModifiers, applyZoomBehaviorTransform, applyZoomTransform, attachZoomBehavior, createZoomBehavior, getFeatureKey, getInverseZoomScale, getMarkerTransform, getObjectStateUpdate, getTopoObject, getZoomScale, isDefined, isFunction, isNullish, isNumber, isPlainObject, isString, isStringOrNumber, isTopology, makeFeatures, makeMapContext, makeMesh, makePathFn, makeProjection, makeTransform, mapObjectState, resolveObjectStyle, setupZoom };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@d3-maps/core",
|
|
3
|
-
"version": "0.1.1-next.0",
|
|
4
3
|
"type": "module",
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Framework-agnostic core utilities for building reactive D3 maps",
|
|
7
7
|
"author": "Georgii Bukharov <souljorje@gmail.com>",
|
|
@@ -46,12 +46,13 @@
|
|
|
46
46
|
"@types/geojson": "^7946.0.16",
|
|
47
47
|
"@types/topojson-client": "^3.1.5",
|
|
48
48
|
"@types/topojson-specification": "^1.0.5",
|
|
49
|
-
"typescript": "^5.9.3",
|
|
50
49
|
"tsdown": "0.19.0",
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
51
|
"vitest": "^4.0.15"
|
|
52
52
|
},
|
|
53
53
|
"scripts": {
|
|
54
54
|
"typecheck": "tsc --noEmit",
|
|
55
|
+
"typecheck:test": "tsc -p tsconfig.test.json --noEmit",
|
|
55
56
|
"build": "pnpm run typecheck && tsdown",
|
|
56
57
|
"dev": "tsdown --watch",
|
|
57
58
|
"test": "vitest run",
|