@kahwee/sf-map-svg 5.1.4 → 6.0.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/CHANGELOG.md +7 -0
- package/README.md +1 -5
- package/dist/data/README.md +1 -1
- package/dist/src/district-layer.d.ts +3 -3
- package/dist/src/district-style.d.ts +2 -2
- package/dist/src/guide-map.d.ts +0 -7
- package/dist/src/guide-map.js +0 -33
- package/dist/src/guide-static.d.ts +4 -4
- package/dist/src/guide-static.js +14 -11
- package/dist/src/guide.d.ts +2 -2
- package/dist/src/guide.js +1 -1
- package/dist/src/palettes.d.ts +2 -2
- package/dist/src/rendering/svg-layers.d.ts +3 -3
- package/dist/src/rendering/svg-map-renderer.d.ts +5 -5
- package/dist/src/static-animation.d.ts +2 -2
- package/dist/src/static-labels.d.ts +2 -2
- package/dist/src/static-labels.js +1 -1
- package/dist/src/static.d.ts +4 -4
- package/dist/src/static.js +3 -8
- package/dist/src/types.d.ts +11 -9
- package/docs/API.md +7 -11
- package/docs/EXAMPLES.md +2 -7
- package/docs/api-audit.md +3 -3
- package/docs/consumer-integration.md +1 -1
- package/docs/developer-guide.md +1 -6
- package/docs/migration-v6.md +57 -0
- package/llms-full.txt +120 -74
- package/llms.txt +2 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@ User-visible changes are recorded here. Unreleased entries describe changes on `
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 6.0.0 — 2026-11-05
|
|
8
|
+
|
|
9
|
+
- Breaking: remove flat static presentation options. Use `layers` for geographic switches and `appearance` for theme, colors and district styles.
|
|
10
|
+
- Breaking: remove element-based `createGuideMap` and `mountGuideMap` factories and their option/element aliases. Use `createGuideController` and `mountGuideController`, mount `.element`, and dispose the controller.
|
|
11
|
+
- Remove older-package capability adapters from the site and snippet generator; require v6 or newer for Pages builds and versioned playground share links. Add a v6 migration guide and rejection coverage for removed contracts.
|
|
12
|
+
- Use official sources only on the Pages election views: remove all newspaper and agency-compilation tallies, projections, history and their validation from the feed, views, trend charts and tests. Local measures without official counts read Pending until official counts are imported.
|
|
13
|
+
|
|
7
14
|
## 5.1.4 — 2026-11-05
|
|
8
15
|
|
|
9
16
|
- Group internal browser controllers, renderers and shells under `src/interactive`, and SVG generation under `src/rendering`. Rename the general map engine, controls and marker renderer to match their responsibilities; clarify selection-detail, neighborhood-results and layer-composition operations. Keep public package entry points unchanged.
|
package/README.md
CHANGED
|
@@ -27,11 +27,7 @@ Upgrading from v3 to v4: update your Node runtime to 24 or newer. The map API, b
|
|
|
27
27
|
import { renderMap } from '@kahwee/sf-map-svg';
|
|
28
28
|
import { staticMapData } from '@kahwee/sf-map-svg/data/static';
|
|
29
29
|
|
|
30
|
-
const { svg, project, viewBox } = renderMap(staticMapData, {
|
|
31
|
-
year: 2022,
|
|
32
|
-
landmarks: true,
|
|
33
|
-
bartStations: true,
|
|
34
|
-
});
|
|
30
|
+
const { svg, project, viewBox } = renderMap(staticMapData, { year: 2022, layers: { landmarks: true, bartStations: true } });
|
|
35
31
|
```
|
|
36
32
|
|
|
37
33
|
`renderMap(data, options)` returns SVG markup and matching projection helpers. `/data/static` includes the complete static map without interactive lookup collections. Small maps can compose selected JSON exports from `/data/*` and pass them as `StaticMapData`. `getLayerPaths(data, options)` returns fitted geographic paths without SVG markup.
|
package/dist/data/README.md
CHANGED
|
@@ -135,7 +135,7 @@ Run `pnpm data:normalize-realtor` when updating realtor geometry, then `pnpm dat
|
|
|
135
135
|
|
|
136
136
|
## Lightweight guide preset
|
|
137
137
|
|
|
138
|
-
Import `@kahwee/sf-map-svg/guide` for the guide preset. It statically imports only a simplified coastline, simplified SFAR neighborhoods, six major park outlines, selected US 101 / I-280 / Highway 1 segments, six curated streets, and eight BART points. It does not import historical districts, alternate neighborhood sources, or the full catalog. `
|
|
138
|
+
Import `@kahwee/sf-map-svg/guide` for the guide preset. It statically imports only a simplified coastline, simplified SFAR neighborhoods, six major park outlines, selected US 101 / I-280 / Highway 1 segments, six curated streets, and eight BART points. It does not import historical districts, alternate neighborhood sources, or the full catalog. `createGuideController()` uses this overview by default. `loadGuideDetailedData()` explicitly loads detailed versions of those same selected datasets; it does not add historical or alternative datasets. Regenerate derived geometry with `pnpm data:guide` after updating canonical source files.
|
|
139
139
|
|
|
140
140
|
Neighborhood overview boundaries use a shared coordinate graph: connected boundary arcs are simplified once and retained vertices are applied to all adjacent polygons. The 0.00009 degree tolerance is approximately subpixel at an 800px city map; overview coastline and park geometry use similarly subpixel tolerances. Roads crossing park polygons remain separate overlays and are drawn above park fills. Detailed collections retain their canonical source coordinates.
|
|
141
141
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DistrictRowData } from './rendering/svg-map-renderer.js';
|
|
2
|
-
import type { DistrictStyle, DistrictYear,
|
|
2
|
+
import type { DistrictStyle, DistrictYear, SvgRenderOptions } from './types.js';
|
|
3
3
|
/** Apply prepared styles and interaction state without invoking consumer callbacks. */
|
|
4
4
|
export declare function renderDistrictAppearance({ svg, rows, styles, selectedDistrict, hoveredDistrict, year, theme, colors, fills, lines, }: {
|
|
5
5
|
svg: SVGSVGElement;
|
|
@@ -8,8 +8,8 @@ export declare function renderDistrictAppearance({ svg, rows, styles, selectedDi
|
|
|
8
8
|
selectedDistrict: number | null;
|
|
9
9
|
hoveredDistrict: number | null;
|
|
10
10
|
year: DistrictYear;
|
|
11
|
-
theme:
|
|
12
|
-
colors: NonNullable<
|
|
11
|
+
theme: SvgRenderOptions['theme'];
|
|
12
|
+
colors: NonNullable<SvgRenderOptions['colors']>;
|
|
13
13
|
fills: boolean;
|
|
14
14
|
lines: boolean;
|
|
15
15
|
}): void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { DistrictRowData } from './rendering/svg-map-renderer.js';
|
|
2
|
-
import type { DistrictStyle,
|
|
2
|
+
import type { DistrictStyle, SvgRenderOptions } from './types.js';
|
|
3
3
|
/** Evaluate user code once and copy its result before changing the map. */
|
|
4
|
-
export declare function prepareDistrictStyles(rows: readonly DistrictRowData[], callback:
|
|
4
|
+
export declare function prepareDistrictStyles(rows: readonly DistrictRowData[], callback: SvgRenderOptions['districtStyle']): ReadonlyMap<number, DistrictStyle>;
|
package/dist/src/guide-map.d.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { MapController, MapOptions } from './controller-types.js';
|
|
2
|
-
import type { NeighborhoodExplorerElement as InteractiveSFMapElement, NeighborhoodExplorerOptions as InteractiveSFMapOptions } from './types.js';
|
|
3
2
|
/** Preferred guide API: the same grouped options, events, camera and lifecycle as createMap. */
|
|
4
3
|
export declare function createGuideController(options?: MapOptions): MapController;
|
|
5
4
|
/** Enhance a static guide shell and return its owning controller. */
|
|
6
5
|
export declare function mountGuideController(shell: HTMLElement, options?: MapOptions): MapController;
|
|
7
|
-
/** Element-based compatibility API. Prefer createGuideController for new integrations. */
|
|
8
|
-
export declare function createGuideMap(options?: InteractiveSFMapOptions): InteractiveSFMapElement;
|
|
9
|
-
/** Enhance createGuideShell() in place with a fixed compact chrome layout.
|
|
10
|
-
* Keep an accessible external place list when hiding the native pickers.
|
|
11
|
-
*/
|
|
12
|
-
export declare function mountGuideMap(shell: HTMLElement, options?: InteractiveSFMapOptions): InteractiveSFMapElement;
|
package/dist/src/guide-map.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { expandMapOptions, prepareConfiguration } from './configuration.js';
|
|
2
2
|
import { guideMapData } from './guide-data.js';
|
|
3
|
-
import { createMapEngine } from './interactive/map-engine.js';
|
|
4
|
-
import { createMapShell } from './interactive/map-shell.js';
|
|
5
3
|
import { createMap } from './map.js';
|
|
6
4
|
import { guideOptions } from './presets.js';
|
|
7
|
-
import { validateExplorerOptions } from './validation.js';
|
|
8
5
|
function controllerOptions(options) {
|
|
9
6
|
expandMapOptions(options);
|
|
10
7
|
const config = prepareConfiguration({ features: {}, layers: guideOptions.layers ?? {}, controls: {}, appearance: {} }, {
|
|
@@ -59,33 +56,3 @@ function mountFrame(frame, map) {
|
|
|
59
56
|
map.querySelector('.sf-explorer-map-column > details')?.classList.add('sf-guide-sources');
|
|
60
57
|
frame.replaceWith(map);
|
|
61
58
|
}
|
|
62
|
-
/** Element-based compatibility API. Prefer createGuideController for new integrations. */
|
|
63
|
-
export function createGuideMap(options = {}) {
|
|
64
|
-
validateExplorerOptions(options);
|
|
65
|
-
return createMapEngine({
|
|
66
|
-
mode: 'neighborhoods',
|
|
67
|
-
...options,
|
|
68
|
-
layers: {
|
|
69
|
-
...guideOptions.layers,
|
|
70
|
-
...options.layers,
|
|
71
|
-
},
|
|
72
|
-
interface: 'map',
|
|
73
|
-
}, guideMapData, { createShell: createMapShell });
|
|
74
|
-
}
|
|
75
|
-
/** Enhance createGuideShell() in place with a fixed compact chrome layout.
|
|
76
|
-
* Keep an accessible external place list when hiding the native pickers.
|
|
77
|
-
*/
|
|
78
|
-
export function mountGuideMap(shell, options = {}) {
|
|
79
|
-
validateExplorerOptions(options);
|
|
80
|
-
const frame = shellFrame(shell, options.attribution);
|
|
81
|
-
const map = createGuideMap({
|
|
82
|
-
...options,
|
|
83
|
-
attribution: 'compact',
|
|
84
|
-
controls: {
|
|
85
|
-
...shellControls,
|
|
86
|
-
...options.controls,
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
mountFrame(frame, map);
|
|
90
|
-
return map;
|
|
91
|
-
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StaticMapOptions } from './types.js';
|
|
2
2
|
/** Server-safe overview using exactly the guide browser geography. */
|
|
3
|
-
export declare function createGuideSVG(options?:
|
|
3
|
+
export declare function createGuideSVG(options?: StaticMapOptions): {
|
|
4
4
|
svg: string;
|
|
5
5
|
project: (coordinates: import("./geometry.js").Position) => [number, number];
|
|
6
6
|
viewBox: [number, number, number, number];
|
|
7
7
|
};
|
|
8
|
-
/** Stable compact frame, progressively enhanced with
|
|
9
|
-
export declare function createGuideShell(options?:
|
|
8
|
+
/** Stable compact frame, progressively enhanced with mountGuideController(). No browser globals. */
|
|
9
|
+
export declare function createGuideShell(options?: StaticMapOptions): string;
|
package/dist/src/guide-static.js
CHANGED
|
@@ -4,20 +4,23 @@ import { renderMap } from './static.js';
|
|
|
4
4
|
/** Server-safe overview using exactly the guide browser geography. */
|
|
5
5
|
export function createGuideSVG(options = {}) {
|
|
6
6
|
return renderMap(guideMapData.map, {
|
|
7
|
-
theme: 'transit',
|
|
8
|
-
districtFills: false,
|
|
9
|
-
districtLines: false,
|
|
10
|
-
districtLabels: false,
|
|
11
|
-
neighborhoodLines: true,
|
|
12
|
-
neighborhoodLabels: options.labelLayout !== undefined,
|
|
13
|
-
landmarks: true,
|
|
14
|
-
highways: true,
|
|
15
|
-
keyRoads: true,
|
|
16
|
-
bartStations: true,
|
|
17
7
|
...options,
|
|
8
|
+
appearance: { theme: 'transit', ...options.appearance },
|
|
9
|
+
layers: {
|
|
10
|
+
districtFills: false,
|
|
11
|
+
districtLines: false,
|
|
12
|
+
districtLabels: false,
|
|
13
|
+
neighborhoodLines: true,
|
|
14
|
+
neighborhoodLabels: options.labelLayout !== undefined,
|
|
15
|
+
landmarks: true,
|
|
16
|
+
highways: true,
|
|
17
|
+
keyRoads: true,
|
|
18
|
+
bartStations: true,
|
|
19
|
+
...options.layers,
|
|
20
|
+
},
|
|
18
21
|
});
|
|
19
22
|
}
|
|
20
|
-
/** Stable compact frame, progressively enhanced with
|
|
23
|
+
/** Stable compact frame, progressively enhanced with mountGuideController(). No browser globals. */
|
|
21
24
|
export function createGuideShell(options = {}) {
|
|
22
25
|
if ((options.width !== undefined && options.width !== 800) ||
|
|
23
26
|
(options.height !== undefined && options.height !== 800) ||
|
package/dist/src/guide.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export type { MapController, MapOptions } from './controller-types.js';
|
|
|
2
2
|
export type { InteractiveSFMapData } from './explorer-data.js';
|
|
3
3
|
export { guideMapData } from './guide-data.js';
|
|
4
4
|
export { loadGuideDetailedData } from './guide-detailed.js';
|
|
5
|
-
export { createGuideController,
|
|
6
|
-
export type { CameraOptions, MapFeatures, MapMarker,
|
|
5
|
+
export { createGuideController, mountGuideController, } from './guide-map.js';
|
|
6
|
+
export type { CameraOptions, MapFeatures, MapMarker, } from './types.js';
|
package/dist/src/guide.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { guideMapData } from './guide-data.js';
|
|
2
2
|
export { loadGuideDetailedData } from './guide-detailed.js';
|
|
3
|
-
export { createGuideController,
|
|
3
|
+
export { createGuideController, mountGuideController, } from './guide-map.js';
|
package/dist/src/palettes.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SvgRenderOptions } from './types.js';
|
|
2
2
|
/** Shared tokens for static SVGs, interactive maps, and consumer-owned place cards. */
|
|
3
3
|
export interface MapPalette {
|
|
4
|
-
readonly colors: NonNullable<
|
|
4
|
+
readonly colors: NonNullable<SvgRenderOptions['colors']>;
|
|
5
5
|
readonly haloColor: string;
|
|
6
6
|
readonly markerColor: string;
|
|
7
7
|
readonly selectedMarkerColor: string;
|
|
@@ -2,14 +2,14 @@ import type { Geometry } from '../../data/types.js';
|
|
|
2
2
|
import type { DistrictRow } from '../data.js';
|
|
3
3
|
import type { Project } from '../geometry.js';
|
|
4
4
|
import type { BartStation, KeyRoad, Landmark } from '../overlays.js';
|
|
5
|
-
import type { MapMarker,
|
|
5
|
+
import type { MapMarker, SvgRenderOptions } from '../types.js';
|
|
6
6
|
interface LayerContext {
|
|
7
7
|
labels: boolean;
|
|
8
8
|
/** Animated static maps index items for staggering and measure lines for drawing. */
|
|
9
9
|
animated?: boolean;
|
|
10
|
-
theme: NonNullable<
|
|
10
|
+
theme: NonNullable<SvgRenderOptions['theme']>;
|
|
11
11
|
idPrefix: string;
|
|
12
|
-
colors: Required<NonNullable<
|
|
12
|
+
colors: Required<NonNullable<SvgRenderOptions['colors']>>;
|
|
13
13
|
project: Project;
|
|
14
14
|
path: (geometry: Geometry | null | undefined) => string;
|
|
15
15
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Geometry, Position } from '../../data/types.js';
|
|
2
|
-
import type { DistrictYear,
|
|
3
|
-
export type { DistrictYear, MapMarker, MapOverlay,
|
|
2
|
+
import type { DistrictYear, SvgRenderOptions } from '../types.js';
|
|
3
|
+
export type { DistrictYear, MapMarker, MapOverlay, SvgRenderOptions } from '../types.js';
|
|
4
4
|
import { type Project } from '../geometry.js';
|
|
5
5
|
export interface SFMapData {
|
|
6
6
|
coast: Geometry;
|
|
@@ -50,7 +50,7 @@ export interface BartStationData {
|
|
|
50
50
|
export declare const districtYears: readonly DistrictYear[];
|
|
51
51
|
export declare const districtColors: readonly string[];
|
|
52
52
|
/** Canonical geometry in the same fitted coordinate space used by renderMap. */
|
|
53
|
-
export declare function getLayerPathsWithData(options:
|
|
53
|
+
export declare function getLayerPathsWithData(options: SvgRenderOptions, data: SFMapData, complete?: boolean): {
|
|
54
54
|
year: DistrictYear;
|
|
55
55
|
viewBox: [number, number, number, number];
|
|
56
56
|
project: (coordinates: Position) => [number, number];
|
|
@@ -82,7 +82,7 @@ export declare function getLayerPathsWithData(options: SFMapOptions, data: SFMap
|
|
|
82
82
|
point: [number, number];
|
|
83
83
|
}[];
|
|
84
84
|
};
|
|
85
|
-
export declare function resolveMapColors(theme:
|
|
85
|
+
export declare function resolveMapColors(theme: SvgRenderOptions['theme'], colors?: SvgRenderOptions['colors']): {
|
|
86
86
|
water: string;
|
|
87
87
|
land: string;
|
|
88
88
|
district: string;
|
|
@@ -97,7 +97,7 @@ export declare function resolveMapColors(theme: SFMapOptions['theme'], colors?:
|
|
|
97
97
|
selected: string;
|
|
98
98
|
};
|
|
99
99
|
/** Make an offline SVG and the matching longitude/latitude projection. */
|
|
100
|
-
export declare function createSFMapWithData(options:
|
|
100
|
+
export declare function createSFMapWithData(options: SvgRenderOptions, data: SFMapData, renderLabels?: (project: Project) => string): {
|
|
101
101
|
svg: string;
|
|
102
102
|
project: (coordinates: Position) => [number, number];
|
|
103
103
|
viewBox: [number, number, number, number];
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SvgRenderOptions } from './types.js';
|
|
2
2
|
export interface StaticAnimation {
|
|
3
3
|
duration: number;
|
|
4
4
|
delay: number;
|
|
5
5
|
}
|
|
6
6
|
/** Validate `animation` and return timings, or null when animation is off. */
|
|
7
|
-
export declare function normalizeStaticAnimation(value:
|
|
7
|
+
export declare function normalizeStaticAnimation(value: SvgRenderOptions['animation']): StaticAnimation | null;
|
|
8
8
|
/**
|
|
9
9
|
* Scoped, self-contained CSS for an animated static map. It runs when the SVG is
|
|
10
10
|
* inserted into a page or loaded as an image, and stays still under reduced motion.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Project } from './geometry.js';
|
|
2
2
|
import type { SFMapData } from './rendering/svg-map-renderer.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { SvgRenderOptions } from './types.js';
|
|
4
4
|
/** Conservative portable metrics; the browser refines these with its actual font. */
|
|
5
5
|
export declare function estimateLabelWidth(text: string, fontSize: number): number;
|
|
6
6
|
/** Interactive overview rules, expressed entirely in screen pixels before serialization. */
|
|
7
|
-
export declare function staticLabels(data: SFMapData, options:
|
|
7
|
+
export declare function staticLabels(data: SFMapData, options: SvgRenderOptions, project: Project): string;
|
|
@@ -97,7 +97,7 @@ export function staticLabels(data, options, project) {
|
|
|
97
97
|
: []),
|
|
98
98
|
...markers.map((item) => {
|
|
99
99
|
const [x, y] = point(item.position);
|
|
100
|
-
// Also cover the
|
|
100
|
+
// Also cover the static SVG marker when it is larger than its interactive counterpart.
|
|
101
101
|
const radius = Math.max(item.radius ?? 6, (item.radius ?? (item.selected ? 8 : 5)) / unit) + 3;
|
|
102
102
|
return [x - radius, y - radius, x + radius, y + radius];
|
|
103
103
|
}),
|
package/dist/src/static.d.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import type { InteractiveSFMapData } from './explorer-data.js';
|
|
2
2
|
import { type SFMapData } from './rendering/svg-map-renderer.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { StaticMapOptions } from './types.js';
|
|
4
4
|
/** Either compact static geography or the same source-aware geography used by createMap. */
|
|
5
5
|
export type StaticMapInput = SFMapData | InteractiveSFMapData;
|
|
6
6
|
export type { DistrictRowData, SFMapData as StaticMapData } from './rendering/svg-map-renderer.js';
|
|
7
|
-
export type { DistrictStyle, DistrictYear,
|
|
7
|
+
export type { DistrictStyle, DistrictYear, StaticMapAppearance, StaticMapLayers, StaticMapOptions, } from './types.js';
|
|
8
8
|
/** Server-safe SVG rendering with explicit data; returns SVG plus projection helpers. */
|
|
9
|
-
export declare function renderMap(data: StaticMapInput, options?:
|
|
9
|
+
export declare function renderMap(data: StaticMapInput, options?: StaticMapOptions): {
|
|
10
10
|
svg: string;
|
|
11
11
|
project: (coordinates: import("./geometry.js").Position) => [number, number];
|
|
12
12
|
viewBox: [number, number, number, number];
|
|
13
13
|
};
|
|
14
14
|
/** Project canonical layer geometry without constructing an SVG string. */
|
|
15
|
-
export declare function getLayerPaths(data: StaticMapInput, options?:
|
|
15
|
+
export declare function getLayerPaths(data: StaticMapInput, options?: StaticMapOptions): {
|
|
16
16
|
year: import("./types.js").DistrictYear;
|
|
17
17
|
viewBox: [number, number, number, number];
|
|
18
18
|
project: (coordinates: import("./geometry.js").Position) => [number, number];
|
package/dist/src/static.js
CHANGED
|
@@ -55,15 +55,11 @@ const staticLayerKeys = [
|
|
|
55
55
|
'keyRoads',
|
|
56
56
|
'roadLabels',
|
|
57
57
|
];
|
|
58
|
-
/**
|
|
58
|
+
/** Validate the public grouped contract before preparing internal renderer options. */
|
|
59
59
|
function expandStaticOptions(options) {
|
|
60
60
|
assertOptions(options, 'static map', [
|
|
61
|
-
...staticLayerKeys,
|
|
62
61
|
'layers',
|
|
63
62
|
'appearance',
|
|
64
|
-
'theme',
|
|
65
|
-
'colors',
|
|
66
|
-
'districtStyle',
|
|
67
63
|
'width',
|
|
68
64
|
'height',
|
|
69
65
|
'padding',
|
|
@@ -77,7 +73,7 @@ function expandStaticOptions(options) {
|
|
|
77
73
|
'idPrefix',
|
|
78
74
|
'animation',
|
|
79
75
|
]);
|
|
80
|
-
for (const key of [
|
|
76
|
+
for (const key of ['labels'])
|
|
81
77
|
if (options[key] !== undefined && typeof options[key] !== 'boolean')
|
|
82
78
|
throw new TypeError(`${key} must be boolean.`);
|
|
83
79
|
for (const key of ['title', 'idPrefix'])
|
|
@@ -117,11 +113,10 @@ function expandStaticOptions(options) {
|
|
|
117
113
|
if (options.appearance !== undefined) {
|
|
118
114
|
assertOptions(options.appearance, 'static appearance', ['theme', 'colors', 'districtStyle']);
|
|
119
115
|
}
|
|
120
|
-
const { layers, appearance,
|
|
116
|
+
const { layers, appearance, ...flat } = options;
|
|
121
117
|
const supplied = (group = {}) => Object.fromEntries(Object.entries(group).filter(([, value]) => value !== undefined));
|
|
122
118
|
return {
|
|
123
119
|
...flat,
|
|
124
|
-
...prepareAppearance({}, { theme, colors, districtStyle }),
|
|
125
120
|
...supplied(layers),
|
|
126
121
|
...supplied(appearance === undefined ? undefined : prepareAppearance({}, appearance)),
|
|
127
122
|
};
|
package/dist/src/types.d.ts
CHANGED
|
@@ -39,10 +39,7 @@ export interface MapOverlay {
|
|
|
39
39
|
visible?: boolean;
|
|
40
40
|
label?: string;
|
|
41
41
|
}
|
|
42
|
-
export interface
|
|
43
|
-
/** Grouped presentation; supplied keys take precedence over flat compatibility options. */
|
|
44
|
-
layers?: StaticMapLayers;
|
|
45
|
-
appearance?: StaticMapAppearance;
|
|
42
|
+
export interface SvgRenderOptions {
|
|
46
43
|
theme?: 'districts' | 'transit';
|
|
47
44
|
width?: number;
|
|
48
45
|
height?: number;
|
|
@@ -96,7 +93,12 @@ export interface SFMapOptions {
|
|
|
96
93
|
}
|
|
97
94
|
/** Presentation supported by both the static and interactive renderers. */
|
|
98
95
|
export type StaticMapLayers = InteractiveLayers;
|
|
99
|
-
export type StaticMapAppearance = Pick<
|
|
96
|
+
export type StaticMapAppearance = Pick<SvgRenderOptions, 'theme' | 'colors' | 'districtStyle'>;
|
|
97
|
+
/** Public static presentation uses the same grouped vocabulary as the map controller. */
|
|
98
|
+
export type StaticMapOptions = Omit<SvgRenderOptions, keyof StaticMapLayers | keyof StaticMapAppearance> & {
|
|
99
|
+
layers?: StaticMapLayers;
|
|
100
|
+
appearance?: StaticMapAppearance;
|
|
101
|
+
};
|
|
100
102
|
/** Serializable viewport in the interactive map's fixed 800 × 800 projected space. */
|
|
101
103
|
export type MapViewport = readonly [x: number, y: number, size: number];
|
|
102
104
|
export type ExplorerMode = 'neighborhoods' | 'districts' | 'basemap';
|
|
@@ -166,8 +168,8 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
|
|
|
166
168
|
source?: NeighborhoodSource;
|
|
167
169
|
neighborhood?: string;
|
|
168
170
|
year?: DistrictYear;
|
|
169
|
-
theme?:
|
|
170
|
-
colors?:
|
|
171
|
+
theme?: SvgRenderOptions['theme'];
|
|
172
|
+
colors?: SvgRenderOptions['colors'];
|
|
171
173
|
labelStyle?: {
|
|
172
174
|
fontFamily?: string;
|
|
173
175
|
fontWeight?: number;
|
|
@@ -179,7 +181,7 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
|
|
|
179
181
|
hoverFill?: string;
|
|
180
182
|
hoverStroke?: string;
|
|
181
183
|
};
|
|
182
|
-
districtStyle?:
|
|
184
|
+
districtStyle?: SvgRenderOptions['districtStyle'];
|
|
183
185
|
legend?: {
|
|
184
186
|
builtins?: boolean;
|
|
185
187
|
hidden?: readonly ('bart' | 'park' | 'highway' | 'road')[];
|
|
@@ -245,7 +247,7 @@ export interface NeighborhoodExplorerElement extends HTMLElement {
|
|
|
245
247
|
} & CameraOptions): boolean;
|
|
246
248
|
getSelectedDistrict(): DistrictSelection | null;
|
|
247
249
|
setDistrictYear(year: DistrictYear, options?: CameraOptions): void;
|
|
248
|
-
setDistrictStyle(style:
|
|
250
|
+
setDistrictStyle(style: SvgRenderOptions['districtStyle']): void;
|
|
249
251
|
setSource(source: NeighborhoodSource): void;
|
|
250
252
|
setMode(mode: ExplorerMode): void;
|
|
251
253
|
setLabels(visible: boolean): void;
|
package/docs/API.md
CHANGED
|
@@ -54,9 +54,9 @@ const { svg } = renderMap(staticMapData, presentation);
|
|
|
54
54
|
const map = createMap(fullMapData, presentation);
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
-
Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected
|
|
57
|
+
Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected. Presentation belongs under `layers` and `appearance`; flat presentation keys are rejected. Omitted or `undefined` grouped keys preserve renderer defaults. Undefined color tokens use the theme default instead of entering SVG attributes. The two renderers retain their existing defaults. Marker arrays accept readonly inputs.
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
Top-level static options are `width`, `height`, `padding`, `year`, `source`, `labels`, `labelLayout`, `markers`, `overlays`, `title`, `idPrefix`, and `animation`, alongside `layers` and `appearance`. Each optional layer is independent. User-supplied text and attributes are escaped in SVG output.
|
|
60
60
|
|
|
61
61
|
Custom district IDs must be finite numbers. An empty `labelPoints` array uses the district's primary `label` position.
|
|
62
62
|
|
|
@@ -64,22 +64,18 @@ The SVG description names the selected neighborhood source for source-aware data
|
|
|
64
64
|
|
|
65
65
|
`animation: true` (or `{ duration, delay }`) makes a static map draw itself with self-contained, scoped CSS: land fades in, the coast and lines draw, districts grow, then labels and points appear. It plays when the SVG is inserted into a page or loaded as an image, needs no JavaScript, and stays still under `prefers-reduced-motion`. Re-insert the markup to replay it. Default output is unchanged.
|
|
66
66
|
|
|
67
|
-
Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `neighborhoodLabels: true
|
|
67
|
+
Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `layers: { neighborhoodLabels: true }` to add area names in this layout. Guide SVGs and shells enable neighborhood names by default only when opting into `labelLayout`. `labels: false` remains the master switch. Default static output is unchanged.
|
|
68
68
|
|
|
69
69
|
For editorial previews, `labelLayout` also accepts `maxLabels` (a nonnegative safe integer), `haloColor` (an SVG color string), and `compact: { width, maxLabels }`. The compact width must be positive, finite, and smaller than the main layout width. Each layout places labels around pins independently, then chooses up to its budget for spatial coverage and nearby-pin context (selected marker first when it fits). Without a budget the existing overview order is unchanged. Equal spatial scores retain the original priority order. A zero budget hides text, never pins. The default halo remains white; use the land color for a quieter dark map.
|
|
70
70
|
|
|
71
71
|
Compact mode embeds two label groups and a media query in the same SVG. At or below the compact width it shows the compact group; above it shows the main group. In an `<img>` or standalone SVG, the breakpoint follows the SVG viewport. In inline SVG it follows the document viewport, so use `<img>` for cards whose width differs from the page. No JavaScript, duplicated geometry, external fonts, or extra image requests are needed. The compact width is also its font-layout hint; very narrow images still scale the text. The interactive renderer continues to use its live collision layout after enhancement.
|
|
72
72
|
|
|
73
73
|
```js
|
|
74
|
-
createGuideSVG({
|
|
75
|
-
labelLayout: {
|
|
74
|
+
createGuideSVG({ labelLayout: {
|
|
76
75
|
width: 800,
|
|
77
76
|
haloColor: '#1b2c28',
|
|
78
77
|
compact: { width: 480, maxLabels: 4 },
|
|
79
|
-
},
|
|
80
|
-
colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' },
|
|
81
|
-
markers: places,
|
|
82
|
-
});
|
|
78
|
+
}, markers: places, appearance: { colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' } } });
|
|
83
79
|
```
|
|
84
80
|
|
|
85
81
|
See the [field-guide preview recipe](consumer-integration.md#editorial-map-previews) for a complete build-time example.
|
|
@@ -110,9 +106,9 @@ Visible markers and clusters share one tab stop. Use `[` and `]` to move focus,
|
|
|
110
106
|
|
|
111
107
|
Activating coincident pins opens a place chooser, including when compact embeds hide the native marker picker. Clusters zoom when their members can separate at maximum zoom; otherwise they open the chooser. Escape or Close returns focus to the originating pin or cluster when it remains visible. Choosing a place selects its marker; replacing markers or destroying the map closes the chooser. `clusteractivate` still reports the activated cluster's markers.
|
|
112
108
|
|
|
113
|
-
For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `
|
|
109
|
+
For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `createGuideController`, `mountGuideController`, and detailed-data loading for existing guide layouts. `/transit` provides the standalone schematic transit animation. See [examples](EXAMPLES.md) and [consumer integration](consumer-integration.md).
|
|
114
110
|
|
|
115
|
-
For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography.
|
|
111
|
+
For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography. See [migration to v6](migration-v6.md) for removed compatibility APIs.
|
|
116
112
|
|
|
117
113
|
Two opt-in features animate the map's lines and layers. `features.layerTransitions` fades layers as `configure({ layers })` and `setMode()` switch them, crossfades neighborhood boundaries when `setSource()` changes the definition, and crossfades district fills on `setDistrictStyle()`. `features.districtMorph` moves district outlines from one map year to the next on `setDistrictYear()`, then settles on the exact published geometry; pass `{ animate: false }` for an instant change. Both default off, own and cancel their animations, and yield to reduced motion.
|
|
118
114
|
|
package/docs/EXAMPLES.md
CHANGED
|
@@ -20,18 +20,13 @@ import { writeFile } from 'node:fs/promises';
|
|
|
20
20
|
import { renderMap } from '@kahwee/sf-map-svg';
|
|
21
21
|
import { staticMapData } from '@kahwee/sf-map-svg/data/static';
|
|
22
22
|
|
|
23
|
-
const svg = renderMap(staticMapData, {
|
|
24
|
-
year: 2022,
|
|
25
|
-
landmarks: true,
|
|
26
|
-
bartStations: true,
|
|
27
|
-
idPrefix: 'example',
|
|
28
|
-
}).svg;
|
|
23
|
+
const svg = renderMap(staticMapData, { year: 2022, idPrefix: 'example', layers: { landmarks: true, bartStations: true } }).svg;
|
|
29
24
|
await writeFile('districts.svg', svg);
|
|
30
25
|
```
|
|
31
26
|
|
|
32
27
|
The static preset includes the packaged map layers without interactive lookup collections. For smaller bundles, pass selected data to the root or `/static` renderer. See the [static recipe](../README.md#static-svg).
|
|
33
28
|
|
|
34
|
-
For an election choropleth, use `renderMap(data, { year, districtStyle })` or
|
|
29
|
+
For an election choropleth, use `renderMap(data, { year, appearance: { districtStyle } })` or
|
|
35
30
|
`createMap({ map: data, districts: districtMaps, neighborhoods: {} }, options)`.
|
|
36
31
|
The controller exposes `setDistrictYear`, `setDistrictStyle`, `selectDistrict`, and typed
|
|
37
32
|
district events; `getLayerPaths(data, { year })` returns fitted paths without SVG markup.
|
package/docs/api-audit.md
CHANGED
|
@@ -28,7 +28,7 @@ unbounded geographic data can never fail.
|
|
|
28
28
|
| Label metrics and camera movement | Reuse screen-space text measurements and nodes across frames. Font loading invalidates measurements; hidden or removed candidates do not remain in the visible layer. |
|
|
29
29
|
| Marker replacement | Reconcile stable IDs, preserve retained nodes/picker options and entrance animations, cancel removed entrances, and restore focus after reordering. Identical ordered values do not mutate the DOM or restart work. |
|
|
30
30
|
| Camera and label scheduling | A shared frame advances the camera before rendering dependent labels, marker sizes, and clusters. State/events remain synchronous; cancellation preserves pending layout, and destruction cancels both kinds of work. |
|
|
31
|
-
| Guide controllers
|
|
31
|
+
| Guide controllers | `createGuideController`/`mountGuideController` share grouped options and lifecycle with `createMap`. Element compatibility factories were removed in v6. |
|
|
32
32
|
| Layer hidden and bundle cost | Visibility never unloads imported geography. Use narrow entrypoints or data injection to save bytes. |
|
|
33
33
|
|
|
34
34
|
Live appearance patches prepare values, district styles and source replacement before committing; token objects merge by key. Styling callbacks that issue a newer presentation update supersede the pending patch. Resolved layer reads distinguish visibility settings from data availability and from zoom/collision label filtering. The additive selection envelope preserves existing event contracts.
|
|
@@ -58,8 +58,8 @@ exceptions are not transactional validation errors and do not roll back an alrea
|
|
|
58
58
|
committed change. Direct mutation of the returned DOM can invalidate invariants;
|
|
59
59
|
use the public methods and `overlayElement` extension point.
|
|
60
60
|
|
|
61
|
-
Static
|
|
62
|
-
rendering.
|
|
61
|
+
Static grouped options reject unknown keys and invalid values before
|
|
62
|
+
rendering. Flat presentation keys were removed in v6;
|
|
63
63
|
static and interactive schemas retain their documented differences. Host layout, delayed images, fonts, and application cards need their
|
|
64
64
|
own CLS tests. The scale bar is an approximate local Mercator scale, not survey
|
|
65
65
|
instrumentation. Coincident locations use a place chooser rather than spiderfying. Geographic
|
|
@@ -80,7 +80,7 @@ function disposeGuide() {
|
|
|
80
80
|
|
|
81
81
|
Compact attribution is required for an existing shell. Invalid configuration leaves its static frame intact. `destroy()` disposes listeners and animation work; your application owns removal of the containing view. Motion is opt-in and follows reduced-motion preferences.
|
|
82
82
|
|
|
83
|
-
For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide.
|
|
83
|
+
For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide. Both guide factories return controllers; mount `map.element` and dispose with `map.destroy()`.
|
|
84
84
|
|
|
85
85
|
## Choose the data boundary
|
|
86
86
|
|
package/docs/developer-guide.md
CHANGED
|
@@ -22,12 +22,7 @@ import { writeFile } from 'node:fs/promises';
|
|
|
22
22
|
import { renderMap } from '@kahwee/sf-map-svg/static';
|
|
23
23
|
import { staticMapData } from '@kahwee/sf-map-svg/data/static';
|
|
24
24
|
|
|
25
|
-
const { svg } = renderMap(staticMapData, {
|
|
26
|
-
year: 2022,
|
|
27
|
-
landmarks: true,
|
|
28
|
-
bartStations: true,
|
|
29
|
-
title: 'San Francisco districts, 2022',
|
|
30
|
-
});
|
|
25
|
+
const { svg } = renderMap(staticMapData, { year: 2022, title: 'San Francisco districts, 2022', layers: { landmarks: true, bartStations: true } });
|
|
31
26
|
await writeFile('san-francisco.svg', svg);
|
|
32
27
|
```
|
|
33
28
|
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Migrating to v6
|
|
2
|
+
|
|
3
|
+
Version 6 removes the remaining compatibility APIs. Geographic datasets, coordinate
|
|
4
|
+
conventions, defaults and rendering precision are unchanged.
|
|
5
|
+
|
|
6
|
+
## Static presentation
|
|
7
|
+
|
|
8
|
+
Move flat geographic switches into `layers`, and `theme`, `colors` and
|
|
9
|
+
`districtStyle` into `appearance`. Flat presentation keys now throw.
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
const { svg } = renderMap(staticMapData, {
|
|
13
|
+
width: 800,
|
|
14
|
+
labels: true,
|
|
15
|
+
layers: { landmarks: true, bartStations: true, districtFills: false },
|
|
16
|
+
appearance: { theme: 'transit', colors: { water: '#e7f0f3' } },
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The same contract applies to `getLayerPaths`, `createGuideSVG` and
|
|
21
|
+
`createGuideShell`. Dimensions, year, source, master labels, label layout,
|
|
22
|
+
markers, overlays, title, ID prefix and animation remain top-level options.
|
|
23
|
+
|
|
24
|
+
## Guide controllers
|
|
25
|
+
|
|
26
|
+
Replace `createGuideMap` with `createGuideController`, and `mountGuideMap` with
|
|
27
|
+
`mountGuideController`. Both return `MapController`; DOM methods live on `.element`.
|
|
28
|
+
The `InteractiveSFMapElement` and `InteractiveSFMapOptions` guide aliases are removed.
|
|
29
|
+
Use `MapController` and `MapOptions`.
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
import { createGuideController } from '@kahwee/sf-map-svg/guide';
|
|
33
|
+
const map = createGuideController({
|
|
34
|
+
features: { motion: true, clustering: true },
|
|
35
|
+
appearance: { colors: { water: '#e7f0f3' } },
|
|
36
|
+
});
|
|
37
|
+
document.querySelector('#map').append(map.element);
|
|
38
|
+
map.configure({ layers: { landmarks: false } });
|
|
39
|
+
map.camera.reset();
|
|
40
|
+
map.on('markerchange', ({ marker }) => console.log(marker));
|
|
41
|
+
// On unmount:
|
|
42
|
+
map.destroy();
|
|
43
|
+
map.element.remove();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Use `configure` for feature, layer, control and appearance changes; use `camera`
|
|
47
|
+
for viewport operations. Replace construction callbacks with `map.on` subscriptions.
|
|
48
|
+
For static-shell enhancement, call `mountGuideController(shell, options)` and keep
|
|
49
|
+
the returned controller for disposal.
|
|
50
|
+
|
|
51
|
+
## Site integrations
|
|
52
|
+
|
|
53
|
+
Pages builds require a v6-or-newer package and generate examples directly for that
|
|
54
|
+
contract. Older-package feature detection and flat-option fallback generation are
|
|
55
|
+
removed. Playground links must include `version: 1` in their design payload;
|
|
56
|
+
links produced by the current Share control already include it. Unversioned
|
|
57
|
+
handwritten links must add that field.
|
package/llms-full.txt
CHANGED
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
> Offline San Francisco SVG maps with explicit geographic imports, no runtime dependencies, static rendering, and a browser controller.
|
|
4
4
|
|
|
5
|
-
@kahwee/sf-map-svg
|
|
5
|
+
@kahwee/sf-map-svg 6.0.0 · local working tree. Node >=24.0.0 for server rendering; browsers need a DOM and a JSON-capable bundler.
|
|
6
6
|
|
|
7
7
|
These are working-tree docs. Unreleased changelog entries may describe APIs absent from npm; verify the installed version before copying them.
|
|
8
8
|
|
|
9
9
|
Use renderMap(data, options) for SVG strings; createMap(data, options) returns a controller. Mount map.element and destroy it on unmount. Choose mode explicitly: createMap defaults to basemap. Geography is separate; staticMapData and fullMapData have different shapes.
|
|
10
10
|
|
|
11
|
-
<!-- Generated from README.md; @kahwee/sf-map-svg
|
|
11
|
+
<!-- Generated from README.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
12
12
|
|
|
13
13
|
# SF Map SVG
|
|
14
14
|
|
|
@@ -39,11 +39,7 @@ Upgrading from v3 to v4: update your Node runtime to 24 or newer. The map API, b
|
|
|
39
39
|
import { renderMap } from '@kahwee/sf-map-svg';
|
|
40
40
|
import { staticMapData } from '@kahwee/sf-map-svg/data/static';
|
|
41
41
|
|
|
42
|
-
const { svg, project, viewBox } = renderMap(staticMapData, {
|
|
43
|
-
year: 2022,
|
|
44
|
-
landmarks: true,
|
|
45
|
-
bartStations: true,
|
|
46
|
-
});
|
|
42
|
+
const { svg, project, viewBox } = renderMap(staticMapData, { year: 2022, layers: { landmarks: true, bartStations: true } });
|
|
47
43
|
```
|
|
48
44
|
|
|
49
45
|
`renderMap(data, options)` returns SVG markup and matching projection helpers. `/data/static` includes the complete static map without interactive lookup collections. Small maps can compose selected JSON exports from `/data/*` and pass them as `StaticMapData`. `getLayerPaths(data, options)` returns fitted geographic paths without SVG markup.
|
|
@@ -267,7 +263,7 @@ for raw samples, output-equivalence checks, and reproducible commands.
|
|
|
267
263
|
|
|
268
264
|
---
|
|
269
265
|
|
|
270
|
-
<!-- Generated from docs/developer-guide.md; @kahwee/sf-map-svg
|
|
266
|
+
<!-- Generated from docs/developer-guide.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
271
267
|
|
|
272
268
|
# Developer guide
|
|
273
269
|
|
|
@@ -293,12 +289,7 @@ import { writeFile } from 'node:fs/promises';
|
|
|
293
289
|
import { renderMap } from '@kahwee/sf-map-svg/static';
|
|
294
290
|
import { staticMapData } from '@kahwee/sf-map-svg/data/static';
|
|
295
291
|
|
|
296
|
-
const { svg } = renderMap(staticMapData, {
|
|
297
|
-
year: 2022,
|
|
298
|
-
landmarks: true,
|
|
299
|
-
bartStations: true,
|
|
300
|
-
title: 'San Francisco districts, 2022',
|
|
301
|
-
});
|
|
292
|
+
const { svg } = renderMap(staticMapData, { year: 2022, title: 'San Francisco districts, 2022', layers: { landmarks: true, bartStations: true } });
|
|
302
293
|
await writeFile('san-francisco.svg', svg);
|
|
303
294
|
```
|
|
304
295
|
|
|
@@ -433,7 +424,7 @@ See [API options](https://github.com/kahwee/sf-map-svg/blob/main/docs/API.md), [
|
|
|
433
424
|
|
|
434
425
|
---
|
|
435
426
|
|
|
436
|
-
<!-- Generated from docs/API.md; @kahwee/sf-map-svg
|
|
427
|
+
<!-- Generated from docs/API.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
437
428
|
|
|
438
429
|
# Map options and lifecycle
|
|
439
430
|
|
|
@@ -491,9 +482,9 @@ const { svg } = renderMap(staticMapData, presentation);
|
|
|
491
482
|
const map = createMap(fullMapData, presentation);
|
|
492
483
|
```
|
|
493
484
|
|
|
494
|
-
Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected
|
|
485
|
+
Static `layers` supports every interactive layer switch. `neighborhoodLabels` applies to the opt-in `labelLayout` described below. Static `appearance` supports `theme`, `colors`, and `districtStyle`; browser typography, area interaction styles, and screen-space marker sizing remain interactive settings. Unknown keys and invalid values are rejected. Presentation belongs under `layers` and `appearance`; flat presentation keys are rejected. Omitted or `undefined` grouped keys preserve renderer defaults. Undefined color tokens use the theme default instead of entering SVG attributes. The two renderers retain their existing defaults. Marker arrays accept readonly inputs.
|
|
495
486
|
|
|
496
|
-
|
|
487
|
+
Top-level static options are `width`, `height`, `padding`, `year`, `source`, `labels`, `labelLayout`, `markers`, `overlays`, `title`, `idPrefix`, and `animation`, alongside `layers` and `appearance`. Each optional layer is independent. User-supplied text and attributes are escaped in SVG output.
|
|
497
488
|
|
|
498
489
|
Custom district IDs must be finite numbers. An empty `labelPoints` array uses the district's primary `label` position.
|
|
499
490
|
|
|
@@ -501,22 +492,18 @@ The SVG description names the selected neighborhood source for source-aware data
|
|
|
501
492
|
|
|
502
493
|
`animation: true` (or `{ duration, delay }`) makes a static map draw itself with self-contained, scoped CSS: land fades in, the coast and lines draw, districts grow, then labels and points appear. It plays when the SVG is inserted into a page or loaded as an image, needs no JavaScript, and stays still under `prefers-reduced-motion`. Re-insert the markup to replay it. Default output is unchanged.
|
|
503
494
|
|
|
504
|
-
Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `neighborhoodLabels: true
|
|
495
|
+
Static `labelLayout: { width: 390 }` opts into shared interactive **overview** label priorities, sizes, anchors and collision rules. `width` must be a positive finite CSS canvas width; it does not alter the SVG viewBox. Set `layers: { neighborhoodLabels: true }` to add area names in this layout. Guide SVGs and shells enable neighborhood names by default only when opting into `labelLayout`. `labels: false` remains the master switch. Default static output is unchanged.
|
|
505
496
|
|
|
506
497
|
For editorial previews, `labelLayout` also accepts `maxLabels` (a nonnegative safe integer), `haloColor` (an SVG color string), and `compact: { width, maxLabels }`. The compact width must be positive, finite, and smaller than the main layout width. Each layout places labels around pins independently, then chooses up to its budget for spatial coverage and nearby-pin context (selected marker first when it fits). Without a budget the existing overview order is unchanged. Equal spatial scores retain the original priority order. A zero budget hides text, never pins. The default halo remains white; use the land color for a quieter dark map.
|
|
507
498
|
|
|
508
499
|
Compact mode embeds two label groups and a media query in the same SVG. At or below the compact width it shows the compact group; above it shows the main group. In an `<img>` or standalone SVG, the breakpoint follows the SVG viewport. In inline SVG it follows the document viewport, so use `<img>` for cards whose width differs from the page. No JavaScript, duplicated geometry, external fonts, or extra image requests are needed. The compact width is also its font-layout hint; very narrow images still scale the text. The interactive renderer continues to use its live collision layout after enhancement.
|
|
509
500
|
|
|
510
501
|
```js
|
|
511
|
-
createGuideSVG({
|
|
512
|
-
labelLayout: {
|
|
502
|
+
createGuideSVG({ labelLayout: {
|
|
513
503
|
width: 800,
|
|
514
504
|
haloColor: '#1b2c28',
|
|
515
505
|
compact: { width: 480, maxLabels: 4 },
|
|
516
|
-
},
|
|
517
|
-
colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' },
|
|
518
|
-
markers: places,
|
|
519
|
-
});
|
|
506
|
+
}, markers: places, appearance: { colors: { water: '#0a1412', land: '#1b2c28', label: '#d5e3e8' } } });
|
|
520
507
|
```
|
|
521
508
|
|
|
522
509
|
See the [field-guide preview recipe](https://github.com/kahwee/sf-map-svg/blob/main/docs/consumer-integration.md#editorial-map-previews) for a complete build-time example.
|
|
@@ -547,9 +534,9 @@ Visible markers and clusters share one tab stop. Use `[` and `]` to move focus,
|
|
|
547
534
|
|
|
548
535
|
Activating coincident pins opens a place chooser, including when compact embeds hide the native marker picker. Clusters zoom when their members can separate at maximum zoom; otherwise they open the chooser. Escape or Close returns focus to the originating pin or cluster when it remains visible. Choosing a place selects its marker; replacing markers or destroying the map closes the chooser. `clusteractivate` still reports the activated cluster's markers.
|
|
549
536
|
|
|
550
|
-
For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `
|
|
537
|
+
For a small guide, import `guideMapData` from `/guide/data` and pass it to `createMap`. The optional `/guide` entry also provides `createGuideController`, `mountGuideController`, and detailed-data loading for existing guide layouts. `/transit` provides the standalone schematic transit animation. See [examples](https://github.com/kahwee/sf-map-svg/blob/main/docs/EXAMPLES.md) and [consumer integration](https://github.com/kahwee/sf-map-svg/blob/main/docs/consumer-integration.md).
|
|
551
538
|
|
|
552
|
-
For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography.
|
|
539
|
+
For the guide preset with the same controller API, use `createGuideController(options)` from `/guide` (or `/guide/map`). It accepts grouped `MapOptions` and returns `MapController`; `mountGuideController(shell, options)` enhances a `createGuideShell()` container. Both use the lightweight guide geography. See [migration to v6](https://github.com/kahwee/sf-map-svg/blob/main/docs/migration-v6.md) for removed compatibility APIs.
|
|
553
540
|
|
|
554
541
|
Two opt-in features animate the map's lines and layers. `features.layerTransitions` fades layers as `configure({ layers })` and `setMode()` switch them, crossfades neighborhood boundaries when `setSource()` changes the definition, and crossfades district fills on `setDistrictStyle()`. `features.districtMorph` moves district outlines from one map year to the next on `setDistrictYear()`, then settles on the exact published geometry; pass `{ animate: false }` for an instant change. Both default off, own and cancel their animations, and yield to reduced motion.
|
|
555
542
|
|
|
@@ -619,7 +606,7 @@ Call `binding.setMarkers(next)` after `map.setMarkers(next)` when the catalog ch
|
|
|
619
606
|
|
|
620
607
|
---
|
|
621
608
|
|
|
622
|
-
<!-- Generated from docs/EXAMPLES.md; @kahwee/sf-map-svg
|
|
609
|
+
<!-- Generated from docs/EXAMPLES.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
623
610
|
|
|
624
611
|
# Examples
|
|
625
612
|
|
|
@@ -643,18 +630,13 @@ import { writeFile } from 'node:fs/promises';
|
|
|
643
630
|
import { renderMap } from '@kahwee/sf-map-svg';
|
|
644
631
|
import { staticMapData } from '@kahwee/sf-map-svg/data/static';
|
|
645
632
|
|
|
646
|
-
const svg = renderMap(staticMapData, {
|
|
647
|
-
year: 2022,
|
|
648
|
-
landmarks: true,
|
|
649
|
-
bartStations: true,
|
|
650
|
-
idPrefix: 'example',
|
|
651
|
-
}).svg;
|
|
633
|
+
const svg = renderMap(staticMapData, { year: 2022, idPrefix: 'example', layers: { landmarks: true, bartStations: true } }).svg;
|
|
652
634
|
await writeFile('districts.svg', svg);
|
|
653
635
|
```
|
|
654
636
|
|
|
655
637
|
The static preset includes the packaged map layers without interactive lookup collections. For smaller bundles, pass selected data to the root or `/static` renderer. See the [static recipe](https://github.com/kahwee/sf-map-svg/blob/main/README.md#static-svg).
|
|
656
638
|
|
|
657
|
-
For an election choropleth, use `renderMap(data, { year, districtStyle })` or
|
|
639
|
+
For an election choropleth, use `renderMap(data, { year, appearance: { districtStyle } })` or
|
|
658
640
|
`createMap({ map: data, districts: districtMaps, neighborhoods: {} }, options)`.
|
|
659
641
|
The controller exposes `setDistrictYear`, `setDistrictStyle`, `selectDistrict`, and typed
|
|
660
642
|
district events; `getLayerPaths(data, { year })` returns fitted paths without SVG markup.
|
|
@@ -760,7 +742,7 @@ See [query semantics and limitations](https://github.com/kahwee/sf-map-svg/blob/
|
|
|
760
742
|
|
|
761
743
|
---
|
|
762
744
|
|
|
763
|
-
<!-- Generated from docs/consumer-integration.md; @kahwee/sf-map-svg
|
|
745
|
+
<!-- Generated from docs/consumer-integration.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
764
746
|
|
|
765
747
|
# Embedding and progressive enhancement
|
|
766
748
|
|
|
@@ -844,7 +826,7 @@ function disposeGuide() {
|
|
|
844
826
|
|
|
845
827
|
Compact attribution is required for an existing shell. Invalid configuration leaves its static frame intact. `destroy()` disposes listeners and animation work; your application owns removal of the containing view. Motion is opt-in and follows reduced-motion preferences.
|
|
846
828
|
|
|
847
|
-
For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide.
|
|
829
|
+
For a new browser-only guide, use `createGuideController()` and mount its `.element` as shown in the developer guide. Both guide factories return controllers; mount `map.element` and dispose with `map.destroy()`.
|
|
848
830
|
|
|
849
831
|
## Choose the data boundary
|
|
850
832
|
|
|
@@ -938,7 +920,69 @@ keyboard, focus, and dismissal behavior. See [coordinates and units](https://git
|
|
|
938
920
|
|
|
939
921
|
---
|
|
940
922
|
|
|
941
|
-
<!-- Generated from docs/migration-
|
|
923
|
+
<!-- Generated from docs/migration-v6.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
924
|
+
|
|
925
|
+
# Migrating to v6
|
|
926
|
+
|
|
927
|
+
Version 6 removes the remaining compatibility APIs. Geographic datasets, coordinate
|
|
928
|
+
conventions, defaults and rendering precision are unchanged.
|
|
929
|
+
|
|
930
|
+
## Static presentation
|
|
931
|
+
|
|
932
|
+
Move flat geographic switches into `layers`, and `theme`, `colors` and
|
|
933
|
+
`districtStyle` into `appearance`. Flat presentation keys now throw.
|
|
934
|
+
|
|
935
|
+
```js
|
|
936
|
+
const { svg } = renderMap(staticMapData, {
|
|
937
|
+
width: 800,
|
|
938
|
+
labels: true,
|
|
939
|
+
layers: { landmarks: true, bartStations: true, districtFills: false },
|
|
940
|
+
appearance: { theme: 'transit', colors: { water: '#e7f0f3' } },
|
|
941
|
+
});
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
The same contract applies to `getLayerPaths`, `createGuideSVG` and
|
|
945
|
+
`createGuideShell`. Dimensions, year, source, master labels, label layout,
|
|
946
|
+
markers, overlays, title, ID prefix and animation remain top-level options.
|
|
947
|
+
|
|
948
|
+
## Guide controllers
|
|
949
|
+
|
|
950
|
+
Replace `createGuideMap` with `createGuideController`, and `mountGuideMap` with
|
|
951
|
+
`mountGuideController`. Both return `MapController`; DOM methods live on `.element`.
|
|
952
|
+
The `InteractiveSFMapElement` and `InteractiveSFMapOptions` guide aliases are removed.
|
|
953
|
+
Use `MapController` and `MapOptions`.
|
|
954
|
+
|
|
955
|
+
```js
|
|
956
|
+
import { createGuideController } from '@kahwee/sf-map-svg/guide';
|
|
957
|
+
const map = createGuideController({
|
|
958
|
+
features: { motion: true, clustering: true },
|
|
959
|
+
appearance: { colors: { water: '#e7f0f3' } },
|
|
960
|
+
});
|
|
961
|
+
document.querySelector('#map').append(map.element);
|
|
962
|
+
map.configure({ layers: { landmarks: false } });
|
|
963
|
+
map.camera.reset();
|
|
964
|
+
map.on('markerchange', ({ marker }) => console.log(marker));
|
|
965
|
+
// On unmount:
|
|
966
|
+
map.destroy();
|
|
967
|
+
map.element.remove();
|
|
968
|
+
```
|
|
969
|
+
|
|
970
|
+
Use `configure` for feature, layer, control and appearance changes; use `camera`
|
|
971
|
+
for viewport operations. Replace construction callbacks with `map.on` subscriptions.
|
|
972
|
+
For static-shell enhancement, call `mountGuideController(shell, options)` and keep
|
|
973
|
+
the returned controller for disposal.
|
|
974
|
+
|
|
975
|
+
## Site integrations
|
|
976
|
+
|
|
977
|
+
Pages builds require a v6-or-newer package and generate examples directly for that
|
|
978
|
+
contract. Older-package feature detection and flat-option fallback generation are
|
|
979
|
+
removed. Playground links must include `version: 1` in their design payload;
|
|
980
|
+
links produced by the current Share control already include it. Unversioned
|
|
981
|
+
handwritten links must add that field.
|
|
982
|
+
|
|
983
|
+
---
|
|
984
|
+
|
|
985
|
+
<!-- Generated from docs/migration-v5.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
942
986
|
|
|
943
987
|
# Migrating to v5
|
|
944
988
|
|
|
@@ -1043,7 +1087,7 @@ collections. Shared edges can match more than one feature. See the
|
|
|
1043
1087
|
|
|
1044
1088
|
---
|
|
1045
1089
|
|
|
1046
|
-
<!-- Generated from docs/migration-v3.md; @kahwee/sf-map-svg
|
|
1090
|
+
<!-- Generated from docs/migration-v3.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
1047
1091
|
|
|
1048
1092
|
# Migrate to version 3
|
|
1049
1093
|
|
|
@@ -1084,7 +1128,7 @@ District styles are now prepared once per district on construction and style/yea
|
|
|
1084
1128
|
|
|
1085
1129
|
---
|
|
1086
1130
|
|
|
1087
|
-
<!-- Generated from SOURCES.md; @kahwee/sf-map-svg
|
|
1131
|
+
<!-- Generated from SOURCES.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
1088
1132
|
|
|
1089
1133
|
# Geometry and provenance
|
|
1090
1134
|
|
|
@@ -1321,7 +1365,7 @@ Report-history points preserve only actual validated source counts and their dis
|
|
|
1321
1365
|
|
|
1322
1366
|
---
|
|
1323
1367
|
|
|
1324
|
-
<!-- Generated from CHANGELOG.md; @kahwee/sf-map-svg
|
|
1368
|
+
<!-- Generated from CHANGELOG.md; @kahwee/sf-map-svg 6.0.0 · local working tree. -->
|
|
1325
1369
|
|
|
1326
1370
|
# Changelog
|
|
1327
1371
|
|
|
@@ -1329,6 +1373,13 @@ User-visible changes are recorded here. Unreleased entries describe changes on `
|
|
|
1329
1373
|
|
|
1330
1374
|
## Unreleased
|
|
1331
1375
|
|
|
1376
|
+
## 6.0.0 — 2026-11-05
|
|
1377
|
+
|
|
1378
|
+
- Breaking: remove flat static presentation options. Use `layers` for geographic switches and `appearance` for theme, colors and district styles.
|
|
1379
|
+
- Breaking: remove element-based `createGuideMap` and `mountGuideMap` factories and their option/element aliases. Use `createGuideController` and `mountGuideController`, mount `.element`, and dispose the controller.
|
|
1380
|
+
- Remove older-package capability adapters from the site and snippet generator; require v6 or newer for Pages builds and versioned playground share links. Add a v6 migration guide and rejection coverage for removed contracts.
|
|
1381
|
+
- Use official sources only on the Pages election views: remove all newspaper and agency-compilation tallies, projections, history and their validation from the feed, views, trend charts and tests. Local measures without official counts read Pending until official counts are imported.
|
|
1382
|
+
|
|
1332
1383
|
## 5.1.4 — 2026-11-05
|
|
1333
1384
|
|
|
1334
1385
|
- Group internal browser controllers, renderers and shells under `src/interactive`, and SVG generation under `src/rendering`. Rename the general map engine, controls and marker renderer to match their responsibilities; clarify selection-detail, neighborhood-results and layer-composition operations. Keep public package entry points unchanged.
|
|
@@ -1729,7 +1780,7 @@ consistent home, and makes animation and subscription ownership predictable.
|
|
|
1729
1780
|
|
|
1730
1781
|
# Published type contracts
|
|
1731
1782
|
|
|
1732
|
-
@kahwee/sf-map-svg
|
|
1783
|
+
@kahwee/sf-map-svg 6.0.0 · local working tree. These declarations are generated by TypeScript. Use package export paths, not the internal filenames below. Imported relative contracts are included for context, not as additional public entry points.
|
|
1733
1784
|
|
|
1734
1785
|
| Public import | Declaration |
|
|
1735
1786
|
| --- | --- |
|
|
@@ -2143,10 +2194,7 @@ export interface MapOverlay {
|
|
|
2143
2194
|
visible?: boolean;
|
|
2144
2195
|
label?: string;
|
|
2145
2196
|
}
|
|
2146
|
-
export interface
|
|
2147
|
-
/** Grouped presentation; supplied keys take precedence over flat compatibility options. */
|
|
2148
|
-
layers?: StaticMapLayers;
|
|
2149
|
-
appearance?: StaticMapAppearance;
|
|
2197
|
+
export interface SvgRenderOptions {
|
|
2150
2198
|
theme?: 'districts' | 'transit';
|
|
2151
2199
|
width?: number;
|
|
2152
2200
|
height?: number;
|
|
@@ -2200,7 +2248,12 @@ export interface SFMapOptions {
|
|
|
2200
2248
|
}
|
|
2201
2249
|
/** Presentation supported by both the static and interactive renderers. */
|
|
2202
2250
|
export type StaticMapLayers = InteractiveLayers;
|
|
2203
|
-
export type StaticMapAppearance = Pick<
|
|
2251
|
+
export type StaticMapAppearance = Pick<SvgRenderOptions, 'theme' | 'colors' | 'districtStyle'>;
|
|
2252
|
+
/** Public static presentation uses the same grouped vocabulary as the map controller. */
|
|
2253
|
+
export type StaticMapOptions = Omit<SvgRenderOptions, keyof StaticMapLayers | keyof StaticMapAppearance> & {
|
|
2254
|
+
layers?: StaticMapLayers;
|
|
2255
|
+
appearance?: StaticMapAppearance;
|
|
2256
|
+
};
|
|
2204
2257
|
/** Serializable viewport in the interactive map's fixed 800 × 800 projected space. */
|
|
2205
2258
|
export type MapViewport = readonly [x: number, y: number, size: number];
|
|
2206
2259
|
export type ExplorerMode = 'neighborhoods' | 'districts' | 'basemap';
|
|
@@ -2270,8 +2323,8 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
|
|
|
2270
2323
|
source?: NeighborhoodSource;
|
|
2271
2324
|
neighborhood?: string;
|
|
2272
2325
|
year?: DistrictYear;
|
|
2273
|
-
theme?:
|
|
2274
|
-
colors?:
|
|
2326
|
+
theme?: SvgRenderOptions['theme'];
|
|
2327
|
+
colors?: SvgRenderOptions['colors'];
|
|
2275
2328
|
labelStyle?: {
|
|
2276
2329
|
fontFamily?: string;
|
|
2277
2330
|
fontWeight?: number;
|
|
@@ -2283,7 +2336,7 @@ export interface NeighborhoodExplorerOptions extends MapFeatures {
|
|
|
2283
2336
|
hoverFill?: string;
|
|
2284
2337
|
hoverStroke?: string;
|
|
2285
2338
|
};
|
|
2286
|
-
districtStyle?:
|
|
2339
|
+
districtStyle?: SvgRenderOptions['districtStyle'];
|
|
2287
2340
|
legend?: {
|
|
2288
2341
|
builtins?: boolean;
|
|
2289
2342
|
hidden?: readonly ('bart' | 'park' | 'highway' | 'road')[];
|
|
@@ -2349,7 +2402,7 @@ export interface NeighborhoodExplorerElement extends HTMLElement {
|
|
|
2349
2402
|
} & CameraOptions): boolean;
|
|
2350
2403
|
getSelectedDistrict(): DistrictSelection | null;
|
|
2351
2404
|
setDistrictYear(year: DistrictYear, options?: CameraOptions): void;
|
|
2352
|
-
setDistrictStyle(style:
|
|
2405
|
+
setDistrictStyle(style: SvgRenderOptions['districtStyle']): void;
|
|
2353
2406
|
setSource(source: NeighborhoodSource): void;
|
|
2354
2407
|
setMode(mode: ExplorerMode): void;
|
|
2355
2408
|
setLabels(visible: boolean): void;
|
|
@@ -2396,8 +2449,8 @@ export interface InteractiveSFMapData {
|
|
|
2396
2449
|
|
|
2397
2450
|
```ts
|
|
2398
2451
|
import type { Geometry, Position } from '../../data/types.js';
|
|
2399
|
-
import type { DistrictYear,
|
|
2400
|
-
export type { DistrictYear, MapMarker, MapOverlay,
|
|
2452
|
+
import type { DistrictYear, SvgRenderOptions } from '../types.js';
|
|
2453
|
+
export type { DistrictYear, MapMarker, MapOverlay, SvgRenderOptions } from '../types.js';
|
|
2401
2454
|
import { type Project } from '../geometry.js';
|
|
2402
2455
|
export interface SFMapData {
|
|
2403
2456
|
coast: Geometry;
|
|
@@ -2447,7 +2500,7 @@ export interface BartStationData {
|
|
|
2447
2500
|
export declare const districtYears: readonly DistrictYear[];
|
|
2448
2501
|
export declare const districtColors: readonly string[];
|
|
2449
2502
|
/** Canonical geometry in the same fitted coordinate space used by renderMap. */
|
|
2450
|
-
export declare function getLayerPathsWithData(options:
|
|
2503
|
+
export declare function getLayerPathsWithData(options: SvgRenderOptions, data: SFMapData, complete?: boolean): {
|
|
2451
2504
|
year: DistrictYear;
|
|
2452
2505
|
viewBox: [number, number, number, number];
|
|
2453
2506
|
project: (coordinates: Position) => [number, number];
|
|
@@ -2479,7 +2532,7 @@ export declare function getLayerPathsWithData(options: SFMapOptions, data: SFMap
|
|
|
2479
2532
|
point: [number, number];
|
|
2480
2533
|
}[];
|
|
2481
2534
|
};
|
|
2482
|
-
export declare function resolveMapColors(theme:
|
|
2535
|
+
export declare function resolveMapColors(theme: SvgRenderOptions['theme'], colors?: SvgRenderOptions['colors']): {
|
|
2483
2536
|
water: string;
|
|
2484
2537
|
land: string;
|
|
2485
2538
|
district: string;
|
|
@@ -2494,7 +2547,7 @@ export declare function resolveMapColors(theme: SFMapOptions['theme'], colors?:
|
|
|
2494
2547
|
selected: string;
|
|
2495
2548
|
};
|
|
2496
2549
|
/** Make an offline SVG and the matching longitude/latitude projection. */
|
|
2497
|
-
export declare function createSFMapWithData(options:
|
|
2550
|
+
export declare function createSFMapWithData(options: SvgRenderOptions, data: SFMapData, renderLabels?: (project: Project) => string): {
|
|
2498
2551
|
svg: string;
|
|
2499
2552
|
project: (coordinates: Position) => [number, number];
|
|
2500
2553
|
viewBox: [number, number, number, number];
|
|
@@ -2521,19 +2574,19 @@ export declare function geometryContainsPoint(geometry: Geometry | null | undefi
|
|
|
2521
2574
|
```ts
|
|
2522
2575
|
import type { InteractiveSFMapData } from './explorer-data.js';
|
|
2523
2576
|
import { type SFMapData } from './rendering/svg-map-renderer.js';
|
|
2524
|
-
import type {
|
|
2577
|
+
import type { StaticMapOptions } from './types.js';
|
|
2525
2578
|
/** Either compact static geography or the same source-aware geography used by createMap. */
|
|
2526
2579
|
export type StaticMapInput = SFMapData | InteractiveSFMapData;
|
|
2527
2580
|
export type { DistrictRowData, SFMapData as StaticMapData } from './rendering/svg-map-renderer.js';
|
|
2528
|
-
export type { DistrictStyle, DistrictYear,
|
|
2581
|
+
export type { DistrictStyle, DistrictYear, StaticMapAppearance, StaticMapLayers, StaticMapOptions, } from './types.js';
|
|
2529
2582
|
/** Server-safe SVG rendering with explicit data; returns SVG plus projection helpers. */
|
|
2530
|
-
export declare function renderMap(data: StaticMapInput, options?:
|
|
2583
|
+
export declare function renderMap(data: StaticMapInput, options?: StaticMapOptions): {
|
|
2531
2584
|
svg: string;
|
|
2532
2585
|
project: (coordinates: import("./geometry.js").Position) => [number, number];
|
|
2533
2586
|
viewBox: [number, number, number, number];
|
|
2534
2587
|
};
|
|
2535
2588
|
/** Project canonical layer geometry without constructing an SVG string. */
|
|
2536
|
-
export declare function getLayerPaths(data: StaticMapInput, options?:
|
|
2589
|
+
export declare function getLayerPaths(data: StaticMapInput, options?: StaticMapOptions): {
|
|
2537
2590
|
year: import("./types.js").DistrictYear;
|
|
2538
2591
|
viewBox: [number, number, number, number];
|
|
2539
2592
|
project: (coordinates: import("./geometry.js").Position) => [number, number];
|
|
@@ -2707,8 +2760,8 @@ export type { MapController, MapOptions } from './controller-types.js';
|
|
|
2707
2760
|
export type { InteractiveSFMapData } from './explorer-data.js';
|
|
2708
2761
|
export { guideMapData } from './guide-data.js';
|
|
2709
2762
|
export { loadGuideDetailedData } from './guide-detailed.js';
|
|
2710
|
-
export { createGuideController,
|
|
2711
|
-
export type { CameraOptions, MapFeatures, MapMarker,
|
|
2763
|
+
export { createGuideController, mountGuideController, } from './guide-map.js';
|
|
2764
|
+
export type { CameraOptions, MapFeatures, MapMarker, } from './types.js';
|
|
2712
2765
|
```
|
|
2713
2766
|
|
|
2714
2767
|
### dist/src/guide-data.d.ts
|
|
@@ -2731,17 +2784,10 @@ export declare function loadGuideDetailedData(): Promise<InteractiveSFMapData>;
|
|
|
2731
2784
|
|
|
2732
2785
|
```ts
|
|
2733
2786
|
import type { MapController, MapOptions } from './controller-types.js';
|
|
2734
|
-
import type { NeighborhoodExplorerElement as InteractiveSFMapElement, NeighborhoodExplorerOptions as InteractiveSFMapOptions } from './types.js';
|
|
2735
2787
|
/** Preferred guide API: the same grouped options, events, camera and lifecycle as createMap. */
|
|
2736
2788
|
export declare function createGuideController(options?: MapOptions): MapController;
|
|
2737
2789
|
/** Enhance a static guide shell and return its owning controller. */
|
|
2738
2790
|
export declare function mountGuideController(shell: HTMLElement, options?: MapOptions): MapController;
|
|
2739
|
-
/** Element-based compatibility API. Prefer createGuideController for new integrations. */
|
|
2740
|
-
export declare function createGuideMap(options?: InteractiveSFMapOptions): InteractiveSFMapElement;
|
|
2741
|
-
/** Enhance createGuideShell() in place with a fixed compact chrome layout.
|
|
2742
|
-
* Keep an accessible external place list when hiding the native pickers.
|
|
2743
|
-
*/
|
|
2744
|
-
export declare function mountGuideMap(shell: HTMLElement, options?: InteractiveSFMapOptions): InteractiveSFMapElement;
|
|
2745
2791
|
```
|
|
2746
2792
|
|
|
2747
2793
|
### ./dist/src/transit.d.ts
|
|
@@ -2755,15 +2801,15 @@ export declare function createTransitAnimation(): TransitAnimationElement;
|
|
|
2755
2801
|
### ./dist/src/guide-static.d.ts
|
|
2756
2802
|
|
|
2757
2803
|
```ts
|
|
2758
|
-
import type {
|
|
2804
|
+
import type { StaticMapOptions } from './types.js';
|
|
2759
2805
|
/** Server-safe overview using exactly the guide browser geography. */
|
|
2760
|
-
export declare function createGuideSVG(options?:
|
|
2806
|
+
export declare function createGuideSVG(options?: StaticMapOptions): {
|
|
2761
2807
|
svg: string;
|
|
2762
2808
|
project: (coordinates: import("./geometry.js").Position) => [number, number];
|
|
2763
2809
|
viewBox: [number, number, number, number];
|
|
2764
2810
|
};
|
|
2765
|
-
/** Stable compact frame, progressively enhanced with
|
|
2766
|
-
export declare function createGuideShell(options?:
|
|
2811
|
+
/** Stable compact frame, progressively enhanced with mountGuideController(). No browser globals. */
|
|
2812
|
+
export declare function createGuideShell(options?: StaticMapOptions): string;
|
|
2767
2813
|
```
|
|
2768
2814
|
|
|
2769
2815
|
### ./dist/src/presets.d.ts
|
|
@@ -2778,10 +2824,10 @@ export { type MapPalette, mapPalettes } from './palettes.js';
|
|
|
2778
2824
|
### dist/src/palettes.d.ts
|
|
2779
2825
|
|
|
2780
2826
|
```ts
|
|
2781
|
-
import type {
|
|
2827
|
+
import type { SvgRenderOptions } from './types.js';
|
|
2782
2828
|
/** Shared tokens for static SVGs, interactive maps, and consumer-owned place cards. */
|
|
2783
2829
|
export interface MapPalette {
|
|
2784
|
-
readonly colors: NonNullable<
|
|
2830
|
+
readonly colors: NonNullable<SvgRenderOptions['colors']>;
|
|
2785
2831
|
readonly haloColor: string;
|
|
2786
2832
|
readonly markerColor: string;
|
|
2787
2833
|
readonly selectedMarkerColor: string;
|
package/llms.txt
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Offline San Francisco SVG maps with explicit geographic imports, no runtime dependencies, static rendering, and a browser controller.
|
|
4
4
|
|
|
5
|
-
@kahwee/sf-map-svg
|
|
5
|
+
@kahwee/sf-map-svg 6.0.0 · local working tree. Node >=24.0.0 for server rendering; browsers need a DOM and a JSON-capable bundler.
|
|
6
6
|
|
|
7
7
|
These are working-tree docs. Unreleased changelog entries may describe APIs absent from npm; verify the installed version before copying them.
|
|
8
8
|
|
|
@@ -15,6 +15,7 @@ Use renderMap(data, options) for SVG strings; createMap(data, options) returns a
|
|
|
15
15
|
- [API options and lifecycle](https://kahwee.github.io/sf-map-svg/api-options.md)
|
|
16
16
|
- [Worked examples](https://kahwee.github.io/sf-map-svg/examples.md)
|
|
17
17
|
- [Consumer integration](https://kahwee.github.io/sf-map-svg/consumer-integration.md)
|
|
18
|
+
- [Migration to v6](https://kahwee.github.io/sf-map-svg/migration-v6.md)
|
|
18
19
|
- [Migration to v5](https://kahwee.github.io/sf-map-svg/migration-v5.md)
|
|
19
20
|
- [Migration from removed APIs](https://kahwee.github.io/sf-map-svg/migration-v3.md)
|
|
20
21
|
- [Exact TypeScript contracts](https://kahwee.github.io/sf-map-svg/types.md)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kahwee/sf-map-svg",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Offline SVG maps of San Francisco with district boundaries, parks, landmarks, and BART stations.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/api.js",
|
|
@@ -128,6 +128,7 @@
|
|
|
128
128
|
"docs/guide-bundle-report.md",
|
|
129
129
|
"docs/migration-v3.md",
|
|
130
130
|
"docs/migration-v5.md",
|
|
131
|
+
"docs/migration-v6.md",
|
|
131
132
|
"CHANGELOG.md",
|
|
132
133
|
"docs/API.md",
|
|
133
134
|
"docs/developer-guide.md",
|