@opendata-ai/openchart-vanilla 8.6.4 → 8.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-RYVV3YIG.js → chunk-DFKLAB67.js} +3 -3
- package/dist/chunk-DFKLAB67.js.map +1 -0
- package/dist/{chunk-CPULCRVF.js → chunk-EZQDCLZN.js} +2 -2
- package/dist/{chunk-6B5OBGIO.js → chunk-I73B3DJI.js} +2 -2
- package/dist/chunk-I73B3DJI.js.map +1 -0
- package/dist/{chunk-W3WPGHYV.js → chunk-QBTRAQAX.js} +795 -124
- package/dist/chunk-QBTRAQAX.js.map +1 -0
- package/dist/{chunk-5RX6ZQGZ.js → chunk-SDJHUELU.js} +1 -2
- package/dist/chunk-SDJHUELU.js.map +1 -0
- package/dist/{chunk-MDK6AILK.js → chunk-SXTHPXG6.js} +2 -2
- package/dist/{chunk-MDK6AILK.js.map → chunk-SXTHPXG6.js.map} +1 -1
- package/dist/export-gif.d.ts +1 -1
- package/dist/export-gif.js +3 -3
- package/dist/index.d.ts +15 -2
- package/dist/index.js +6 -6
- package/dist/{mount-Bs8nFSf1.d.ts → mount-WiY9BIr9.d.ts} +1 -1
- package/dist/static.js +3 -3
- package/dist/story/index.d.ts +2 -2
- package/dist/story/index.js +4 -4
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-5RX6ZQGZ.js.map +0 -1
- package/dist/chunk-6B5OBGIO.js.map +0 -1
- package/dist/chunk-RYVV3YIG.js.map +0 -1
- package/dist/chunk-W3WPGHYV.js.map +0 -1
- /package/dist/{chunk-CPULCRVF.js.map → chunk-EZQDCLZN.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
exportPNG,
|
|
5
5
|
exportSVG,
|
|
6
6
|
exportSVGWithFonts
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-I73B3DJI.js";
|
|
8
8
|
import {
|
|
9
9
|
buildGradientDefs,
|
|
10
10
|
buildPatternDefs,
|
|
@@ -17,12 +17,12 @@ import {
|
|
|
17
17
|
resolveMarkFill,
|
|
18
18
|
resolvePatternFill,
|
|
19
19
|
stampAnimationVars
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-SXTHPXG6.js";
|
|
21
21
|
import {
|
|
22
22
|
SVG_NS,
|
|
23
23
|
createSVGElement,
|
|
24
24
|
setAttrs
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-SDJHUELU.js";
|
|
26
26
|
import {
|
|
27
27
|
AnimationScheduler,
|
|
28
28
|
SpatialIndex,
|
|
@@ -3122,21 +3122,40 @@ function applySecondaryOpacity(els, elapsed, enterDelay, enterDuration) {
|
|
|
3122
3122
|
}
|
|
3123
3123
|
}
|
|
3124
3124
|
|
|
3125
|
+
// src/dom-helpers.ts
|
|
3126
|
+
function applySrOnlyStyles(el) {
|
|
3127
|
+
el.style.position = "absolute";
|
|
3128
|
+
el.style.width = "1px";
|
|
3129
|
+
el.style.height = "1px";
|
|
3130
|
+
el.style.padding = "0";
|
|
3131
|
+
el.style.margin = "-1px";
|
|
3132
|
+
el.style.overflow = "clip";
|
|
3133
|
+
el.style.clipPath = "inset(50%)";
|
|
3134
|
+
el.style.whiteSpace = "nowrap";
|
|
3135
|
+
el.style.borderWidth = "0";
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3125
3138
|
// src/you-draw-it.ts
|
|
3126
3139
|
var MIN_TOUCH_TARGET = 24;
|
|
3140
|
+
var TRAIL_RESOLUTION = 1e3;
|
|
3141
|
+
var START_SLOP_PX = 16;
|
|
3127
3142
|
function buildLinearPath(points) {
|
|
3128
3143
|
if (points.length === 0) return "";
|
|
3129
3144
|
const sorted = [...points].sort((a, b) => a.x - b.x);
|
|
3130
3145
|
return sorted.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
|
|
3131
3146
|
}
|
|
3147
|
+
function round2(n) {
|
|
3148
|
+
return Math.round(n * 100) / 100;
|
|
3149
|
+
}
|
|
3132
3150
|
function createYouDrawIt(options) {
|
|
3133
3151
|
const { container, onReveal } = options;
|
|
3134
3152
|
let destroyed = false;
|
|
3135
3153
|
let revealed = false;
|
|
3136
3154
|
let config = null;
|
|
3137
3155
|
let svgEl = null;
|
|
3138
|
-
const
|
|
3156
|
+
const trail = /* @__PURE__ */ new Map();
|
|
3139
3157
|
let cleanupPointerEvents = null;
|
|
3158
|
+
let activePointer = null;
|
|
3140
3159
|
function buildHatchPattern(id, color) {
|
|
3141
3160
|
const pattern = document.createElementNS(SVG_NS, "pattern");
|
|
3142
3161
|
pattern.setAttribute("id", id);
|
|
@@ -3219,11 +3238,12 @@ function createYouDrawIt(options) {
|
|
|
3219
3238
|
guessPath.setAttribute("pointer-events", "none");
|
|
3220
3239
|
group.appendChild(guessPath);
|
|
3221
3240
|
if (!revealed) {
|
|
3241
|
+
const overlayX = Math.max(area.x, fromX - START_SLOP_PX);
|
|
3222
3242
|
const overlay = createSVGElement("rect");
|
|
3223
3243
|
setAttrs(overlay, {
|
|
3224
|
-
x:
|
|
3244
|
+
x: overlayX,
|
|
3225
3245
|
y: area.y,
|
|
3226
|
-
width: regionWidth,
|
|
3246
|
+
width: regionWidth + (fromX - overlayX),
|
|
3227
3247
|
height: area.height,
|
|
3228
3248
|
fill: "transparent"
|
|
3229
3249
|
});
|
|
@@ -3240,97 +3260,146 @@ function createYouDrawIt(options) {
|
|
|
3240
3260
|
}
|
|
3241
3261
|
svg.appendChild(group);
|
|
3242
3262
|
}
|
|
3263
|
+
function regionWidthOf(cfg) {
|
|
3264
|
+
return Math.max(0, cfg.area.x + cfg.area.width - cfg.fromX);
|
|
3265
|
+
}
|
|
3266
|
+
function pxToIndex(cfg, px) {
|
|
3267
|
+
const w = regionWidthOf(cfg);
|
|
3268
|
+
if (w === 0) return 0;
|
|
3269
|
+
return (px - cfg.fromX) / w * TRAIL_RESOLUTION;
|
|
3270
|
+
}
|
|
3271
|
+
function indexToPx(cfg, index) {
|
|
3272
|
+
return cfg.fromX + index / TRAIL_RESOLUTION * regionWidthOf(cfg);
|
|
3273
|
+
}
|
|
3243
3274
|
function redrawGuessPath() {
|
|
3244
|
-
if (!svgEl) return;
|
|
3275
|
+
if (!svgEl || !config) return;
|
|
3245
3276
|
const path = svgEl.querySelector("[data-ydi-guess-path]");
|
|
3246
3277
|
if (!path) return;
|
|
3247
|
-
const
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
}
|
|
3260
|
-
}
|
|
3261
|
-
return nearestPx;
|
|
3278
|
+
const cfg = config;
|
|
3279
|
+
const keys = Array.from(trail.keys()).sort((a, b) => a - b);
|
|
3280
|
+
const d = keys.map((i, n) => {
|
|
3281
|
+
const cmd = n === 0 || i - keys[n - 1] > 1 ? "M" : "L";
|
|
3282
|
+
return `${cmd}${round2(indexToPx(cfg, i))},${round2(dataToPixelY(trail.get(i)))}`;
|
|
3283
|
+
}).join(" ");
|
|
3284
|
+
path.setAttribute("d", d);
|
|
3285
|
+
syncResetButton();
|
|
3286
|
+
}
|
|
3287
|
+
function clampX(px) {
|
|
3288
|
+
if (!config) return px;
|
|
3289
|
+
return Math.min(config.area.x + config.area.width, Math.max(config.fromX, px));
|
|
3262
3290
|
}
|
|
3263
3291
|
function clampY(py) {
|
|
3264
3292
|
if (!config) return py;
|
|
3265
3293
|
return Math.min(config.area.y + config.area.height, Math.max(config.area.y, py));
|
|
3266
3294
|
}
|
|
3295
|
+
function paintSegment(x0, y0, x1, y1) {
|
|
3296
|
+
if (!config) return;
|
|
3297
|
+
const i0 = pxToIndex(config, x0);
|
|
3298
|
+
const i1 = pxToIndex(config, x1);
|
|
3299
|
+
const lo = Math.max(0, Math.ceil(Math.min(i0, i1)));
|
|
3300
|
+
const hi = Math.min(TRAIL_RESOLUTION, Math.floor(Math.max(i0, i1)));
|
|
3301
|
+
const span = i1 - i0;
|
|
3302
|
+
for (let i = lo; i <= hi; i++) {
|
|
3303
|
+
const t = span === 0 ? 1 : (i - i0) / span;
|
|
3304
|
+
trail.set(i, pixelYToData(y0 + t * (y1 - y0)));
|
|
3305
|
+
}
|
|
3306
|
+
const end = Math.min(TRAIL_RESOLUTION, Math.max(0, Math.round(i1)));
|
|
3307
|
+
trail.set(end, pixelYToData(y1));
|
|
3308
|
+
}
|
|
3267
3309
|
function wirePointerEvents(svg) {
|
|
3268
3310
|
const overlay = svg.querySelector("[data-ydi-overlay]");
|
|
3269
3311
|
if (!overlay) return () => {
|
|
3270
3312
|
};
|
|
3271
|
-
let
|
|
3272
|
-
|
|
3313
|
+
let last = null;
|
|
3314
|
+
if (activePointer !== null) {
|
|
3315
|
+
try {
|
|
3316
|
+
overlay.setPointerCapture?.(activePointer);
|
|
3317
|
+
} catch {
|
|
3318
|
+
activePointer = null;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
const toSvgPoint = (clientX, clientY) => {
|
|
3273
3322
|
const svgRect = svg.getBoundingClientRect();
|
|
3274
3323
|
const viewBox = svg.viewBox?.baseVal;
|
|
3275
3324
|
const scaleX = viewBox?.width && svgRect.width ? viewBox.width / svgRect.width : 1;
|
|
3276
3325
|
const scaleY = viewBox?.height && svgRect.height ? viewBox.height / svgRect.height : 1;
|
|
3277
3326
|
return {
|
|
3278
|
-
|
|
3279
|
-
|
|
3327
|
+
x: clampX((clientX - svgRect.left) * scaleX),
|
|
3328
|
+
y: clampY((clientY - svgRect.top) * scaleY)
|
|
3280
3329
|
};
|
|
3281
3330
|
};
|
|
3282
|
-
const
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
guessByX.set(snapped, clampY(svgY));
|
|
3287
|
-
redrawGuessPath();
|
|
3331
|
+
const nearAnchor = (p) => {
|
|
3332
|
+
if (!config?.anchor) return false;
|
|
3333
|
+
if (p.x - config.fromX <= START_SLOP_PX) return true;
|
|
3334
|
+
return config.samples.length > 0 && p.x <= config.samples[0].px;
|
|
3288
3335
|
};
|
|
3289
|
-
const
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
paintAt(me.clientX, me.clientY);
|
|
3336
|
+
const endStroke = () => {
|
|
3337
|
+
activePointer = null;
|
|
3338
|
+
last = null;
|
|
3293
3339
|
};
|
|
3294
|
-
const
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3340
|
+
const handleDown = (e) => {
|
|
3341
|
+
const pe = e;
|
|
3342
|
+
if (pe.button !== 0) return;
|
|
3343
|
+
if (activePointer !== null && activePointer !== pe.pointerId && overlay.hasPointerCapture?.(activePointer)) {
|
|
3344
|
+
return;
|
|
3345
|
+
}
|
|
3346
|
+
if (pe.cancelable) pe.preventDefault();
|
|
3347
|
+
activePointer = pe.pointerId;
|
|
3348
|
+
overlay.setPointerCapture?.(pe.pointerId);
|
|
3349
|
+
live.textContent = "";
|
|
3350
|
+
const p = toSvgPoint(pe.clientX, pe.clientY);
|
|
3351
|
+
const anchor = config?.anchor;
|
|
3352
|
+
if (trail.size === 0 && anchor && nearAnchor(p)) {
|
|
3353
|
+
trail.set(0, pixelYToData(anchor.y));
|
|
3354
|
+
if (p.x > anchor.x) {
|
|
3355
|
+
paintSegment(anchor.x, anchor.y, p.x, p.y);
|
|
3356
|
+
last = p;
|
|
3357
|
+
} else {
|
|
3358
|
+
last = { x: anchor.x, y: anchor.y };
|
|
3359
|
+
}
|
|
3360
|
+
} else {
|
|
3361
|
+
paintSegment(p.x, p.y, p.x, p.y);
|
|
3362
|
+
last = p;
|
|
3363
|
+
}
|
|
3364
|
+
redrawGuessPath();
|
|
3298
3365
|
};
|
|
3299
|
-
const
|
|
3300
|
-
|
|
3366
|
+
const handleMove = (e) => {
|
|
3367
|
+
const pe = e;
|
|
3368
|
+
if (activePointer !== pe.pointerId) return;
|
|
3369
|
+
if (pe.buttons === 0) {
|
|
3370
|
+
endStroke();
|
|
3371
|
+
return;
|
|
3372
|
+
}
|
|
3373
|
+
if (pe.cancelable) pe.preventDefault();
|
|
3374
|
+
const coalesced = pe.getCoalescedEvents?.() ?? [];
|
|
3375
|
+
const events = coalesced.length > 0 ? coalesced : [pe];
|
|
3376
|
+
for (const ev of events) {
|
|
3377
|
+
const p = toSvgPoint(ev.clientX, ev.clientY);
|
|
3378
|
+
const from = last ?? p;
|
|
3379
|
+
paintSegment(from.x, from.y, p.x, p.y);
|
|
3380
|
+
last = p;
|
|
3381
|
+
}
|
|
3382
|
+
redrawGuessPath();
|
|
3301
3383
|
};
|
|
3302
|
-
const
|
|
3303
|
-
const
|
|
3304
|
-
if (
|
|
3305
|
-
|
|
3306
|
-
dragging = true;
|
|
3307
|
-
paintAt(te.touches[0].clientX, te.touches[0].clientY);
|
|
3384
|
+
const handleUp = (e) => {
|
|
3385
|
+
const pe = e;
|
|
3386
|
+
if (activePointer !== pe.pointerId) return;
|
|
3387
|
+
endStroke();
|
|
3308
3388
|
};
|
|
3309
|
-
const
|
|
3310
|
-
|
|
3311
|
-
const te = e;
|
|
3312
|
-
if (te.touches.length === 0) return;
|
|
3313
|
-
if (te.cancelable) te.preventDefault();
|
|
3314
|
-
paintAt(te.touches[0].clientX, te.touches[0].clientY);
|
|
3389
|
+
const handleLostCapture = () => {
|
|
3390
|
+
endStroke();
|
|
3315
3391
|
};
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
overlay.addEventListener("
|
|
3320
|
-
|
|
3321
|
-
document.addEventListener("mouseup", handleMouseUp);
|
|
3322
|
-
overlay.addEventListener("touchstart", handleTouchStart, { passive: false });
|
|
3323
|
-
overlay.addEventListener("touchmove", handleTouchMove, { passive: false });
|
|
3324
|
-
overlay.addEventListener("touchend", handleTouchEnd);
|
|
3325
|
-
overlay.addEventListener("touchcancel", handleTouchEnd);
|
|
3392
|
+
overlay.addEventListener("pointerdown", handleDown);
|
|
3393
|
+
overlay.addEventListener("pointermove", handleMove);
|
|
3394
|
+
overlay.addEventListener("pointerup", handleUp);
|
|
3395
|
+
overlay.addEventListener("pointercancel", handleUp);
|
|
3396
|
+
overlay.addEventListener("lostpointercapture", handleLostCapture);
|
|
3326
3397
|
return () => {
|
|
3327
|
-
overlay.removeEventListener("
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
overlay.removeEventListener("
|
|
3331
|
-
overlay.removeEventListener("
|
|
3332
|
-
overlay.removeEventListener("touchend", handleTouchEnd);
|
|
3333
|
-
overlay.removeEventListener("touchcancel", handleTouchEnd);
|
|
3398
|
+
overlay.removeEventListener("pointerdown", handleDown);
|
|
3399
|
+
overlay.removeEventListener("pointermove", handleMove);
|
|
3400
|
+
overlay.removeEventListener("pointerup", handleUp);
|
|
3401
|
+
overlay.removeEventListener("pointercancel", handleUp);
|
|
3402
|
+
overlay.removeEventListener("lostpointercapture", handleLostCapture);
|
|
3334
3403
|
};
|
|
3335
3404
|
}
|
|
3336
3405
|
const root = document.createElement("div");
|
|
@@ -3339,10 +3408,21 @@ function createYouDrawIt(options) {
|
|
|
3339
3408
|
root.style.position = "absolute";
|
|
3340
3409
|
const prompt = document.createElement("div");
|
|
3341
3410
|
prompt.className = "oc-ydi-prompt";
|
|
3411
|
+
const resetButton = document.createElement("button");
|
|
3412
|
+
resetButton.type = "button";
|
|
3413
|
+
resetButton.className = "oc-ydi-reset-button";
|
|
3414
|
+
resetButton.hidden = true;
|
|
3342
3415
|
const revealButton = document.createElement("button");
|
|
3343
3416
|
revealButton.type = "button";
|
|
3344
3417
|
revealButton.className = "oc-ydi-reveal-button";
|
|
3345
|
-
|
|
3418
|
+
const actions = document.createElement("div");
|
|
3419
|
+
actions.className = "oc-ydi-actions";
|
|
3420
|
+
actions.append(resetButton, revealButton);
|
|
3421
|
+
const live = document.createElement("span");
|
|
3422
|
+
live.className = "oc-sr-only";
|
|
3423
|
+
applySrOnlyStyles(live);
|
|
3424
|
+
live.setAttribute("aria-live", "polite");
|
|
3425
|
+
root.append(prompt, actions, live);
|
|
3346
3426
|
container.style.position = container.style.position || "relative";
|
|
3347
3427
|
container.appendChild(root);
|
|
3348
3428
|
function reduceMotion() {
|
|
@@ -3360,14 +3440,48 @@ function createYouDrawIt(options) {
|
|
|
3360
3440
|
const t = (py - inv.topPixel) / span;
|
|
3361
3441
|
return inv.topData + t * (inv.bottomData - inv.topData);
|
|
3362
3442
|
}
|
|
3443
|
+
function dataToPixelY(value) {
|
|
3444
|
+
if (!config) return value;
|
|
3445
|
+
const inv = config.yInvert;
|
|
3446
|
+
if (!inv) {
|
|
3447
|
+
const area = config.area;
|
|
3448
|
+
return area.y + (1 - value) * area.height;
|
|
3449
|
+
}
|
|
3450
|
+
const dataSpan = inv.bottomData - inv.topData;
|
|
3451
|
+
if (dataSpan === 0) return inv.topPixel;
|
|
3452
|
+
const t = (value - inv.topData) / dataSpan;
|
|
3453
|
+
return inv.topPixel + t * (inv.bottomPixel - inv.topPixel);
|
|
3454
|
+
}
|
|
3363
3455
|
function getGuessData() {
|
|
3364
|
-
if (!config) return [];
|
|
3365
|
-
const
|
|
3366
|
-
|
|
3456
|
+
if (!config || trail.size === 0) return [];
|
|
3457
|
+
const cfg = config;
|
|
3458
|
+
const keys = Array.from(trail.keys()).sort((a, b) => a - b);
|
|
3459
|
+
const first = keys[0];
|
|
3460
|
+
const lastKey = keys[keys.length - 1];
|
|
3461
|
+
const out = [];
|
|
3462
|
+
for (const sample of cfg.samples) {
|
|
3463
|
+
const i = pxToIndex(cfg, sample.px);
|
|
3464
|
+
if (i < first - 0.5 || i > lastKey + 0.5) continue;
|
|
3465
|
+
let hiPos = keys.findIndex((k) => k >= i);
|
|
3466
|
+
if (hiPos === -1) hiPos = keys.length - 1;
|
|
3467
|
+
const loPos = hiPos > 0 && keys[hiPos] > i ? hiPos - 1 : hiPos;
|
|
3468
|
+
const k0 = keys[loPos];
|
|
3469
|
+
const k1 = keys[hiPos];
|
|
3470
|
+
if (k1 - k0 > 1) continue;
|
|
3471
|
+
const v0 = trail.get(k0);
|
|
3472
|
+
const v1 = trail.get(k1);
|
|
3473
|
+
const t = k1 === k0 ? 0 : (i - k0) / (k1 - k0);
|
|
3474
|
+
out.push({ x: sample.xValue, y: v0 + t * (v1 - v0) });
|
|
3475
|
+
}
|
|
3476
|
+
return out;
|
|
3477
|
+
}
|
|
3478
|
+
function syncResetButton() {
|
|
3479
|
+
resetButton.hidden = revealed || trail.size === 0;
|
|
3367
3480
|
}
|
|
3368
3481
|
function doReveal() {
|
|
3369
3482
|
if (destroyed || revealed || !svgEl || !config) return;
|
|
3370
3483
|
revealed = true;
|
|
3484
|
+
activePointer = null;
|
|
3371
3485
|
const clipRect = svgEl.querySelector("[data-ydi-clip-rect]");
|
|
3372
3486
|
if (clipRect) {
|
|
3373
3487
|
if (reduceMotion()) {
|
|
@@ -3386,9 +3500,30 @@ function createYouDrawIt(options) {
|
|
|
3386
3500
|
root.classList.add("oc-ydi-revealed");
|
|
3387
3501
|
prompt.textContent = "";
|
|
3388
3502
|
revealButton.disabled = true;
|
|
3503
|
+
syncResetButton();
|
|
3389
3504
|
onReveal?.(getGuessData());
|
|
3390
3505
|
}
|
|
3506
|
+
function doReset() {
|
|
3507
|
+
if (destroyed) return;
|
|
3508
|
+
revealed = false;
|
|
3509
|
+
activePointer = null;
|
|
3510
|
+
trail.clear();
|
|
3511
|
+
revealButton.disabled = false;
|
|
3512
|
+
root.classList.remove("oc-ydi-revealed");
|
|
3513
|
+
syncResetButton();
|
|
3514
|
+
if (config && svgEl) {
|
|
3515
|
+
render(config, svgEl);
|
|
3516
|
+
prompt.textContent = config.prompt;
|
|
3517
|
+
cleanupPointerEvents?.();
|
|
3518
|
+
cleanupPointerEvents = wirePointerEvents(svgEl);
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3391
3521
|
revealButton.addEventListener("click", doReveal);
|
|
3522
|
+
resetButton.addEventListener("click", () => {
|
|
3523
|
+
doReset();
|
|
3524
|
+
revealButton.focus();
|
|
3525
|
+
live.textContent = "Drawing cleared";
|
|
3526
|
+
});
|
|
3392
3527
|
return {
|
|
3393
3528
|
update(cfg, svg) {
|
|
3394
3529
|
if (destroyed) return;
|
|
@@ -3403,6 +3538,9 @@ function createYouDrawIt(options) {
|
|
|
3403
3538
|
revealButton.setAttribute("aria-label", cfg.revealLabel);
|
|
3404
3539
|
revealButton.style.minHeight = `${MIN_TOUCH_TARGET}px`;
|
|
3405
3540
|
revealButton.disabled = revealed;
|
|
3541
|
+
resetButton.textContent = cfg.resetLabel;
|
|
3542
|
+
resetButton.style.minHeight = `${MIN_TOUCH_TARGET}px`;
|
|
3543
|
+
syncResetButton();
|
|
3406
3544
|
if (revealed) root.classList.add("oc-ydi-revealed");
|
|
3407
3545
|
else root.classList.remove("oc-ydi-revealed");
|
|
3408
3546
|
const viewBox = svg.viewBox?.baseVal;
|
|
@@ -3421,6 +3559,7 @@ function createYouDrawIt(options) {
|
|
|
3421
3559
|
}
|
|
3422
3560
|
},
|
|
3423
3561
|
hide() {
|
|
3562
|
+
activePointer = null;
|
|
3424
3563
|
root.style.display = "none";
|
|
3425
3564
|
svgEl?.querySelector("[data-you-draw-it]")?.remove();
|
|
3426
3565
|
cleanupPointerEvents?.();
|
|
@@ -3430,17 +3569,7 @@ function createYouDrawIt(options) {
|
|
|
3430
3569
|
doReveal();
|
|
3431
3570
|
},
|
|
3432
3571
|
reset() {
|
|
3433
|
-
|
|
3434
|
-
revealed = false;
|
|
3435
|
-
guessByX.clear();
|
|
3436
|
-
revealButton.disabled = false;
|
|
3437
|
-
root.classList.remove("oc-ydi-revealed");
|
|
3438
|
-
if (config && svgEl) {
|
|
3439
|
-
render(config, svgEl);
|
|
3440
|
-
prompt.textContent = config.prompt;
|
|
3441
|
-
cleanupPointerEvents?.();
|
|
3442
|
-
cleanupPointerEvents = wirePointerEvents(svgEl);
|
|
3443
|
-
}
|
|
3572
|
+
doReset();
|
|
3444
3573
|
},
|
|
3445
3574
|
get isRevealed() {
|
|
3446
3575
|
return revealed;
|
|
@@ -4140,7 +4269,7 @@ function wireAnnotationDrag(svg, specAnnotations, onAnnotationEdit, onEdit, setD
|
|
|
4140
4269
|
};
|
|
4141
4270
|
}
|
|
4142
4271
|
function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
|
|
4143
|
-
const
|
|
4272
|
+
const SVG_NS5 = "http://www.w3.org/2000/svg";
|
|
4144
4273
|
const cleanups = [];
|
|
4145
4274
|
const annotationGroups = svg.querySelectorAll(".oc-annotation-text");
|
|
4146
4275
|
for (const el of annotationGroups) {
|
|
@@ -4178,7 +4307,7 @@ function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
|
|
|
4178
4307
|
const createdHandles = [];
|
|
4179
4308
|
for (const ep of endpoints) {
|
|
4180
4309
|
if (!Number.isFinite(ep.cx) || !Number.isFinite(ep.cy)) continue;
|
|
4181
|
-
const handleEl = document.createElementNS(
|
|
4310
|
+
const handleEl = document.createElementNS(SVG_NS5, "circle");
|
|
4182
4311
|
handleEl.setAttribute("class", "oc-connector-handle");
|
|
4183
4312
|
handleEl.setAttribute("data-endpoint", ep.name);
|
|
4184
4313
|
handleEl.setAttribute("cx", String(ep.cx));
|
|
@@ -4455,7 +4584,7 @@ function wireSeriesLabelDrag(svg, spec, onEdit, setDragging) {
|
|
|
4455
4584
|
function wireAnchorDrag(svg, specAnnotations, layout, onEdit, setDragging) {
|
|
4456
4585
|
if (!onEdit || !layout.xInvert || !layout.yInvert) return () => {
|
|
4457
4586
|
};
|
|
4458
|
-
const
|
|
4587
|
+
const SVG_NS5 = "http://www.w3.org/2000/svg";
|
|
4459
4588
|
const cleanups = [];
|
|
4460
4589
|
const annotationGroups = svg.querySelectorAll(".oc-annotation-text");
|
|
4461
4590
|
for (const el of annotationGroups) {
|
|
@@ -4470,7 +4599,7 @@ function wireAnchorDrag(svg, specAnnotations, layout, onEdit, setDragging) {
|
|
|
4470
4599
|
if (!resolved?.dot) continue;
|
|
4471
4600
|
const anchorX = resolved.dot.x;
|
|
4472
4601
|
const anchorY = resolved.dot.y;
|
|
4473
|
-
const handleEl = document.createElementNS(
|
|
4602
|
+
const handleEl = document.createElementNS(SVG_NS5, "circle");
|
|
4474
4603
|
handleEl.setAttribute("class", "oc-anchor-handle");
|
|
4475
4604
|
handleEl.setAttribute("cx", String(anchorX));
|
|
4476
4605
|
handleEl.setAttribute("cy", String(anchorY));
|
|
@@ -4843,21 +4972,6 @@ function wireLegendInteraction(svg, _layout, toggleSeries, onLegendToggle, onEdi
|
|
|
4843
4972
|
|
|
4844
4973
|
// src/interactions/selection.ts
|
|
4845
4974
|
import { elementRef as elementRef2 } from "@opendata-ai/openchart-core";
|
|
4846
|
-
|
|
4847
|
-
// src/dom-helpers.ts
|
|
4848
|
-
function applySrOnlyStyles(el) {
|
|
4849
|
-
el.style.position = "absolute";
|
|
4850
|
-
el.style.width = "1px";
|
|
4851
|
-
el.style.height = "1px";
|
|
4852
|
-
el.style.padding = "0";
|
|
4853
|
-
el.style.margin = "-1px";
|
|
4854
|
-
el.style.overflow = "clip";
|
|
4855
|
-
el.style.clipPath = "inset(50%)";
|
|
4856
|
-
el.style.whiteSpace = "nowrap";
|
|
4857
|
-
el.style.borderWidth = "0";
|
|
4858
|
-
}
|
|
4859
|
-
|
|
4860
|
-
// src/interactions/selection.ts
|
|
4861
4975
|
function findElementByRef(svg, ref) {
|
|
4862
4976
|
switch (ref.type) {
|
|
4863
4977
|
case "annotation": {
|
|
@@ -6889,6 +7003,42 @@ function cameraForTarget(layout, target) {
|
|
|
6889
7003
|
const cam = fitTarget(target, vb);
|
|
6890
7004
|
return { ...cam, k: Math.max(1, Math.min(40, cam.k)) };
|
|
6891
7005
|
}
|
|
7006
|
+
var DEFAULT_MAX_ZOOM = 12;
|
|
7007
|
+
function resolveMapZoom(zoom) {
|
|
7008
|
+
if (!zoom) return null;
|
|
7009
|
+
const cfg = zoom === true ? {} : zoom;
|
|
7010
|
+
const max = cfg.maxZoom;
|
|
7011
|
+
return {
|
|
7012
|
+
maxZoom: typeof max === "number" && Number.isFinite(max) ? Math.max(1, max) : DEFAULT_MAX_ZOOM,
|
|
7013
|
+
controls: cfg.controls !== false
|
|
7014
|
+
};
|
|
7015
|
+
}
|
|
7016
|
+
function clampMapCamera(camera, vb, maxZoom) {
|
|
7017
|
+
const k = Math.min(Math.max(camera.k, 1), Math.max(1, maxZoom));
|
|
7018
|
+
const halfW = vb.width / (2 * k);
|
|
7019
|
+
const halfH = vb.height / (2 * k);
|
|
7020
|
+
return {
|
|
7021
|
+
cx: Math.min(Math.max(camera.cx, halfW), vb.width - halfW),
|
|
7022
|
+
cy: Math.min(Math.max(camera.cy, halfH), vb.height - halfH),
|
|
7023
|
+
k
|
|
7024
|
+
};
|
|
7025
|
+
}
|
|
7026
|
+
function zoomCameraAt(camera, vb, k, pivotX, pivotY) {
|
|
7027
|
+
const ox = pivotX - vb.width / 2;
|
|
7028
|
+
const oy = pivotY - vb.height / 2;
|
|
7029
|
+
const px = camera.cx + ox / camera.k;
|
|
7030
|
+
const py = camera.cy + oy / camera.k;
|
|
7031
|
+
return { cx: px - ox / k, cy: py - oy / k, k };
|
|
7032
|
+
}
|
|
7033
|
+
function panCamera(camera, dx, dy) {
|
|
7034
|
+
return { cx: camera.cx - dx / camera.k, cy: camera.cy - dy / camera.k, k: camera.k };
|
|
7035
|
+
}
|
|
7036
|
+
function wheelZoomFactor(e) {
|
|
7037
|
+
const perUnit = e.deltaMode === 1 ? 0.05 : e.deltaMode === 2 ? 1 : 2e-3;
|
|
7038
|
+
let exp = -e.deltaY * perUnit;
|
|
7039
|
+
if (e.ctrlKey && e.deltaMode === 0 && Math.abs(e.deltaY) < 50) exp *= 5;
|
|
7040
|
+
return 2 ** Math.max(-1, Math.min(1, exp));
|
|
7041
|
+
}
|
|
6892
7042
|
function applyMapCamera(svg, camera, layout) {
|
|
6893
7043
|
const cameraGroup = svg.querySelector("[data-oc-map-camera]");
|
|
6894
7044
|
if (!cameraGroup) return;
|
|
@@ -7410,6 +7560,468 @@ function runMapFillTransition(svg, prev, opts) {
|
|
|
7410
7560
|
};
|
|
7411
7561
|
}
|
|
7412
7562
|
|
|
7563
|
+
// src/map-zoom.ts
|
|
7564
|
+
var ZOOM_STEP = 2;
|
|
7565
|
+
var KEY_PAN_FRACTION = 0.1;
|
|
7566
|
+
var DRAG_THRESHOLD = 3;
|
|
7567
|
+
var HINT_MS = 1500;
|
|
7568
|
+
var EPS = 1e-3;
|
|
7569
|
+
var SVG_NS4 = "http://www.w3.org/2000/svg";
|
|
7570
|
+
var clipIdCounter = 0;
|
|
7571
|
+
var ICONS = {
|
|
7572
|
+
in: '<path d="M8 3v10M3 8h10"/>',
|
|
7573
|
+
out: '<path d="M3 8h10"/>',
|
|
7574
|
+
reset: '<path d="M3 8a5 5 0 1 0 1.6-3.7"/><path d="M3 2.5v2.8h2.8"/>'
|
|
7575
|
+
};
|
|
7576
|
+
function isMacLike() {
|
|
7577
|
+
if (typeof navigator === "undefined") return false;
|
|
7578
|
+
return /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
|
|
7579
|
+
}
|
|
7580
|
+
function createMapZoomController(host) {
|
|
7581
|
+
const { container } = host;
|
|
7582
|
+
const clipId = `oc-map-zoom-clip-${++clipIdCounter}`;
|
|
7583
|
+
let overlay = null;
|
|
7584
|
+
let buttons = null;
|
|
7585
|
+
let hint = null;
|
|
7586
|
+
let hintTimer = null;
|
|
7587
|
+
let drag = null;
|
|
7588
|
+
let suppressClick = false;
|
|
7589
|
+
let pinch = null;
|
|
7590
|
+
let touchPan = null;
|
|
7591
|
+
let gestureStartK = null;
|
|
7592
|
+
function vb() {
|
|
7593
|
+
return host.getLayout().mapSize;
|
|
7594
|
+
}
|
|
7595
|
+
function clamp(camera) {
|
|
7596
|
+
const cfg = host.getConfig();
|
|
7597
|
+
return clampMapCamera(camera, vb(), cfg?.maxZoom ?? 1);
|
|
7598
|
+
}
|
|
7599
|
+
function clampK(k) {
|
|
7600
|
+
const cfg = host.getConfig();
|
|
7601
|
+
return Math.min(Math.max(k, 1), cfg?.maxZoom ?? 1);
|
|
7602
|
+
}
|
|
7603
|
+
function svgRect() {
|
|
7604
|
+
const svg = host.getSvg();
|
|
7605
|
+
let rect = svg?.getBoundingClientRect();
|
|
7606
|
+
if (!rect || !rect.width || !rect.height) rect = container.getBoundingClientRect();
|
|
7607
|
+
if (!rect.width || !rect.height) return null;
|
|
7608
|
+
return rect;
|
|
7609
|
+
}
|
|
7610
|
+
function toMapFrame(clientX, clientY) {
|
|
7611
|
+
const rect = svgRect();
|
|
7612
|
+
if (!rect) return null;
|
|
7613
|
+
const layout = host.getLayout();
|
|
7614
|
+
const x = (clientX - rect.left) * (layout.width / rect.width) - layout.area.x;
|
|
7615
|
+
const y = (clientY - rect.top) * (layout.height / rect.height) - layout.area.y;
|
|
7616
|
+
const inside = x >= 0 && y >= 0 && x <= layout.area.width && y <= layout.area.height;
|
|
7617
|
+
return { x, y, inside };
|
|
7618
|
+
}
|
|
7619
|
+
function unitsPerPx() {
|
|
7620
|
+
const rect = svgRect();
|
|
7621
|
+
return rect ? host.getLayout().width / rect.width : 1;
|
|
7622
|
+
}
|
|
7623
|
+
function isZoomed() {
|
|
7624
|
+
return host.getCamera().k > 1 + EPS;
|
|
7625
|
+
}
|
|
7626
|
+
function fromControls(e) {
|
|
7627
|
+
const t = e.target;
|
|
7628
|
+
return !!t?.closest?.(".oc-map-zoom");
|
|
7629
|
+
}
|
|
7630
|
+
function zoomAround(factor, x, y, animate) {
|
|
7631
|
+
const cam = host.getCamera();
|
|
7632
|
+
const next = clamp(zoomCameraAt(cam, vb(), clampK(cam.k * factor), x, y));
|
|
7633
|
+
if (animate) host.animateCamera(next);
|
|
7634
|
+
else host.setCamera(next);
|
|
7635
|
+
}
|
|
7636
|
+
function zoomAtCenter(factor) {
|
|
7637
|
+
const { width, height } = vb();
|
|
7638
|
+
zoomAround(factor, width / 2, height / 2, true);
|
|
7639
|
+
}
|
|
7640
|
+
function showHint() {
|
|
7641
|
+
if (!hint) return;
|
|
7642
|
+
hint.setAttribute("data-visible", "");
|
|
7643
|
+
if (hintTimer) clearTimeout(hintTimer);
|
|
7644
|
+
hintTimer = setTimeout(() => {
|
|
7645
|
+
hint?.removeAttribute("data-visible");
|
|
7646
|
+
hintTimer = null;
|
|
7647
|
+
}, HINT_MS);
|
|
7648
|
+
}
|
|
7649
|
+
function onWheel(e) {
|
|
7650
|
+
if (!host.getConfig() || fromControls(e)) return;
|
|
7651
|
+
const p = toMapFrame(e.clientX, e.clientY);
|
|
7652
|
+
if (!p?.inside) return;
|
|
7653
|
+
if (!e.ctrlKey && !e.metaKey) {
|
|
7654
|
+
if (Math.abs(e.deltaY) > Math.abs(e.deltaX)) showHint();
|
|
7655
|
+
return;
|
|
7656
|
+
}
|
|
7657
|
+
e.preventDefault();
|
|
7658
|
+
hint?.removeAttribute("data-visible");
|
|
7659
|
+
zoomAround(wheelZoomFactor(e), p.x, p.y, false);
|
|
7660
|
+
}
|
|
7661
|
+
function onGestureStart(e) {
|
|
7662
|
+
if (!host.getConfig()) return;
|
|
7663
|
+
e.preventDefault();
|
|
7664
|
+
gestureStartK = host.getCamera().k;
|
|
7665
|
+
}
|
|
7666
|
+
function onGestureChange(e) {
|
|
7667
|
+
if (!host.getConfig() || gestureStartK === null) return;
|
|
7668
|
+
e.preventDefault();
|
|
7669
|
+
if (pinch) return;
|
|
7670
|
+
const g = e;
|
|
7671
|
+
const p = toMapFrame(g.clientX, g.clientY);
|
|
7672
|
+
if (!p) return;
|
|
7673
|
+
const cam = host.getCamera();
|
|
7674
|
+
host.setCamera(clamp(zoomCameraAt(cam, vb(), clampK(gestureStartK * g.scale), p.x, p.y)));
|
|
7675
|
+
}
|
|
7676
|
+
function onGestureEnd(e) {
|
|
7677
|
+
if (gestureStartK === null) return;
|
|
7678
|
+
e.preventDefault();
|
|
7679
|
+
gestureStartK = null;
|
|
7680
|
+
}
|
|
7681
|
+
function onPointerDown(e) {
|
|
7682
|
+
if (e.pointerType === "touch" || e.button !== 0) return;
|
|
7683
|
+
if (!host.getConfig() || fromControls(e) || !isZoomed()) return;
|
|
7684
|
+
const p = toMapFrame(e.clientX, e.clientY);
|
|
7685
|
+
if (!p?.inside) return;
|
|
7686
|
+
drag = {
|
|
7687
|
+
id: e.pointerId,
|
|
7688
|
+
startX: e.clientX,
|
|
7689
|
+
startY: e.clientY,
|
|
7690
|
+
lastX: e.clientX,
|
|
7691
|
+
lastY: e.clientY,
|
|
7692
|
+
moved: false
|
|
7693
|
+
};
|
|
7694
|
+
}
|
|
7695
|
+
function onMouseDown(e) {
|
|
7696
|
+
if (e.button !== 0 || !host.getConfig() || fromControls(e)) return;
|
|
7697
|
+
if (!isZoomed() && e.detail < 2) return;
|
|
7698
|
+
const p = toMapFrame(e.clientX, e.clientY);
|
|
7699
|
+
if (!p?.inside) return;
|
|
7700
|
+
e.preventDefault();
|
|
7701
|
+
host.getSvg()?.focus({ preventScroll: true });
|
|
7702
|
+
}
|
|
7703
|
+
function onPointerMove(e) {
|
|
7704
|
+
if (!drag || e.pointerId !== drag.id) return;
|
|
7705
|
+
if (!drag.moved) {
|
|
7706
|
+
if (Math.hypot(e.clientX - drag.startX, e.clientY - drag.startY) < DRAG_THRESHOLD) return;
|
|
7707
|
+
drag.moved = true;
|
|
7708
|
+
const svg = host.getSvg();
|
|
7709
|
+
try {
|
|
7710
|
+
svg?.setPointerCapture(e.pointerId);
|
|
7711
|
+
} catch {
|
|
7712
|
+
}
|
|
7713
|
+
svg?.classList.add("oc-map--panning");
|
|
7714
|
+
host.hideTooltip();
|
|
7715
|
+
}
|
|
7716
|
+
e.preventDefault();
|
|
7717
|
+
const s = unitsPerPx();
|
|
7718
|
+
const dx = (e.clientX - drag.lastX) * s;
|
|
7719
|
+
const dy = (e.clientY - drag.lastY) * s;
|
|
7720
|
+
drag.lastX = e.clientX;
|
|
7721
|
+
drag.lastY = e.clientY;
|
|
7722
|
+
host.setCamera(clamp(panCamera(host.getCamera(), dx, dy)));
|
|
7723
|
+
}
|
|
7724
|
+
function endDrag(e) {
|
|
7725
|
+
if (!drag || e.pointerId !== drag.id) return;
|
|
7726
|
+
const svg = host.getSvg();
|
|
7727
|
+
if (drag.moved) {
|
|
7728
|
+
suppressClick = true;
|
|
7729
|
+
setTimeout(() => {
|
|
7730
|
+
suppressClick = false;
|
|
7731
|
+
}, 0);
|
|
7732
|
+
}
|
|
7733
|
+
try {
|
|
7734
|
+
if (svg?.hasPointerCapture?.(e.pointerId)) svg.releasePointerCapture(e.pointerId);
|
|
7735
|
+
} catch {
|
|
7736
|
+
}
|
|
7737
|
+
svg?.classList.remove("oc-map--panning");
|
|
7738
|
+
drag = null;
|
|
7739
|
+
}
|
|
7740
|
+
function onClickCapture(e) {
|
|
7741
|
+
if (!suppressClick) return;
|
|
7742
|
+
suppressClick = false;
|
|
7743
|
+
e.stopPropagation();
|
|
7744
|
+
e.preventDefault();
|
|
7745
|
+
}
|
|
7746
|
+
function onDblClick(e) {
|
|
7747
|
+
if (!host.getConfig() || fromControls(e)) return;
|
|
7748
|
+
const p = toMapFrame(e.clientX, e.clientY);
|
|
7749
|
+
if (!p?.inside) return;
|
|
7750
|
+
e.preventDefault();
|
|
7751
|
+
zoomAround(e.shiftKey ? 1 / ZOOM_STEP : ZOOM_STEP, p.x, p.y, true);
|
|
7752
|
+
}
|
|
7753
|
+
function touchPoint(t) {
|
|
7754
|
+
return toMapFrame(t.clientX, t.clientY);
|
|
7755
|
+
}
|
|
7756
|
+
function startPinch(e) {
|
|
7757
|
+
const a = touchPoint(e.touches[0]);
|
|
7758
|
+
const b = touchPoint(e.touches[1]);
|
|
7759
|
+
if (!a || !b) return;
|
|
7760
|
+
pinch = {
|
|
7761
|
+
dist: Math.hypot(b.x - a.x, b.y - a.y) || 1,
|
|
7762
|
+
x: (a.x + b.x) / 2,
|
|
7763
|
+
y: (a.y + b.y) / 2
|
|
7764
|
+
};
|
|
7765
|
+
touchPan = null;
|
|
7766
|
+
}
|
|
7767
|
+
function startTouchPan(t) {
|
|
7768
|
+
touchPan = isZoomed() ? { x: t.clientX, y: t.clientY, moved: false } : null;
|
|
7769
|
+
}
|
|
7770
|
+
function onTouchStart(e) {
|
|
7771
|
+
if (!host.getConfig() || fromControls(e)) return;
|
|
7772
|
+
if (e.touches.length >= 2) {
|
|
7773
|
+
const a = touchPoint(e.touches[0]);
|
|
7774
|
+
if (!a?.inside) return;
|
|
7775
|
+
e.preventDefault();
|
|
7776
|
+
host.hideTooltip();
|
|
7777
|
+
startPinch(e);
|
|
7778
|
+
} else if (e.touches.length === 1) {
|
|
7779
|
+
const p = touchPoint(e.touches[0]);
|
|
7780
|
+
if (!p?.inside) return;
|
|
7781
|
+
startTouchPan(e.touches[0]);
|
|
7782
|
+
}
|
|
7783
|
+
}
|
|
7784
|
+
function onTouchMove(e) {
|
|
7785
|
+
if (!host.getConfig()) return;
|
|
7786
|
+
if (pinch && e.touches.length >= 2) {
|
|
7787
|
+
e.preventDefault();
|
|
7788
|
+
const a = touchPoint(e.touches[0]);
|
|
7789
|
+
const b = touchPoint(e.touches[1]);
|
|
7790
|
+
if (!a || !b) return;
|
|
7791
|
+
const dist = Math.hypot(b.x - a.x, b.y - a.y) || 1;
|
|
7792
|
+
const x = (a.x + b.x) / 2;
|
|
7793
|
+
const y = (a.y + b.y) / 2;
|
|
7794
|
+
let cam = host.getCamera();
|
|
7795
|
+
cam = zoomCameraAt(cam, vb(), clampK(cam.k * (dist / pinch.dist)), x, y);
|
|
7796
|
+
cam = panCamera(cam, x - pinch.x, y - pinch.y);
|
|
7797
|
+
host.setCamera(clamp(cam));
|
|
7798
|
+
pinch = { dist, x, y };
|
|
7799
|
+
return;
|
|
7800
|
+
}
|
|
7801
|
+
if (touchPan && e.touches.length === 1) {
|
|
7802
|
+
const t = e.touches[0];
|
|
7803
|
+
if (!touchPan.moved) {
|
|
7804
|
+
if (Math.hypot(t.clientX - touchPan.x, t.clientY - touchPan.y) < DRAG_THRESHOLD) return;
|
|
7805
|
+
touchPan.moved = true;
|
|
7806
|
+
host.hideTooltip();
|
|
7807
|
+
}
|
|
7808
|
+
if (e.cancelable) e.preventDefault();
|
|
7809
|
+
const s = unitsPerPx();
|
|
7810
|
+
const dx = (t.clientX - touchPan.x) * s;
|
|
7811
|
+
const dy = (t.clientY - touchPan.y) * s;
|
|
7812
|
+
touchPan.x = t.clientX;
|
|
7813
|
+
touchPan.y = t.clientY;
|
|
7814
|
+
host.setCamera(clamp(panCamera(host.getCamera(), dx, dy)));
|
|
7815
|
+
}
|
|
7816
|
+
}
|
|
7817
|
+
function onTouchEnd(e) {
|
|
7818
|
+
if (e.touches.length >= 2) {
|
|
7819
|
+
startPinch(e);
|
|
7820
|
+
return;
|
|
7821
|
+
}
|
|
7822
|
+
pinch = null;
|
|
7823
|
+
if (e.touches.length === 1) {
|
|
7824
|
+
startTouchPan(e.touches[0]);
|
|
7825
|
+
if (touchPan) touchPan.moved = true;
|
|
7826
|
+
} else {
|
|
7827
|
+
touchPan = null;
|
|
7828
|
+
}
|
|
7829
|
+
}
|
|
7830
|
+
function onKeyDown(e) {
|
|
7831
|
+
if (!host.getConfig() || e.target !== host.getSvg()) return;
|
|
7832
|
+
if (e.ctrlKey || e.metaKey || e.altKey) return;
|
|
7833
|
+
const { width, height } = vb();
|
|
7834
|
+
switch (e.key) {
|
|
7835
|
+
case "+":
|
|
7836
|
+
case "=":
|
|
7837
|
+
zoomAtCenter(ZOOM_STEP);
|
|
7838
|
+
break;
|
|
7839
|
+
case "-":
|
|
7840
|
+
case "_":
|
|
7841
|
+
zoomAtCenter(1 / ZOOM_STEP);
|
|
7842
|
+
break;
|
|
7843
|
+
case "0":
|
|
7844
|
+
host.reset();
|
|
7845
|
+
break;
|
|
7846
|
+
case "ArrowLeft":
|
|
7847
|
+
case "ArrowRight":
|
|
7848
|
+
case "ArrowUp":
|
|
7849
|
+
case "ArrowDown": {
|
|
7850
|
+
if (!isZoomed()) return;
|
|
7851
|
+
const dx = e.key === "ArrowLeft" ? width * KEY_PAN_FRACTION : e.key === "ArrowRight" ? -width * KEY_PAN_FRACTION : 0;
|
|
7852
|
+
const dy = e.key === "ArrowUp" ? height * KEY_PAN_FRACTION : e.key === "ArrowDown" ? -height * KEY_PAN_FRACTION : 0;
|
|
7853
|
+
host.setCamera(clamp(panCamera(host.getCamera(), dx, dy)));
|
|
7854
|
+
break;
|
|
7855
|
+
}
|
|
7856
|
+
default:
|
|
7857
|
+
return;
|
|
7858
|
+
}
|
|
7859
|
+
e.preventDefault();
|
|
7860
|
+
}
|
|
7861
|
+
function makeButton(kind, label) {
|
|
7862
|
+
const btn = document.createElement("button");
|
|
7863
|
+
btn.type = "button";
|
|
7864
|
+
btn.className = "oc-map-zoom-btn";
|
|
7865
|
+
btn.setAttribute("data-zoom", kind);
|
|
7866
|
+
btn.setAttribute("aria-label", label);
|
|
7867
|
+
btn.title = label;
|
|
7868
|
+
btn.innerHTML = `<svg viewBox="0 0 16 16" width="16" height="16" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">${ICONS[kind]}</svg>`;
|
|
7869
|
+
btn.addEventListener("click", (e) => {
|
|
7870
|
+
e.stopPropagation();
|
|
7871
|
+
if (kind === "in") zoomAtCenter(ZOOM_STEP);
|
|
7872
|
+
else if (kind === "out") zoomAtCenter(1 / ZOOM_STEP);
|
|
7873
|
+
else host.reset();
|
|
7874
|
+
});
|
|
7875
|
+
return btn;
|
|
7876
|
+
}
|
|
7877
|
+
function ensureOverlay(showControls) {
|
|
7878
|
+
if (!overlay) {
|
|
7879
|
+
overlay = document.createElement("div");
|
|
7880
|
+
overlay.className = "oc-map-zoom";
|
|
7881
|
+
hint = document.createElement("div");
|
|
7882
|
+
hint.className = "oc-map-zoom-hint";
|
|
7883
|
+
hint.setAttribute("aria-hidden", "true");
|
|
7884
|
+
hint.textContent = isMacLike() ? "Use \u2318 + scroll to zoom the map" : "Use Ctrl + scroll to zoom the map";
|
|
7885
|
+
overlay.appendChild(hint);
|
|
7886
|
+
if (getComputedStyle(container).position === "static") {
|
|
7887
|
+
container.style.position = "relative";
|
|
7888
|
+
}
|
|
7889
|
+
container.appendChild(overlay);
|
|
7890
|
+
}
|
|
7891
|
+
if (showControls && !buttons) {
|
|
7892
|
+
const group = document.createElement("div");
|
|
7893
|
+
group.className = "oc-map-zoom-controls";
|
|
7894
|
+
group.setAttribute("role", "group");
|
|
7895
|
+
group.setAttribute("aria-label", "Map zoom");
|
|
7896
|
+
buttons = {
|
|
7897
|
+
in: makeButton("in", "Zoom in"),
|
|
7898
|
+
out: makeButton("out", "Zoom out"),
|
|
7899
|
+
reset: makeButton("reset", "Reset zoom")
|
|
7900
|
+
};
|
|
7901
|
+
group.append(buttons.in, buttons.out, buttons.reset);
|
|
7902
|
+
overlay.appendChild(group);
|
|
7903
|
+
} else if (!showControls && buttons) {
|
|
7904
|
+
buttons.in.parentElement?.remove();
|
|
7905
|
+
buttons = null;
|
|
7906
|
+
}
|
|
7907
|
+
}
|
|
7908
|
+
function removeOverlay() {
|
|
7909
|
+
if (hintTimer) clearTimeout(hintTimer);
|
|
7910
|
+
hintTimer = null;
|
|
7911
|
+
overlay?.remove();
|
|
7912
|
+
overlay = null;
|
|
7913
|
+
buttons = null;
|
|
7914
|
+
hint = null;
|
|
7915
|
+
}
|
|
7916
|
+
function placeOverlay(layout) {
|
|
7917
|
+
if (!overlay || !layout.width || !layout.height) return;
|
|
7918
|
+
const { area, width, height } = layout;
|
|
7919
|
+
overlay.style.left = `${area.x / width * 100}%`;
|
|
7920
|
+
overlay.style.top = `${area.y / height * 100}%`;
|
|
7921
|
+
overlay.style.width = `${area.width / width * 100}%`;
|
|
7922
|
+
overlay.style.height = `${area.height / height * 100}%`;
|
|
7923
|
+
}
|
|
7924
|
+
function ensureClip(svg, layout) {
|
|
7925
|
+
if (svg.querySelector(`#${clipId}`)) return;
|
|
7926
|
+
let defs = svg.querySelector("defs");
|
|
7927
|
+
if (!defs) {
|
|
7928
|
+
defs = document.createElementNS(SVG_NS4, "defs");
|
|
7929
|
+
svg.insertBefore(defs, svg.firstChild);
|
|
7930
|
+
}
|
|
7931
|
+
const clip = document.createElementNS(SVG_NS4, "clipPath");
|
|
7932
|
+
clip.setAttribute("id", clipId);
|
|
7933
|
+
const rect = document.createElementNS(SVG_NS4, "rect");
|
|
7934
|
+
rect.setAttribute("width", String(layout.area.width));
|
|
7935
|
+
rect.setAttribute("height", String(layout.area.height));
|
|
7936
|
+
clip.appendChild(rect);
|
|
7937
|
+
defs.appendChild(clip);
|
|
7938
|
+
}
|
|
7939
|
+
function onRender(restoreFocus) {
|
|
7940
|
+
const cfg = host.getConfig();
|
|
7941
|
+
const svg = host.getSvg();
|
|
7942
|
+
if (!cfg || !svg) {
|
|
7943
|
+
removeOverlay();
|
|
7944
|
+
return;
|
|
7945
|
+
}
|
|
7946
|
+
const layout = host.getLayout();
|
|
7947
|
+
svg.setAttribute("tabindex", "0");
|
|
7948
|
+
svg.setAttribute("aria-keyshortcuts", "+ - 0 ArrowUp ArrowDown ArrowLeft ArrowRight");
|
|
7949
|
+
ensureClip(svg, layout);
|
|
7950
|
+
ensureOverlay(cfg.controls);
|
|
7951
|
+
placeOverlay(layout);
|
|
7952
|
+
if (restoreFocus) svg.focus({ preventScroll: true });
|
|
7953
|
+
onCamera();
|
|
7954
|
+
}
|
|
7955
|
+
function onCamera() {
|
|
7956
|
+
const cfg = host.getConfig();
|
|
7957
|
+
const svg = host.getSvg();
|
|
7958
|
+
if (!cfg || !svg) return;
|
|
7959
|
+
const cam = host.getCamera();
|
|
7960
|
+
const zoomed = cam.k > 1 + EPS;
|
|
7961
|
+
const { width, height } = vb();
|
|
7962
|
+
const atFullView = !zoomed && Math.abs(cam.cx - width / 2) < EPS && Math.abs(cam.cy - height / 2) < EPS;
|
|
7963
|
+
const group = svg.querySelector(".oc-map-group");
|
|
7964
|
+
if (zoomed) group?.setAttribute("clip-path", `url(#${clipId})`);
|
|
7965
|
+
else group?.removeAttribute("clip-path");
|
|
7966
|
+
svg.style.touchAction = zoomed ? "none" : "pan-x pan-y";
|
|
7967
|
+
if (zoomed) svg.setAttribute("data-oc-zoomed", "");
|
|
7968
|
+
else svg.removeAttribute("data-oc-zoomed");
|
|
7969
|
+
if (buttons) {
|
|
7970
|
+
setDisabled(buttons.in, cam.k >= cfg.maxZoom - EPS, svg);
|
|
7971
|
+
setDisabled(buttons.out, !zoomed, svg);
|
|
7972
|
+
setDisabled(buttons.reset, atFullView, svg);
|
|
7973
|
+
}
|
|
7974
|
+
}
|
|
7975
|
+
function setDisabled(btn, disabled, svg) {
|
|
7976
|
+
if (btn.disabled === disabled) return;
|
|
7977
|
+
const hadFocus = disabled && document.activeElement === btn;
|
|
7978
|
+
btn.disabled = disabled;
|
|
7979
|
+
if (hadFocus) svg.focus({ preventScroll: true });
|
|
7980
|
+
}
|
|
7981
|
+
const touchOpts = { passive: false };
|
|
7982
|
+
container.addEventListener("wheel", onWheel, { passive: false });
|
|
7983
|
+
container.addEventListener("pointerdown", onPointerDown);
|
|
7984
|
+
container.addEventListener("mousedown", onMouseDown);
|
|
7985
|
+
container.addEventListener("pointermove", onPointerMove);
|
|
7986
|
+
container.addEventListener("pointerup", endDrag);
|
|
7987
|
+
container.addEventListener("pointercancel", endDrag);
|
|
7988
|
+
container.addEventListener("click", onClickCapture, true);
|
|
7989
|
+
container.addEventListener("dblclick", onDblClick);
|
|
7990
|
+
container.addEventListener("touchstart", onTouchStart, touchOpts);
|
|
7991
|
+
container.addEventListener("touchmove", onTouchMove, touchOpts);
|
|
7992
|
+
container.addEventListener("touchend", onTouchEnd);
|
|
7993
|
+
container.addEventListener("touchcancel", onTouchEnd);
|
|
7994
|
+
container.addEventListener("gesturestart", onGestureStart);
|
|
7995
|
+
container.addEventListener("gesturechange", onGestureChange);
|
|
7996
|
+
container.addEventListener("gestureend", onGestureEnd);
|
|
7997
|
+
container.addEventListener("keydown", onKeyDown);
|
|
7998
|
+
return {
|
|
7999
|
+
onRender,
|
|
8000
|
+
onCamera,
|
|
8001
|
+
destroy() {
|
|
8002
|
+
container.removeEventListener("wheel", onWheel);
|
|
8003
|
+
container.removeEventListener("pointerdown", onPointerDown);
|
|
8004
|
+
container.removeEventListener("mousedown", onMouseDown);
|
|
8005
|
+
container.removeEventListener("pointermove", onPointerMove);
|
|
8006
|
+
container.removeEventListener("pointerup", endDrag);
|
|
8007
|
+
container.removeEventListener("pointercancel", endDrag);
|
|
8008
|
+
container.removeEventListener("click", onClickCapture, true);
|
|
8009
|
+
container.removeEventListener("dblclick", onDblClick);
|
|
8010
|
+
container.removeEventListener("touchstart", onTouchStart);
|
|
8011
|
+
container.removeEventListener("touchmove", onTouchMove);
|
|
8012
|
+
container.removeEventListener("touchend", onTouchEnd);
|
|
8013
|
+
container.removeEventListener("touchcancel", onTouchEnd);
|
|
8014
|
+
container.removeEventListener("gesturestart", onGestureStart);
|
|
8015
|
+
container.removeEventListener("gesturechange", onGestureChange);
|
|
8016
|
+
container.removeEventListener("gestureend", onGestureEnd);
|
|
8017
|
+
container.removeEventListener("keydown", onKeyDown);
|
|
8018
|
+
const svg = host.getSvg();
|
|
8019
|
+
svg?.removeAttribute("tabindex");
|
|
8020
|
+
removeOverlay();
|
|
8021
|
+
}
|
|
8022
|
+
};
|
|
8023
|
+
}
|
|
8024
|
+
|
|
7413
8025
|
// src/map-mount.ts
|
|
7414
8026
|
function focusSignature(focus) {
|
|
7415
8027
|
if (!focus) return null;
|
|
@@ -7438,6 +8050,7 @@ function restoreFeatureOrder(el) {
|
|
|
7438
8050
|
parent.appendChild(el);
|
|
7439
8051
|
}
|
|
7440
8052
|
}
|
|
8053
|
+
var USER_ZOOM_MS = 250;
|
|
7441
8054
|
function prefersReducedMotion2() {
|
|
7442
8055
|
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
7443
8056
|
try {
|
|
@@ -7460,6 +8073,7 @@ function createGeoMap(container, spec, options) {
|
|
|
7460
8073
|
let currentCamera = { cx: 0, cy: 0, k: 1 };
|
|
7461
8074
|
let currentFocusIds = null;
|
|
7462
8075
|
let cameraTween = null;
|
|
8076
|
+
let zoomController = null;
|
|
7463
8077
|
let isFirstRender = true;
|
|
7464
8078
|
let fontsReloadPending = false;
|
|
7465
8079
|
container.classList.add("oc-map-root");
|
|
@@ -7660,6 +8274,18 @@ function createGeoMap(container, spec, options) {
|
|
|
7660
8274
|
}
|
|
7661
8275
|
return cameraForTarget(currentLayout, null);
|
|
7662
8276
|
}
|
|
8277
|
+
function commitCamera(cam) {
|
|
8278
|
+
currentCamera = cam;
|
|
8279
|
+
if (svgElement) applyMapCamera(svgElement, cam, currentLayout);
|
|
8280
|
+
zoomController?.onCamera();
|
|
8281
|
+
options?.onCameraChange?.({ ...cam });
|
|
8282
|
+
}
|
|
8283
|
+
function cancelCameraTween() {
|
|
8284
|
+
if (cameraTween) {
|
|
8285
|
+
cameraTween.cancel();
|
|
8286
|
+
cameraTween = null;
|
|
8287
|
+
}
|
|
8288
|
+
}
|
|
7663
8289
|
function animateCamera(target, duration) {
|
|
7664
8290
|
if (cameraTween) cameraTween.cancel();
|
|
7665
8291
|
cameraTween = createTween2({
|
|
@@ -7668,20 +8294,64 @@ function createGeoMap(container, spec, options) {
|
|
|
7668
8294
|
duration,
|
|
7669
8295
|
ease: easingFns.easeInOutCubic,
|
|
7670
8296
|
onFrame(cam) {
|
|
7671
|
-
|
|
7672
|
-
if (svgElement) applyMapCamera(svgElement, cam, currentLayout);
|
|
8297
|
+
commitCamera(cam);
|
|
7673
8298
|
}
|
|
7674
8299
|
});
|
|
7675
8300
|
cameraTween.to(target);
|
|
7676
8301
|
}
|
|
7677
8302
|
function driveCamera(cam, duration) {
|
|
7678
8303
|
if (duration === 0 || prefersReducedMotion2()) {
|
|
7679
|
-
|
|
7680
|
-
|
|
8304
|
+
cancelCameraTween();
|
|
8305
|
+
commitCamera(cam);
|
|
7681
8306
|
} else {
|
|
7682
8307
|
animateCamera(cam, duration);
|
|
7683
8308
|
}
|
|
7684
8309
|
}
|
|
8310
|
+
function resetCamera(duration) {
|
|
8311
|
+
currentFocusIds = null;
|
|
8312
|
+
const cam = cameraForTarget(currentLayout, null);
|
|
8313
|
+
driveCamera(cam, duration);
|
|
8314
|
+
applyFocusDim(null);
|
|
8315
|
+
updateA11yLive(null);
|
|
8316
|
+
}
|
|
8317
|
+
function rescaleFreeCamera(prev) {
|
|
8318
|
+
const next = currentLayout.mapSize;
|
|
8319
|
+
if (!prev.width || !prev.height || prev.width === next.width && prev.height === next.height) {
|
|
8320
|
+
return;
|
|
8321
|
+
}
|
|
8322
|
+
const scaled = {
|
|
8323
|
+
cx: currentCamera.cx * next.width / prev.width,
|
|
8324
|
+
cy: currentCamera.cy * next.height / prev.height,
|
|
8325
|
+
k: currentCamera.k
|
|
8326
|
+
};
|
|
8327
|
+
const zoom = resolveMapZoom(currentSpec.geo?.zoom);
|
|
8328
|
+
currentCamera = zoom ? clampMapCamera(scaled, next, zoom.maxZoom) : scaled;
|
|
8329
|
+
}
|
|
8330
|
+
function syncZoomController(restoreFocus) {
|
|
8331
|
+
const zoom = resolveMapZoom(currentSpec.geo?.zoom);
|
|
8332
|
+
if (!zoom && !zoomController) return;
|
|
8333
|
+
if (!zoomController) {
|
|
8334
|
+
zoomController = createMapZoomController({
|
|
8335
|
+
container,
|
|
8336
|
+
getSvg: () => svgElement,
|
|
8337
|
+
getLayout: () => currentLayout,
|
|
8338
|
+
getConfig: () => resolveMapZoom(currentSpec.geo?.zoom),
|
|
8339
|
+
getCamera: () => ({ ...currentCamera }),
|
|
8340
|
+
setCamera(cam) {
|
|
8341
|
+
cancelCameraTween();
|
|
8342
|
+
currentFocusIds = null;
|
|
8343
|
+
commitCamera(cam);
|
|
8344
|
+
},
|
|
8345
|
+
animateCamera(cam) {
|
|
8346
|
+
currentFocusIds = null;
|
|
8347
|
+
driveCamera(cam, USER_ZOOM_MS);
|
|
8348
|
+
},
|
|
8349
|
+
reset: () => resetCamera(USER_ZOOM_MS),
|
|
8350
|
+
hideTooltip: () => tooltipManager?.hide()
|
|
8351
|
+
});
|
|
8352
|
+
}
|
|
8353
|
+
zoomController.onRender(restoreFocus);
|
|
8354
|
+
}
|
|
7685
8355
|
function updateA11yLive(ids) {
|
|
7686
8356
|
let liveEl = container.querySelector(".oc-map-live");
|
|
7687
8357
|
if (!liveEl) {
|
|
@@ -7728,6 +8398,7 @@ function createGeoMap(container, spec, options) {
|
|
|
7728
8398
|
fillTransitionHandle = null;
|
|
7729
8399
|
}
|
|
7730
8400
|
const oldSvg = svgElement;
|
|
8401
|
+
const oldSvgHadFocus = !!oldSvg && document.activeElement === oldSvg;
|
|
7731
8402
|
const newSvg = renderMapSVG(currentLayout, { animate });
|
|
7732
8403
|
if (oldSvg) {
|
|
7733
8404
|
if (cleanupTooltipEvents) {
|
|
@@ -7779,6 +8450,7 @@ function createGeoMap(container, spec, options) {
|
|
|
7779
8450
|
}
|
|
7780
8451
|
}
|
|
7781
8452
|
isFirstRender = false;
|
|
8453
|
+
syncZoomController(oldSvgHadFocus);
|
|
7782
8454
|
}
|
|
7783
8455
|
function update(newSpec) {
|
|
7784
8456
|
currentSpec = newSpec;
|
|
@@ -7791,7 +8463,9 @@ function createGeoMap(container, spec, options) {
|
|
|
7791
8463
|
const prevPaint = canAnimate ? captureMapSnapshot(svgElement) : null;
|
|
7792
8464
|
const prevFocusIds = currentFocusIds ? currentFocusIds.map(String).sort().join(",") : null;
|
|
7793
8465
|
const prevFocusSig = focusSignature(currentLayout.focus);
|
|
8466
|
+
const prevMapSize = currentLayout.mapSize;
|
|
7794
8467
|
currentLayout = compile();
|
|
8468
|
+
if (!currentFocusIds) rescaleFreeCamera(prevMapSize);
|
|
7795
8469
|
render();
|
|
7796
8470
|
if (canAnimate && prevPaint && (prevPaint.fills.size > 0 || prevPaint.points.size > 0) && svgElement && currentLayout.animation?.update) {
|
|
7797
8471
|
fillTransitionHandle = runMapFillTransition(svgElement, prevPaint, {
|
|
@@ -7820,11 +8494,10 @@ function createGeoMap(container, spec, options) {
|
|
|
7820
8494
|
pendingResize = true;
|
|
7821
8495
|
return;
|
|
7822
8496
|
}
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
cameraTween = null;
|
|
7826
|
-
}
|
|
8497
|
+
cancelCameraTween();
|
|
8498
|
+
const prevMapSize = currentLayout.mapSize;
|
|
7827
8499
|
currentLayout = compile();
|
|
8500
|
+
if (!currentFocusIds) rescaleFreeCamera(prevMapSize);
|
|
7828
8501
|
render();
|
|
7829
8502
|
if (currentFocusIds && currentFocusIds.length > 0) {
|
|
7830
8503
|
currentCamera = resolveCamera();
|
|
@@ -7835,6 +8508,7 @@ function createGeoMap(container, spec, options) {
|
|
|
7835
8508
|
if (svgElement) applyMapCamera(svgElement, currentCamera, currentLayout);
|
|
7836
8509
|
}
|
|
7837
8510
|
applyFocusDim(currentFocusIds);
|
|
8511
|
+
zoomController?.onCamera();
|
|
7838
8512
|
}
|
|
7839
8513
|
function exportChart(format, options_) {
|
|
7840
8514
|
if (!svgElement) return "";
|
|
@@ -7863,9 +8537,10 @@ function createGeoMap(container, spec, options) {
|
|
|
7863
8537
|
fillTransitionHandle.cancel();
|
|
7864
8538
|
fillTransitionHandle = null;
|
|
7865
8539
|
}
|
|
7866
|
-
|
|
7867
|
-
|
|
7868
|
-
|
|
8540
|
+
cancelCameraTween();
|
|
8541
|
+
if (zoomController) {
|
|
8542
|
+
zoomController.destroy();
|
|
8543
|
+
zoomController = null;
|
|
7869
8544
|
}
|
|
7870
8545
|
if (cleanupTooltipEvents) {
|
|
7871
8546
|
cleanupTooltipEvents();
|
|
@@ -7948,19 +8623,15 @@ function createGeoMap(container, spec, options) {
|
|
|
7948
8623
|
applyFocusDim(null);
|
|
7949
8624
|
},
|
|
7950
8625
|
resetView(opts) {
|
|
7951
|
-
|
|
7952
|
-
const cam = cameraForTarget(currentLayout, null);
|
|
7953
|
-
driveCamera(cam, opts?.duration ?? storyMotion.camera);
|
|
7954
|
-
applyFocusDim(null);
|
|
7955
|
-
updateA11yLive(null);
|
|
8626
|
+
resetCamera(opts?.duration ?? storyMotion.camera);
|
|
7956
8627
|
},
|
|
7957
8628
|
getCamera() {
|
|
7958
8629
|
return { ...currentCamera };
|
|
7959
8630
|
},
|
|
7960
8631
|
setCamera(camera) {
|
|
7961
|
-
|
|
8632
|
+
cancelCameraTween();
|
|
7962
8633
|
currentFocusIds = null;
|
|
7963
|
-
|
|
8634
|
+
commitCamera(camera);
|
|
7964
8635
|
}
|
|
7965
8636
|
};
|
|
7966
8637
|
}
|
|
@@ -7994,4 +8665,4 @@ export {
|
|
|
7994
8665
|
scrubCamera,
|
|
7995
8666
|
createGeoMap
|
|
7996
8667
|
};
|
|
7997
|
-
//# sourceMappingURL=chunk-
|
|
8668
|
+
//# sourceMappingURL=chunk-QBTRAQAX.js.map
|