import { GeoPath, GeoProjection } from 'd3-geo'; import { ComputedRef, MaybeRefOrGetter } from '../../node_modules/vue'; import { MapTransform } from '../types'; /** * Reactive inputs driving {@link useMapProjection}. Everything that affects the * projection geometry is passed in as a plain value, ref or getter so the * composable adapts to how the caller wires its state. The composable holds no * DOM state: the measured `width`/`height` and the parsed `geojson` come from * the component. */ export interface UseMapProjectionOptions { /** * The d3-geo projection factory (for example `geoRobinson`). Called once per * recomputation to obtain a fresh, mutable projection. */ projection: MaybeRefOrGetter<(() => GeoProjection) | undefined>; /** * The GeoJSON object the projection is fitted to (typically the topojson * features collection, or the markers bounds for a symbol map). */ geojson: MaybeRefOrGetter; /** * Measured outer width of the map, in pixels. */ width: MaybeRefOrGetter; /** * Measured outer height of the map, in pixels. */ height: MaybeRefOrGetter; /** * Whether the projection is spherical (a globe). Spherical maps rotate to * their center and fit by height; planar maps recenter in place. */ spherical?: MaybeRefOrGetter; /** * Initial center of the map as `[longitude, latitude]`, or `null` for the * world origin. */ center?: MaybeRefOrGetter; /** * The live zoom/pan transform, whose `rotateX`/`rotateY` drive the rotating * projection used while a spherical map is dragged. */ transform?: MaybeRefOrGetter; /** * Step, in degrees, of the graticule grid (parallels and meridians). */ graticuleStep?: MaybeRefOrGetter<[number, number]>; } /** * Reactive API returned by {@link useMapProjection}. */ export interface UseMapProjection { /** * The base projection, fitted to the map size and the geojson bounds. * * WARNING: this is a single d3 projection object mutated in place, not an * immutable snapshot. Reading {@link initialMapProjection} or * {@link rotatingMapProjection} re-centers/re-rotates THIS same instance, so * its state reflects whichever of those was evaluated last. Treat it as a * live view of the projection, not a stable value. */ mapProjection: ComputedRef; /** * The geo path generator bound to {@link mapProjection}. * * WARNING: this is the SAME GeoPath instance returned by * {@link initialFeaturePath} — there is only one path generator. Reading * `initialFeaturePath` repoints this generator at the initial projection, so * both refs alias one mutated object rather than two independent generators. */ featurePath: ComputedRef; /** * The projection used for the first render: spherical maps are rotated to * their center, fitted by height and translated to the middle; planar maps * are recentered on their planar center. * * WARNING: this does NOT return a new projection — it mutates * {@link mapProjection} in place and returns that same instance. Evaluating * it changes the base projection's center/rotation/translation as a side * effect. */ initialMapProjection: ComputedRef; /** * The geo path generator bound to {@link initialMapProjection}. * * WARNING: this is the SAME GeoPath instance as {@link featurePath}, re-bound * to {@link initialMapProjection}. Reading it repoints `featurePath` too; * they are two views of one mutated generator. */ initialFeaturePath: ComputedRef; /** * The rendered graticule grid path, drawn through {@link initialFeaturePath}. */ initialGraticulePath: ComputedRef; /** * The base projection rotated by the transform's `rotateX`/`rotateY`, used * while a spherical map is dragged. Falls back to {@link mapProjection} when * no rotation is set. * * WARNING: when a rotation is set this mutates {@link mapProjection} in place * (via `.rotate(...)`) and returns that same instance; it is not an * independent projection. */ rotatingMapProjection: ComputedRef; /** * The raw graticule GeoJSON (a MultiLineString of parallels and meridians). */ graticuleLines: ComputedRef; /** * The projection's geographic center as `[longitude, latitude]`. */ mapCenter: ComputedRef<[number, number]>; } /** * Owns the pure d3-geo projection geometry shared by the map components: it * fits a projection to the map size and the geojson bounds, derives the geo * path generators, and handles the spherical/planar centering and rotation * variants. It holds no DOM state — the measured size and parsed geojson are * passed in, and rendering stays in the component. * * @remarks The returned projection/path refs are mutating VIEWS over two shared * d3 objects, not independent snapshots: there is one projection (mutated in * place by `initialMapProjection`/`rotatingMapProjection`) and one GeoPath * (`featurePath` and `initialFeaturePath` are the same instance, re-bound on * read). Reading one ref can change another's state as a side effect. See the * per-field warnings on {@link UseMapProjection}. * @param options - Reactive projection options (see {@link UseMapProjectionOptions}). * @returns The {@link UseMapProjection} API of derived projection geometry. * @example * // Internal building block of the map components; not exported from the * // package root. Inside a `