@d3-maps/core 0.1.1-next.0 → 0.2.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.d.ts CHANGED
@@ -366,8 +366,10 @@ interface MapContext {
366
366
  height: number;
367
367
  projection?: GeoProjection;
368
368
  features: MapFeature[];
369
+ mesh?: MultiLineString$1;
369
370
  path: GeoPath;
370
371
  renderPath: (feature: Feature) => ReturnType<GeoPath>;
372
+ renderMesh: () => ReturnType<GeoPath>;
371
373
  }
372
374
  /**
373
375
  * Creates a configured projection and fits it to the provided GeoJSON (if present).
@@ -393,6 +395,10 @@ declare function makeProjection({
393
395
  */
394
396
  declare function makeFeatures(geoData: MapData, dataTransformer?: DataTransformer): [features: MapFeature[], geoJson: FeatureCollection];
395
397
  declare const makePathFn: (mapProjection: GeoProjection) => GeoPath;
398
+ /**
399
+ * Returns a TopoJSON mesh when topology data is provided.
400
+ */
401
+ declare function makeMesh(geoData: MapData): MultiLineString$1 | undefined;
396
402
  /**
397
403
  * Creates a full {@link MapContext} from a {@link MapConfig}.
398
404
  */
@@ -409,6 +415,7 @@ declare function makeMapContext({
409
415
  * Type guard for TopoJSON topology inputs.
410
416
  */
411
417
  declare function isTopology(data: MapData): data is Topology;
418
+ declare function getTopoObject(geoData: Topology): GeometryObject;
412
419
  //#endregion
413
420
  //#region src/lib/marker.d.ts
414
421
  type MapMarkerCoordinates = [number, number];
@@ -431,11 +438,11 @@ declare function isString(value: unknown): value is string;
431
438
  declare function isDefined<T>(value: T | null | undefined): value is T;
432
439
  declare const isNullish: (value: unknown) => value is null | undefined;
433
440
  declare const isNumber: (value: unknown) => value is number;
434
- declare const isStringOrNumber: (value: unknown) => value is string | number;
441
+ declare function isStringOrNumber(value: unknown): value is string | number;
435
442
  declare function isFunction(value: unknown): value is (...args: unknown[]) => unknown;
436
443
  declare function isPlainObject(value: unknown): value is Record<string, unknown>;
437
444
  declare function get<T>(url: string): Promise<T>;
438
- declare const makeTransform: (x: number, y: number, k?: number) => string;
445
+ declare function makeTransform(x: number, y: number, k?: number): string;
439
446
  //#endregion
440
447
  //#region src/lib/zoom.d.ts
441
448
  type Extent = [[number, number], [number, number]];
@@ -448,8 +455,7 @@ interface ZoomConfig {
448
455
  scaleExtent: [number, number];
449
456
  translateExtent: Extent;
450
457
  }
451
- type ZoomBehaviorOwnMethodName<TElement extends Element, TDatum> = Exclude<keyof ZoomBehavior$1<TElement, TDatum>, keyof Function>;
452
- type ZoomBehaviorMethodName<TElement extends Element, TDatum> = Extract<{ [K in ZoomBehaviorOwnMethodName<TElement, TDatum>]: ZoomBehavior$1<TElement, TDatum>[K] extends ((...args: unknown[]) => unknown) ? K : never }[ZoomBehaviorOwnMethodName<TElement, TDatum>], string>;
458
+ type ZoomBehaviorMethodName<TElement extends Element, TDatum> = Extract<{ [K in keyof ZoomBehavior$1<TElement, TDatum>]: ZoomBehavior$1<TElement, TDatum>[K] extends ((...args: unknown[]) => unknown) ? K : never }[keyof ZoomBehavior$1<TElement, TDatum>], string>;
453
459
  type ZoomBehaviorMethodArgs<TElement extends Element, TDatum, TMethod extends ZoomBehaviorMethodName<TElement, TDatum>> = ZoomBehavior$1<TElement, TDatum>[TMethod] extends ((...args: infer TArgs) => unknown) ? TArgs : never;
454
460
  type ZoomBehaviorSingleArg<TElement extends Element, TDatum, TMethod extends ZoomBehaviorMethodName<TElement, TDatum>> = ZoomBehaviorMethodArgs<TElement, TDatum, TMethod> extends [infer TArg] ? TArg : never;
455
461
  type ZoomModifierValue<TElement extends Element, TDatum, TMethod extends ZoomBehaviorMethodName<TElement, TDatum>> = ZoomBehaviorMethodArgs<TElement, TDatum, TMethod> | ZoomBehaviorSingleArg<TElement, TDatum, TMethod>;
@@ -498,4 +504,4 @@ declare function setupZoom(options: SetupZoomOptions): void;
498
504
  declare function getZoomScale(source: ZoomScaleSource): number;
499
505
  declare function getInverseZoomScale(source: ZoomScaleSource, fallback?: number): number;
500
506
  //#endregion
501
- export { ApplyZoomOptions, type D3ZoomEvent, DataTransformer, Extent, MapConfig, MapContext, MapData, MapFeature, MapFeatureProps, MapMarkerCoordinates, MapMarkerProps, MapObject, MapObjectEvent, MapObjectEventType, MapObjectFocusEventType, MapObjectMouseEventType, MapObjectState, MapObjectStyles, ProjectionConfig, SetupZoomOptions, ZOOM_DEFAULTS, type ZoomBehavior, ZoomBehaviorMethodArgs, ZoomBehaviorMethodName, ZoomBehaviorOptions, ZoomBehaviorOwnMethodName, ZoomBehaviorSingleArg, ZoomConfig, ZoomConfigOptions, ZoomEvent, ZoomEvents, ZoomModifierValue, ZoomModifiers, ZoomProps, ZoomScaleSource, ZoomTargetElement, type ZoomTransform, applyZoomBehaviorTransform, applyZoomTransform, attachZoomBehavior, createZoomBehavior, createZoomConfig, createZoomTransform, get, getDefaultTranslateExtent, getFeatureKey, getInverseZoomScale, getMarkerTransform, getObjectStateUpdate, getZoomScale, isDefined, isFunction, isNullish, isNumber, isPlainObject, isString, isStringOrNumber, isTopology, makeFeatures, makeMapContext, makePathFn, makeProjection, makeTransform, mapObjectState, resolveObjectStyle, setupZoom };
507
+ export { ApplyZoomOptions, type D3ZoomEvent, DataTransformer, Extent, MapConfig, MapContext, MapData, MapFeature, MapFeatureProps, MapMarkerCoordinates, MapMarkerProps, MapObject, MapObjectEvent, MapObjectEventType, MapObjectFocusEventType, MapObjectMouseEventType, MapObjectState, MapObjectStyles, ProjectionConfig, SetupZoomOptions, ZOOM_DEFAULTS, type ZoomBehavior, ZoomBehaviorMethodArgs, ZoomBehaviorMethodName, ZoomBehaviorOptions, ZoomBehaviorSingleArg, ZoomConfig, ZoomConfigOptions, ZoomEvent, ZoomEvents, ZoomModifierValue, ZoomModifiers, ZoomProps, ZoomScaleSource, ZoomTargetElement, type ZoomTransform, applyZoomBehaviorTransform, applyZoomTransform, attachZoomBehavior, createZoomBehavior, createZoomConfig, createZoomTransform, get, getDefaultTranslateExtent, getFeatureKey, getInverseZoomScale, getMarkerTransform, getObjectStateUpdate, getTopoObject, getZoomScale, isDefined, isFunction, isNullish, isNumber, isPlainObject, isString, isStringOrNumber, isTopology, makeFeatures, makeMapContext, makeMesh, makePathFn, makeProjection, makeTransform, mapObjectState, resolveObjectStyle, setupZoom };
@@ -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),l=e=>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}async function f(e){return(await fetch(e)).json()}let p=(e,t,n)=>`translate(${e}, ${t}) scale(${n??1})`;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();if(n?.center){let[e,t]=n.center;c(e)&&c(t)&&a.center([e,t])}if(n?.rotate){let[e,t,r]=n.rotate;c(e)&&c(t)&&a.rotate([e,t,c(r)?r:0])}return n&&c(n.scale)&&a.scale(n.scale),i?a.fitSize([e,t],i):a.translate([e/2,t/2]),a}function g(e,t){let r;if(y(e)){let t=Object.keys(e.objects)[0];if(t){let i=e.objects[t],a=(0,n.feature)(e,i);r=a.type===`FeatureCollection`?a:{type:`FeatureCollection`,features:[a]}}else r={type:`FeatureCollection`,features:[]}}else r=e;return[t?t(r.features):r.features,r]}let _=e=>(0,t.geoPath)().projection(e);function v({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=n||e/r,d=h({width:e,height:u,projection:o,config:s,geoJson:l}),f=_(d);return{width:e,height:u,projection:d,features:c,path:f,renderPath:e=>f(e)}}function y(e){return e?.type===`Topology`}let b=[`default`,`hover`,`active`];function x(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 S(e,t){return t?.[e]??t?.default}function C(e,t,n=`translate(0, 0)`){let r=e?.projection;if(!r)return n;let i=r(t);return i?p(...i):n}let w={center:[0,0],zoom:1,minZoom:1,maxZoom:8,extent:[[0,0],[0,0]]};function T(e){return[[0,0],[e?.width??0,e?.height??0]]}function E(e,t){return i.zoomIdentity.translate(...e).scale(t)}function D(e){return{scaleExtent:[e.minZoom??w.minZoom,e.maxZoom??w.maxZoom],translateExtent:e.translateExtent??w.extent}}function O(e,t={}){let n=(0,i.zoom)(),r=D({minZoom:t.minZoom,maxZoom:t.maxZoom,translateExtent:t.translateExtent??T(e)});return n.scaleExtent(r.scaleExtent).translateExtent(r.translateExtent),t.onZoomStart&&n.on(`start`,t.onZoomStart),t.onZoom&&n.on(`zoom`,t.onZoom),t.onZoomEnd&&n.on(`end`,t.onZoomEnd),I(n,t.modifiers),n}function k(e,t){let n=L(e);n&&(0,r.select)(n).call(t)}function A(e,t,n){let i=L(e);i&&(0,r.select)(i).call(t.transform,n)}function j(e){let t=e.center??w.center,n=e.zoom??w.zoom;A(e.element,e.behavior,E(t,n))}function M(e){k(e.element,e.behavior),j(e)}function N(e){return c(e)?e:F(e)?e.k:e?.transform?.k??1}function P(e,t=1){let n=N(e);return!c(n)||n===0?t:1/n}function F(e){return!!(e&&c(e.k)&&c(e.x)&&c(e.y))}function I(e,t){if(t)for(let[n,r]of Object.entries(t)){if(!n||r===void 0)continue;let t=e[n];if(typeof t!=`function`)continue;let i=Array.isArray(r)?r:[r];t.apply(e,i)}}function L(e){return e?e instanceof SVGSVGElement?e:e.closest(`svg`):null}e.ZOOM_DEFAULTS=w,e.applyZoomBehaviorTransform=A,e.applyZoomTransform=j,e.attachZoomBehavior=k,e.createZoomBehavior=O,e.createZoomConfig=D,e.createZoomTransform=E,e.get=f,e.getDefaultTranslateExtent=T,e.getFeatureKey=m,e.getInverseZoomScale=P,e.getMarkerTransform=C,e.getObjectStateUpdate=x,e.getZoomScale=N,e.isDefined=o,e.isFunction=u,e.isNullish=s,e.isNumber=c,e.isPlainObject=d,e.isString=a,e.isStringOrNumber=l,e.isTopology=y,e.makeFeatures=g,e.makeMapContext=v,e.makePathFn=_,e.makeProjection=h,e.makeTransform=p,e.mapObjectState=b,e.resolveObjectStyle=S,e.setupZoom=M})(this.D3Maps=this.D3Maps||{},d3,topojson,d3,d3);
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}async function f(e){return(await fetch(e)).json()}function p(e,t,n){return`translate(${e}, ${t}) scale(${n??1})`}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();if(n?.center){let[e,t]=n.center;c(e)&&c(t)&&a.center([e,t])}if(n?.rotate){let[e,t,r]=n.rotate;c(e)&&c(t)&&a.rotate([e,t,c(r)?r:0])}return n&&c(n.scale)&&a.scale(n.scale),i?a.fitSize([e,t],i):a.translate([e/2,t/2]),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?p(...i):n}let E={center:[0,0],zoom:1,minZoom:1,maxZoom:8,extent:[[0,0],[0,0]]};function D(e){return[[0,0],[e?.width??0,e?.height??0]]}function O(e,t){return i.zoomIdentity.translate(...e).scale(t)}function k(e){return{scaleExtent:[e.minZoom??E.minZoom,e.maxZoom??E.maxZoom],translateExtent:e.translateExtent??E.extent}}function A(e,t={}){let n=(0,i.zoom)(),r=k({minZoom:t.minZoom,maxZoom:t.maxZoom,translateExtent:t.translateExtent??D(e)});return n.scaleExtent(r.scaleExtent).translateExtent(r.translateExtent),t.onZoomStart&&n.on(`start`,t.onZoomStart),t.onZoom&&n.on(`zoom`,t.onZoom),t.onZoomEnd&&n.on(`end`,t.onZoomEnd),R(n,t.modifiers),n}function j(e,t){let n=z(e);n&&(0,r.select)(n).call(t)}function M(e,t,n){let i=z(e);i&&(0,r.select)(i).call(t.transform,n)}function N(e){let t=e.center??E.center,n=e.zoom??E.zoom;M(e.element,e.behavior,O(t,n))}function P(e){j(e.element,e.behavior),N(e)}function F(e){return c(e)?e:L(e)?e.k:e?.transform?.k??1}function I(e,t=1){let n=F(e);return!c(n)||n===0?t:1/n}function L(e){return!!(e&&c(e.k)&&c(e.x)&&c(e.y))}function R(e,t){if(t)for(let[n,r]of Object.entries(t)){if(!n||r===void 0)continue;let t=e[n];if(typeof t!=`function`)continue;let i=Array.isArray(r)?r:[r];t.apply(e,i)}}function z(e){return e?e instanceof SVGSVGElement?e:e.closest(`svg`):null}e.ZOOM_DEFAULTS=E,e.applyZoomBehaviorTransform=M,e.applyZoomTransform=N,e.attachZoomBehavior=j,e.createZoomBehavior=A,e.createZoomConfig=k,e.createZoomTransform=O,e.get=f,e.getDefaultTranslateExtent=D,e.getFeatureKey=m,e.getInverseZoomScale=I,e.getMarkerTransform=T,e.getObjectStateUpdate=C,e.getTopoObject=x,e.getZoomScale=F,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=p,e.mapObjectState=S,e.resolveObjectStyle=w,e.setupZoom=P})(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
- const isStringOrNumber = (value) => isString(value) || isNumber(value);
15
+ function isStringOrNumber(value) {
16
+ return isString(value) || isNumber(value);
17
+ }
16
18
  function isFunction(value) {
17
19
  return typeof value === "function";
18
20
  }
@@ -24,7 +26,9 @@ function isPlainObject(value) {
24
26
  async function get(url) {
25
27
  return (await fetch(url)).json();
26
28
  }
27
- const makeTransform = (x, y, k) => `translate(${x}, ${y}) scale(${k ?? 1})`;
29
+ function makeTransform(x, y, k) {
30
+ return `translate(${x}, ${y}) scale(${k ?? 1})`;
31
+ }
28
32
 
29
33
  //#endregion
30
34
  //#region src/lib/feature.ts
@@ -77,27 +81,28 @@ function makeProjection({ width, height, config, projection, geoJson }) {
77
81
  function makeFeatures(geoData, dataTransformer) {
78
82
  let geoJson;
79
83
  if (isTopology(geoData)) {
80
- const objectKey = Object.keys(geoData.objects)[0];
81
- if (objectKey) {
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 = {
84
+ const normalizedGeoJson = feature(geoData, getTopoObject(geoData));
85
+ geoJson = normalizedGeoJson.type === "FeatureCollection" ? normalizedGeoJson : {
89
86
  type: "FeatureCollection",
90
- features: []
87
+ features: [normalizedGeoJson]
91
88
  };
92
89
  } else geoJson = geoData;
93
90
  return [dataTransformer ? dataTransformer(geoJson.features) : geoJson.features, geoJson];
94
91
  }
95
92
  const makePathFn = (mapProjection) => geoPath().projection(mapProjection);
96
93
  /**
94
+ * Returns a TopoJSON mesh when topology data is provided.
95
+ */
96
+ function makeMesh(geoData) {
97
+ if (!isTopology(geoData)) return void 0;
98
+ return mesh(geoData, getTopoObject(geoData));
99
+ }
100
+ /**
97
101
  * Creates a full {@link MapContext} from a {@link MapConfig}.
98
102
  */
99
103
  function makeMapContext({ width = 600, height: passedHeight, aspectRatio = 16 / 9, data, dataTransformer, projection: providedProjection = geoEqualEarth, projectionConfig }) {
100
104
  const [features, geoJson] = makeFeatures(data, dataTransformer);
105
+ const mapMesh = makeMesh(data);
101
106
  const height = passedHeight || width / aspectRatio;
102
107
  const projection = makeProjection({
103
108
  width,
@@ -112,8 +117,10 @@ function makeMapContext({ width = 600, height: passedHeight, aspectRatio = 16 /
112
117
  height,
113
118
  projection,
114
119
  features,
120
+ mesh: mapMesh,
115
121
  path: pathFn,
116
- renderPath: (feature$1) => pathFn(feature$1)
122
+ renderPath: (feature$1) => pathFn(feature$1),
123
+ renderMesh: () => mapMesh ? pathFn(mapMesh) : null
117
124
  };
118
125
  }
119
126
  /**
@@ -122,6 +129,10 @@ function makeMapContext({ width = 600, height: passedHeight, aspectRatio = 16 /
122
129
  function isTopology(data) {
123
130
  return data?.type === "Topology";
124
131
  }
132
+ function getTopoObject(geoData) {
133
+ const objectKey = Object.keys(geoData.objects)[0];
134
+ return geoData.objects[objectKey];
135
+ }
125
136
 
126
137
  //#endregion
127
138
  //#region src/lib/mapObject.ts
@@ -253,4 +264,4 @@ function getSvgElement(element) {
253
264
  }
254
265
 
255
266
  //#endregion
256
- export { ZOOM_DEFAULTS, applyZoomBehaviorTransform, applyZoomTransform, attachZoomBehavior, createZoomBehavior, createZoomConfig, createZoomTransform, get, getDefaultTranslateExtent, getFeatureKey, getInverseZoomScale, getMarkerTransform, getObjectStateUpdate, getZoomScale, isDefined, isFunction, isNullish, isNumber, isPlainObject, isString, isStringOrNumber, isTopology, makeFeatures, makeMapContext, makePathFn, makeProjection, makeTransform, mapObjectState, resolveObjectStyle, setupZoom };
267
+ export { ZOOM_DEFAULTS, applyZoomBehaviorTransform, applyZoomTransform, attachZoomBehavior, createZoomBehavior, createZoomConfig, createZoomTransform, get, getDefaultTranslateExtent, 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.2.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,8 +46,8 @@
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": {