@invinite-org/chartlang-adapter-kit 1.3.0 → 1.5.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.
Files changed (155) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +7 -0
  3. package/dist/canvas/index.d.ts +5 -0
  4. package/dist/canvas/index.d.ts.map +1 -0
  5. package/dist/canvas/index.js +5 -0
  6. package/dist/canvas/index.js.map +1 -0
  7. package/dist/canvas/mockContext.d.ts +168 -0
  8. package/dist/canvas/mockContext.d.ts.map +1 -0
  9. package/dist/canvas/mockContext.js +198 -0
  10. package/dist/canvas/mockContext.js.map +1 -0
  11. package/dist/canvas/paintPrimitive.d.ts +35 -0
  12. package/dist/canvas/paintPrimitive.d.ts.map +1 -0
  13. package/dist/canvas/paintPrimitive.js +171 -0
  14. package/dist/canvas/paintPrimitive.js.map +1 -0
  15. package/dist/canvas/renderCtx.d.ts +40 -0
  16. package/dist/canvas/renderCtx.d.ts.map +1 -0
  17. package/dist/canvas/renderCtx.js +4 -0
  18. package/dist/canvas/renderCtx.js.map +1 -0
  19. package/dist/geometry/_lib/arrowhead.d.ts +18 -0
  20. package/dist/geometry/_lib/arrowhead.d.ts.map +1 -0
  21. package/dist/geometry/_lib/arrowhead.js +38 -0
  22. package/dist/geometry/_lib/arrowhead.js.map +1 -0
  23. package/dist/geometry/_lib/bezier.d.ts +57 -0
  24. package/dist/geometry/_lib/bezier.d.ts.map +1 -0
  25. package/dist/geometry/_lib/bezier.js +84 -0
  26. package/dist/geometry/_lib/bezier.js.map +1 -0
  27. package/dist/geometry/_lib/chevron.d.ts +29 -0
  28. package/dist/geometry/_lib/chevron.d.ts.map +1 -0
  29. package/dist/geometry/_lib/chevron.js +37 -0
  30. package/dist/geometry/_lib/chevron.js.map +1 -0
  31. package/dist/geometry/_lib/dash.d.ts +30 -0
  32. package/dist/geometry/_lib/dash.d.ts.map +1 -0
  33. package/dist/geometry/_lib/dash.js +40 -0
  34. package/dist/geometry/_lib/dash.js.map +1 -0
  35. package/dist/geometry/_lib/fibLevels.d.ts +36 -0
  36. package/dist/geometry/_lib/fibLevels.d.ts.map +1 -0
  37. package/dist/geometry/_lib/fibLevels.js +44 -0
  38. package/dist/geometry/_lib/fibLevels.js.map +1 -0
  39. package/dist/geometry/_lib/gannLevels.d.ts +54 -0
  40. package/dist/geometry/_lib/gannLevels.d.ts.map +1 -0
  41. package/dist/geometry/_lib/gannLevels.js +88 -0
  42. package/dist/geometry/_lib/gannLevels.js.map +1 -0
  43. package/dist/geometry/_lib/lineExtend.d.ts +31 -0
  44. package/dist/geometry/_lib/lineExtend.d.ts.map +1 -0
  45. package/dist/geometry/_lib/lineExtend.js +48 -0
  46. package/dist/geometry/_lib/lineExtend.js.map +1 -0
  47. package/dist/geometry/_lib/namedPolyline.d.ts +25 -0
  48. package/dist/geometry/_lib/namedPolyline.d.ts.map +1 -0
  49. package/dist/geometry/_lib/namedPolyline.js +64 -0
  50. package/dist/geometry/_lib/namedPolyline.js.map +1 -0
  51. package/dist/geometry/_lib/pitchforkGeom.d.ts +46 -0
  52. package/dist/geometry/_lib/pitchforkGeom.d.ts.map +1 -0
  53. package/dist/geometry/_lib/pitchforkGeom.js +70 -0
  54. package/dist/geometry/_lib/pitchforkGeom.js.map +1 -0
  55. package/dist/geometry/_lib/shapeStyle.d.ts +21 -0
  56. package/dist/geometry/_lib/shapeStyle.d.ts.map +1 -0
  57. package/dist/geometry/_lib/shapeStyle.js +41 -0
  58. package/dist/geometry/_lib/shapeStyle.js.map +1 -0
  59. package/dist/geometry/_lib/strokeStyle.d.ts +34 -0
  60. package/dist/geometry/_lib/strokeStyle.d.ts.map +1 -0
  61. package/dist/geometry/_lib/strokeStyle.js +26 -0
  62. package/dist/geometry/_lib/strokeStyle.js.map +1 -0
  63. package/dist/geometry/_lib/textStyle.d.ts +70 -0
  64. package/dist/geometry/_lib/textStyle.d.ts.map +1 -0
  65. package/dist/geometry/_lib/textStyle.js +78 -0
  66. package/dist/geometry/_lib/textStyle.js.map +1 -0
  67. package/dist/geometry/decompose.d.ts +28 -0
  68. package/dist/geometry/decompose.d.ts.map +1 -0
  69. package/dist/geometry/decompose.js +176 -0
  70. package/dist/geometry/decompose.js.map +1 -0
  71. package/dist/geometry/index.d.ts +4 -0
  72. package/dist/geometry/index.d.ts.map +1 -0
  73. package/dist/geometry/index.js +5 -0
  74. package/dist/geometry/index.js.map +1 -0
  75. package/dist/geometry/kinds/annotations.d.ts +77 -0
  76. package/dist/geometry/kinds/annotations.d.ts.map +1 -0
  77. package/dist/geometry/kinds/annotations.js +219 -0
  78. package/dist/geometry/kinds/annotations.js.map +1 -0
  79. package/dist/geometry/kinds/boxes.d.ts +116 -0
  80. package/dist/geometry/kinds/boxes.d.ts.map +1 -0
  81. package/dist/geometry/kinds/boxes.js +285 -0
  82. package/dist/geometry/kinds/boxes.js.map +1 -0
  83. package/dist/geometry/kinds/channels.d.ts +72 -0
  84. package/dist/geometry/kinds/channels.d.ts.map +1 -0
  85. package/dist/geometry/kinds/channels.js +148 -0
  86. package/dist/geometry/kinds/channels.js.map +1 -0
  87. package/dist/geometry/kinds/containers.d.ts +54 -0
  88. package/dist/geometry/kinds/containers.d.ts.map +1 -0
  89. package/dist/geometry/kinds/containers.js +268 -0
  90. package/dist/geometry/kinds/containers.js.map +1 -0
  91. package/dist/geometry/kinds/curves.d.ts +53 -0
  92. package/dist/geometry/kinds/curves.d.ts.map +1 -0
  93. package/dist/geometry/kinds/curves.js +110 -0
  94. package/dist/geometry/kinds/curves.js.map +1 -0
  95. package/dist/geometry/kinds/cycles.d.ts +52 -0
  96. package/dist/geometry/kinds/cycles.d.ts.map +1 -0
  97. package/dist/geometry/kinds/cycles.js +158 -0
  98. package/dist/geometry/kinds/cycles.js.map +1 -0
  99. package/dist/geometry/kinds/elliott.d.ts +73 -0
  100. package/dist/geometry/kinds/elliott.d.ts.map +1 -0
  101. package/dist/geometry/kinds/elliott.js +116 -0
  102. package/dist/geometry/kinds/elliott.js.map +1 -0
  103. package/dist/geometry/kinds/fibonacci.d.ts +166 -0
  104. package/dist/geometry/kinds/fibonacci.d.ts.map +1 -0
  105. package/dist/geometry/kinds/fibonacci.js +458 -0
  106. package/dist/geometry/kinds/fibonacci.js.map +1 -0
  107. package/dist/geometry/kinds/freehand.d.ts +53 -0
  108. package/dist/geometry/kinds/freehand.d.ts.map +1 -0
  109. package/dist/geometry/kinds/freehand.js +115 -0
  110. package/dist/geometry/kinds/freehand.js.map +1 -0
  111. package/dist/geometry/kinds/gann.d.ts +63 -0
  112. package/dist/geometry/kinds/gann.d.ts.map +1 -0
  113. package/dist/geometry/kinds/gann.js +153 -0
  114. package/dist/geometry/kinds/gann.js.map +1 -0
  115. package/dist/geometry/kinds/lines.d.ts +90 -0
  116. package/dist/geometry/kinds/lines.d.ts.map +1 -0
  117. package/dist/geometry/kinds/lines.js +201 -0
  118. package/dist/geometry/kinds/lines.js.map +1 -0
  119. package/dist/geometry/kinds/marker.d.ts +21 -0
  120. package/dist/geometry/kinds/marker.d.ts.map +1 -0
  121. package/dist/geometry/kinds/marker.js +47 -0
  122. package/dist/geometry/kinds/marker.js.map +1 -0
  123. package/dist/geometry/kinds/patterns.d.ts +85 -0
  124. package/dist/geometry/kinds/patterns.d.ts.map +1 -0
  125. package/dist/geometry/kinds/patterns.js +133 -0
  126. package/dist/geometry/kinds/patterns.js.map +1 -0
  127. package/dist/geometry/kinds/pitchforks.d.ts +36 -0
  128. package/dist/geometry/kinds/pitchforks.d.ts.map +1 -0
  129. package/dist/geometry/kinds/pitchforks.js +109 -0
  130. package/dist/geometry/kinds/pitchforks.js.map +1 -0
  131. package/dist/geometry/project.d.ts +50 -0
  132. package/dist/geometry/project.d.ts.map +1 -0
  133. package/dist/geometry/project.js +62 -0
  134. package/dist/geometry/project.js.map +1 -0
  135. package/dist/geometry/types.d.ts +146 -0
  136. package/dist/geometry/types.d.ts.map +1 -0
  137. package/dist/geometry/types.js +4 -0
  138. package/dist/geometry/types.js.map +1 -0
  139. package/dist/index.d.ts +4 -0
  140. package/dist/index.d.ts.map +1 -1
  141. package/dist/index.js +2 -0
  142. package/dist/index.js.map +1 -1
  143. package/dist/interaction/domWiring.d.ts +90 -0
  144. package/dist/interaction/domWiring.d.ts.map +1 -0
  145. package/dist/interaction/domWiring.js +113 -0
  146. package/dist/interaction/domWiring.js.map +1 -0
  147. package/dist/interaction/index.d.ts +5 -0
  148. package/dist/interaction/index.d.ts.map +1 -0
  149. package/dist/interaction/index.js +5 -0
  150. package/dist/interaction/index.js.map +1 -0
  151. package/dist/interaction/viewController.d.ts +120 -0
  152. package/dist/interaction/viewController.d.ts.map +1 -0
  153. package/dist/interaction/viewController.js +112 -0
  154. package/dist/interaction/viewController.js.map +1 -0
  155. package/package.json +8 -1
