@cfasim-ui/docs 0.6.1 → 0.6.2
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.
|
@@ -258,6 +258,8 @@ Use an array of `CategoricalStop` objects to map string values to colors. Each s
|
|
|
258
258
|
|
|
259
259
|
Set `geoType="counties"` to render county-level data using 5-digit FIPS codes. State borders are drawn on top for context. Use `pan` and `zoom` props to enable interactive navigation — useful for dense county data.
|
|
260
260
|
|
|
261
|
+
On touch devices, add `two-finger-pan` so a single finger scrolls the page (the map sets `touch-action: pan-y`) and two fingers pan/pinch-zoom the map — tap-to-select still works with one finger.
|
|
262
|
+
|
|
261
263
|
<ComponentDemo>
|
|
262
264
|
<ChoroplethMap
|
|
263
265
|
:topology="countiesTopo"
|
|
@@ -356,6 +358,58 @@ Set `geoType="hsas"` to render Health Service Area boundaries. HSAs are dissolve
|
|
|
356
358
|
</template>
|
|
357
359
|
</ComponentDemo>
|
|
358
360
|
|
|
361
|
+
### Single-state map (`state`)
|
|
362
|
+
|
|
363
|
+
Set the `state` prop to render just one state's outline with its `counties` or
|
|
364
|
+
`hsas` inside it — no surrounding states — and the projection zooms to fit it.
|
|
365
|
+
Accepts a state **name** (`"California"`) or a 2-digit **FIPS code** (`"06"`).
|
|
366
|
+
This needs a counties topology (the same `us-atlas/counties-10m.json`). `data`
|
|
367
|
+
can stay national; only features inside the selected state are drawn and
|
|
368
|
+
colored.
|
|
369
|
+
|
|
370
|
+
<ComponentDemo>
|
|
371
|
+
<ChoroplethMap
|
|
372
|
+
:topology="countiesTopo"
|
|
373
|
+
geo-type="counties"
|
|
374
|
+
state="California"
|
|
375
|
+
:data="[
|
|
376
|
+
{ id: '06037', value: 100 },
|
|
377
|
+
{ id: '06073', value: 80 },
|
|
378
|
+
{ id: '06059', value: 65 },
|
|
379
|
+
{ id: '06065', value: 55 },
|
|
380
|
+
{ id: '06001', value: 45 },
|
|
381
|
+
{ id: '06085', value: 40 },
|
|
382
|
+
]"
|
|
383
|
+
title="California cases by county"
|
|
384
|
+
:legend-title="'Cases'"
|
|
385
|
+
:height="400"
|
|
386
|
+
/>
|
|
387
|
+
|
|
388
|
+
<template #code>
|
|
389
|
+
|
|
390
|
+
```vue
|
|
391
|
+
<ChoroplethMap
|
|
392
|
+
:topology="countiesTopo"
|
|
393
|
+
geo-type="counties"
|
|
394
|
+
state="California"
|
|
395
|
+
:data="[
|
|
396
|
+
{ id: '06037', value: 100 }, // Los Angeles
|
|
397
|
+
{ id: '06073', value: 80 }, // San Diego
|
|
398
|
+
{ id: '06059', value: 65 }, // Orange
|
|
399
|
+
]"
|
|
400
|
+
title="California cases by county"
|
|
401
|
+
:legend-title="'Cases'"
|
|
402
|
+
:height="400"
|
|
403
|
+
/>
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
</template>
|
|
407
|
+
</ComponentDemo>
|
|
408
|
+
|
|
409
|
+
Switch `geo-type="hsas"` to fill the same state with Health Service Areas
|
|
410
|
+
instead. An unrecognized `state` value logs a warning and falls back to the
|
|
411
|
+
full national map.
|
|
412
|
+
|
|
359
413
|
### Click to focus (`v-model:focus`)
|
|
360
414
|
|
|
361
415
|
Bind the `focus` prop to pan and zoom to a specific feature. Pass a feature
|
|
@@ -365,6 +419,10 @@ the focused feature toggles back off. If a tooltip is configured, focusing
|
|
|
365
419
|
shows that feature's tooltip. Users can pan/zoom freely around the focused
|
|
366
420
|
area; the built-in **Reset** button clears focus and snaps back.
|
|
367
421
|
|
|
422
|
+
Set `:focus-zoom="false"` to highlight (and draw cross-geoType overlays)
|
|
423
|
+
**without** panning or zooming — useful for a click-to-select interaction
|
|
424
|
+
where the map should stay put while a side panel shows the details.
|
|
425
|
+
|
|
368
426
|
Selection works on touch too: a single-finger **tap** on a feature emits
|
|
369
427
|
`stateClick` and toggles focus, while drags (pan) and pinches (zoom) are left
|
|
370
428
|
to the map. Hover tooltips stay off on touch for performance.
|
|
@@ -695,6 +753,7 @@ set `tooltip-trigger`.
|
|
|
695
753
|
| `data` | `StateData[]` | No | — |
|
|
696
754
|
| `geoType` | `GeoType` | No | `"states"` |
|
|
697
755
|
| `dataGeoType` | `GeoType` | No | — |
|
|
756
|
+
| `state` | `string` | No | — |
|
|
698
757
|
| `width` | `number` | No | — |
|
|
699
758
|
| `height` | `number` | No | — |
|
|
700
759
|
| `colorScale` | `ChoroplethColorScale \| ThresholdStop[] \| CategoricalStop[]` | No | — |
|
|
@@ -709,6 +768,7 @@ set `tooltip-trigger`.
|
|
|
709
768
|
| `legendTitle` | `string` | No | — |
|
|
710
769
|
| `zoom` | `boolean` | No | `false` |
|
|
711
770
|
| `pan` | `boolean` | No | `false` |
|
|
771
|
+
| `twoFingerPan` | `boolean` | No | `false` |
|
|
712
772
|
| `tooltipTrigger` | `"hover" \| "click"` | No | — |
|
|
713
773
|
| `tooltipFormat` | `(data: {
|
|
714
774
|
id: string` | No | — |
|
|
@@ -718,6 +778,7 @@ set `tooltip-trigger`.
|
|
|
718
778
|
| `tooltipClamp` | `"none" \| "chart" \| "window"` | No | `"chart"` |
|
|
719
779
|
| `focus` | `FocusValue` | No | — |
|
|
720
780
|
| `focusZoomLevel` | `number` | No | `4` |
|
|
781
|
+
| `focusZoom` | `boolean` | No | `true` |
|
|
721
782
|
| `fullscreenTarget` | `string \| HTMLElement` | No | — |
|
|
722
783
|
|
|
723
784
|
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
toRaw,
|
|
9
9
|
useSlots,
|
|
10
10
|
} from "vue";
|
|
11
|
-
import { geoPath, geoAlbersUsa } from "d3-geo";
|
|
11
|
+
import { geoPath, geoAlbersUsa, geoMercator } from "d3-geo";
|
|
12
12
|
import { zoom as d3Zoom, zoomIdentity } from "d3-zoom";
|
|
13
13
|
import { select } from "d3-selection";
|
|
14
14
|
// Side-effect import: enables `selection.transition()` on d3 selections so
|
|
@@ -107,6 +107,15 @@ const props = withDefaults(
|
|
|
107
107
|
* When unset, data ids must match the base `geoType`.
|
|
108
108
|
*/
|
|
109
109
|
dataGeoType?: GeoType;
|
|
110
|
+
/**
|
|
111
|
+
* Scope the map to a single state: render only that state's outline with
|
|
112
|
+
* its `counties` or `hsas` inside it (no surrounding states), and refit
|
|
113
|
+
* the projection to zoom to it. Accepts a state name ("California") or a
|
|
114
|
+
* 2-digit FIPS code ("06"). Requires a counties topology when `geoType`
|
|
115
|
+
* is `"counties"` or `"hsas"`. If the value matches no state, the full
|
|
116
|
+
* national map is rendered and a warning is logged.
|
|
117
|
+
*/
|
|
118
|
+
state?: string;
|
|
110
119
|
width?: number;
|
|
111
120
|
height?: number;
|
|
112
121
|
colorScale?: ChoroplethColorScale | ThresholdStop[] | CategoricalStop[];
|
|
@@ -131,6 +140,14 @@ const props = withDefaults(
|
|
|
131
140
|
zoom?: boolean;
|
|
132
141
|
/** Enable click-and-drag panning. Default: false */
|
|
133
142
|
pan?: boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Require two fingers to pan/zoom on touch devices. Default `false`.
|
|
145
|
+
* When `true`, a single finger scrolls the page (the map sets
|
|
146
|
+
* `touch-action: pan-y` and ignores one-finger drags) while two fingers
|
|
147
|
+
* pan and pinch-zoom the map. Single-finger tap-to-select still works.
|
|
148
|
+
* Has no effect with a mouse.
|
|
149
|
+
*/
|
|
150
|
+
twoFingerPan?: boolean;
|
|
134
151
|
/** Tooltip activation mode */
|
|
135
152
|
tooltipTrigger?: "hover" | "click";
|
|
136
153
|
/**
|
|
@@ -174,6 +191,14 @@ const props = withDefaults(
|
|
|
174
191
|
focus?: FocusValue;
|
|
175
192
|
/** Scale factor applied when `focus` is set. Default: 4 */
|
|
176
193
|
focusZoomLevel?: number;
|
|
194
|
+
/**
|
|
195
|
+
* Whether setting `focus` pans/zooms to fit the focused feature.
|
|
196
|
+
* Default `true`. Set `false` to highlight (and draw cross-geoType
|
|
197
|
+
* overlays) without changing the current pan/zoom — useful for a
|
|
198
|
+
* click-to-select interaction where the map should stay put. The
|
|
199
|
+
* built-in Reset button is unaffected.
|
|
200
|
+
*/
|
|
201
|
+
focusZoom?: boolean;
|
|
177
202
|
/**
|
|
178
203
|
* Where to teleport the map while expanded (the Expand menu item). A
|
|
179
204
|
* CSS selector or element; defaults to `body`. Moving it to the
|
|
@@ -193,8 +218,10 @@ const props = withDefaults(
|
|
|
193
218
|
legend: true,
|
|
194
219
|
zoom: false,
|
|
195
220
|
pan: false,
|
|
221
|
+
twoFingerPan: false,
|
|
196
222
|
tooltipClamp: "chart",
|
|
197
223
|
focusZoomLevel: 4,
|
|
224
|
+
focusZoom: true,
|
|
198
225
|
},
|
|
199
226
|
);
|
|
200
227
|
|
|
@@ -425,16 +452,28 @@ function setupZoom() {
|
|
|
425
452
|
// Dynamic filter: re-evaluated per event, so toggling `focus`,
|
|
426
453
|
// `zoom`, or `pan` doesn't require tearing down the zoom behavior.
|
|
427
454
|
// When focus is active we always allow drag + wheel so users can
|
|
428
|
-
// explore away from the focused area regardless of `zoom`/`pan
|
|
455
|
+
// explore away from the focused area regardless of `zoom`/`pan` — but
|
|
456
|
+
// not in highlight-only mode (`focusZoom=false`), where focus is purely
|
|
457
|
+
// visual and shouldn't grant interaction the props didn't ask for.
|
|
429
458
|
// Programmatic `.transform()` calls bypass this filter entirely.
|
|
430
459
|
zoomBehavior.filter((event) => {
|
|
431
|
-
const focused =
|
|
460
|
+
const focused =
|
|
461
|
+
normalizedFocus.value.length > 0 && props.focusZoom !== false;
|
|
432
462
|
const allowZoom = !!props.zoom || focused;
|
|
433
463
|
const allowPan = !!props.pan || focused;
|
|
434
464
|
if (event.type === "wheel" || event.type === "dblclick") {
|
|
435
465
|
if (!allowZoom) return false;
|
|
436
466
|
} else if (event.type === "mousedown" || event.type === "touchstart") {
|
|
437
467
|
if (!allowPan) return false;
|
|
468
|
+
// Two-finger-only mode: ignore single-finger touches so the page can
|
|
469
|
+
// scroll; a second finger drives the map (pan + pinch-zoom).
|
|
470
|
+
if (
|
|
471
|
+
props.twoFingerPan &&
|
|
472
|
+
event.type === "touchstart" &&
|
|
473
|
+
(event as TouchEvent).touches.length < 2
|
|
474
|
+
) {
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
438
477
|
} else if (!allowZoom && !allowPan) {
|
|
439
478
|
return false;
|
|
440
479
|
}
|
|
@@ -541,6 +580,13 @@ function applyFocus() {
|
|
|
541
580
|
return;
|
|
542
581
|
}
|
|
543
582
|
|
|
583
|
+
// Highlight-only mode: the strokes + overlays above are applied; skip the
|
|
584
|
+
// pan/zoom transform so the current view stays put (click-to-select).
|
|
585
|
+
if (props.focusZoom === false) {
|
|
586
|
+
focusApplied = true;
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
|
|
544
590
|
const svg = select(svgRef.value);
|
|
545
591
|
// Always cancel any in-flight transition first — d3-transition queues
|
|
546
592
|
// same-named transitions rather than replacing them, so rapid focus
|
|
@@ -667,6 +713,19 @@ watch(
|
|
|
667
713
|
},
|
|
668
714
|
);
|
|
669
715
|
|
|
716
|
+
// Switching the scoped `state` refits the projection to a different region,
|
|
717
|
+
// so any leftover pan/zoom transform would leave the new map off-center.
|
|
718
|
+
// Reset it instantly (no animation) when the region changes.
|
|
719
|
+
watch(
|
|
720
|
+
() => props.state,
|
|
721
|
+
() => {
|
|
722
|
+
if (!svgRef.value || !zoomBehavior) return;
|
|
723
|
+
const svg = select(svgRef.value);
|
|
724
|
+
svg.interrupt();
|
|
725
|
+
zoomBehavior.transform(svg, zoomIdentity);
|
|
726
|
+
},
|
|
727
|
+
);
|
|
728
|
+
|
|
670
729
|
// Canonical internal coordinate system. All layout (projection, legend,
|
|
671
730
|
// title) is computed at this size; the SVG's viewBox makes the browser
|
|
672
731
|
// scale the entire canvas to whatever the container provides, so there's no
|
|
@@ -692,6 +751,58 @@ type CountiesTopo = Topology<{
|
|
|
692
751
|
states: NamedGeometry;
|
|
693
752
|
}>;
|
|
694
753
|
|
|
754
|
+
type StateFeature = GeoJSON.Feature<GeoJSON.Geometry | null, { name?: string }>;
|
|
755
|
+
|
|
756
|
+
// ─── Single-state scoping (`state` prop) ─────────────────────────────────
|
|
757
|
+
//
|
|
758
|
+
// Resolved directly from the topology's `states` object (not from
|
|
759
|
+
// featuresByGeoType) so it stays free of the featuresGeo → featuresById →
|
|
760
|
+
// featuresByGeoType chain — that chain reads `stateFips`, so depending on it
|
|
761
|
+
// here would form a reactive cycle.
|
|
762
|
+
const statesFeatures = computed<StateFeature[]>(() => {
|
|
763
|
+
const topo = toRaw(props.topology) as unknown as {
|
|
764
|
+
objects?: { states?: NamedGeometry };
|
|
765
|
+
};
|
|
766
|
+
const statesObj = topo?.objects?.states;
|
|
767
|
+
if (!statesObj) return [];
|
|
768
|
+
const fc = feature(topo as unknown as Topology, statesObj) as
|
|
769
|
+
| GeoJSON.FeatureCollection<GeoJSON.Geometry | null, { name?: string }>
|
|
770
|
+
| StateFeature;
|
|
771
|
+
return fc.type === "FeatureCollection" ? fc.features : [fc];
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
// 2-digit FIPS for the active `state` prop, or null when unset/unresolved.
|
|
775
|
+
const stateFips = computed<string | null>(() => {
|
|
776
|
+
const s = props.state?.trim();
|
|
777
|
+
if (!s) return null;
|
|
778
|
+
if (/^\d{1,2}$/.test(s)) return s.padStart(2, "0");
|
|
779
|
+
const match = statesFeatures.value.find((f) => f.properties?.name === s);
|
|
780
|
+
return match?.id != null ? String(match.id).padStart(2, "0") : null;
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
// The single state's GeoJSON feature — drives the outline path and the
|
|
784
|
+
// projection fit in single-state mode.
|
|
785
|
+
const stateOutlineFeature = computed<StateFeature | null>(() => {
|
|
786
|
+
const fips = stateFips.value;
|
|
787
|
+
if (!fips) return null;
|
|
788
|
+
return (
|
|
789
|
+
statesFeatures.value.find((f) => String(f.id).padStart(2, "0") === fips) ??
|
|
790
|
+
null
|
|
791
|
+
);
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
watch(
|
|
795
|
+
() => [props.state, stateFips.value] as const,
|
|
796
|
+
([state, fips]) => {
|
|
797
|
+
if (state && state.trim() && !fips) {
|
|
798
|
+
console.warn(
|
|
799
|
+
`[ChoroplethMap] state="${state}" matched no state name or FIPS code; rendering the full map.`,
|
|
800
|
+
);
|
|
801
|
+
}
|
|
802
|
+
},
|
|
803
|
+
{ immediate: true },
|
|
804
|
+
);
|
|
805
|
+
|
|
695
806
|
// HSA mapping is loaded lazily — it's ~25KB gzipped and only needed when
|
|
696
807
|
// geoType or dataGeoType is "hsas". Keeps the main bundle small for users
|
|
697
808
|
// who only need states/counties maps.
|
|
@@ -727,10 +838,14 @@ const hsaFeaturesGeo = computed(() => {
|
|
|
727
838
|
const { fipsToHsa, hsaNames } = mod;
|
|
728
839
|
const topo = toRaw(props.topology) as unknown as CountiesTopo;
|
|
729
840
|
const countyGeometries = topo.objects.counties.geometries;
|
|
841
|
+
const scopeFips = stateFips.value;
|
|
730
842
|
const groups = new Map<string, typeof countyGeometries>();
|
|
731
843
|
|
|
732
844
|
for (const geom of countyGeometries) {
|
|
733
845
|
const fips = String(geom.id).padStart(5, "0");
|
|
846
|
+
// Single-state mode: drop counties outside the state before grouping, so
|
|
847
|
+
// the resulting HSAs only cover the selected state.
|
|
848
|
+
if (scopeFips && fips.slice(0, 2) !== scopeFips) continue;
|
|
734
849
|
const hsaCode = fipsToHsa[fips];
|
|
735
850
|
if (!hsaCode) continue;
|
|
736
851
|
if (!groups.has(hsaCode)) groups.set(hsaCode, []);
|
|
@@ -751,30 +866,71 @@ const hsaFeaturesGeo = computed(() => {
|
|
|
751
866
|
});
|
|
752
867
|
|
|
753
868
|
const featuresGeo = computed(() => {
|
|
869
|
+
// hsaFeaturesGeo already honors `state` (it scopes the source counties).
|
|
754
870
|
if (props.geoType === "hsas") return hsaFeaturesGeo.value;
|
|
871
|
+
const scopeFips = stateFips.value;
|
|
755
872
|
if (props.geoType === "counties") {
|
|
756
873
|
const topo = toRaw(props.topology) as unknown as CountiesTopo;
|
|
757
|
-
|
|
874
|
+
const fc = feature(topo, topo.objects.counties);
|
|
875
|
+
if (!scopeFips) return fc;
|
|
876
|
+
return {
|
|
877
|
+
type: "FeatureCollection" as const,
|
|
878
|
+
features: fc.features.filter(
|
|
879
|
+
(f) => String(f.id).padStart(5, "0").slice(0, 2) === scopeFips,
|
|
880
|
+
),
|
|
881
|
+
};
|
|
758
882
|
}
|
|
759
883
|
const topo = toRaw(props.topology) as unknown as StatesTopo;
|
|
760
|
-
|
|
884
|
+
const fc = feature(topo, topo.objects.states);
|
|
885
|
+
if (!scopeFips) return fc;
|
|
886
|
+
return {
|
|
887
|
+
type: "FeatureCollection" as const,
|
|
888
|
+
features: fc.features.filter(
|
|
889
|
+
(f) => String(f.id).padStart(2, "0") === scopeFips,
|
|
890
|
+
),
|
|
891
|
+
};
|
|
761
892
|
});
|
|
762
893
|
|
|
763
894
|
const stateBordersPath = computed(() => {
|
|
764
895
|
if (props.geoType !== "counties" && props.geoType !== "hsas") return null;
|
|
896
|
+
// Single-state mode: trace just the selected state's outline instead of
|
|
897
|
+
// the full national state-border mesh.
|
|
898
|
+
if (stateFips.value) return stateOutlineFeature.value;
|
|
765
899
|
const topo = toRaw(props.topology) as unknown as CountiesTopo;
|
|
766
900
|
return mesh(topo, topo.objects.states, (a, b) => a !== b);
|
|
767
901
|
});
|
|
768
902
|
|
|
769
|
-
|
|
770
|
-
|
|
903
|
+
// Breathing room (canonical px) around a single state so its outline isn't
|
|
904
|
+
// flush against the SVG edge. Only applied in single-state mode.
|
|
905
|
+
const STATE_FIT_INSET = 12;
|
|
906
|
+
|
|
907
|
+
const projection = computed(() => {
|
|
908
|
+
const outline = stateOutlineFeature.value;
|
|
909
|
+
if (stateFips.value && outline) {
|
|
910
|
+
const extent: [[number, number], [number, number]] = [
|
|
911
|
+
[STATE_FIT_INSET, STATE_FIT_INSET],
|
|
912
|
+
[width.value - STATE_FIT_INSET, height.value - STATE_FIT_INSET],
|
|
913
|
+
];
|
|
914
|
+
const albers = geoAlbersUsa().fitExtent(extent, outline);
|
|
915
|
+
// geoAlbersUsa only covers the 50 states + DC (it handles Alaska and
|
|
916
|
+
// Hawaii via insets). The island territories — Puerto Rico, Guam, the
|
|
917
|
+
// US Virgin Islands, American Samoa, the N. Mariana Islands — fall
|
|
918
|
+
// outside it and project to null, so fitExtent yields a NaN transform
|
|
919
|
+
// and every path renders as "MNaN,NaN…". Detect that by projecting the
|
|
920
|
+
// outline's centroid and fall back to a plain Mercator that can render
|
|
921
|
+
// any region.
|
|
922
|
+
const c = geoPath(albers).centroid(outline);
|
|
923
|
+
if (Number.isFinite(c[0]) && Number.isFinite(c[1])) return albers;
|
|
924
|
+
return geoMercator().fitExtent(extent, outline);
|
|
925
|
+
}
|
|
926
|
+
return geoAlbersUsa().fitExtent(
|
|
771
927
|
[
|
|
772
928
|
[0, 0],
|
|
773
929
|
[width.value, height.value],
|
|
774
930
|
],
|
|
775
931
|
featuresGeo.value,
|
|
776
|
-
)
|
|
777
|
-
);
|
|
932
|
+
);
|
|
933
|
+
});
|
|
778
934
|
|
|
779
935
|
const pathGenerator = computed(() => geoPath(projection.value));
|
|
780
936
|
|
|
@@ -1481,9 +1637,12 @@ const menuItems = computed<ChartMenuItem[]>(() => {
|
|
|
1481
1637
|
// Registered last so the eagerly-evaluated source getters can read every
|
|
1482
1638
|
// computed defined above without hitting a TDZ.
|
|
1483
1639
|
|
|
1484
|
-
// Geometry / projection / tooltip-mode → full rebuild.
|
|
1640
|
+
// Geometry / projection / tooltip-mode → full rebuild. `featuresGeo` is
|
|
1641
|
+
// watched explicitly because in single-state mode the projection is pinned
|
|
1642
|
+
// to the static state outline, so an async change to the feature set (e.g.
|
|
1643
|
+
// the lazy HSA module resolving) wouldn't otherwise change `pathGenerator`.
|
|
1485
1644
|
watch(
|
|
1486
|
-
() => [pathGenerator.value, hasInteractiveTooltip.value],
|
|
1645
|
+
() => [featuresGeo.value, pathGenerator.value, hasInteractiveTooltip.value],
|
|
1487
1646
|
() => rebuildPaths(),
|
|
1488
1647
|
);
|
|
1489
1648
|
|
|
@@ -1596,6 +1755,7 @@ watch(
|
|
|
1596
1755
|
ref="svgRef"
|
|
1597
1756
|
:viewBox="`0 0 ${width} ${height}`"
|
|
1598
1757
|
preserveAspectRatio="xMidYMid meet"
|
|
1758
|
+
:style="twoFingerPan ? { touchAction: 'pan-y' } : undefined"
|
|
1599
1759
|
>
|
|
1600
1760
|
<!--
|
|
1601
1761
|
Path elements are created imperatively in `rebuildPaths()`; Vue never
|
package/index.json
CHANGED