graphein 0.20.0 → 0.22.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/animation/animate.d.ts +6 -1
- package/dist/animation/animate.d.ts.map +1 -1
- package/dist/animation/animate.js +2 -2
- package/dist/animation/animate.js.map +2 -2
- package/dist/animation/env.d.ts +5 -0
- package/dist/animation/env.d.ts.map +1 -1
- package/dist/animation/env.js +4 -0
- package/dist/animation/env.js.map +2 -2
- package/dist/animation/index.d.ts +1 -0
- package/dist/animation/index.d.ts.map +1 -1
- package/dist/animation/index.js +1 -0
- package/dist/animation/index.js.map +2 -2
- package/dist/animation/stagger.d.ts +13 -0
- package/dist/animation/stagger.d.ts.map +1 -0
- package/dist/animation/stagger.js +13 -0
- package/dist/animation/stagger.js.map +7 -0
- package/dist/axes/draw.d.ts +5 -1
- package/dist/axes/draw.d.ts.map +1 -1
- package/dist/axes/draw.js +13 -1
- package/dist/axes/draw.js.map +2 -2
- package/dist/axes/morph.d.ts +111 -0
- package/dist/axes/morph.d.ts.map +1 -0
- package/dist/axes/morph.js +207 -0
- package/dist/axes/morph.js.map +7 -0
- package/dist/axes/overlay.d.ts.map +1 -1
- package/dist/axes/overlay.js +88 -25
- package/dist/axes/overlay.js.map +2 -2
- package/dist/axes/text.d.ts +2 -0
- package/dist/axes/text.d.ts.map +1 -1
- package/dist/axes/text.js +1 -0
- package/dist/axes/text.js.map +2 -2
- package/dist/axes/tickLabels.d.ts +2 -0
- package/dist/axes/tickLabels.d.ts.map +1 -1
- package/dist/axes/tickLabels.js +2 -2
- package/dist/axes/tickLabels.js.map +2 -2
- package/dist/charts/annotations.d.ts +9 -3
- package/dist/charts/annotations.d.ts.map +1 -1
- package/dist/charts/annotations.js +82 -27
- package/dist/charts/annotations.js.map +2 -2
- package/dist/charts/area.d.ts +37 -1
- package/dist/charts/area.d.ts.map +1 -1
- package/dist/charts/area.js +35 -17
- package/dist/charts/area.js.map +2 -2
- package/dist/charts/bar.d.ts +53 -0
- package/dist/charts/bar.d.ts.map +1 -1
- package/dist/charts/bar.js +117 -83
- package/dist/charts/bar.js.map +2 -2
- package/dist/charts/box.d.ts +31 -0
- package/dist/charts/box.d.ts.map +1 -1
- package/dist/charts/box.js +93 -70
- package/dist/charts/box.js.map +2 -2
- package/dist/charts/bubbleMap.d.ts +20 -0
- package/dist/charts/bubbleMap.d.ts.map +1 -0
- package/dist/charts/bubbleMap.js +951 -0
- package/dist/charts/bubbleMap.js.map +7 -0
- package/dist/charts/bullet.d.ts.map +1 -1
- package/dist/charts/bullet.js +69 -51
- package/dist/charts/bullet.js.map +2 -2
- package/dist/charts/calendarHeatmap.d.ts.map +1 -1
- package/dist/charts/calendarHeatmap.js +56 -19
- package/dist/charts/calendarHeatmap.js.map +2 -2
- package/dist/charts/candlestick.d.ts +40 -0
- package/dist/charts/candlestick.d.ts.map +1 -0
- package/dist/charts/candlestick.js +325 -0
- package/dist/charts/candlestick.js.map +7 -0
- package/dist/charts/choropleth.d.ts.map +1 -1
- package/dist/charts/choropleth.js +46 -67
- package/dist/charts/choropleth.js.map +2 -2
- package/dist/charts/combo.d.ts.map +1 -1
- package/dist/charts/combo.js +127 -27
- package/dist/charts/combo.js.map +3 -3
- package/dist/charts/dumbbell.d.ts.map +1 -1
- package/dist/charts/dumbbell.js +100 -31
- package/dist/charts/dumbbell.js.map +2 -2
- package/dist/charts/funnel.d.ts.map +1 -1
- package/dist/charts/funnel.js +93 -28
- package/dist/charts/funnel.js.map +3 -3
- package/dist/charts/gantt.d.ts +22 -0
- package/dist/charts/gantt.d.ts.map +1 -0
- package/dist/charts/gantt.js +564 -0
- package/dist/charts/gantt.js.map +7 -0
- package/dist/charts/gauge.d.ts.map +1 -1
- package/dist/charts/gauge.js +30 -4
- package/dist/charts/gauge.js.map +2 -2
- package/dist/charts/geo.d.ts +87 -0
- package/dist/charts/geo.d.ts.map +1 -0
- package/dist/charts/geo.js +140 -0
- package/dist/charts/geo.js.map +7 -0
- package/dist/charts/geometry.d.ts +20 -0
- package/dist/charts/geometry.d.ts.map +1 -0
- package/dist/charts/geometry.js +25 -0
- package/dist/charts/geometry.js.map +7 -0
- package/dist/charts/heatmap.d.ts.map +1 -1
- package/dist/charts/heatmap.js +58 -49
- package/dist/charts/heatmap.js.map +2 -2
- package/dist/charts/histogram.d.ts +1 -1
- package/dist/charts/histogram.d.ts.map +1 -1
- package/dist/charts/histogram.js +49 -31
- package/dist/charts/histogram.js.map +2 -2
- package/dist/charts/index.d.ts +35 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +12 -0
- package/dist/charts/index.js.map +2 -2
- package/dist/charts/legibility.d.ts +38 -0
- package/dist/charts/legibility.d.ts.map +1 -0
- package/dist/charts/legibility.js +72 -0
- package/dist/charts/legibility.js.map +7 -0
- package/dist/charts/line.d.ts +39 -1
- package/dist/charts/line.d.ts.map +1 -1
- package/dist/charts/line.js +48 -16
- package/dist/charts/line.js.map +2 -2
- package/dist/charts/matrix.d.ts +2 -1
- package/dist/charts/matrix.d.ts.map +1 -1
- package/dist/charts/matrix.js +481 -319
- package/dist/charts/matrix.js.map +3 -3
- package/dist/charts/morphFrame.d.ts +83 -0
- package/dist/charts/morphFrame.d.ts.map +1 -0
- package/dist/charts/morphFrame.js +128 -0
- package/dist/charts/morphFrame.js.map +7 -0
- package/dist/charts/pie.d.ts.map +1 -1
- package/dist/charts/pie.js +89 -26
- package/dist/charts/pie.js.map +2 -2
- package/dist/charts/pieState.d.ts +27 -0
- package/dist/charts/pieState.d.ts.map +1 -0
- package/dist/charts/pieState.js +55 -0
- package/dist/charts/pieState.js.map +7 -0
- package/dist/charts/radar.d.ts +62 -0
- package/dist/charts/radar.d.ts.map +1 -0
- package/dist/charts/radar.js +912 -0
- package/dist/charts/radar.js.map +7 -0
- package/dist/charts/radialBar.d.ts +60 -0
- package/dist/charts/radialBar.d.ts.map +1 -0
- package/dist/charts/radialBar.js +708 -0
- package/dist/charts/radialBar.js.map +7 -0
- package/dist/charts/sankey.d.ts.map +1 -1
- package/dist/charts/sankey.js +223 -57
- package/dist/charts/sankey.js.map +3 -3
- package/dist/charts/scatter.d.ts +31 -0
- package/dist/charts/scatter.d.ts.map +1 -1
- package/dist/charts/scatter.js +48 -12
- package/dist/charts/scatter.js.map +2 -2
- package/dist/charts/slope.d.ts.map +1 -1
- package/dist/charts/slope.js +55 -3
- package/dist/charts/slope.js.map +2 -2
- package/dist/charts/sunburst.d.ts +14 -0
- package/dist/charts/sunburst.d.ts.map +1 -0
- package/dist/charts/sunburst.js +885 -0
- package/dist/charts/sunburst.js.map +7 -0
- package/dist/charts/table.d.ts +2 -1
- package/dist/charts/table.d.ts.map +1 -1
- package/dist/charts/table.js +214 -224
- package/dist/charts/table.js.map +3 -3
- package/dist/charts/tableView/canvas.d.ts +16 -1
- package/dist/charts/tableView/canvas.d.ts.map +1 -1
- package/dist/charts/tableView/canvas.js +361 -252
- package/dist/charts/tableView/canvas.js.map +3 -3
- package/dist/charts/tableView/conditional.d.ts +66 -40
- package/dist/charts/tableView/conditional.d.ts.map +1 -1
- package/dist/charts/tableView/conditional.js +163 -256
- package/dist/charts/tableView/conditional.js.map +3 -3
- package/dist/charts/tableView/dom.d.ts +26 -2
- package/dist/charts/tableView/dom.d.ts.map +1 -1
- package/dist/charts/tableView/dom.js +609 -269
- package/dist/charts/tableView/dom.js.map +3 -3
- package/dist/charts/tableView/layout.d.ts +22 -0
- package/dist/charts/tableView/layout.d.ts.map +1 -0
- package/dist/charts/tableView/layout.js +246 -0
- package/dist/charts/tableView/layout.js.map +7 -0
- package/dist/charts/tableView/sketch.d.ts +3 -2
- package/dist/charts/tableView/sketch.d.ts.map +1 -1
- package/dist/charts/tableView/sketch.js +2 -2
- package/dist/charts/tableView/sketch.js.map +2 -2
- package/dist/charts/tableView/sketchBar.d.ts +7 -0
- package/dist/charts/tableView/sketchBar.d.ts.map +1 -0
- package/dist/charts/tableView/sketchBar.js +32 -0
- package/dist/charts/tableView/sketchBar.js.map +7 -0
- package/dist/charts/tableView/sort.d.ts +9 -0
- package/dist/charts/tableView/sort.d.ts.map +1 -0
- package/dist/charts/tableView/sort.js +70 -0
- package/dist/charts/tableView/sort.js.map +7 -0
- package/dist/charts/tableView/sparkline.d.ts +30 -0
- package/dist/charts/tableView/sparkline.d.ts.map +1 -0
- package/dist/charts/tableView/sparkline.js +63 -0
- package/dist/charts/tableView/sparkline.js.map +7 -0
- package/dist/charts/tableView/style.d.ts +67 -0
- package/dist/charts/tableView/style.d.ts.map +1 -0
- package/dist/charts/tableView/style.js +131 -0
- package/dist/charts/tableView/style.js.map +7 -0
- package/dist/charts/tableView/types.d.ts +69 -46
- package/dist/charts/tableView/types.d.ts.map +1 -1
- package/dist/charts/tableView/types.js +22 -87
- package/dist/charts/tableView/types.js.map +2 -2
- package/dist/charts/tableView.d.ts +10 -5
- package/dist/charts/tableView.d.ts.map +1 -1
- package/dist/charts/tableView.js +12 -8
- package/dist/charts/tableView.js.map +2 -2
- package/dist/charts/treemap.d.ts.map +1 -1
- package/dist/charts/treemap.js +177 -68
- package/dist/charts/treemap.js.map +3 -3
- package/dist/charts/trendline.d.ts +13 -5
- package/dist/charts/trendline.d.ts.map +1 -1
- package/dist/charts/trendline.js +205 -56
- package/dist/charts/trendline.js.map +2 -2
- package/dist/charts/waterfall.d.ts.map +1 -1
- package/dist/charts/waterfall.js +76 -5
- package/dist/charts/waterfall.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/interaction/cartesian.d.ts +4 -1
- package/dist/interaction/cartesian.d.ts.map +1 -1
- package/dist/interaction/cartesian.js +104 -34
- package/dist/interaction/cartesian.js.map +2 -2
- package/dist/interaction/controller.d.ts +29 -1
- package/dist/interaction/controller.d.ts.map +1 -1
- package/dist/interaction/controller.js +131 -8
- package/dist/interaction/controller.js.map +2 -2
- package/dist/interaction/focus.d.ts +23 -0
- package/dist/interaction/focus.d.ts.map +1 -0
- package/dist/interaction/focus.js +65 -0
- package/dist/interaction/focus.js.map +7 -0
- package/dist/interaction/tooltip.d.ts +6 -0
- package/dist/interaction/tooltip.d.ts.map +1 -1
- package/dist/interaction/tooltip.js +41 -16
- package/dist/interaction/tooltip.js.map +2 -2
- package/dist/interaction/types.d.ts +19 -0
- package/dist/interaction/types.d.ts.map +1 -1
- package/dist/interaction/veil.d.ts +25 -0
- package/dist/interaction/veil.d.ts.map +1 -0
- package/dist/interaction/veil.js +35 -0
- package/dist/interaction/veil.js.map +7 -0
- package/dist/pivot/pivot.d.ts +18 -0
- package/dist/pivot/pivot.d.ts.map +1 -1
- package/dist/pivot/pivot.js +46 -34
- package/dist/pivot/pivot.js.map +2 -2
- package/dist/render/chromeMotion.d.ts +65 -0
- package/dist/render/chromeMotion.d.ts.map +1 -0
- package/dist/render/chromeMotion.js +79 -0
- package/dist/render/chromeMotion.js.map +7 -0
- package/dist/render/pathSample.d.ts +24 -0
- package/dist/render/pathSample.d.ts.map +1 -0
- package/dist/render/pathSample.js +76 -0
- package/dist/render/pathSample.js.map +7 -0
- package/dist/render/transient.d.ts +18 -0
- package/dist/render/transient.d.ts.map +1 -0
- package/dist/render/transient.js +19 -0
- package/dist/render/transient.js.map +7 -0
- package/dist/runtime/candlestick.d.ts +112 -0
- package/dist/runtime/candlestick.d.ts.map +1 -0
- package/dist/runtime/candlestick.js +531 -0
- package/dist/runtime/candlestick.js.map +7 -0
- package/dist/runtime/cartesian.d.ts +14 -3
- package/dist/runtime/cartesian.d.ts.map +1 -1
- package/dist/runtime/cartesian.js.map +2 -2
- package/dist/runtime/chartAnimation.d.ts +54 -7
- package/dist/runtime/chartAnimation.d.ts.map +1 -1
- package/dist/runtime/chartAnimation.js +146 -28
- package/dist/runtime/chartAnimation.js.map +2 -2
- package/dist/runtime/chartRuntime.d.ts +42 -0
- package/dist/runtime/chartRuntime.d.ts.map +1 -1
- package/dist/runtime/chartRuntime.js +196 -30
- package/dist/runtime/chartRuntime.js.map +2 -2
- package/dist/runtime/dashboardDom.d.ts.map +1 -1
- package/dist/runtime/dashboardDom.js +45 -0
- package/dist/runtime/dashboardDom.js.map +2 -2
- package/dist/runtime/facet.d.ts +1 -1
- package/dist/runtime/facet.d.ts.map +1 -1
- package/dist/runtime/gantt.d.ts +137 -0
- package/dist/runtime/gantt.d.ts.map +1 -0
- package/dist/runtime/gantt.js +647 -0
- package/dist/runtime/gantt.js.map +7 -0
- package/dist/runtime/morph.d.ts +33 -0
- package/dist/runtime/morph.d.ts.map +1 -0
- package/dist/runtime/morph.js +332 -0
- package/dist/runtime/morph.js.map +7 -0
- package/dist/runtime/radar.d.ts +75 -0
- package/dist/runtime/radar.d.ts.map +1 -0
- package/dist/runtime/radar.js +201 -0
- package/dist/runtime/radar.js.map +7 -0
- package/dist/runtime/radialBar.d.ts +81 -0
- package/dist/runtime/radialBar.d.ts.map +1 -0
- package/dist/runtime/radialBar.js +125 -0
- package/dist/runtime/radialBar.js.map +7 -0
- package/dist/runtime/report/constants.d.ts +2 -2
- package/dist/runtime/report/constants.d.ts.map +1 -1
- package/dist/runtime/runtimeShared.d.ts +3 -3
- package/dist/runtime/runtimeShared.d.ts.map +1 -1
- package/dist/runtime/sunburst.d.ts +74 -0
- package/dist/runtime/sunburst.d.ts.map +1 -0
- package/dist/runtime/sunburst.js +150 -0
- package/dist/runtime/sunburst.js.map +7 -0
- package/dist/runtime/wire.d.ts.map +1 -1
- package/dist/runtime/wire.js +3 -1
- package/dist/runtime/wire.js.map +2 -2
- package/dist/shape/arc.d.ts +15 -2
- package/dist/shape/arc.d.ts.map +1 -1
- package/dist/shape/arc.js +204 -32
- package/dist/shape/arc.js.map +2 -2
- package/dist/spec/chartDefinitions.d.ts +6 -0
- package/dist/spec/chartDefinitions.d.ts.map +1 -1
- package/dist/spec/chartDefinitions.js +7 -1
- package/dist/spec/chartDefinitions.js.map +2 -2
- package/dist/spec/templates.d.ts.map +1 -1
- package/dist/spec/templates.js +177 -2
- package/dist/spec/templates.js.map +2 -2
- package/dist/spec/types.d.ts +258 -6
- package/dist/spec/types.d.ts.map +1 -1
- package/dist/spec/types.js +6 -0
- package/dist/spec/types.js.map +2 -2
- package/dist/spec/validate/charts.js +147 -15
- package/dist/spec/validate/charts.js.map +2 -2
- package/dist/spec/validate/common.d.ts +6 -0
- package/dist/spec/validate/common.d.ts.map +1 -1
- package/dist/spec/validate/overlays.js +2 -2
- package/dist/spec/validate/overlays.js.map +2 -2
- package/dist/spec/validate.data.d.ts.map +1 -1
- package/dist/spec/validate.data.js +8 -3
- package/dist/spec/validate.data.js.map +2 -2
- package/package.json +1 -1
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
import { interactionMotionDisabled } from "../animation/env.js";
|
|
5
|
+
import { cubicOut } from "../animation/easing.js";
|
|
4
6
|
import { Tooltip } from "./tooltip.js";
|
|
7
|
+
const FOCUS_MS = 160;
|
|
8
|
+
const GLIDE_MS = 180;
|
|
5
9
|
function resolveLegendHit(model, px, py) {
|
|
6
10
|
for (const hit of model.legendHits ?? []) {
|
|
7
11
|
const r = hit.rect;
|
|
@@ -18,6 +22,9 @@ function eventToSurfacePoint(surface, event) {
|
|
|
18
22
|
y: (event.clientY - rect.top) * scaleY
|
|
19
23
|
};
|
|
20
24
|
}
|
|
25
|
+
function clock() {
|
|
26
|
+
return globalThis.performance?.now() ?? Date.now();
|
|
27
|
+
}
|
|
21
28
|
class InteractionController {
|
|
22
29
|
constructor(surface, tokens) {
|
|
23
30
|
__publicField(this, "surface", surface);
|
|
@@ -26,12 +33,30 @@ class InteractionController {
|
|
|
26
33
|
__publicField(this, "tooltip");
|
|
27
34
|
__publicField(this, "raf", 0);
|
|
28
35
|
__publicField(this, "pending", null);
|
|
36
|
+
// The last pointer position inside the surface, so a redraw can re-resolve
|
|
37
|
+
// the hover under a pointer that hasn't moved.
|
|
38
|
+
__publicField(this, "lastPoint", null);
|
|
39
|
+
__publicField(this, "pointerInside", false);
|
|
29
40
|
__publicField(this, "activeKey", null);
|
|
30
41
|
__publicField(this, "selectCfg", null);
|
|
31
42
|
__publicField(this, "pickable", false);
|
|
43
|
+
// Animated highlight state. `shown` is the hover being painted (it outlives
|
|
44
|
+
// `activeKey` while focus fades out); `from` is the hover being glided from.
|
|
45
|
+
__publicField(this, "shown", null);
|
|
46
|
+
__publicField(this, "from");
|
|
47
|
+
__publicField(this, "focus", 0);
|
|
48
|
+
__publicField(this, "focusFrom", 0);
|
|
49
|
+
__publicField(this, "focusTarget", 0);
|
|
50
|
+
__publicField(this, "focusStart", 0);
|
|
51
|
+
__publicField(this, "glideStart", 0);
|
|
52
|
+
__publicField(this, "motionRaf", 0);
|
|
53
|
+
__publicField(this, "scheduling", false);
|
|
54
|
+
__publicField(this, "ranSynchronously", false);
|
|
32
55
|
__publicField(this, "onMove", (e) => {
|
|
33
56
|
if (!this.model) return;
|
|
34
57
|
this.pending = eventToSurfacePoint(this.surface, e);
|
|
58
|
+
this.lastPoint = this.pending;
|
|
59
|
+
this.pointerInside = true;
|
|
35
60
|
if (!this.raf) this.raf = requestAnimationFrame(this.flush);
|
|
36
61
|
});
|
|
37
62
|
__publicField(this, "onLeave", () => {
|
|
@@ -40,6 +65,8 @@ class InteractionController {
|
|
|
40
65
|
this.raf = 0;
|
|
41
66
|
}
|
|
42
67
|
this.pending = null;
|
|
68
|
+
this.pointerInside = false;
|
|
69
|
+
this.lastPoint = null;
|
|
43
70
|
this.clearHover();
|
|
44
71
|
});
|
|
45
72
|
__publicField(this, "onClick", (e) => {
|
|
@@ -67,6 +94,27 @@ class InteractionController {
|
|
|
67
94
|
}
|
|
68
95
|
this.render(hover);
|
|
69
96
|
});
|
|
97
|
+
__publicField(this, "tick", () => {
|
|
98
|
+
const settle = this.scheduling;
|
|
99
|
+
if (settle) this.ranSynchronously = true;
|
|
100
|
+
this.motionRaf = 0;
|
|
101
|
+
const now = clock();
|
|
102
|
+
const focusT = settle ? 1 : Math.min(1, (now - this.focusStart) / FOCUS_MS);
|
|
103
|
+
const glideT = settle || !this.from ? 1 : Math.min(1, (now - this.glideStart) / GLIDE_MS);
|
|
104
|
+
this.focus = this.focusFrom + (this.focusTarget - this.focusFrom) * cubicOut(focusT);
|
|
105
|
+
const ctx = this.surface.interaction.ctx;
|
|
106
|
+
ctx.clearRect(0, 0, this.surface.width, this.surface.height);
|
|
107
|
+
const hover = this.shown;
|
|
108
|
+
if (hover?.paint && this.focus > 0) {
|
|
109
|
+
hover.paint(ctx, { focus: this.focus, glide: this.from ? cubicOut(glideT) : 1, from: this.from });
|
|
110
|
+
}
|
|
111
|
+
if (focusT >= 1 && glideT >= 1) {
|
|
112
|
+
this.from = void 0;
|
|
113
|
+
if (this.focusTarget === 0) this.shown = null;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!settle) this.kick();
|
|
117
|
+
});
|
|
70
118
|
this.tokens = tokens;
|
|
71
119
|
this.tooltip = new Tooltip(surface.root, tokens);
|
|
72
120
|
const root = surface.root;
|
|
@@ -81,8 +129,31 @@ class InteractionController {
|
|
|
81
129
|
this.tokens = tokens;
|
|
82
130
|
this.tooltip.setTokens(tokens);
|
|
83
131
|
this.activeKey = null;
|
|
132
|
+
this.stopMotion();
|
|
133
|
+
this.shown = null;
|
|
134
|
+
this.from = void 0;
|
|
84
135
|
this.pickable = Boolean(model?.pick || model?.legendHits?.length);
|
|
85
|
-
if (!model)
|
|
136
|
+
if (!model) {
|
|
137
|
+
this.focus = 0;
|
|
138
|
+
this.tooltip.hide();
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
if (this.pointerInside && this.lastPoint) {
|
|
142
|
+
this.pending = this.lastPoint;
|
|
143
|
+
if (!this.raf) this.raf = requestAnimationFrame(this.flush);
|
|
144
|
+
} else this.focus = 0;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Repaint the current hover against the latest frame geometry — called when an
|
|
148
|
+
* entrance or update transition settles, so focus drawn mid-animation lands on
|
|
149
|
+
* the finished marks.
|
|
150
|
+
*/
|
|
151
|
+
refresh() {
|
|
152
|
+
if (!this.shown || this.activeKey === null || this.motionRaf) return;
|
|
153
|
+
const ctx = this.surface.interaction.ctx;
|
|
154
|
+
ctx.clearRect(0, 0, this.surface.width, this.surface.height);
|
|
155
|
+
if (this.animated(this.shown)) this.shown.paint(ctx, { focus: this.focus, glide: 1 });
|
|
156
|
+
else this.paintHighlight(this.shown);
|
|
86
157
|
}
|
|
87
158
|
/** Wire click/tap selection for this chart (or `null` to disable it). */
|
|
88
159
|
setSelect(cfg) {
|
|
@@ -91,26 +162,78 @@ class InteractionController {
|
|
|
91
162
|
render(hover) {
|
|
92
163
|
if (hover.key !== this.activeKey) {
|
|
93
164
|
this.activeKey = hover.key;
|
|
94
|
-
this.paintHighlight(hover);
|
|
95
165
|
this.tooltip.setContent(hover.content);
|
|
166
|
+
this.show(hover);
|
|
96
167
|
}
|
|
97
168
|
this.tooltip.place(hover.anchorX, hover.anchorY, this.surface.width, this.surface.height);
|
|
98
169
|
if (this.selectCfg && this.pickable) this.surface.root.style.cursor = "pointer";
|
|
99
170
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
171
|
+
animated(hover) {
|
|
172
|
+
return Boolean(hover?.paint) && !interactionMotionDisabled();
|
|
173
|
+
}
|
|
174
|
+
show(hover) {
|
|
175
|
+
if (!this.animated(hover)) {
|
|
176
|
+
this.stopMotion();
|
|
177
|
+
this.shown = hover;
|
|
178
|
+
this.from = void 0;
|
|
179
|
+
this.focus = 1;
|
|
180
|
+
this.paintHighlight(hover);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const previous = this.shown && this.focus > 0 && this.animated(this.shown) ? this.shown : void 0;
|
|
184
|
+
this.from = previous;
|
|
185
|
+
this.glideStart = clock();
|
|
186
|
+
this.shown = hover;
|
|
187
|
+
this.retargetFocus(1);
|
|
188
|
+
this.kick();
|
|
104
189
|
}
|
|
105
190
|
clearHover() {
|
|
106
|
-
if (this.activeKey === null)
|
|
191
|
+
if (this.activeKey === null) {
|
|
192
|
+
if (!this.shown) this.focus = 0;
|
|
193
|
+
this.tooltip.hide();
|
|
194
|
+
if (this.selectCfg && this.pickable) this.surface.root.style.cursor = "";
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
107
197
|
this.activeKey = null;
|
|
108
|
-
this.surface.interaction.ctx.clearRect(0, 0, this.surface.width, this.surface.height);
|
|
109
198
|
this.tooltip.hide();
|
|
110
199
|
if (this.selectCfg && this.pickable) this.surface.root.style.cursor = "";
|
|
200
|
+
if (this.animated(this.shown) && this.focus > 0) {
|
|
201
|
+
this.retargetFocus(0);
|
|
202
|
+
this.kick();
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
this.stopMotion();
|
|
206
|
+
this.shown = null;
|
|
207
|
+
this.from = void 0;
|
|
208
|
+
this.focus = 0;
|
|
209
|
+
this.surface.interaction.ctx.clearRect(0, 0, this.surface.width, this.surface.height);
|
|
210
|
+
}
|
|
211
|
+
retargetFocus(target) {
|
|
212
|
+
this.focusFrom = this.focus;
|
|
213
|
+
this.focusTarget = target;
|
|
214
|
+
this.focusStart = this.focus === target ? -Infinity : clock();
|
|
215
|
+
}
|
|
216
|
+
kick() {
|
|
217
|
+
if (this.motionRaf) return;
|
|
218
|
+
this.scheduling = true;
|
|
219
|
+
this.ranSynchronously = false;
|
|
220
|
+
const id = requestAnimationFrame(this.tick);
|
|
221
|
+
this.scheduling = false;
|
|
222
|
+
this.motionRaf = this.ranSynchronously ? 0 : id;
|
|
223
|
+
}
|
|
224
|
+
stopMotion() {
|
|
225
|
+
if (this.motionRaf) cancelAnimationFrame(this.motionRaf);
|
|
226
|
+
this.motionRaf = 0;
|
|
227
|
+
}
|
|
228
|
+
paintHighlight(hover) {
|
|
229
|
+
const ctx = this.surface.interaction.ctx;
|
|
230
|
+
ctx.clearRect(0, 0, this.surface.width, this.surface.height);
|
|
231
|
+
if (hover.draw) hover.draw(ctx);
|
|
232
|
+
else hover.paint?.(ctx, { focus: 1, glide: 1 });
|
|
111
233
|
}
|
|
112
234
|
destroy() {
|
|
113
235
|
if (this.raf) cancelAnimationFrame(this.raf);
|
|
236
|
+
this.stopMotion();
|
|
114
237
|
const root = this.surface.root;
|
|
115
238
|
root.removeEventListener("pointermove", this.onMove);
|
|
116
239
|
root.removeEventListener("pointerleave", this.onLeave);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/interaction/controller.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * InteractionController \u2014 the single owner of pointer events for a Surface.\n *\n * Created once per chart instance; handed a fresh `InteractionModel` on every\n * redraw. It throttles pointer moves to one rAF, hit-tests against the current\n * model, paints the highlight onto the interaction canvas, and drives the HTML\n * tooltip. Hover never touches the marks layer.\n */\n\nimport type { Surface } from '../render/surface';\nimport type { ThemeTokens } from '../theme';\nimport { Tooltip } from './tooltip';\nimport type { Hover, InteractionModel, LegendHitRegion } from './types';\nimport type { SelectionValue } from '../spec/selection';\n\n/** How the controller publishes a click/tap selection from the current model. */\nexport interface ControllerSelect {\n /** Called with the picked value (or `null` when empty space is clicked). */\n onPick?(value: SelectionValue | null): void;\n /** Called when an interactive legend swatch is clicked. */\n onLegendToggle?(hit: LegendHitRegion, event: MouseEvent): void;\n}\n\nfunction resolveLegendHit(model: InteractionModel, px: number, py: number): LegendHitRegion | null {\n for (const hit of model.legendHits ?? []) {\n const r = hit.rect;\n if (px >= r.x && px <= r.x + r.width && py >= r.y && py <= r.y + r.height) return hit;\n }\n return null;\n}\n\nexport function eventToSurfacePoint(surface: Surface, event: Pick<PointerEvent, 'clientX' | 'clientY'>): { x: number; y: number } {\n const rect = surface.root.getBoundingClientRect();\n const scaleX = rect.width > 0 ? surface.width / rect.width : 1;\n const scaleY = rect.height > 0 ? surface.height / rect.height : 1;\n return {\n x: (event.clientX - rect.left) * scaleX,\n y: (event.clientY - rect.top) * scaleY,\n };\n}\n\nexport class InteractionController {\n private model: InteractionModel | null = null;\n private tokens: ThemeTokens;\n private readonly tooltip: Tooltip;\n\n private raf = 0;\n private pending: { x: number; y: number } | null = null;\n private activeKey: string | null = null;\n private selectCfg: ControllerSelect | null = null;\n private pickable = false;\n\n constructor(\n private readonly surface: Surface,\n tokens: ThemeTokens,\n ) {\n this.tokens = tokens;\n this.tooltip = new Tooltip(surface.root, tokens);\n const root = surface.root;\n root.addEventListener('pointermove', this.onMove);\n root.addEventListener('pointerleave', this.onLeave);\n root.addEventListener('pointerdown', this.onMove);\n root.addEventListener('click', this.onClick);\n }\n\n /** Install the model for the current frame (or `null` to disable hover). */\n setModel(model: InteractionModel | null, tokens: ThemeTokens): void {\n this.model = model;\n this.tokens = tokens;\n this.tooltip.setTokens(tokens);\n // The per-frame surface.clear() already wiped the interaction canvas and\n // any prior highlight; drop the active hover so the next move re-resolves.\n this.activeKey = null;\n this.pickable = Boolean(model?.pick || model?.legendHits?.length);\n if (!model) this.tooltip.hide();\n }\n\n /** Wire click/tap selection for this chart (or `null` to disable it). */\n setSelect(cfg: ControllerSelect | null): void {\n this.selectCfg = cfg;\n }\n\n private readonly onMove = (e: PointerEvent): void => {\n if (!this.model) return;\n this.pending = eventToSurfacePoint(this.surface, e);\n if (!this.raf) this.raf = requestAnimationFrame(this.flush);\n };\n\n private readonly onLeave = (): void => {\n if (this.raf) {\n cancelAnimationFrame(this.raf);\n this.raf = 0;\n }\n this.pending = null;\n this.clearHover();\n };\n\n private readonly onClick = (e: PointerEvent): void => {\n const cfg = this.selectCfg;\n const model = this.model;\n if (!cfg || !model) return;\n const { x: px, y: py } = eventToSurfacePoint(this.surface, e);\n const onLegendToggle = cfg.onLegendToggle;\n const legendHit = onLegendToggle ? resolveLegendHit(model, px, py) : null;\n if (legendHit && onLegendToggle) {\n onLegendToggle(legendHit, e);\n return;\n }\n if (model.pick && cfg.onPick) cfg.onPick(model.pick(px, py));\n };\n\n private readonly flush = (): void => {\n this.raf = 0;\n const pt = this.pending;\n this.pending = null;\n if (!pt || !this.model) return;\n\n const hover = this.model.hitTest(pt.x, pt.y);\n if (!hover) {\n this.clearHover();\n return;\n }\n this.render(hover);\n };\n\n private render(hover: Hover): void {\n if (hover.key !== this.activeKey) {\n this.activeKey = hover.key;\n this.paintHighlight(hover);\n this.tooltip.setContent(hover.content);\n }\n this.tooltip.place(hover.anchorX, hover.anchorY, this.surface.width, this.surface.height);\n if (this.selectCfg && this.pickable) this.surface.root.style.cursor = 'pointer';\n }\n\n private paintHighlight(hover: Hover): void {\n const ctx = this.surface.interaction.ctx;\n ctx.clearRect(0, 0, this.surface.width, this.surface.height);\n if (hover.draw) hover.draw(ctx);\n }\n\n private clearHover(): void {\n if (this.activeKey === null) return;\n this.activeKey = null;\n this.surface.interaction.ctx.clearRect(0, 0, this.surface.width, this.surface.height);\n this.tooltip.hide();\n if (this.selectCfg && this.pickable) this.surface.root.style.cursor = '';\n }\n\n destroy(): void {\n if (this.raf) cancelAnimationFrame(this.raf);\n const root = this.surface.root;\n root.removeEventListener('pointermove', this.onMove);\n root.removeEventListener('pointerleave', this.onLeave);\n root.removeEventListener('pointerdown', this.onMove);\n root.removeEventListener('click', this.onClick);\n this.tooltip.destroy();\n }\n}\n"],
|
|
5
|
-
"mappings": ";;;
|
|
4
|
+
"sourcesContent": ["/**\n * InteractionController \u2014 the single owner of pointer events for a Surface.\n *\n * Created once per chart instance; handed a fresh `InteractionModel` on every\n * redraw. It throttles pointer moves to one rAF, hit-tests against the current\n * model, paints the highlight onto the interaction canvas, and drives the HTML\n * tooltip. Hover never touches the marks layer.\n *\n * Hovers that expose an animated `paint` get a short, retargetable motion loop:\n * focus fades in when the pointer arrives and out when it leaves, and moving\n * between marks glides the highlight from the previous hover to the new one.\n */\n\nimport type { Surface } from '../render/surface';\nimport type { ThemeTokens } from '../theme';\nimport { interactionMotionDisabled } from '../animation/env';\nimport { cubicOut } from '../animation/easing';\nimport { Tooltip } from './tooltip';\nimport type { Hover, InteractionModel, LegendHitRegion } from './types';\nimport type { SelectionValue } from '../spec/selection';\n\n/** Focus fade (ms) when a hover starts or ends. */\nconst FOCUS_MS = 160;\n/** Glide (ms) between consecutive hovers. */\nconst GLIDE_MS = 180;\n\n/** How the controller publishes a click/tap selection from the current model. */\nexport interface ControllerSelect {\n /** Called with the picked value (or `null` when empty space is clicked). */\n onPick?(value: SelectionValue | null): void;\n /** Called when an interactive legend swatch is clicked. */\n onLegendToggle?(hit: LegendHitRegion, event: MouseEvent): void;\n}\n\nfunction resolveLegendHit(model: InteractionModel, px: number, py: number): LegendHitRegion | null {\n for (const hit of model.legendHits ?? []) {\n const r = hit.rect;\n if (px >= r.x && px <= r.x + r.width && py >= r.y && py <= r.y + r.height) return hit;\n }\n return null;\n}\n\nexport function eventToSurfacePoint(surface: Surface, event: Pick<PointerEvent, 'clientX' | 'clientY'>): { x: number; y: number } {\n const rect = surface.root.getBoundingClientRect();\n const scaleX = rect.width > 0 ? surface.width / rect.width : 1;\n const scaleY = rect.height > 0 ? surface.height / rect.height : 1;\n return {\n x: (event.clientX - rect.left) * scaleX,\n y: (event.clientY - rect.top) * scaleY,\n };\n}\n\nfunction clock(): number {\n return globalThis.performance?.now() ?? Date.now();\n}\n\nexport class InteractionController {\n private model: InteractionModel | null = null;\n private tokens: ThemeTokens;\n private readonly tooltip: Tooltip;\n\n private raf = 0;\n private pending: { x: number; y: number } | null = null;\n // The last pointer position inside the surface, so a redraw can re-resolve\n // the hover under a pointer that hasn't moved.\n private lastPoint: { x: number; y: number } | null = null;\n private pointerInside = false;\n private activeKey: string | null = null;\n private selectCfg: ControllerSelect | null = null;\n private pickable = false;\n\n // Animated highlight state. `shown` is the hover being painted (it outlives\n // `activeKey` while focus fades out); `from` is the hover being glided from.\n private shown: Hover | null = null;\n private from: Hover | undefined;\n private focus = 0;\n private focusFrom = 0;\n private focusTarget = 0;\n private focusStart = 0;\n private glideStart = 0;\n private motionRaf = 0;\n private scheduling = false;\n private ranSynchronously = false;\n\n constructor(\n private readonly surface: Surface,\n tokens: ThemeTokens,\n ) {\n this.tokens = tokens;\n this.tooltip = new Tooltip(surface.root, tokens);\n const root = surface.root;\n root.addEventListener('pointermove', this.onMove);\n root.addEventListener('pointerleave', this.onLeave);\n root.addEventListener('pointerdown', this.onMove);\n root.addEventListener('click', this.onClick);\n }\n\n /** Install the model for the current frame (or `null` to disable hover). */\n setModel(model: InteractionModel | null, tokens: ThemeTokens): void {\n this.model = model;\n this.tokens = tokens;\n this.tooltip.setTokens(tokens);\n // The per-frame surface.clear() already wiped the interaction canvas and\n // any prior highlight; drop the active hover so the next move re-resolves.\n this.activeKey = null;\n this.stopMotion();\n this.shown = null;\n this.from = undefined;\n this.pickable = Boolean(model?.pick || model?.legendHits?.length);\n if (!model) {\n this.focus = 0;\n this.tooltip.hide();\n return;\n }\n // A redraw under a resting pointer (a click selection, a cross-filter, an\n // update) re-resolves the hover right away and keeps its focus, instead of\n // dropping the highlight until the pointer moves again.\n if (this.pointerInside && this.lastPoint) {\n this.pending = this.lastPoint;\n if (!this.raf) this.raf = requestAnimationFrame(this.flush);\n } else this.focus = 0;\n }\n\n /**\n * Repaint the current hover against the latest frame geometry \u2014 called when an\n * entrance or update transition settles, so focus drawn mid-animation lands on\n * the finished marks.\n */\n refresh(): void {\n if (!this.shown || this.activeKey === null || this.motionRaf) return;\n const ctx = this.surface.interaction.ctx;\n ctx.clearRect(0, 0, this.surface.width, this.surface.height);\n if (this.animated(this.shown)) this.shown.paint(ctx, { focus: this.focus, glide: 1 });\n else this.paintHighlight(this.shown);\n }\n\n /** Wire click/tap selection for this chart (or `null` to disable it). */\n setSelect(cfg: ControllerSelect | null): void {\n this.selectCfg = cfg;\n }\n\n private readonly onMove = (e: PointerEvent): void => {\n if (!this.model) return;\n this.pending = eventToSurfacePoint(this.surface, e);\n this.lastPoint = this.pending;\n this.pointerInside = true;\n if (!this.raf) this.raf = requestAnimationFrame(this.flush);\n };\n\n private readonly onLeave = (): void => {\n if (this.raf) {\n cancelAnimationFrame(this.raf);\n this.raf = 0;\n }\n this.pending = null;\n this.pointerInside = false;\n this.lastPoint = null;\n this.clearHover();\n };\n\n private readonly onClick = (e: PointerEvent): void => {\n const cfg = this.selectCfg;\n const model = this.model;\n if (!cfg || !model) return;\n const { x: px, y: py } = eventToSurfacePoint(this.surface, e);\n const onLegendToggle = cfg.onLegendToggle;\n const legendHit = onLegendToggle ? resolveLegendHit(model, px, py) : null;\n if (legendHit && onLegendToggle) {\n onLegendToggle(legendHit, e);\n return;\n }\n if (model.pick && cfg.onPick) cfg.onPick(model.pick(px, py));\n };\n\n private readonly flush = (): void => {\n this.raf = 0;\n const pt = this.pending;\n this.pending = null;\n if (!pt || !this.model) return;\n\n const hover = this.model.hitTest(pt.x, pt.y);\n if (!hover) {\n this.clearHover();\n return;\n }\n this.render(hover);\n };\n\n private render(hover: Hover): void {\n if (hover.key !== this.activeKey) {\n this.activeKey = hover.key;\n this.tooltip.setContent(hover.content);\n this.show(hover);\n }\n this.tooltip.place(hover.anchorX, hover.anchorY, this.surface.width, this.surface.height);\n if (this.selectCfg && this.pickable) this.surface.root.style.cursor = 'pointer';\n }\n\n private animated(hover: Hover | null): hover is Hover & Required<Pick<Hover, 'paint'>> {\n return Boolean(hover?.paint) && !interactionMotionDisabled();\n }\n\n private show(hover: Hover): void {\n if (!this.animated(hover)) {\n this.stopMotion();\n this.shown = hover;\n this.from = undefined;\n this.focus = 1;\n this.paintHighlight(hover);\n return;\n }\n // Glide from whatever is on screen (including a hover still fading out).\n const previous = this.shown && this.focus > 0 && this.animated(this.shown) ? this.shown : undefined;\n this.from = previous;\n this.glideStart = clock();\n this.shown = hover;\n this.retargetFocus(1);\n this.kick();\n }\n\n private clearHover(): void {\n if (this.activeKey === null) {\n if (!this.shown) this.focus = 0;\n // A redraw resets the active key while the tooltip may still be up (the\n // pointer was resting); if the re-check under it finds nothing, it must go.\n this.tooltip.hide();\n if (this.selectCfg && this.pickable) this.surface.root.style.cursor = '';\n return;\n }\n this.activeKey = null;\n this.tooltip.hide();\n if (this.selectCfg && this.pickable) this.surface.root.style.cursor = '';\n if (this.animated(this.shown) && this.focus > 0) {\n this.retargetFocus(0);\n this.kick();\n return;\n }\n this.stopMotion();\n this.shown = null;\n this.from = undefined;\n this.focus = 0;\n this.surface.interaction.ctx.clearRect(0, 0, this.surface.width, this.surface.height);\n }\n\n private retargetFocus(target: number): void {\n this.focusFrom = this.focus;\n this.focusTarget = target;\n // Already there: nothing to fade, so the loop only runs for a glide.\n this.focusStart = this.focus === target ? -Infinity : clock();\n }\n\n private kick(): void {\n if (this.motionRaf) return;\n this.scheduling = true;\n this.ranSynchronously = false;\n const id = requestAnimationFrame(this.tick);\n this.scheduling = false;\n // When the callback already ran inside requestAnimationFrame, no frame is pending.\n this.motionRaf = this.ranSynchronously ? 0 : id;\n }\n\n private stopMotion(): void {\n if (this.motionRaf) cancelAnimationFrame(this.motionRaf);\n this.motionRaf = 0;\n }\n\n private readonly tick = (): void => {\n // A synchronous requestAnimationFrame (tests, some embedded hosts) can't\n // animate; settle on the final state rather than recursing frame by frame.\n const settle = this.scheduling;\n if (settle) this.ranSynchronously = true;\n this.motionRaf = 0;\n const now = clock();\n const focusT = settle ? 1 : Math.min(1, (now - this.focusStart) / FOCUS_MS);\n const glideT = settle || !this.from ? 1 : Math.min(1, (now - this.glideStart) / GLIDE_MS);\n this.focus = this.focusFrom + (this.focusTarget - this.focusFrom) * cubicOut(focusT);\n const ctx = this.surface.interaction.ctx;\n ctx.clearRect(0, 0, this.surface.width, this.surface.height);\n const hover = this.shown;\n if (hover?.paint && this.focus > 0) {\n hover.paint(ctx, { focus: this.focus, glide: this.from ? cubicOut(glideT) : 1, from: this.from });\n }\n if (focusT >= 1 && glideT >= 1) {\n this.from = undefined;\n if (this.focusTarget === 0) this.shown = null;\n return;\n }\n if (!settle) this.kick();\n };\n\n private paintHighlight(hover: Hover): void {\n const ctx = this.surface.interaction.ctx;\n ctx.clearRect(0, 0, this.surface.width, this.surface.height);\n if (hover.draw) hover.draw(ctx);\n else hover.paint?.(ctx, { focus: 1, glide: 1 });\n }\n\n destroy(): void {\n if (this.raf) cancelAnimationFrame(this.raf);\n this.stopMotion();\n const root = this.surface.root;\n root.removeEventListener('pointermove', this.onMove);\n root.removeEventListener('pointerleave', this.onLeave);\n root.removeEventListener('pointerdown', this.onMove);\n root.removeEventListener('click', this.onClick);\n this.tooltip.destroy();\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;AAeA,SAAS,iCAAiC;AAC1C,SAAS,gBAAgB;AACzB,SAAS,eAAe;AAKxB,MAAM,WAAW;AAEjB,MAAM,WAAW;AAUjB,SAAS,iBAAiB,OAAyB,IAAY,IAAoC;AACjG,aAAW,OAAO,MAAM,cAAc,CAAC,GAAG;AACxC,UAAM,IAAI,IAAI;AACd,QAAI,MAAM,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,OAAQ,QAAO;AAAA,EACpF;AACA,SAAO;AACT;AAEO,SAAS,oBAAoB,SAAkB,OAA4E;AAChI,QAAM,OAAO,QAAQ,KAAK,sBAAsB;AAChD,QAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ,QAAQ,KAAK,QAAQ;AAC7D,QAAM,SAAS,KAAK,SAAS,IAAI,QAAQ,SAAS,KAAK,SAAS;AAChE,SAAO;AAAA,IACL,IAAI,MAAM,UAAU,KAAK,QAAQ;AAAA,IACjC,IAAI,MAAM,UAAU,KAAK,OAAO;AAAA,EAClC;AACF;AAEA,SAAS,QAAgB;AACvB,SAAO,WAAW,aAAa,IAAI,KAAK,KAAK,IAAI;AACnD;AAEO,MAAM,sBAAsB;AAAA,EA4BjC,YACmB,SACjB,QACA;AAFiB;AA5BnB,wBAAQ,SAAiC;AACzC,wBAAQ;AACR,wBAAiB;AAEjB,wBAAQ,OAAM;AACd,wBAAQ,WAA2C;AAGnD;AAAA;AAAA,wBAAQ,aAA6C;AACrD,wBAAQ,iBAAgB;AACxB,wBAAQ,aAA2B;AACnC,wBAAQ,aAAqC;AAC7C,wBAAQ,YAAW;AAInB;AAAA;AAAA,wBAAQ,SAAsB;AAC9B,wBAAQ;AACR,wBAAQ,SAAQ;AAChB,wBAAQ,aAAY;AACpB,wBAAQ,eAAc;AACtB,wBAAQ,cAAa;AACrB,wBAAQ,cAAa;AACrB,wBAAQ,aAAY;AACpB,wBAAQ,cAAa;AACrB,wBAAQ,oBAAmB;AA2D3B,wBAAiB,UAAS,CAAC,MAA0B;AACnD,UAAI,CAAC,KAAK,MAAO;AACjB,WAAK,UAAU,oBAAoB,KAAK,SAAS,CAAC;AAClD,WAAK,YAAY,KAAK;AACtB,WAAK,gBAAgB;AACrB,UAAI,CAAC,KAAK,IAAK,MAAK,MAAM,sBAAsB,KAAK,KAAK;AAAA,IAC5D;AAEA,wBAAiB,WAAU,MAAY;AACrC,UAAI,KAAK,KAAK;AACZ,6BAAqB,KAAK,GAAG;AAC7B,aAAK,MAAM;AAAA,MACb;AACA,WAAK,UAAU;AACf,WAAK,gBAAgB;AACrB,WAAK,YAAY;AACjB,WAAK,WAAW;AAAA,IAClB;AAEA,wBAAiB,WAAU,CAAC,MAA0B;AACpD,YAAM,MAAM,KAAK;AACjB,YAAM,QAAQ,KAAK;AACnB,UAAI,CAAC,OAAO,CAAC,MAAO;AACpB,YAAM,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,oBAAoB,KAAK,SAAS,CAAC;AAC5D,YAAM,iBAAiB,IAAI;AAC3B,YAAM,YAAY,iBAAiB,iBAAiB,OAAO,IAAI,EAAE,IAAI;AACrE,UAAI,aAAa,gBAAgB;AAC/B,uBAAe,WAAW,CAAC;AAC3B;AAAA,MACF;AACA,UAAI,MAAM,QAAQ,IAAI,OAAQ,KAAI,OAAO,MAAM,KAAK,IAAI,EAAE,CAAC;AAAA,IAC7D;AAEA,wBAAiB,SAAQ,MAAY;AACnC,WAAK,MAAM;AACX,YAAM,KAAK,KAAK;AAChB,WAAK,UAAU;AACf,UAAI,CAAC,MAAM,CAAC,KAAK,MAAO;AAExB,YAAM,QAAQ,KAAK,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC;AAC3C,UAAI,CAAC,OAAO;AACV,aAAK,WAAW;AAChB;AAAA,MACF;AACA,WAAK,OAAO,KAAK;AAAA,IACnB;AAgFA,wBAAiB,QAAO,MAAY;AAGlC,YAAM,SAAS,KAAK;AACpB,UAAI,OAAQ,MAAK,mBAAmB;AACpC,WAAK,YAAY;AACjB,YAAM,MAAM,MAAM;AAClB,YAAM,SAAS,SAAS,IAAI,KAAK,IAAI,IAAI,MAAM,KAAK,cAAc,QAAQ;AAC1E,YAAM,SAAS,UAAU,CAAC,KAAK,OAAO,IAAI,KAAK,IAAI,IAAI,MAAM,KAAK,cAAc,QAAQ;AACxF,WAAK,QAAQ,KAAK,aAAa,KAAK,cAAc,KAAK,aAAa,SAAS,MAAM;AACnF,YAAM,MAAM,KAAK,QAAQ,YAAY;AACrC,UAAI,UAAU,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AAC3D,YAAM,QAAQ,KAAK;AACnB,UAAI,OAAO,SAAS,KAAK,QAAQ,GAAG;AAClC,cAAM,MAAM,KAAK,EAAE,OAAO,KAAK,OAAO,OAAO,KAAK,OAAO,SAAS,MAAM,IAAI,GAAG,MAAM,KAAK,KAAK,CAAC;AAAA,MAClG;AACA,UAAI,UAAU,KAAK,UAAU,GAAG;AAC9B,aAAK,OAAO;AACZ,YAAI,KAAK,gBAAgB,EAAG,MAAK,QAAQ;AACzC;AAAA,MACF;AACA,UAAI,CAAC,OAAQ,MAAK,KAAK;AAAA,IACzB;AAxME,SAAK,SAAS;AACd,SAAK,UAAU,IAAI,QAAQ,QAAQ,MAAM,MAAM;AAC/C,UAAM,OAAO,QAAQ;AACrB,SAAK,iBAAiB,eAAe,KAAK,MAAM;AAChD,SAAK,iBAAiB,gBAAgB,KAAK,OAAO;AAClD,SAAK,iBAAiB,eAAe,KAAK,MAAM;AAChD,SAAK,iBAAiB,SAAS,KAAK,OAAO;AAAA,EAC7C;AAAA;AAAA,EAGA,SAAS,OAAgC,QAA2B;AAClE,SAAK,QAAQ;AACb,SAAK,SAAS;AACd,SAAK,QAAQ,UAAU,MAAM;AAG7B,SAAK,YAAY;AACjB,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,OAAO;AACZ,SAAK,WAAW,QAAQ,OAAO,QAAQ,OAAO,YAAY,MAAM;AAChE,QAAI,CAAC,OAAO;AACV,WAAK,QAAQ;AACb,WAAK,QAAQ,KAAK;AAClB;AAAA,IACF;AAIA,QAAI,KAAK,iBAAiB,KAAK,WAAW;AACxC,WAAK,UAAU,KAAK;AACpB,UAAI,CAAC,KAAK,IAAK,MAAK,MAAM,sBAAsB,KAAK,KAAK;AAAA,IAC5D,MAAO,MAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAgB;AACd,QAAI,CAAC,KAAK,SAAS,KAAK,cAAc,QAAQ,KAAK,UAAW;AAC9D,UAAM,MAAM,KAAK,QAAQ,YAAY;AACrC,QAAI,UAAU,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AAC3D,QAAI,KAAK,SAAS,KAAK,KAAK,EAAG,MAAK,MAAM,MAAM,KAAK,EAAE,OAAO,KAAK,OAAO,OAAO,EAAE,CAAC;AAAA,QAC/E,MAAK,eAAe,KAAK,KAAK;AAAA,EACrC;AAAA;AAAA,EAGA,UAAU,KAAoC;AAC5C,SAAK,YAAY;AAAA,EACnB;AAAA,EAiDQ,OAAO,OAAoB;AACjC,QAAI,MAAM,QAAQ,KAAK,WAAW;AAChC,WAAK,YAAY,MAAM;AACvB,WAAK,QAAQ,WAAW,MAAM,OAAO;AACrC,WAAK,KAAK,KAAK;AAAA,IACjB;AACA,SAAK,QAAQ,MAAM,MAAM,SAAS,MAAM,SAAS,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AACxF,QAAI,KAAK,aAAa,KAAK,SAAU,MAAK,QAAQ,KAAK,MAAM,SAAS;AAAA,EACxE;AAAA,EAEQ,SAAS,OAAsE;AACrF,WAAO,QAAQ,OAAO,KAAK,KAAK,CAAC,0BAA0B;AAAA,EAC7D;AAAA,EAEQ,KAAK,OAAoB;AAC/B,QAAI,CAAC,KAAK,SAAS,KAAK,GAAG;AACzB,WAAK,WAAW;AAChB,WAAK,QAAQ;AACb,WAAK,OAAO;AACZ,WAAK,QAAQ;AACb,WAAK,eAAe,KAAK;AACzB;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,SAAS,KAAK,QAAQ,KAAK,KAAK,SAAS,KAAK,KAAK,IAAI,KAAK,QAAQ;AAC1F,SAAK,OAAO;AACZ,SAAK,aAAa,MAAM;AACxB,SAAK,QAAQ;AACb,SAAK,cAAc,CAAC;AACpB,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,aAAmB;AACzB,QAAI,KAAK,cAAc,MAAM;AAC3B,UAAI,CAAC,KAAK,MAAO,MAAK,QAAQ;AAG9B,WAAK,QAAQ,KAAK;AAClB,UAAI,KAAK,aAAa,KAAK,SAAU,MAAK,QAAQ,KAAK,MAAM,SAAS;AACtE;AAAA,IACF;AACA,SAAK,YAAY;AACjB,SAAK,QAAQ,KAAK;AAClB,QAAI,KAAK,aAAa,KAAK,SAAU,MAAK,QAAQ,KAAK,MAAM,SAAS;AACtE,QAAI,KAAK,SAAS,KAAK,KAAK,KAAK,KAAK,QAAQ,GAAG;AAC/C,WAAK,cAAc,CAAC;AACpB,WAAK,KAAK;AACV;AAAA,IACF;AACA,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,OAAO;AACZ,SAAK,QAAQ;AACb,SAAK,QAAQ,YAAY,IAAI,UAAU,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AAAA,EACtF;AAAA,EAEQ,cAAc,QAAsB;AAC1C,SAAK,YAAY,KAAK;AACtB,SAAK,cAAc;AAEnB,SAAK,aAAa,KAAK,UAAU,SAAS,YAAY,MAAM;AAAA,EAC9D;AAAA,EAEQ,OAAa;AACnB,QAAI,KAAK,UAAW;AACpB,SAAK,aAAa;AAClB,SAAK,mBAAmB;AACxB,UAAM,KAAK,sBAAsB,KAAK,IAAI;AAC1C,SAAK,aAAa;AAElB,SAAK,YAAY,KAAK,mBAAmB,IAAI;AAAA,EAC/C;AAAA,EAEQ,aAAmB;AACzB,QAAI,KAAK,UAAW,sBAAqB,KAAK,SAAS;AACvD,SAAK,YAAY;AAAA,EACnB;AAAA,EA0BQ,eAAe,OAAoB;AACzC,UAAM,MAAM,KAAK,QAAQ,YAAY;AACrC,QAAI,UAAU,GAAG,GAAG,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AAC3D,QAAI,MAAM,KAAM,OAAM,KAAK,GAAG;AAAA,QACzB,OAAM,QAAQ,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;AAAA,EAChD;AAAA,EAEA,UAAgB;AACd,QAAI,KAAK,IAAK,sBAAqB,KAAK,GAAG;AAC3C,SAAK,WAAW;AAChB,UAAM,OAAO,KAAK,QAAQ;AAC1B,SAAK,oBAAoB,eAAe,KAAK,MAAM;AACnD,SAAK,oBAAoB,gBAAgB,KAAK,OAAO;AACrD,SAAK,oBAAoB,eAAe,KAAK,MAAM;AACnD,SAAK,oBAAoB,SAAS,KAAK,OAAO;AAC9C,SAAK,QAAQ,QAAQ;AAAA,EACvB;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hover focus — recede everything except the marks under the pointer.
|
|
3
|
+
*
|
|
4
|
+
* The interaction canvas sits above the marks layer, so focus is painted as a
|
|
5
|
+
* translucent veil of the chart background over the plot (dimming every mark
|
|
6
|
+
* beneath it) with the focused subset of the frame's mark geometry repainted on
|
|
7
|
+
* top at full strength. Nothing touches the marks layer or the render report.
|
|
8
|
+
*/
|
|
9
|
+
import type { CartesianModel } from '../runtime/cartesian.js';
|
|
10
|
+
import { type CartesianGeometry } from '../charts/geometry.js';
|
|
11
|
+
export { FOCUS_VEIL, hoverFocusEnabled, paintCutoutVeil, paintFocusVeil } from './veil.js';
|
|
12
|
+
/** What a hover focuses: a category (bar group), a series, or both. */
|
|
13
|
+
export interface FocusTarget {
|
|
14
|
+
category?: string;
|
|
15
|
+
series?: string;
|
|
16
|
+
}
|
|
17
|
+
/** The subset of `geometry` a hover focuses, or null when nothing would be emphasized. */
|
|
18
|
+
export declare function focusSubset(geometry: CartesianGeometry | undefined, target: FocusTarget | null): CartesianGeometry | null;
|
|
19
|
+
/** Repaint focused geometry onto `ctx` (the interaction layer) at `alpha`. */
|
|
20
|
+
export declare function paintFocusedGeometry(ctx: CanvasRenderingContext2D, model: CartesianModel, geometry: CartesianGeometry, alpha?: number): void;
|
|
21
|
+
/** The color a veil should use for this chart: its background. */
|
|
22
|
+
export declare function focusVeilColor(model: CartesianModel): string;
|
|
23
|
+
//# sourceMappingURL=focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"focus.d.ts","sourceRoot":"","sources":["../../src/interaction/focus.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAiB,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE3E,OAAO,EAAE,UAAU,EAAE,iBAAiB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAExF,uEAAuE;AACvE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,CAAC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,iBAAiB,GAAG,IAAI,CA6BzH;AAmBD,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,wBAAwB,EAC7B,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,iBAAiB,EAC3B,KAAK,SAAI,GACR,IAAI,CAIN;AAED,kEAAkE;AAClE,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAE5D"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { paintGeometry } from "../charts/geometry.js";
|
|
2
|
+
import { FOCUS_VEIL, hoverFocusEnabled, paintCutoutVeil, paintFocusVeil } from "./veil.js";
|
|
3
|
+
function focusSubset(geometry, target) {
|
|
4
|
+
if (!geometry || !target) return null;
|
|
5
|
+
const { category, series } = target;
|
|
6
|
+
switch (geometry.kind) {
|
|
7
|
+
case "bar": {
|
|
8
|
+
const marks = geometry.marks.filter(
|
|
9
|
+
(mark) => (category == null || mark.category === category) && (series == null || mark.seriesKey === series)
|
|
10
|
+
);
|
|
11
|
+
return marks.length ? { ...geometry, marks } : null;
|
|
12
|
+
}
|
|
13
|
+
case "line": {
|
|
14
|
+
const kept = geometry.series.filter((s) => s.series.key === series);
|
|
15
|
+
return kept.length ? { ...geometry, series: kept } : null;
|
|
16
|
+
}
|
|
17
|
+
case "area": {
|
|
18
|
+
const bands = geometry.bands.filter((band) => band.series.key === series);
|
|
19
|
+
return bands.length ? { ...geometry, bands } : null;
|
|
20
|
+
}
|
|
21
|
+
case "scatter": {
|
|
22
|
+
const points = geometry.points.filter((point) => point.seriesKey === series);
|
|
23
|
+
return points.length ? { ...geometry, points } : null;
|
|
24
|
+
}
|
|
25
|
+
case "box": {
|
|
26
|
+
const marks = geometry.marks.filter(
|
|
27
|
+
(mark) => (category == null || mark.category === category) && (series == null || mark.seriesKey === series)
|
|
28
|
+
);
|
|
29
|
+
return marks.length ? { ...geometry, marks } : null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function fadeGeometry(geometry, alpha) {
|
|
34
|
+
if (alpha >= 1) return geometry;
|
|
35
|
+
switch (geometry.kind) {
|
|
36
|
+
case "bar":
|
|
37
|
+
return { ...geometry, marks: geometry.marks.map((mark) => ({ ...mark, alpha: mark.alpha * alpha })) };
|
|
38
|
+
case "line":
|
|
39
|
+
return { ...geometry, series: geometry.series.map((s) => ({ ...s, alpha: s.alpha * alpha })) };
|
|
40
|
+
case "area":
|
|
41
|
+
return { ...geometry, bands: geometry.bands.map((band) => ({ ...band, alpha: band.alpha * alpha })) };
|
|
42
|
+
case "scatter":
|
|
43
|
+
return { ...geometry, points: geometry.points.map((point) => ({ ...point, alpha: point.alpha * alpha })) };
|
|
44
|
+
case "box":
|
|
45
|
+
return { ...geometry, marks: geometry.marks.map((mark) => ({ ...mark, alpha: mark.alpha * alpha })) };
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function paintFocusedGeometry(ctx, model, geometry, alpha = 1) {
|
|
49
|
+
if (!(alpha > 0)) return;
|
|
50
|
+
const surface = { marks: { ctx } };
|
|
51
|
+
paintGeometry(surface, model, fadeGeometry(geometry, Math.min(1, alpha)));
|
|
52
|
+
}
|
|
53
|
+
function focusVeilColor(model) {
|
|
54
|
+
return model.spec.background ?? model.tokens.color.background;
|
|
55
|
+
}
|
|
56
|
+
export {
|
|
57
|
+
FOCUS_VEIL,
|
|
58
|
+
focusSubset,
|
|
59
|
+
focusVeilColor,
|
|
60
|
+
hoverFocusEnabled,
|
|
61
|
+
paintCutoutVeil,
|
|
62
|
+
paintFocusVeil,
|
|
63
|
+
paintFocusedGeometry
|
|
64
|
+
};
|
|
65
|
+
//# sourceMappingURL=focus.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/interaction/focus.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Hover focus \u2014 recede everything except the marks under the pointer.\n *\n * The interaction canvas sits above the marks layer, so focus is painted as a\n * translucent veil of the chart background over the plot (dimming every mark\n * beneath it) with the focused subset of the frame's mark geometry repainted on\n * top at full strength. Nothing touches the marks layer or the render report.\n */\n\nimport type { Surface } from '../render/surface';\nimport type { CartesianModel } from '../runtime/cartesian';\nimport { paintGeometry, type CartesianGeometry } from '../charts/geometry';\n\nexport { FOCUS_VEIL, hoverFocusEnabled, paintCutoutVeil, paintFocusVeil } from './veil';\n\n/** What a hover focuses: a category (bar group), a series, or both. */\nexport interface FocusTarget {\n category?: string;\n series?: string;\n}\n\n/** The subset of `geometry` a hover focuses, or null when nothing would be emphasized. */\nexport function focusSubset(geometry: CartesianGeometry | undefined, target: FocusTarget | null): CartesianGeometry | null {\n if (!geometry || !target) return null;\n const { category, series } = target;\n switch (geometry.kind) {\n case 'bar': {\n const marks = geometry.marks.filter(\n (mark) => (category == null || mark.category === category) && (series == null || mark.seriesKey === series),\n );\n return marks.length ? { ...geometry, marks } : null;\n }\n case 'line': {\n const kept = geometry.series.filter((s) => s.series.key === series);\n return kept.length ? { ...geometry, series: kept } : null;\n }\n case 'area': {\n const bands = geometry.bands.filter((band) => band.series.key === series);\n return bands.length ? { ...geometry, bands } : null;\n }\n case 'scatter': {\n const points = geometry.points.filter((point) => point.seriesKey === series);\n return points.length ? { ...geometry, points } : null;\n }\n case 'box': {\n const marks = geometry.marks.filter(\n (mark) => (category == null || mark.category === category) && (series == null || mark.seriesKey === series),\n );\n return marks.length ? { ...geometry, marks } : null;\n }\n }\n}\n\n/** A copy of `geometry` with every mark's opacity scaled by `alpha`. */\nfunction fadeGeometry(geometry: CartesianGeometry, alpha: number): CartesianGeometry {\n if (alpha >= 1) return geometry;\n switch (geometry.kind) {\n case 'bar':\n return { ...geometry, marks: geometry.marks.map((mark) => ({ ...mark, alpha: mark.alpha * alpha })) };\n case 'line':\n return { ...geometry, series: geometry.series.map((s) => ({ ...s, alpha: s.alpha * alpha })) };\n case 'area':\n return { ...geometry, bands: geometry.bands.map((band) => ({ ...band, alpha: band.alpha * alpha })) };\n case 'scatter':\n return { ...geometry, points: geometry.points.map((point) => ({ ...point, alpha: point.alpha * alpha })) };\n case 'box':\n return { ...geometry, marks: geometry.marks.map((mark) => ({ ...mark, alpha: mark.alpha * alpha })) };\n }\n}\n\n/** Repaint focused geometry onto `ctx` (the interaction layer) at `alpha`. */\nexport function paintFocusedGeometry(\n ctx: CanvasRenderingContext2D,\n model: CartesianModel,\n geometry: CartesianGeometry,\n alpha = 1,\n): void {\n if (!(alpha > 0)) return;\n const surface = { marks: { ctx } } as unknown as Surface;\n paintGeometry(surface, model, fadeGeometry(geometry, Math.min(1, alpha)));\n}\n\n/** The color a veil should use for this chart: its background. */\nexport function focusVeilColor(model: CartesianModel): string {\n return model.spec.background ?? model.tokens.color.background;\n}\n"],
|
|
5
|
+
"mappings": "AAWA,SAAS,qBAA6C;AAEtD,SAAS,YAAY,mBAAmB,iBAAiB,sBAAsB;AASxE,SAAS,YAAY,UAAyC,QAAsD;AACzH,MAAI,CAAC,YAAY,CAAC,OAAQ,QAAO;AACjC,QAAM,EAAE,UAAU,OAAO,IAAI;AAC7B,UAAQ,SAAS,MAAM;AAAA,IACrB,KAAK,OAAO;AACV,YAAM,QAAQ,SAAS,MAAM;AAAA,QAC3B,CAAC,UAAU,YAAY,QAAQ,KAAK,aAAa,cAAc,UAAU,QAAQ,KAAK,cAAc;AAAA,MACtG;AACA,aAAO,MAAM,SAAS,EAAE,GAAG,UAAU,MAAM,IAAI;AAAA,IACjD;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,OAAO,SAAS,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,QAAQ,MAAM;AAClE,aAAO,KAAK,SAAS,EAAE,GAAG,UAAU,QAAQ,KAAK,IAAI;AAAA,IACvD;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,QAAQ,SAAS,MAAM,OAAO,CAAC,SAAS,KAAK,OAAO,QAAQ,MAAM;AACxE,aAAO,MAAM,SAAS,EAAE,GAAG,UAAU,MAAM,IAAI;AAAA,IACjD;AAAA,IACA,KAAK,WAAW;AACd,YAAM,SAAS,SAAS,OAAO,OAAO,CAAC,UAAU,MAAM,cAAc,MAAM;AAC3E,aAAO,OAAO,SAAS,EAAE,GAAG,UAAU,OAAO,IAAI;AAAA,IACnD;AAAA,IACA,KAAK,OAAO;AACV,YAAM,QAAQ,SAAS,MAAM;AAAA,QAC3B,CAAC,UAAU,YAAY,QAAQ,KAAK,aAAa,cAAc,UAAU,QAAQ,KAAK,cAAc;AAAA,MACtG;AACA,aAAO,MAAM,SAAS,EAAE,GAAG,UAAU,MAAM,IAAI;AAAA,IACjD;AAAA,EACF;AACF;AAGA,SAAS,aAAa,UAA6B,OAAkC;AACnF,MAAI,SAAS,EAAG,QAAO;AACvB,UAAQ,SAAS,MAAM;AAAA,IACrB,KAAK;AACH,aAAO,EAAE,GAAG,UAAU,OAAO,SAAS,MAAM,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,KAAK,QAAQ,MAAM,EAAE,EAAE;AAAA,IACtG,KAAK;AACH,aAAO,EAAE,GAAG,UAAU,QAAQ,SAAS,OAAO,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,OAAO,EAAE,QAAQ,MAAM,EAAE,EAAE;AAAA,IAC/F,KAAK;AACH,aAAO,EAAE,GAAG,UAAU,OAAO,SAAS,MAAM,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,KAAK,QAAQ,MAAM,EAAE,EAAE;AAAA,IACtG,KAAK;AACH,aAAO,EAAE,GAAG,UAAU,QAAQ,SAAS,OAAO,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,OAAO,MAAM,QAAQ,MAAM,EAAE,EAAE;AAAA,IAC3G,KAAK;AACH,aAAO,EAAE,GAAG,UAAU,OAAO,SAAS,MAAM,IAAI,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,KAAK,QAAQ,MAAM,EAAE,EAAE;AAAA,EACxG;AACF;AAGO,SAAS,qBACd,KACA,OACA,UACA,QAAQ,GACF;AACN,MAAI,EAAE,QAAQ,GAAI;AAClB,QAAM,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE;AACjC,gBAAc,SAAS,OAAO,aAAa,UAAU,KAAK,IAAI,GAAG,KAAK,CAAC,CAAC;AAC1E;AAGO,SAAS,eAAe,OAA+B;AAC5D,SAAO,MAAM,KAAK,cAAc,MAAM,OAAO,MAAM;AACrD;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -11,9 +11,15 @@ export declare class Tooltip {
|
|
|
11
11
|
private readonly el;
|
|
12
12
|
private tokens;
|
|
13
13
|
private visible;
|
|
14
|
+
private parkTimer;
|
|
14
15
|
constructor(root: HTMLElement, tokens: ThemeTokens);
|
|
15
16
|
setTokens(tokens: ThemeTokens): void;
|
|
16
17
|
private applyShell;
|
|
18
|
+
/**
|
|
19
|
+
* The card glides between anchors (decelerating) and fades/scales in and out.
|
|
20
|
+
* Reduced motion keeps only a short fade.
|
|
21
|
+
*/
|
|
22
|
+
private motion;
|
|
17
23
|
/** Replace the card contents from structured data. */
|
|
18
24
|
setContent(content: TooltipContent): void;
|
|
19
25
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../src/interaction/tooltip.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"tooltip.d.ts","sourceRoot":"","sources":["../../src/interaction/tooltip.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAG5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAU9C,qBAAa,OAAO;IAOhB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANvB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAiB;IACpC,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAA4C;gBAG1C,IAAI,EAAE,WAAW,EAClC,MAAM,EAAE,WAAW;IAQrB,SAAS,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAKpC,OAAO,CAAC,UAAU;IA4BlB;;;OAGG;IACH,OAAO,CAAC,MAAM;IAMd,sDAAsD;IACtD,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;IA2DzC;;;OAGG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IA8BjF,IAAI,IAAI,IAAI;IAWZ,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -2,14 +2,19 @@ var __defProp = Object.defineProperty;
|
|
|
2
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
3
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
4
|
import { createDiv, setStyle } from "../render/dom.js";
|
|
5
|
+
import { interactionMotionDisabled } from "../animation/env.js";
|
|
5
6
|
const OFFSET = 14;
|
|
6
7
|
const EDGE_PAD = 8;
|
|
8
|
+
const GLIDE = "cubic-bezier(0.22, 1, 0.36, 1)";
|
|
9
|
+
const PARK_DELAY = 220;
|
|
10
|
+
const PARKED = "translate(-9999px, -9999px)";
|
|
7
11
|
class Tooltip {
|
|
8
12
|
constructor(root, tokens) {
|
|
9
13
|
__publicField(this, "root", root);
|
|
10
14
|
__publicField(this, "el");
|
|
11
15
|
__publicField(this, "tokens");
|
|
12
16
|
__publicField(this, "visible", false);
|
|
17
|
+
__publicField(this, "parkTimer");
|
|
13
18
|
this.tokens = tokens;
|
|
14
19
|
this.el = createDiv("graphein-tooltip");
|
|
15
20
|
this.applyShell();
|
|
@@ -32,17 +37,25 @@ class Tooltip {
|
|
|
32
37
|
background: t.color.surface,
|
|
33
38
|
color: t.color.text,
|
|
34
39
|
border: `1px solid ${t.color.border}`,
|
|
35
|
-
borderRadius: `${t.radius.
|
|
36
|
-
boxShadow: t.dark ? "0
|
|
40
|
+
borderRadius: `${t.radius.lg}px`,
|
|
41
|
+
boxShadow: t.dark ? "0 1px 2px rgba(0,0,0,0.35), 0 12px 32px rgba(0,0,0,0.5)" : "0 1px 2px rgba(15,23,42,0.06), 0 10px 28px rgba(15,23,42,0.14)",
|
|
37
42
|
font: `${t.font.size.small}px/1.45 ${t.font.family}`,
|
|
38
43
|
fontWeight: String(t.font.weight.normal),
|
|
39
|
-
opacity: "0",
|
|
40
|
-
transform:
|
|
41
|
-
|
|
44
|
+
opacity: this.visible ? "1" : "0",
|
|
45
|
+
transform: this.visible ? this.el.style.transform : PARKED,
|
|
46
|
+
transformOrigin: "top left",
|
|
47
|
+
transition: this.motion(),
|
|
42
48
|
zIndex: "20",
|
|
43
49
|
whiteSpace: "nowrap"
|
|
44
50
|
});
|
|
45
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The card glides between anchors (decelerating) and fades/scales in and out.
|
|
54
|
+
* Reduced motion keeps only a short fade.
|
|
55
|
+
*/
|
|
56
|
+
motion() {
|
|
57
|
+
return interactionMotionDisabled() ? "opacity 120ms ease" : `opacity 140ms ease, transform 200ms ${GLIDE}, scale 200ms ${GLIDE}`;
|
|
58
|
+
}
|
|
46
59
|
/** Replace the card contents from structured data. */
|
|
47
60
|
setContent(content) {
|
|
48
61
|
const t = this.tokens;
|
|
@@ -69,10 +82,11 @@ class Tooltip {
|
|
|
69
82
|
if (row.swatch) {
|
|
70
83
|
const chip = createDiv("graphein-tooltip-swatch", {
|
|
71
84
|
flex: "0 0 auto",
|
|
72
|
-
width: "
|
|
73
|
-
height: "
|
|
74
|
-
borderRadius: "
|
|
75
|
-
background: row.swatch
|
|
85
|
+
width: "8px",
|
|
86
|
+
height: "8px",
|
|
87
|
+
borderRadius: "2.5px",
|
|
88
|
+
background: row.swatch,
|
|
89
|
+
boxShadow: `0 0 0 1px ${t.dark ? "rgba(255,255,255,0.12)" : "rgba(15,23,42,0.08)"}`
|
|
76
90
|
});
|
|
77
91
|
line.appendChild(chip);
|
|
78
92
|
}
|
|
@@ -109,20 +123,31 @@ class Tooltip {
|
|
|
109
123
|
let top = anchorY + OFFSET;
|
|
110
124
|
if (top + h > surfaceH - EDGE_PAD) top = anchorY - OFFSET - h;
|
|
111
125
|
top = Math.max(EDGE_PAD, Math.min(top, surfaceH - h - EDGE_PAD));
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
this.
|
|
115
|
-
void
|
|
116
|
-
|
|
126
|
+
const transform = `translate(${Math.round(left)}px, ${Math.round(top)}px)`;
|
|
127
|
+
if (this.parkTimer !== void 0) {
|
|
128
|
+
clearTimeout(this.parkTimer);
|
|
129
|
+
this.parkTimer = void 0;
|
|
130
|
+
}
|
|
131
|
+
if (this.visible) {
|
|
132
|
+
setStyle(this.el, { transform });
|
|
133
|
+
return;
|
|
117
134
|
}
|
|
135
|
+
this.visible = true;
|
|
136
|
+
setStyle(this.el, { transition: "none", transform, scale: "0.97" });
|
|
137
|
+
void this.el.offsetWidth;
|
|
138
|
+
setStyle(this.el, { transition: this.motion(), opacity: "1", scale: "1" });
|
|
118
139
|
}
|
|
119
140
|
hide() {
|
|
120
141
|
if (!this.visible) return;
|
|
121
142
|
this.visible = false;
|
|
122
|
-
this.el
|
|
123
|
-
this.
|
|
143
|
+
setStyle(this.el, { opacity: "0", scale: "0.97" });
|
|
144
|
+
this.parkTimer = setTimeout(() => {
|
|
145
|
+
this.parkTimer = void 0;
|
|
146
|
+
if (!this.visible) this.el.style.transform = PARKED;
|
|
147
|
+
}, PARK_DELAY);
|
|
124
148
|
}
|
|
125
149
|
destroy() {
|
|
150
|
+
if (this.parkTimer !== void 0) clearTimeout(this.parkTimer);
|
|
126
151
|
this.el.remove();
|
|
127
152
|
}
|
|
128
153
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/interaction/tooltip.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * The hover tooltip \u2014 a flat, themed HTML card the controller positions next to\n * the cursor. It lives as a direct child of the Surface root (a sibling of the\n * overlay layer) so the per-frame `surface.clear()` never wipes it; the\n * controller owns its full lifecycle.\n */\n\nimport type { ThemeTokens } from '../theme';\nimport { createDiv, setStyle } from '../render/dom';\nimport type { TooltipContent } from './types';\n\nconst OFFSET = 14;\nconst EDGE_PAD = 8;\n\nexport class Tooltip {\n private readonly el: HTMLDivElement;\n private tokens: ThemeTokens;\n private visible = false;\n\n constructor(\n private readonly root: HTMLElement,\n tokens: ThemeTokens,\n ) {\n this.tokens = tokens;\n this.el = createDiv('graphein-tooltip');\n this.applyShell();\n this.root.appendChild(this.el);\n }\n\n setTokens(tokens: ThemeTokens): void {\n this.tokens = tokens;\n this.applyShell();\n }\n\n private applyShell(): void {\n const t = this.tokens;\n setStyle(this.el, {\n position: 'absolute',\n top: '0',\n left: '0',\n pointerEvents: 'none',\n boxSizing: 'border-box',\n maxWidth: '280px',\n padding: `${t.spacing.sm}px ${t.spacing.md}px`,\n background: t.color.surface,\n color: t.color.text,\n border: `1px solid ${t.color.border}`,\n borderRadius: `${t.radius.
|
|
5
|
-
"mappings": ";;;AAQA,SAAS,WAAW,gBAAgB;
|
|
4
|
+
"sourcesContent": ["/**\n * The hover tooltip \u2014 a flat, themed HTML card the controller positions next to\n * the cursor. It lives as a direct child of the Surface root (a sibling of the\n * overlay layer) so the per-frame `surface.clear()` never wipes it; the\n * controller owns its full lifecycle.\n */\n\nimport type { ThemeTokens } from '../theme';\nimport { createDiv, setStyle } from '../render/dom';\nimport { interactionMotionDisabled } from '../animation/env';\nimport type { TooltipContent } from './types';\n\nconst OFFSET = 14;\nconst EDGE_PAD = 8;\n/** Decelerating glide: quick to respond, soft to settle. */\nconst GLIDE = 'cubic-bezier(0.22, 1, 0.36, 1)';\n/** How long a hidden card lingers (fading) before it is parked off-surface. */\nconst PARK_DELAY = 220;\nconst PARKED = 'translate(-9999px, -9999px)';\n\nexport class Tooltip {\n private readonly el: HTMLDivElement;\n private tokens: ThemeTokens;\n private visible = false;\n private parkTimer: ReturnType<typeof setTimeout> | undefined;\n\n constructor(\n private readonly root: HTMLElement,\n tokens: ThemeTokens,\n ) {\n this.tokens = tokens;\n this.el = createDiv('graphein-tooltip');\n this.applyShell();\n this.root.appendChild(this.el);\n }\n\n setTokens(tokens: ThemeTokens): void {\n this.tokens = tokens;\n this.applyShell();\n }\n\n private applyShell(): void {\n const t = this.tokens;\n setStyle(this.el, {\n position: 'absolute',\n top: '0',\n left: '0',\n pointerEvents: 'none',\n boxSizing: 'border-box',\n maxWidth: '280px',\n padding: `${t.spacing.sm}px ${t.spacing.md}px`,\n background: t.color.surface,\n color: t.color.text,\n border: `1px solid ${t.color.border}`,\n borderRadius: `${t.radius.lg}px`,\n boxShadow: t.dark\n ? '0 1px 2px rgba(0,0,0,0.35), 0 12px 32px rgba(0,0,0,0.5)'\n : '0 1px 2px rgba(15,23,42,0.06), 0 10px 28px rgba(15,23,42,0.14)',\n font: `${t.font.size.small}px/1.45 ${t.font.family}`,\n fontWeight: String(t.font.weight.normal),\n opacity: this.visible ? '1' : '0',\n transform: this.visible ? this.el.style.transform : PARKED,\n transformOrigin: 'top left',\n transition: this.motion(),\n zIndex: '20',\n whiteSpace: 'nowrap',\n });\n }\n\n /**\n * The card glides between anchors (decelerating) and fades/scales in and out.\n * Reduced motion keeps only a short fade.\n */\n private motion(): string {\n return interactionMotionDisabled()\n ? 'opacity 120ms ease'\n : `opacity 140ms ease, transform 200ms ${GLIDE}, scale 200ms ${GLIDE}`;\n }\n\n /** Replace the card contents from structured data. */\n setContent(content: TooltipContent): void {\n const t = this.tokens;\n this.el.replaceChildren();\n\n if (content.title) {\n const head = createDiv('graphein-tooltip-title', {\n fontWeight: String(t.font.weight.bold),\n fontSize: `${t.font.size.base}px`,\n color: t.color.text,\n marginBottom: content.rows.length ? `${t.spacing.xs}px` : '0',\n });\n head.textContent = content.title;\n this.el.appendChild(head);\n }\n\n for (const row of content.rows) {\n const line = createDiv('graphein-tooltip-row', {\n display: 'flex',\n alignItems: 'center',\n gap: `${t.spacing.sm}px`,\n padding: '1px 0',\n color: row.muted ? t.color.textMuted : t.color.text,\n fontWeight: String(row.strong ? t.font.weight.bold : t.font.weight.normal),\n });\n\n if (row.swatch) {\n const chip = createDiv('graphein-tooltip-swatch', {\n flex: '0 0 auto',\n width: '8px',\n height: '8px',\n borderRadius: '2.5px',\n background: row.swatch,\n boxShadow: `0 0 0 1px ${t.dark ? 'rgba(255,255,255,0.12)' : 'rgba(15,23,42,0.08)'}`,\n });\n line.appendChild(chip);\n }\n\n const label = createDiv('graphein-tooltip-label', {\n flex: '1 1 auto',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n paddingRight: `${t.spacing.md}px`,\n });\n label.textContent = row.label;\n line.appendChild(label);\n\n const value = createDiv('graphein-tooltip-value', {\n flex: '0 0 auto',\n marginLeft: 'auto',\n fontVariantNumeric: 'tabular-nums',\n fontWeight: String(row.strong ? t.font.weight.bold : t.font.weight.medium),\n });\n value.textContent = row.value;\n line.appendChild(value);\n\n this.el.appendChild(line);\n }\n }\n\n /**\n * Position the card near (anchorX, anchorY) in CSS px, flipping away from the\n * surface edges so it never clips. `surfaceW/H` bound the placement.\n */\n place(anchorX: number, anchorY: number, surfaceW: number, surfaceH: number): void {\n const rect = this.el.getBoundingClientRect();\n const w = rect.width || this.el.offsetWidth;\n const h = rect.height || this.el.offsetHeight;\n\n let left = anchorX + OFFSET;\n if (left + w > surfaceW - EDGE_PAD) left = anchorX - OFFSET - w;\n left = Math.max(EDGE_PAD, Math.min(left, surfaceW - w - EDGE_PAD));\n\n let top = anchorY + OFFSET;\n if (top + h > surfaceH - EDGE_PAD) top = anchorY - OFFSET - h;\n top = Math.max(EDGE_PAD, Math.min(top, surfaceH - h - EDGE_PAD));\n\n const transform = `translate(${Math.round(left)}px, ${Math.round(top)}px)`;\n if (this.parkTimer !== undefined) {\n clearTimeout(this.parkTimer);\n this.parkTimer = undefined;\n }\n if (this.visible) {\n setStyle(this.el, { transform });\n return;\n }\n this.visible = true;\n // Appear in place (no glide from wherever the card was parked), then\n // re-enable motion so later moves glide and the card eases in.\n setStyle(this.el, { transition: 'none', transform, scale: '0.97' });\n void this.el.offsetWidth;\n setStyle(this.el, { transition: this.motion(), opacity: '1', scale: '1' });\n }\n\n hide(): void {\n if (!this.visible) return;\n this.visible = false;\n setStyle(this.el, { opacity: '0', scale: '0.97' });\n // Fade out in place, then park the card off-surface once it's invisible.\n this.parkTimer = setTimeout(() => {\n this.parkTimer = undefined;\n if (!this.visible) this.el.style.transform = PARKED;\n }, PARK_DELAY);\n }\n\n destroy(): void {\n if (this.parkTimer !== undefined) clearTimeout(this.parkTimer);\n this.el.remove();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -28,6 +28,18 @@ export interface TooltipContent {
|
|
|
28
28
|
title?: string;
|
|
29
29
|
rows: TooltipRow[];
|
|
30
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Animation state the controller hands to {@link Hover.paint} each frame.
|
|
33
|
+
* `focus` fades 0→1 when a hover starts and back to 0 when the pointer leaves;
|
|
34
|
+
* `glide` runs 0→1 when the hover moves from `from` (the previously shown hover
|
|
35
|
+
* of the same frame) to this one, so crosshairs and markers can travel instead
|
|
36
|
+
* of jumping. Both are already eased.
|
|
37
|
+
*/
|
|
38
|
+
export interface HoverPaintState {
|
|
39
|
+
focus: number;
|
|
40
|
+
glide: number;
|
|
41
|
+
from?: Hover;
|
|
42
|
+
}
|
|
31
43
|
/** The resolved hover under the cursor. */
|
|
32
44
|
export interface Hover {
|
|
33
45
|
/**
|
|
@@ -44,6 +56,13 @@ export interface Hover {
|
|
|
44
56
|
* already-cleared interaction context. Coordinates are CSS px.
|
|
45
57
|
*/
|
|
46
58
|
draw?(ctx: CanvasRenderingContext2D): void;
|
|
59
|
+
/**
|
|
60
|
+
* Animated alternative to {@link draw}: paint the highlight for one frame of
|
|
61
|
+
* the controller's focus/glide animation onto the cleared interaction
|
|
62
|
+
* context. When present it is preferred over `draw` (and `draw` is used when
|
|
63
|
+
* motion is reduced).
|
|
64
|
+
*/
|
|
65
|
+
paint?(ctx: CanvasRenderingContext2D, state: HoverPaintState): void;
|
|
47
66
|
}
|
|
48
67
|
/** A click target for an interactive legend item. */
|
|
49
68
|
export interface LegendHitRegion {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/interaction/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,EAAE,CAAC;CACpB;AAED,2CAA2C;AAC3C,MAAM,WAAW,KAAK;IACpB;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,CAAC,GAAG,EAAE,wBAAwB,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/interaction/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAExD,kCAAkC;AAClC,MAAM,WAAW,UAAU;IACzB,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,0CAA0C;IAC1C,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,4DAA4D;IAC5D,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,4EAA4E;AAC5E,MAAM,WAAW,cAAc;IAC7B,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,EAAE,CAAC;CACpB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,KAAK,CAAC;CACd;AAED,2CAA2C;AAC3C,MAAM,WAAW,KAAK;IACpB;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,cAAc,CAAC;IACxB;;;OAGG;IACH,IAAI,CAAC,CAAC,GAAG,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC3C;;;;;OAKG;IACH,KAAK,CAAC,CAAC,GAAG,EAAE,wBAAwB,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI,CAAC;CACrE;AAED,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,kCAAkC;IAClC,IAAI,EAAE,IAAI,CAAC;IACX,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,yDAAyD;IACzD,KAAK,EAAE,OAAO,CAAC;IACf,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,gEAAgE;AAChE,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,MAAM,EAAE,IAAI,CAAC;IACb,kEAAkE;IAClE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAAC;IAC9C;;;;OAIG;IACH,IAAI,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAAC;IACrD,gEAAgE;IAChE,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;CAChC;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,gFAAgF;IAChF,KAAK,CAAC,GAAG,EAAE,KAAK,GAAG,OAAO,CAAC;IAC3B,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAC;CACb"}
|