@@ -0,0 +1,146 @@
1
+ /**
2
+ * A 2D point in renderer pixel space — the structural type every
3
+ * projection helper returns and every {@link DrawPrimitive} consumes.
4
+ * Read-only so decomposers can't mutate vertices they don't own.
5
+ *
6
+ * @since 1.3
7
+ * @stable
8
+ * @example
9
+ * const p: Point2 = { x: 100, y: 50 };
10
+ * void p;
11
+ */
12
+ export type Point2 = {
13
+ readonly x: number;
14
+ readonly y: number;
15
+ };
16
+ /**
17
+ * Visible window into world coordinates. `xMin`/`xMax` are bar times in
18
+ * UTC milliseconds; `yMin`/`yMax` are prices in the quote currency.
19
+ * `pxWidth`/`pxHeight` are the renderer's drawable size in CSS pixels.
20
+ * Ported verbatim from the canvas2d adapter's `render/coords.ts` so all
21
+ * adapters share one projection contract.
22
+ *
23
+ * @since 1.3
24
+ * @stable
25
+ * @example
26
+ * const vp: Viewport = {
27
+ * xMin: 0, xMax: 9, yMin: 100, yMax: 110,
28
+ * pxWidth: 800, pxHeight: 400,
29
+ * };
30
+ * void vp;
31
+ */
32
+ export type Viewport = {
33
+ readonly xMin: number;
34
+ readonly xMax: number;
35
+ readonly yMin: number;
36
+ readonly yMax: number;
37
+ readonly pxWidth: number;
38
+ readonly pxHeight: number;
39
+ };
40
+ /**
41
+ * Resolved stroke styling for a {@link DrawPrimitive}. `dash` is the
42
+ * `setLineDash` segment array — `[]` is a solid stroke. Decomposers map
43
+ * a `LineStyle` to `dash` via the `_lib/dash` helper.
44
+ *
45
+ * `alpha ∈ [0, 1]` is the optional stroke opacity the painter brackets
46
+ * around the `stroke()` call (the `highlighter` freehand kind sets it).
47
+ * When omitted the stroke is fully opaque and the painter emits no
48
+ * `globalAlpha` mutation — so a stroke without `alpha` is byte-identical
49
+ * to a Task-1 stroke.
50
+ *
51
+ * @since 1.3
52
+ * @stable
53
+ * @example
54
+ * const s: StrokeStyle = { color: "#000000", width: 1, dash: [] };
55
+ * void s;
56
+ */
57
+ export type StrokeStyle = {
58
+ readonly color: string;
59
+ readonly width: number;
60
+ readonly dash: ReadonlyArray<number>;
61
+ readonly alpha?: number;
62
+ };
63
+ /**
64
+ * Resolved fill styling for a {@link DrawPrimitive}. `alpha ∈ [0, 1]`
65
+ * is applied around the fill so a subsequent stroke draws at full
66
+ * opacity.
67
+ *
68
+ * @since 1.3
69
+ * @stable
70
+ * @example
71
+ * const f: FillStyle = { color: "#dbeafe", alpha: 0.4 };
72
+ * void f;
73
+ */
74
+ export type FillStyle = {
75
+ readonly color: string;
76
+ readonly alpha: number;
77
+ };
78
+ /**
79
+ * Renderer-agnostic intermediate representation every drawing reduces
80
+ * to. {@link decomposeDrawing} returns a flat `DrawPrimitive[]`; each
81
+ * adapter paints the list with its own sink (canvas `paintPrimitive`,
82
+ * Konva nodes, ECharts `graphic`, …). The four shapes — `polyline`,
83
+ * `arc`, `text`, `marker` — are the smallest set all the target chart
84
+ * libraries can consume.
85
+ *
86
+ * - `polyline` — an open or `closed` path with optional `stroke` / `fill`.
87
+ * - `arc` — a circular arc centred on `(cx, cy)` from `start` to `end`
88
+ * radians, with optional `stroke` / `fill`.
89
+ * - `text` — a single label at `(x, y)` with explicit `align` / `baseline`.
90
+ * - `marker` — a sized glyph at `(x, y)` (reserved for adapter / future
91
+ * kinds; no basic kind emits it).
92
+ *
93
+ * @since 1.3
94
+ * @stable
95
+ * @example
96
+ * const seg: DrawPrimitive = {
97
+ * kind: "polyline",
98
+ * points: [{ x: 0, y: 0 }, { x: 10, y: 10 }],
99
+ * closed: false,
100
+ * stroke: { color: "#000000", width: 1, dash: [] },
101
+ * };
102
+ * void seg;
103
+ */
104
+ export type DrawPrimitive = {
105
+ readonly kind: "polyline";
106
+ readonly points: ReadonlyArray<Point2>;
107
+ readonly closed: boolean;
108
+ readonly stroke?: StrokeStyle;
109
+ readonly fill?: FillStyle;
110
+ } | {
111
+ readonly kind: "arc";
112
+ readonly cx: number;
113
+ readonly cy: number;
114
+ readonly r: number;
115
+ readonly start: number;
116
+ readonly end: number;
117
+ /**
118
+ * Whether the painter issues `closePath()` after the arc —
119
+ * drawing the chord back to the arc's start. `true` only for a
120
+ * full-circle shape (e.g. `circle`); partial arcs (the
121
+ * `trend-angle` indicator, `time-cycles`) MUST be `false`, else
122
+ * the chord renders as a spurious diameter line.
123
+ */
124
+ readonly closed: boolean;
125
+ readonly stroke?: StrokeStyle;
126
+ readonly fill?: FillStyle;
127
+ } | {
128
+ readonly kind: "text";
129
+ readonly x: number;
130
+ readonly y: number;
131
+ readonly text: string;
132
+ readonly color: string;
133
+ readonly font: string;
134
+ readonly align: "left" | "center" | "right";
135
+ readonly baseline: "top" | "middle" | "bottom";
136
+ readonly bgColor?: string;
137
+ } | {
138
+ readonly kind: "marker";
139
+ readonly shape: "circle" | "square" | "diamond" | "triangle-up" | "triangle-down";
140
+ readonly x: number;
141
+ readonly y: number;
142
+ readonly size: number;
143
+ readonly stroke?: StrokeStyle;
144
+ readonly fill?: FillStyle;
145
+ };
146
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/geometry/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ // Copyright (c) 2026 Invinite. Licensed under the MIT License.
2
+ // See the LICENSE file in the repo root for full license text.
3
+ export {};
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/geometry/types.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\n/**\n * A 2D point in renderer pixel space — the structural type every\n * projection helper returns and every {@link DrawPrimitive} consumes.\n * Read-only so decomposers can't mutate vertices they don't own.\n *\n * @since 1.3\n * @stable\n * @example\n * const p: Point2 = { x: 100, y: 50 };\n * void p;\n */\nexport type Point2 = { readonly x: number; readonly y: number };\n\n/**\n * Visible window into world coordinates. `xMin`/`xMax` are bar times in\n * UTC milliseconds; `yMin`/`yMax` are prices in the quote currency.\n * `pxWidth`/`pxHeight` are the renderer's drawable size in CSS pixels.\n * Ported verbatim from the canvas2d adapter's `render/coords.ts` so all\n * adapters share one projection contract.\n *\n * @since 1.3\n * @stable\n * @example\n * const vp: Viewport = {\n * xMin: 0, xMax: 9, yMin: 100, yMax: 110,\n * pxWidth: 800, pxHeight: 400,\n * };\n * void vp;\n */\nexport type Viewport = {\n readonly xMin: number;\n readonly xMax: number;\n readonly yMin: number;\n readonly yMax: number;\n readonly pxWidth: number;\n readonly pxHeight: number;\n};\n\n/**\n * Resolved stroke styling for a {@link DrawPrimitive}. `dash` is the\n * `setLineDash` segment array — `[]` is a solid stroke. Decomposers map\n * a `LineStyle` to `dash` via the `_lib/dash` helper.\n *\n * `alpha ∈ [0, 1]` is the optional stroke opacity the painter brackets\n * around the `stroke()` call (the `highlighter` freehand kind sets it).\n * When omitted the stroke is fully opaque and the painter emits no\n * `globalAlpha` mutation — so a stroke without `alpha` is byte-identical\n * to a Task-1 stroke.\n *\n * @since 1.3\n * @stable\n * @example\n * const s: StrokeStyle = { color: \"#000000\", width: 1, dash: [] };\n * void s;\n */\nexport type StrokeStyle = {\n readonly color: string;\n readonly width: number;\n readonly dash: ReadonlyArray<number>;\n readonly alpha?: number;\n};\n\n/**\n * Resolved fill styling for a {@link DrawPrimitive}. `alpha ∈ [0, 1]`\n * is applied around the fill so a subsequent stroke draws at full\n * opacity.\n *\n * @since 1.3\n * @stable\n * @example\n * const f: FillStyle = { color: \"#dbeafe\", alpha: 0.4 };\n * void f;\n */\nexport type FillStyle = { readonly color: string; readonly alpha: number };\n\n/**\n * Renderer-agnostic intermediate representation every drawing reduces\n * to. {@link decomposeDrawing} returns a flat `DrawPrimitive[]`; each\n * adapter paints the list with its own sink (canvas `paintPrimitive`,\n * Konva nodes, ECharts `graphic`, …). The four shapes — `polyline`,\n * `arc`, `text`, `marker` — are the smallest set all the target chart\n * libraries can consume.\n *\n * - `polyline` — an open or `closed` path with optional `stroke` / `fill`.\n * - `arc` — a circular arc centred on `(cx, cy)` from `start` to `end`\n * radians, with optional `stroke` / `fill`.\n * - `text` — a single label at `(x, y)` with explicit `align` / `baseline`.\n * - `marker` — a sized glyph at `(x, y)` (reserved for adapter / future\n * kinds; no basic kind emits it).\n *\n * @since 1.3\n * @stable\n * @example\n * const seg: DrawPrimitive = {\n * kind: \"polyline\",\n * points: [{ x: 0, y: 0 }, { x: 10, y: 10 }],\n * closed: false,\n * stroke: { color: \"#000000\", width: 1, dash: [] },\n * };\n * void seg;\n */\nexport type DrawPrimitive =\n | {\n readonly kind: \"polyline\";\n readonly points: ReadonlyArray<Point2>;\n readonly closed: boolean;\n readonly stroke?: StrokeStyle;\n readonly fill?: FillStyle;\n }\n | {\n readonly kind: \"arc\";\n readonly cx: number;\n readonly cy: number;\n readonly r: number;\n readonly start: number;\n readonly end: number;\n /**\n * Whether the painter issues `closePath()` after the arc —\n * drawing the chord back to the arc's start. `true` only for a\n * full-circle shape (e.g. `circle`); partial arcs (the\n * `trend-angle` indicator, `time-cycles`) MUST be `false`, else\n * the chord renders as a spurious diameter line.\n */\n readonly closed: boolean;\n readonly stroke?: StrokeStyle;\n readonly fill?: FillStyle;\n }\n | {\n readonly kind: \"text\";\n readonly x: number;\n readonly y: number;\n readonly text: string;\n readonly color: string;\n readonly font: string;\n readonly align: \"left\" | \"center\" | \"right\";\n readonly baseline: \"top\" | \"middle\" | \"bottom\";\n readonly bgColor?: string;\n }\n | {\n readonly kind: \"marker\";\n readonly shape: \"circle\" | \"square\" | \"diamond\" | \"triangle-up\" | \"triangle-down\";\n readonly x: number;\n readonly y: number;\n readonly size: number;\n readonly stroke?: StrokeStyle;\n readonly fill?: FillStyle;\n };\n"]}
package/dist/index.d.ts CHANGED
@@ -8,5 +8,9 @@ export type { ValidationFail, ValidationOk, ValidationResult } from "./validatio
8
8
  export { mockCandleSource } from "./mocks/index.js";
9
9
  export type { MockCandleSourceMode, MockCandleSourceOpts } from "./mocks/index.js";
10
10
  export { BufferingAdapter, PassThroughAdapter } from "./base/index.js";
11
+ export { decomposeDrawing, priceToY, timeToX, worldPointToPixel } from "./geometry/index.js";
12
+ export type { DrawPrimitive, FillStyle, Point2, StrokeStyle, Viewport, } from "./geometry/index.js";
13
+ export { attachInteraction, createViewController, onDblCore, onDragCore, onWheelCore, yRangeInWindow, } from "./interaction/index.js";
14
+ export type { InteractionHandlers, ViewController, ViewControllerOpts, WindowYInput, XWindow, } from "./interaction/index.js";
11
15
  export type { Adapter, AdapterSymInfo, AlertChannel, AlertConditionEmission, AlertEmission, Capabilities, CandleEvent, DiagnosticCode, DrawingCounts, DrawingEmission, DrawingKind, InputKind, LogEmission, PlotEmission, PlotKind, PlotOverride, PlotSlotDescriptor, PlotStyle, RunnerEmissions, RuntimeDiagnostic, SymInfoField, } from "./types.js";
12
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACxE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,YAAY,EACR,OAAO,EACP,cAAc,EACd,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,cAAc,EACd,aAAa,EACb,eAAe,EACf,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,YAAY,GACf,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACtE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,YAAY,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACxE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC7F,YAAY,EACR,aAAa,EACb,SAAS,EACT,MAAM,EACN,WAAW,EACX,QAAQ,GACX,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACH,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,UAAU,EACV,WAAW,EACX,cAAc,GACjB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACR,mBAAmB,EACnB,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,OAAO,GACV,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACR,OAAO,EACP,cAAc,EACd,YAAY,EACZ,sBAAsB,EACtB,aAAa,EACb,YAAY,EACZ,WAAW,EACX,cAAc,EACd,aAAa,EACb,eAAe,EACf,WAAW,EACX,SAAS,EACT,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,eAAe,EACf,iBAAiB,EACjB,YAAY,GACf,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -6,4 +6,6 @@ export { PHASE_5_PLOT_KINDS, capabilities } from "./capabilities/index.js";
6
6
  export { decodeDrawing, validateEmission } from "./validation/index.js";
7
7
  export { mockCandleSource } from "./mocks/index.js";
8
8
  export { BufferingAdapter, PassThroughAdapter } from "./base/index.js";
9
+ export { decomposeDrawing, priceToY, timeToX, worldPointToPixel } from "./geometry/index.js";
10
+ export { attachInteraction, createViewController, onDblCore, onDragCore, onWheelCore, yRangeInWindow, } from "./interaction/index.js";
9
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAE/D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nexport { KIND_BUCKET, bucketFor } from \"@invinite-org/chartlang-core\";\nexport type { DrawingBucket, DrawingState } from \"@invinite-org/chartlang-core\";\nexport { defineAdapter } from \"./defineAdapter.js\";\nexport type { DefineAdapterOpts } from \"./defineAdapter.js\";\nexport { PHASE_5_PLOT_KINDS, capabilities } from \"./capabilities/index.js\";\nexport { decodeDrawing, validateEmission } from \"./validation/index.js\";\nexport type { ValidationFail, ValidationOk, ValidationResult } from \"./validation/index.js\";\nexport { mockCandleSource } from \"./mocks/index.js\";\nexport type { MockCandleSourceMode, MockCandleSourceOpts } from \"./mocks/index.js\";\nexport { BufferingAdapter, PassThroughAdapter } from \"./base/index.js\";\nexport type {\n Adapter,\n AdapterSymInfo,\n AlertChannel,\n AlertConditionEmission,\n AlertEmission,\n Capabilities,\n CandleEvent,\n DiagnosticCode,\n DrawingCounts,\n DrawingEmission,\n DrawingKind,\n InputKind,\n LogEmission,\n PlotEmission,\n PlotKind,\n PlotOverride,\n PlotSlotDescriptor,\n PlotStyle,\n RunnerEmissions,\n RuntimeDiagnostic,\n SymInfoField,\n} from \"./types.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAE/D,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAEtE,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAExE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAQ7F,OAAO,EACH,iBAAiB,EACjB,oBAAoB,EACpB,SAAS,EACT,UAAU,EACV,WAAW,EACX,cAAc,GACjB,MAAM,wBAAwB,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nexport { KIND_BUCKET, bucketFor } from \"@invinite-org/chartlang-core\";\nexport type { DrawingBucket, DrawingState } from \"@invinite-org/chartlang-core\";\nexport { defineAdapter } from \"./defineAdapter.js\";\nexport type { DefineAdapterOpts } from \"./defineAdapter.js\";\nexport { PHASE_5_PLOT_KINDS, capabilities } from \"./capabilities/index.js\";\nexport { decodeDrawing, validateEmission } from \"./validation/index.js\";\nexport type { ValidationFail, ValidationOk, ValidationResult } from \"./validation/index.js\";\nexport { mockCandleSource } from \"./mocks/index.js\";\nexport type { MockCandleSourceMode, MockCandleSourceOpts } from \"./mocks/index.js\";\nexport { BufferingAdapter, PassThroughAdapter } from \"./base/index.js\";\nexport { decomposeDrawing, priceToY, timeToX, worldPointToPixel } from \"./geometry/index.js\";\nexport type {\n DrawPrimitive,\n FillStyle,\n Point2,\n StrokeStyle,\n Viewport,\n} from \"./geometry/index.js\";\nexport {\n attachInteraction,\n createViewController,\n onDblCore,\n onDragCore,\n onWheelCore,\n yRangeInWindow,\n} from \"./interaction/index.js\";\nexport type {\n InteractionHandlers,\n ViewController,\n ViewControllerOpts,\n WindowYInput,\n XWindow,\n} from \"./interaction/index.js\";\nexport type {\n Adapter,\n AdapterSymInfo,\n AlertChannel,\n AlertConditionEmission,\n AlertEmission,\n Capabilities,\n CandleEvent,\n DiagnosticCode,\n DrawingCounts,\n DrawingEmission,\n DrawingKind,\n InputKind,\n LogEmission,\n PlotEmission,\n PlotKind,\n PlotOverride,\n PlotSlotDescriptor,\n PlotStyle,\n RunnerEmissions,\n RuntimeDiagnostic,\n SymInfoField,\n} from \"./types.js\";\n"]}
@@ -0,0 +1,90 @@
1
+ import type { ViewController } from "./viewController.js";
2
+ /**
3
+ * The per-frame projection + data context {@link attachInteraction} needs
4
+ * to translate pixel gestures into world-x transforms. The adapter supplies
5
+ * these closing over its latest overlay `Viewport`, so the math always uses
6
+ * the current frame's scale.
7
+ *
8
+ * @since 1.6
9
+ * @stable
10
+ * @example
11
+ * declare const view: import("./viewController.js").ViewController;
12
+ * const h: InteractionHandlers = {
13
+ * controller: view,
14
+ * pxToWorldX: (px) => px,
15
+ * worldXPerPx: () => 1,
16
+ * dataBounds: () => ({ xMin: 0, xMax: 100 }),
17
+ * requestRender: () => {},
18
+ * };
19
+ * void h;
20
+ */
21
+ export type InteractionHandlers = {
22
+ /** The controller whose window the gestures mutate. */
23
+ readonly controller: ViewController;
24
+ /** Map a plot-area pixel x to a world x for the current frame. */
25
+ readonly pxToWorldX: (px: number) => number;
26
+ /** World-x units per pixel for the current frame (pan delta scale). */
27
+ readonly worldXPerPx: () => number;
28
+ /** The current data x extent (grows as bars stream in). */
29
+ readonly dataBounds: () => {
30
+ readonly xMin: number;
31
+ readonly xMax: number;
32
+ };
33
+ /** Re-render the adapter after a gesture mutates the window. */
34
+ readonly requestRender: () => void;
35
+ /** Override the wheel zoom sensitivity (default {@link DEFAULT_ZOOM_STEP}). */
36
+ readonly zoomStep?: number;
37
+ };
38
+ /**
39
+ * Apply one wheel notch: zoom the controller about the world-x under the
40
+ * cursor, then request a render. Pure on `(offsetX, deltaY)` so it is unit
41
+ * tested without a DOM event.
42
+ *
43
+ * @since 1.6
44
+ * @stable
45
+ * @example
46
+ * declare const h: InteractionHandlers;
47
+ * onWheelCore(h, 50, -120); // zoom in about pixel x=50
48
+ */
49
+ export declare function onWheelCore(h: InteractionHandlers, offsetX: number, deltaY: number): void;
50
+ /**
51
+ * Apply one drag step: pan the controller by the pixel delta converted to
52
+ * world x (dragging right reveals earlier data), then request a render.
53
+ * Pure on `dxPx`.
54
+ *
55
+ * @since 1.6
56
+ * @stable
57
+ * @example
58
+ * declare const h: InteractionHandlers;
59
+ * onDragCore(h, 12); // pan left by 12 px
60
+ */
61
+ export declare function onDragCore(h: InteractionHandlers, dxPx: number): void;
62
+ /**
63
+ * Apply a double-click: reset the controller to auto-follow, then request a
64
+ * render.
65
+ *
66
+ * @since 1.6
67
+ * @stable
68
+ * @example
69
+ * declare const h: InteractionHandlers;
70
+ * onDblCore(h);
71
+ */
72
+ export declare function onDblCore(h: InteractionHandlers): void;
73
+ /**
74
+ * Wire wheel-zoom, drag-pan, and double-click-reset on `el`, driving the
75
+ * supplied {@link InteractionHandlers}. Returns a detach function that
76
+ * removes every listener (call it from the adapter's `dispose`). The
77
+ * `addEventListener` plumbing is the only DOM-bound part; the decision
78
+ * logic lives in {@link onWheelCore} / {@link onDragCore} / {@link
79
+ * onDblCore}, which are unit tested directly.
80
+ *
81
+ * @since 1.6
82
+ * @stable
83
+ * @example
84
+ * declare const el: HTMLElement;
85
+ * declare const h: InteractionHandlers;
86
+ * const detach = attachInteraction(el, h);
87
+ * detach();
88
+ */
89
+ export declare function attachInteraction(el: HTMLElement, h: InteractionHandlers): () => void;
90
+ //# sourceMappingURL=domWiring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domWiring.d.ts","sourceRoot":"","sources":["../../src/interaction/domWiring.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAQ1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAC9B,uDAAuD;IACvD,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,kEAAkE;IAClE,QAAQ,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;IAC5C,uEAAuE;IACvE,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;IACnC,2DAA2D;IAC3D,QAAQ,CAAC,UAAU,EAAE,MAAM;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,gEAAgE;IAChE,QAAQ,CAAC,aAAa,EAAE,MAAM,IAAI,CAAC;IACnC,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAKzF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIrE;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAGtD;AAED;;;;;;;;;;;;;;;GAeG;AAEH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,WAAW,EAAE,CAAC,EAAE,mBAAmB,GAAG,MAAM,IAAI,CAwCrF"}
@@ -0,0 +1,113 @@
1
+ // Copyright (c) 2026 Invinite. Licensed under the MIT License.
2
+ // See the LICENSE file in the repo root for full license text.
3
+ // Wheel notch → zoom factor sensitivity. A positive `deltaY` (scroll down)
4
+ // yields a factor > 1 (zoom out); negative (scroll up) yields < 1 (zoom in).
5
+ // `Math.exp` keeps both directions symmetric, so zoom-out always exists —
6
+ // the bug the native-default drag-zoom-in lacked.
7
+ const DEFAULT_ZOOM_STEP = 0.0015;
8
+ /**
9
+ * Apply one wheel notch: zoom the controller about the world-x under the
10
+ * cursor, then request a render. Pure on `(offsetX, deltaY)` so it is unit
11
+ * tested without a DOM event.
12
+ *
13
+ * @since 1.6
14
+ * @stable
15
+ * @example
16
+ * declare const h: InteractionHandlers;
17
+ * onWheelCore(h, 50, -120); // zoom in about pixel x=50
18
+ */
19
+ export function onWheelCore(h, offsetX, deltaY) {
20
+ const factor = Math.exp(deltaY * (h.zoomStep ?? DEFAULT_ZOOM_STEP));
21
+ const { xMin, xMax } = h.dataBounds();
22
+ h.controller.zoomAt(h.pxToWorldX(offsetX), factor, xMin, xMax);
23
+ h.requestRender();
24
+ }
25
+ /**
26
+ * Apply one drag step: pan the controller by the pixel delta converted to
27
+ * world x (dragging right reveals earlier data), then request a render.
28
+ * Pure on `dxPx`.
29
+ *
30
+ * @since 1.6
31
+ * @stable
32
+ * @example
33
+ * declare const h: InteractionHandlers;
34
+ * onDragCore(h, 12); // pan left by 12 px
35
+ */
36
+ export function onDragCore(h, dxPx) {
37
+ const { xMin, xMax } = h.dataBounds();
38
+ h.controller.panBy(-dxPx * h.worldXPerPx(), xMin, xMax);
39
+ h.requestRender();
40
+ }
41
+ /**
42
+ * Apply a double-click: reset the controller to auto-follow, then request a
43
+ * render.
44
+ *
45
+ * @since 1.6
46
+ * @stable
47
+ * @example
48
+ * declare const h: InteractionHandlers;
49
+ * onDblCore(h);
50
+ */
51
+ export function onDblCore(h) {
52
+ h.controller.reset();
53
+ h.requestRender();
54
+ }
55
+ /**
56
+ * Wire wheel-zoom, drag-pan, and double-click-reset on `el`, driving the
57
+ * supplied {@link InteractionHandlers}. Returns a detach function that
58
+ * removes every listener (call it from the adapter's `dispose`). The
59
+ * `addEventListener` plumbing is the only DOM-bound part; the decision
60
+ * logic lives in {@link onWheelCore} / {@link onDragCore} / {@link
61
+ * onDblCore}, which are unit tested directly.
62
+ *
63
+ * @since 1.6
64
+ * @stable
65
+ * @example
66
+ * declare const el: HTMLElement;
67
+ * declare const h: InteractionHandlers;
68
+ * const detach = attachInteraction(el, h);
69
+ * detach();
70
+ */
71
+ /* v8 ignore start -- DOM event plumbing; the pure cores above carry the coverage */
72
+ export function attachInteraction(el, h) {
73
+ let dragging = false;
74
+ let lastX = 0;
75
+ const onWheel = (e) => {
76
+ e.preventDefault();
77
+ onWheelCore(h, e.offsetX, e.deltaY);
78
+ };
79
+ const onPointerDown = (e) => {
80
+ dragging = true;
81
+ lastX = e.clientX;
82
+ el.setPointerCapture(e.pointerId);
83
+ };
84
+ const onPointerMove = (e) => {
85
+ if (!dragging)
86
+ return;
87
+ const dx = e.clientX - lastX;
88
+ lastX = e.clientX;
89
+ onDragCore(h, dx);
90
+ };
91
+ const onPointerUp = (e) => {
92
+ dragging = false;
93
+ if (el.hasPointerCapture(e.pointerId))
94
+ el.releasePointerCapture(e.pointerId);
95
+ };
96
+ const onDblClick = () => {
97
+ onDblCore(h);
98
+ };
99
+ el.addEventListener("wheel", onWheel, { passive: false });
100
+ el.addEventListener("pointerdown", onPointerDown);
101
+ el.addEventListener("pointermove", onPointerMove);
102
+ el.addEventListener("pointerup", onPointerUp);
103
+ el.addEventListener("dblclick", onDblClick);
104
+ return () => {
105
+ el.removeEventListener("wheel", onWheel);
106
+ el.removeEventListener("pointerdown", onPointerDown);
107
+ el.removeEventListener("pointermove", onPointerMove);
108
+ el.removeEventListener("pointerup", onPointerUp);
109
+ el.removeEventListener("dblclick", onDblClick);
110
+ };
111
+ }
112
+ /* v8 ignore stop */
113
+ //# sourceMappingURL=domWiring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"domWiring.js","sourceRoot":"","sources":["../../src/interaction/domWiring.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nimport type { ViewController } from \"./viewController.js\";\n\n// Wheel notch → zoom factor sensitivity. A positive `deltaY` (scroll down)\n// yields a factor > 1 (zoom out); negative (scroll up) yields < 1 (zoom in).\n// `Math.exp` keeps both directions symmetric, so zoom-out always exists —\n// the bug the native-default drag-zoom-in lacked.\nconst DEFAULT_ZOOM_STEP = 0.0015;\n\n/**\n * The per-frame projection + data context {@link attachInteraction} needs\n * to translate pixel gestures into world-x transforms. The adapter supplies\n * these closing over its latest overlay `Viewport`, so the math always uses\n * the current frame's scale.\n *\n * @since 1.6\n * @stable\n * @example\n * declare const view: import(\"./viewController.js\").ViewController;\n * const h: InteractionHandlers = {\n * controller: view,\n * pxToWorldX: (px) => px,\n * worldXPerPx: () => 1,\n * dataBounds: () => ({ xMin: 0, xMax: 100 }),\n * requestRender: () => {},\n * };\n * void h;\n */\nexport type InteractionHandlers = {\n /** The controller whose window the gestures mutate. */\n readonly controller: ViewController;\n /** Map a plot-area pixel x to a world x for the current frame. */\n readonly pxToWorldX: (px: number) => number;\n /** World-x units per pixel for the current frame (pan delta scale). */\n readonly worldXPerPx: () => number;\n /** The current data x extent (grows as bars stream in). */\n readonly dataBounds: () => { readonly xMin: number; readonly xMax: number };\n /** Re-render the adapter after a gesture mutates the window. */\n readonly requestRender: () => void;\n /** Override the wheel zoom sensitivity (default {@link DEFAULT_ZOOM_STEP}). */\n readonly zoomStep?: number;\n};\n\n/**\n * Apply one wheel notch: zoom the controller about the world-x under the\n * cursor, then request a render. Pure on `(offsetX, deltaY)` so it is unit\n * tested without a DOM event.\n *\n * @since 1.6\n * @stable\n * @example\n * declare const h: InteractionHandlers;\n * onWheelCore(h, 50, -120); // zoom in about pixel x=50\n */\nexport function onWheelCore(h: InteractionHandlers, offsetX: number, deltaY: number): void {\n const factor = Math.exp(deltaY * (h.zoomStep ?? DEFAULT_ZOOM_STEP));\n const { xMin, xMax } = h.dataBounds();\n h.controller.zoomAt(h.pxToWorldX(offsetX), factor, xMin, xMax);\n h.requestRender();\n}\n\n/**\n * Apply one drag step: pan the controller by the pixel delta converted to\n * world x (dragging right reveals earlier data), then request a render.\n * Pure on `dxPx`.\n *\n * @since 1.6\n * @stable\n * @example\n * declare const h: InteractionHandlers;\n * onDragCore(h, 12); // pan left by 12 px\n */\nexport function onDragCore(h: InteractionHandlers, dxPx: number): void {\n const { xMin, xMax } = h.dataBounds();\n h.controller.panBy(-dxPx * h.worldXPerPx(), xMin, xMax);\n h.requestRender();\n}\n\n/**\n * Apply a double-click: reset the controller to auto-follow, then request a\n * render.\n *\n * @since 1.6\n * @stable\n * @example\n * declare const h: InteractionHandlers;\n * onDblCore(h);\n */\nexport function onDblCore(h: InteractionHandlers): void {\n h.controller.reset();\n h.requestRender();\n}\n\n/**\n * Wire wheel-zoom, drag-pan, and double-click-reset on `el`, driving the\n * supplied {@link InteractionHandlers}. Returns a detach function that\n * removes every listener (call it from the adapter's `dispose`). The\n * `addEventListener` plumbing is the only DOM-bound part; the decision\n * logic lives in {@link onWheelCore} / {@link onDragCore} / {@link\n * onDblCore}, which are unit tested directly.\n *\n * @since 1.6\n * @stable\n * @example\n * declare const el: HTMLElement;\n * declare const h: InteractionHandlers;\n * const detach = attachInteraction(el, h);\n * detach();\n */\n/* v8 ignore start -- DOM event plumbing; the pure cores above carry the coverage */\nexport function attachInteraction(el: HTMLElement, h: InteractionHandlers): () => void {\n let dragging = false;\n let lastX = 0;\n\n const onWheel = (e: WheelEvent): void => {\n e.preventDefault();\n onWheelCore(h, e.offsetX, e.deltaY);\n };\n const onPointerDown = (e: PointerEvent): void => {\n dragging = true;\n lastX = e.clientX;\n el.setPointerCapture(e.pointerId);\n };\n const onPointerMove = (e: PointerEvent): void => {\n if (!dragging) return;\n const dx = e.clientX - lastX;\n lastX = e.clientX;\n onDragCore(h, dx);\n };\n const onPointerUp = (e: PointerEvent): void => {\n dragging = false;\n if (el.hasPointerCapture(e.pointerId)) el.releasePointerCapture(e.pointerId);\n };\n const onDblClick = (): void => {\n onDblCore(h);\n };\n\n el.addEventListener(\"wheel\", onWheel, { passive: false });\n el.addEventListener(\"pointerdown\", onPointerDown);\n el.addEventListener(\"pointermove\", onPointerMove);\n el.addEventListener(\"pointerup\", onPointerUp);\n el.addEventListener(\"dblclick\", onDblClick);\n\n return (): void => {\n el.removeEventListener(\"wheel\", onWheel);\n el.removeEventListener(\"pointerdown\", onPointerDown);\n el.removeEventListener(\"pointermove\", onPointerMove);\n el.removeEventListener(\"pointerup\", onPointerUp);\n el.removeEventListener(\"dblclick\", onDblClick);\n };\n}\n/* v8 ignore stop */\n"]}
@@ -0,0 +1,5 @@
1
+ export { createViewController, yRangeInWindow } from "./viewController.js";
2
+ export type { ViewController, ViewControllerOpts, WindowYInput, XWindow, } from "./viewController.js";
3
+ export { attachInteraction, onDblCore, onDragCore, onWheelCore } from "./domWiring.js";
4
+ export type { InteractionHandlers } from "./domWiring.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interaction/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC3E,YAAY,EACR,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,OAAO,GACV,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AACvF,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,5 @@
1
+ // Copyright (c) 2026 Invinite. Licensed under the MIT License.
2
+ // See the LICENSE file in the repo root for full license text.
3
+ export { createViewController, yRangeInWindow } from "./viewController.js";
4
+ export { attachInteraction, onDblCore, onDragCore, onWheelCore } from "./domWiring.js";
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interaction/index.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,+DAA+D;AAE/D,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAO3E,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC","sourcesContent":["// Copyright (c) 2026 Invinite. Licensed under the MIT License.\n// See the LICENSE file in the repo root for full license text.\n\nexport { createViewController, yRangeInWindow } from \"./viewController.js\";\nexport type {\n ViewController,\n ViewControllerOpts,\n WindowYInput,\n XWindow,\n} from \"./viewController.js\";\nexport { attachInteraction, onDblCore, onDragCore, onWheelCore } from \"./domWiring.js\";\nexport type { InteractionHandlers } from \"./domWiring.js\";\n"]}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * A visible window into the world x axis (bar times in UTC ms). The two
3
+ * self-scaled adapters (canvas2d, konva) resolve one per frame from a
4
+ * {@link ViewController} and feed `xMin`/`xMax` into their `Viewport`.
5
+ *
6
+ * @since 1.6
7
+ * @stable
8
+ * @example
9
+ * const win: XWindow = { xMin: 0, xMax: 100 };
10
+ * void win;
11
+ */
12
+ export type XWindow = {
13
+ readonly xMin: number;
14
+ readonly xMax: number;
15
+ };
16
+ /**
17
+ * Construction options for {@link createViewController}. `minSpan` is the
18
+ * smallest world-x span a zoom-in can reach (so the window never collapses
19
+ * to a point); `maxSpanFactor` is the largest span a zoom-out can reach as
20
+ * a multiple of the current data span (default `1` ⇒ cannot zoom out past
21
+ * "all data visible").
22
+ *
23
+ * @since 1.6
24
+ * @stable
25
+ * @example
26
+ * const opts: ViewControllerOpts = { minSpan: 1, maxSpanFactor: 1 };
27
+ * void opts;
28
+ */
29
+ export type ViewControllerOpts = {
30
+ readonly minSpan?: number;
31
+ readonly maxSpanFactor?: number;
32
+ };
33
+ /**
34
+ * Stateful, library-agnostic pan/zoom controller for an adapter that
35
+ * computes its own x scale every frame. It holds a user x-window plus a
36
+ * `userInteracted` flag: until the user wheels or drags, {@link
37
+ * ViewController.resolveXWindow} returns the full data range (auto-follow
38
+ * live bars); after the first interaction it returns the held window
39
+ * (re-clamped as data grows), so live frames stop snapping the view back.
40
+ *
41
+ * All transforms are pure functions of the current state + the supplied
42
+ * data bounds — there is no DOM or library coupling. The example adapters
43
+ * wire DOM events to {@link ViewController.zoomAt} / {@link
44
+ * ViewController.panBy} / {@link ViewController.reset} via {@link
45
+ * attachInteraction}.
46
+ *
47
+ * @since 1.6
48
+ * @stable
49
+ * @example
50
+ * const view = createViewController();
51
+ * view.resolveXWindow(0, 100); // { xMin: 0, xMax: 100 } (auto-follow)
52
+ * view.panBy(10, 0, 100);
53
+ * view.userInteracted; // true
54
+ */
55
+ export type ViewController = {
56
+ /** `true` once the user has zoomed or panned (auto-follow is paused). */
57
+ readonly userInteracted: boolean;
58
+ /**
59
+ * The x-window to render this frame: `[dataXMin, dataXMax]` while not
60
+ * interacted (auto-follow), else the held window clamped into the
61
+ * current data bounds.
62
+ */
63
+ resolveXWindow(dataXMin: number, dataXMax: number): XWindow;
64
+ /** Zoom by `factor` (`<1` in, `>1` out) about a world-x pivot. */
65
+ zoomAt(pivotX: number, factor: number, dataXMin: number, dataXMax: number): void;
66
+ /** Pan the window by a signed world-x delta. */
67
+ panBy(deltaWorldX: number, dataXMin: number, dataXMax: number): void;
68
+ /** Clear the held window + flag so the view auto-follows again. */
69
+ reset(): void;
70
+ };
71
+ /**
72
+ * Build a {@link ViewController}. Pass `opts` to tune the zoom-in floor
73
+ * (`minSpan`) and zoom-out ceiling (`maxSpanFactor`); both default to a
74
+ * "1 ms floor, all-data ceiling" policy.
75
+ *
76
+ * @since 1.6
77
+ * @stable
78
+ * @example
79
+ * const view = createViewController({ minSpan: 2, maxSpanFactor: 1 });
80
+ * view.zoomAt(50, 0.5, 0, 100); // zoom in 2× about x=50
81
+ * void view.resolveXWindow(0, 100);
82
+ */
83
+ export declare function createViewController(opts?: ViewControllerOpts): ViewController;
84
+ /**
85
+ * One candidate row for {@link yRangeInWindow}: a world `x` (bar time) plus
86
+ * the low / high values to fold into the y range when `x` is inside the
87
+ * window. Bars pass `{ x: time, lo: low, hi: high }`; a scalar series point
88
+ * passes `lo === hi === value`.
89
+ *
90
+ * @since 1.6
91
+ * @stable
92
+ * @example
93
+ * const c: WindowYInput = { x: 10, lo: 99, hi: 101 };
94
+ * void c;
95
+ */
96
+ export type WindowYInput = {
97
+ readonly x: number;
98
+ readonly lo: number;
99
+ readonly hi: number;
100
+ };
101
+ /**
102
+ * Fold the y range of every candidate whose `x` falls inside `win` — the
103
+ * shared "auto-fit the price scale to the visible window" helper (matching
104
+ * lightweight-charts' auto price scale). Non-finite `lo`/`hi` rows are
105
+ * skipped. Returns `undefined` when no finite in-window candidate is seen,
106
+ * so the caller keeps its own degenerate-range fallback. Horizontal lines
107
+ * (no `x`) are folded in by the caller, not here.
108
+ *
109
+ * @since 1.6
110
+ * @stable
111
+ * @example
112
+ * const r = yRangeInWindow([{ x: 5, lo: 1, hi: 3 }], { xMin: 0, xMax: 10 });
113
+ * // r === { yMin: 1, yMax: 3 }
114
+ * void r;
115
+ */
116
+ export declare function yRangeInWindow(candidates: Iterable<WindowYInput>, win: XWindow): {
117
+ readonly yMin: number;
118
+ readonly yMax: number;
119
+ } | undefined;
120
+ //# sourceMappingURL=viewController.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewController.d.ts","sourceRoot":"","sources":["../../src/interaction/viewController.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,MAAM,MAAM,OAAO,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,MAAM,cAAc,GAAG;IACzB,yEAAyE;IACzE,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC;;;;OAIG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5D,kEAAkE;IAClE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjF,gDAAgD;IAChD,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACrE,mEAAmE;IACnE,KAAK,IAAI,IAAI,CAAC;CACjB,CAAC;AAsCF;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,CAAC,EAAE,kBAAkB,GAAG,cAAc,CAgD9E;AAED;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,YAAY,GAAG;IAAE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5F;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,cAAc,CAC1B,UAAU,EAAE,QAAQ,CAAC,YAAY,CAAC,EAClC,GAAG,EAAE,OAAO,GACb;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAW9D"}