web-annotation-renderer 0.6.4 → 0.7.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 (112) hide show
  1. package/CHANGELOG.md +129 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.js +62 -61
  5. package/dist/index.js.map +1 -1
  6. package/dist/index10.cjs +1 -1
  7. package/dist/index10.cjs.map +1 -1
  8. package/dist/index10.js +160 -13
  9. package/dist/index10.js.map +1 -1
  10. package/dist/index11.cjs +1 -1
  11. package/dist/index11.cjs.map +1 -1
  12. package/dist/index11.js +13 -50
  13. package/dist/index11.js.map +1 -1
  14. package/dist/index12.cjs +1 -1
  15. package/dist/index12.cjs.map +1 -1
  16. package/dist/index12.js +48 -155
  17. package/dist/index12.js.map +1 -1
  18. package/dist/index13.cjs +1 -1
  19. package/dist/index13.cjs.map +1 -1
  20. package/dist/index13.js +150 -34
  21. package/dist/index13.js.map +1 -1
  22. package/dist/index14.cjs +1 -1
  23. package/dist/index14.cjs.map +1 -1
  24. package/dist/index14.js +32 -65
  25. package/dist/index14.js.map +1 -1
  26. package/dist/index15.cjs +1 -1
  27. package/dist/index15.cjs.map +1 -1
  28. package/dist/index15.js +66 -33
  29. package/dist/index15.js.map +1 -1
  30. package/dist/index16.cjs +1 -1
  31. package/dist/index16.cjs.map +1 -1
  32. package/dist/index16.js +35 -77
  33. package/dist/index16.js.map +1 -1
  34. package/dist/index17.cjs +1 -1
  35. package/dist/index17.cjs.map +1 -1
  36. package/dist/index17.js +53 -28
  37. package/dist/index17.js.map +1 -1
  38. package/dist/index18.cjs +1 -1
  39. package/dist/index18.cjs.map +1 -1
  40. package/dist/index18.js +28 -22
  41. package/dist/index18.js.map +1 -1
  42. package/dist/index19.cjs +1 -1
  43. package/dist/index19.cjs.map +1 -1
  44. package/dist/index19.js +22 -117
  45. package/dist/index19.js.map +1 -1
  46. package/dist/index2.cjs +1 -1
  47. package/dist/index2.cjs.map +1 -1
  48. package/dist/index2.js +94 -98
  49. package/dist/index2.js.map +1 -1
  50. package/dist/index20.cjs +1 -1
  51. package/dist/index20.cjs.map +1 -1
  52. package/dist/index20.js +137 -100
  53. package/dist/index20.js.map +1 -1
  54. package/dist/index21.cjs +1 -1
  55. package/dist/index21.cjs.map +1 -1
  56. package/dist/index21.js +34 -76
  57. package/dist/index21.js.map +1 -1
  58. package/dist/index22.cjs +1 -1
  59. package/dist/index22.cjs.map +1 -1
  60. package/dist/index22.js +35 -139
  61. package/dist/index22.js.map +1 -1
  62. package/dist/index23.cjs +1 -1
  63. package/dist/index23.cjs.map +1 -1
  64. package/dist/index23.js +37 -37
  65. package/dist/index23.js.map +1 -1
  66. package/dist/index24.cjs +1 -1
  67. package/dist/index24.cjs.map +1 -1
  68. package/dist/index24.js +69 -37
  69. package/dist/index24.js.map +1 -1
  70. package/dist/index25.cjs +1 -1
  71. package/dist/index25.cjs.map +1 -1
  72. package/dist/index25.js +40 -38
  73. package/dist/index25.js.map +1 -1
  74. package/dist/index26.cjs +1 -1
  75. package/dist/index26.cjs.map +1 -1
  76. package/dist/index26.js +4 -39
  77. package/dist/index26.js.map +1 -1
  78. package/dist/index27.cjs +1 -1
  79. package/dist/index27.js +4 -4
  80. package/dist/index28.cjs +1 -1
  81. package/dist/index28.cjs.map +1 -1
  82. package/dist/index28.js +71 -5
  83. package/dist/index28.js.map +1 -1
  84. package/dist/index29.cjs +1 -1
  85. package/dist/index29.cjs.map +1 -1
  86. package/dist/index29.js +24 -69
  87. package/dist/index29.js.map +1 -1
  88. package/dist/index3.cjs +1 -1
  89. package/dist/index3.cjs.map +1 -1
  90. package/dist/index3.js +31 -31
  91. package/dist/index3.js.map +1 -1
  92. package/dist/index5.cjs +1 -1
  93. package/dist/index5.cjs.map +1 -1
  94. package/dist/index5.js +237 -190
  95. package/dist/index5.js.map +1 -1
  96. package/dist/index6.cjs +1 -1
  97. package/dist/index6.cjs.map +1 -1
  98. package/dist/index6.js +37 -19
  99. package/dist/index6.js.map +1 -1
  100. package/dist/index7.cjs +1 -1
  101. package/dist/index7.cjs.map +1 -1
  102. package/dist/index7.js +11 -17
  103. package/dist/index7.js.map +1 -1
  104. package/dist/index8.cjs +1 -1
  105. package/dist/index8.cjs.map +1 -1
  106. package/dist/index8.js +16 -125
  107. package/dist/index8.js.map +1 -1
  108. package/dist/index9.cjs +1 -1
  109. package/dist/index9.cjs.map +1 -1
  110. package/dist/index9.js +118 -201
  111. package/dist/index9.js.map +1 -1
  112. package/package.json +6 -3
package/dist/index5.js CHANGED
@@ -1,75 +1,13 @@
1
- import { inkToStrokes as T } from "./index18.js";
2
- import { circleToStrokes as _ } from "./index17.js";
3
- import { arrowToStrokes as P } from "./index16.js";
4
- import { underlineToStrokes as R } from "./index15.js";
5
- import { textToStrokes as E } from "./index14.js";
6
- import { highlightToStrokes as O } from "./index13.js";
7
- const v = [
8
- "highlight",
9
- "text",
10
- "underline",
11
- "arrow",
12
- "circle",
13
- "ink"
14
- ], S = 500, A = {
15
- highlight: {
16
- color: "rgba(255, 255, 0, 0.3)",
17
- width: 24,
18
- lineCap: "square",
19
- roughness: 1.5,
20
- bowing: 1.4,
21
- curveFitting: 0.95,
22
- curveStepCount: 9,
23
- maxRandomnessOffset: 2.5,
24
- disableMultiStroke: !1
25
- },
26
- text: {
27
- color: "rgba(220, 20, 60, 1.0)",
28
- width: 2,
29
- fontSize: 16,
30
- lineCap: "round",
31
- roughness: 0.8
32
- },
33
- underline: {
34
- color: "rgba(0, 0, 255, 0.8)",
35
- width: 2,
36
- lineCap: "round",
37
- roughness: 1.4,
38
- bowing: 1.5,
39
- curveFitting: 0.85,
40
- curveStepCount: 9,
41
- maxRandomnessOffset: 2,
42
- disableMultiStroke: !1
43
- },
44
- arrow: {
45
- color: "rgba(255, 0, 0, 0.8)",
46
- width: 2,
47
- lineCap: "round",
48
- roughness: 1.8,
49
- bowing: 1.8,
50
- curveFitting: 0.9,
51
- curveStepCount: 9,
52
- maxRandomnessOffset: 2,
53
- disableMultiStroke: !1
54
- },
55
- circle: {
56
- color: "rgba(255, 165, 0, 0.8)",
57
- width: 3,
58
- lineCap: "round",
59
- roughness: 1.1,
60
- bowing: 1.3,
61
- curveFitting: 0.8,
62
- curveStepCount: 12,
63
- maxRandomnessOffset: 2,
64
- disableMultiStroke: !1
65
- },
66
- ink: {
67
- color: "#DC143C",
68
- width: 2,
69
- lineCap: "round"
70
- }
71
- };
72
- class $ {
1
+ import { ANNOTATION_TYPES as m, DEFAULT_CONFIG as B, REFERENCE_HEIGHT as v } from "./index24.js";
2
+ import { normalizeAnnotationArray as E } from "./index10.js";
3
+ import { pointNormToAbs as S } from "./index7.js";
4
+ import { inkToStrokes as O } from "./index19.js";
5
+ import { circleToStrokes as j } from "./index18.js";
6
+ import { arrowToStrokes as N } from "./index17.js";
7
+ import { underlineToStrokes as z } from "./index16.js";
8
+ import { textToStrokes as H } from "./index15.js";
9
+ import { highlightToStrokes as V } from "./index14.js";
10
+ class D {
73
11
  /**
74
12
  * Create StrokeRenderer instance
75
13
  *
@@ -81,21 +19,21 @@ class $ {
81
19
  * @param {Object} [config.arrow] - Arrow type settings
82
20
  * @param {Object} [config.circle] - Circle type settings
83
21
  */
84
- constructor(t, r = {}) {
22
+ constructor(t, e = {}) {
85
23
  if (!t || !(t instanceof HTMLCanvasElement))
86
24
  throw new Error(
87
25
  "StrokeRenderer: canvas must be a valid HTMLCanvasElement"
88
26
  );
89
- this.canvas = t, this.ctx = t.getContext("2d"), this.strokes = [], this.viewport = { width: 0, height: 0 }, this.config = {};
90
- for (const i of v)
91
- this.config[i] = { ...A[i] };
92
- Object.keys(r).length > 0 && this.setConfig(r), this.converters = {
93
- highlight: O,
94
- text: E,
95
- underline: R,
96
- arrow: P,
97
- circle: _,
98
- ink: T
27
+ this.canvas = t, this.ctx = t.getContext("2d"), this.strokes = [], this.viewport = { width: 0, height: 0 }, this._strokeCacheByPage = /* @__PURE__ */ new Map(), this._lastAnnotationsRef = null, this.config = {};
28
+ for (const n of m)
29
+ this.config[n] = { ...B[n] };
30
+ Object.keys(e).length > 0 && this.setConfig(e), this.converters = {
31
+ highlight: V,
32
+ text: H,
33
+ underline: z,
34
+ arrow: N,
35
+ circle: j,
36
+ ink: O
99
37
  };
100
38
  }
101
39
  /**
@@ -128,16 +66,16 @@ class $ {
128
66
  * });
129
67
  */
130
68
  setConfig(t) {
131
- const r = {}, i = {};
132
- for (const [e, s] of Object.entries(t))
133
- v.includes(e) ? i[e] = s : r[e] = s;
134
- for (const e of v)
135
- this.config[e] = {
136
- ...this.config[e],
137
- ...r,
138
- ...i[e] || {}
69
+ const e = {}, n = {};
70
+ for (const [s, i] of Object.entries(t))
71
+ m.includes(s) ? n[s] = i : e[s] = i;
72
+ for (const s of m)
73
+ this.config[s] = {
74
+ ...this.config[s],
75
+ ...e,
76
+ ...n[s] || {}
139
77
  };
140
- return this;
78
+ return this._strokeCacheByPage && this._strokeCacheByPage.clear(), this._lastAnnotationsRef = null, this;
141
79
  }
142
80
  /**
143
81
  * Register a custom converter for a new annotation type
@@ -145,12 +83,12 @@ class $ {
145
83
  * @param {string} type - Annotation type name
146
84
  * @param {Function} converter - Converter function (annotation, style) => strokes[]
147
85
  */
148
- registerConverter(t, r) {
149
- if (typeof r != "function")
86
+ registerConverter(t, e) {
87
+ if (typeof e != "function")
150
88
  throw new Error(
151
89
  "StrokeRenderer.registerConverter: converter must be a function"
152
90
  );
153
- this.converters[t] = r;
91
+ this.converters[t] = e;
154
92
  }
155
93
  /**
156
94
  * Set viewport dimensions and configure canvas
@@ -160,35 +98,80 @@ class $ {
160
98
  * @param {number} width - Viewport width in CSS pixels
161
99
  * @param {number} height - Viewport height in CSS pixels
162
100
  */
163
- setViewport(t, r) {
164
- this.viewport = { width: t, height: r };
165
- const i = window.devicePixelRatio || 1;
166
- this.canvas.width = t * i, this.canvas.height = r * i, this.canvas.style.width = `${t}px`, this.canvas.style.height = `${r}px`, this.ctx.setTransform(i, 0, 0, i, 0, 0);
101
+ setViewport(t, e) {
102
+ this.viewport = { width: t, height: e };
103
+ const n = window.devicePixelRatio || 1;
104
+ this.canvas.width = t * n, this.canvas.height = e * n, this.canvas.style.width = `${t}px`, this.canvas.style.height = `${e}px`, this.ctx.setTransform(n, 0, 0, n, 0, 0);
167
105
  }
168
106
  /**
169
107
  * Set annotations and convert them to strokes
170
108
  *
171
- * Clears existing strokes and converts all annotations.
109
+ * Behavior:
110
+ * - When `page` is null, all annotations are converted and exposed via
111
+ * `this.strokes`. Per-page cache is still populated.
112
+ * - When `page` is a number, conversion is performed per page (cached) and
113
+ * `this.strokes` is set to the cache entry for the requested page.
114
+ * - When the `annotations` reference changes between calls, the cache is
115
+ * invalidated.
172
116
  *
173
117
  * @param {Array} annotations - Array of annotation objects
174
- * @param {number} [page] - Optional page filter (only convert annotations for this page)
118
+ * @param {number|null} [page=null] - Optional page filter
119
+ * @param {Object} [options]
120
+ * @param {boolean} [options.validate=false] - Run normalizeAnnotationArray
121
+ * first and convert the normalized result instead of the raw input.
122
+ * @param {boolean} [options.noCache=false] - Skip the per-page cache and
123
+ * convert the filtered annotations directly (legacy fast path).
175
124
  */
176
- setAnnotations(t, r = null) {
125
+ setAnnotations(t, e = null, n = {}) {
177
126
  if (!Array.isArray(t)) {
178
127
  console.warn(
179
128
  "StrokeRenderer.setAnnotations: annotations must be an array"
180
- ), this.strokes = [];
129
+ ), this.strokes = [], this._strokeCacheByPage.clear(), this._lastAnnotationsRef = null;
181
130
  return;
182
131
  }
183
- const i = r !== null ? t.filter((e) => e.page === r) : t;
184
- this.strokes = i.flatMap((e) => {
185
- const s = this.converters[e.type];
186
- if (!s)
132
+ const { validate: s = !1, noCache: i = !1 } = n;
133
+ let r = t;
134
+ if (s && (r = E(t).normalized), r !== this._lastAnnotationsRef && (this._strokeCacheByPage.clear(), this._lastAnnotationsRef = r), i) {
135
+ const o = e !== null ? r.filter((h) => h.page === e) : r;
136
+ this.strokes = this._convertAnnotations(o);
137
+ return;
138
+ }
139
+ if (this._strokeCacheByPage.size === 0) {
140
+ const o = /* @__PURE__ */ new Map();
141
+ for (const h of r) {
142
+ const a = h && h.page != null ? h.page : null;
143
+ let c = o.get(a);
144
+ c || (c = [], o.set(a, c)), c.push(h);
145
+ }
146
+ for (const [h, a] of o)
147
+ this._strokeCacheByPage.set(h, this._convertAnnotations(a));
148
+ }
149
+ if (e !== null)
150
+ this.strokes = this._strokeCacheByPage.get(e) || [];
151
+ else {
152
+ const o = [];
153
+ for (const h of this._strokeCacheByPage.values())
154
+ for (const a of h) o.push(a);
155
+ this.strokes = o;
156
+ }
157
+ }
158
+ /**
159
+ * Convert a list of annotations to stroke commands using the registered
160
+ * converters. Unknown types are skipped with a warning.
161
+ *
162
+ * @private
163
+ * @param {Array} annotations
164
+ * @returns {Array} stroke command objects
165
+ */
166
+ _convertAnnotations(t) {
167
+ return t.flatMap((e) => {
168
+ const n = this.converters[e.type];
169
+ if (!n)
187
170
  return console.warn(
188
171
  `StrokeRenderer: Unknown annotation type "${e.type}"`
189
172
  ), [];
190
- const n = this._resolveStyle(e);
191
- return s(e, n);
173
+ const s = this._resolveStyle(e);
174
+ return n(e, s);
192
175
  });
193
176
  }
194
177
  /**
@@ -213,13 +196,13 @@ class $ {
213
196
  * @param {number} time - Current time in seconds
214
197
  */
215
198
  render(t) {
216
- const { ctx: r, viewport: i, strokes: e } = this;
217
- r.clearRect(0, 0, i.width, i.height);
218
- for (const s of e) {
219
- if (t < s.start)
199
+ const { ctx: e, viewport: n, strokes: s } = this;
200
+ e.clearRect(0, 0, n.width, n.height);
201
+ for (const i of s) {
202
+ if (t < i.start)
220
203
  continue;
221
- const n = s.end - s.start, h = t - s.start, o = n > 0 ? Math.min(1, h / n) : 1;
222
- this._drawStroke(s, o);
204
+ const r = i.end - i.start, o = t - i.start, h = r > 0 ? Math.min(1, o / r) : 1;
205
+ this._drawStroke(i, h);
223
206
  }
224
207
  }
225
208
  /**
@@ -232,7 +215,7 @@ class $ {
232
215
  * Destroy the renderer and release resources
233
216
  */
234
217
  destroy() {
235
- this.strokes = [], this.ctx = null, this.canvas = null, this.config = null, this.converters = null;
218
+ this.strokes = [], this._strokeCacheByPage && this._strokeCacheByPage.clear(), this._strokeCacheByPage = null, this._lastAnnotationsRef = null, this.ctx = null, this.canvas = null, this.config = null, this.converters = null;
236
219
  }
237
220
  /**
238
221
  * Resolve style for an annotation
@@ -245,8 +228,8 @@ class $ {
245
228
  * @returns {Object} Resolved style object
246
229
  */
247
230
  _resolveStyle(t) {
248
- const { type: r } = t;
249
- return this.config[r] || {};
231
+ const { type: e } = t;
232
+ return this.config[e] || {};
250
233
  }
251
234
  /**
252
235
  * Linearly interpolate between two points
@@ -257,8 +240,41 @@ class $ {
257
240
  * @param {number} t - Interpolation factor (0-1)
258
241
  * @returns {Array} Interpolated point [x, y]
259
242
  */
260
- _interpolatePoint(t, r, i) {
261
- return [t[0] + (r[0] - t[0]) * i, t[1] + (r[1] - t[1]) * i];
243
+ _interpolatePoint(t, e, n) {
244
+ return [t[0] + (e[0] - t[0]) * n, t[1] + (e[1] - t[1]) * n];
245
+ }
246
+ /**
247
+ * Project a normalized stroke point into screen pixel space, honouring
248
+ * the legacy `uniformScale` / `baseX/baseY` flags used by glyph strokes.
249
+ *
250
+ * Three cases:
251
+ * - hasBase : `[coordX, coordY]` is an offset from `(baseX, baseY)` in
252
+ * uniform-scaled space (both axes by viewport.height).
253
+ * - uniform : `[coordX, coordY]` is a full position in uniform-scaled
254
+ * space (legacy text glyph fallback).
255
+ * - default : `[coordX, coordY]` is a normalized 0–1 page coordinate;
256
+ * converted via `pointNormToAbs`.
257
+ *
258
+ * @private
259
+ * @param {number} coordX
260
+ * @param {number} coordY
261
+ * @param {boolean} uniformScale
262
+ * @param {boolean} hasBase
263
+ * @param {number|null} baseX
264
+ * @param {number|null} baseY
265
+ * @returns {[number, number]}
266
+ */
267
+ _projectPoint(t, e, n, s, i, r) {
268
+ const { viewport: o } = this;
269
+ if (s)
270
+ return [
271
+ i * o.width + t * o.height,
272
+ r * o.height + e * o.height
273
+ ];
274
+ if (n)
275
+ return [t * o.height, e * o.height];
276
+ const { x: h, y: a } = S({ x: t, y: e }, o);
277
+ return [h, a];
262
278
  }
263
279
  /**
264
280
  * Get pressure values for visible points including interpolated final
@@ -269,13 +285,13 @@ class $ {
269
285
  * @param {number} segmentProgress - Progress within current segment (0-1)
270
286
  * @returns {Array} Pressure values for visible points
271
287
  */
272
- _interpolatePressures(t, r, i) {
273
- const e = t.slice(0, r + 1);
274
- if (r < t.length - 1 && i > 0) {
275
- const s = t[r], n = t[r + 1];
276
- e.push(s + (n - s) * i);
288
+ _interpolatePressures(t, e, n) {
289
+ const s = t.slice(0, e + 1);
290
+ if (e < t.length - 1 && n > 0) {
291
+ const i = t[e], r = t[e + 1];
292
+ s.push(i + (r - i) * n);
277
293
  }
278
- return e;
294
+ return s;
279
295
  }
280
296
  /**
281
297
  * Draw a single stroke with progress
@@ -286,62 +302,66 @@ class $ {
286
302
  * @param {Object} stroke - Stroke command object
287
303
  * @param {number} progress - Progress from 0 to 1
288
304
  */
289
- _drawStroke(t, r) {
290
- const { ctx: i } = this, {
291
- points: e,
292
- color: s,
293
- width: n,
294
- lineCap: h,
295
- pressures: o,
296
- uniformScale: f,
297
- baseX: l,
298
- baseY: a
305
+ _drawStroke(t, e) {
306
+ if (t.screenSpaceWing) {
307
+ this._drawScreenSpaceWingStroke(t, e);
308
+ return;
309
+ }
310
+ const { ctx: n } = this, {
311
+ points: s,
312
+ color: i,
313
+ width: r,
314
+ lineCap: o,
315
+ pressures: h,
316
+ uniformScale: a,
317
+ baseX: c,
318
+ baseY: f
299
319
  } = t;
300
- if (!e || e.length < 2) return;
301
- if (i.strokeStyle = s || "rgba(0, 0, 0, 0.5)", i.lineCap = h || "round", i.lineJoin = "round", r >= 1) {
302
- o && o.length >= e.length ? this._drawVariableWidthStroke(
303
- e,
304
- n,
305
- o,
306
- f,
307
- l,
308
- a
320
+ if (!s || s.length < 2) return;
321
+ if (n.strokeStyle = i || "rgba(0, 0, 0, 0.5)", n.lineCap = o || "round", n.lineJoin = "round", e >= 1) {
322
+ h && h.length >= s.length ? this._drawVariableWidthStroke(
323
+ s,
324
+ r,
325
+ h,
326
+ a,
327
+ c,
328
+ f
309
329
  ) : this._drawConstantWidthStroke(
310
- e,
311
- n,
312
- f,
313
- l,
314
- a
330
+ s,
331
+ r,
332
+ a,
333
+ c,
334
+ f
315
335
  );
316
336
  return;
317
337
  }
318
- const u = e.length - 1, g = r * u, c = Math.floor(g), w = g - c, d = e.slice(0, c + 1);
319
- if (c < u && w > 0) {
320
- const p = e[c], k = e[c + 1];
321
- d.push(this._interpolatePoint(p, k, w));
338
+ const p = s.length - 1, u = e * p, l = Math.floor(u), g = u - l, k = s.slice(0, l + 1);
339
+ if (l < p && g > 0) {
340
+ const y = s[l], d = s[l + 1];
341
+ k.push(this._interpolatePoint(y, d, g));
322
342
  }
323
- if (!(d.length < 2))
324
- if (o && o.length >= e.length) {
325
- const p = this._interpolatePressures(
326
- o,
327
- c,
328
- w
343
+ if (!(k.length < 2))
344
+ if (h && h.length >= s.length) {
345
+ const y = this._interpolatePressures(
346
+ h,
347
+ l,
348
+ g
329
349
  );
330
350
  this._drawVariableWidthStroke(
331
- d,
332
- n,
333
- p,
334
- f,
335
- l,
336
- a
351
+ k,
352
+ r,
353
+ y,
354
+ a,
355
+ c,
356
+ f
337
357
  );
338
358
  } else
339
359
  this._drawConstantWidthStroke(
340
- d,
341
- n,
342
- f,
343
- l,
344
- a
360
+ k,
361
+ r,
362
+ a,
363
+ c,
364
+ f
345
365
  );
346
366
  }
347
367
  /**
@@ -354,16 +374,15 @@ class $ {
354
374
  * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)
355
375
  * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)
356
376
  */
357
- _drawConstantWidthStroke(t, r, i = !1, e = null, s = null) {
358
- const { ctx: n, viewport: h } = this, o = h.height / S;
359
- n.lineWidth = (r || 2) * o, n.beginPath();
360
- const f = i && e !== null && s !== null;
361
- for (let l = 0; l < t.length; l++) {
362
- const [a, u] = t[l];
363
- let g, c;
364
- f ? (g = e * h.width + a * h.height, c = s * h.height + u * h.height) : i ? (g = a * h.height, c = u * h.height) : (g = a * h.width, c = u * h.height), l === 0 ? n.moveTo(g, c) : n.lineTo(g, c);
377
+ _drawConstantWidthStroke(t, e, n = !1, s = null, i = null) {
378
+ const { ctx: r, viewport: o } = this, h = o.height / v;
379
+ r.lineWidth = (e || 2) * h, r.beginPath();
380
+ const a = n && s !== null && i !== null;
381
+ for (let c = 0; c < t.length; c++) {
382
+ const [f, p] = t[c], [u, l] = this._projectPoint(f, p, n, a, s, i);
383
+ c === 0 ? r.moveTo(u, l) : r.lineTo(u, l);
365
384
  }
366
- n.stroke();
385
+ r.stroke();
367
386
  }
368
387
  /**
369
388
  * Draw stroke with variable width based on pressure
@@ -376,19 +395,47 @@ class $ {
376
395
  * @param {number} [baseX] - Base X position in width-normalized coords (for uniformScale with offset points)
377
396
  * @param {number} [baseY] - Base Y position in height-normalized coords (for uniformScale with offset points)
378
397
  */
379
- _drawVariableWidthStroke(t, r, i, e = !1, s = null, n = null) {
380
- const { ctx: h, viewport: o } = this, f = e && s !== null && n !== null;
381
- for (let l = 1; l < t.length; l++) {
382
- const [a, u] = t[l - 1], [g, c] = t[l];
383
- let w, d, p, k;
384
- f ? (w = s * o.width + a * o.height, d = n * o.height + u * o.height, p = s * o.width + g * o.height, k = n * o.height + c * o.height) : e ? (w = a * o.height, d = u * o.height, p = g * o.height, k = c * o.height) : (w = a * o.width, d = u * o.height, p = g * o.width, k = c * o.height);
385
- const m = i[l - 1] || 1, y = i[l] || 1, b = (m + y) / 2, x = o.height / S, C = Math.max(0.5, r * b) * x;
386
- h.lineWidth = C, h.beginPath(), h.moveTo(w, d), h.lineTo(p, k), h.stroke();
398
+ _drawVariableWidthStroke(t, e, n, s = !1, i = null, r = null) {
399
+ const { ctx: o, viewport: h } = this, a = s && i !== null && r !== null, c = h.height / v;
400
+ for (let f = 1; f < t.length; f++) {
401
+ const [p, u] = t[f - 1], [l, g] = t[f], [k, y] = this._projectPoint(p, u, s, a, i, r), [d, w] = this._projectPoint(l, g, s, a, i, r), _ = ((n[f - 1] || 1) + (n[f] || 1)) / 2;
402
+ o.lineWidth = Math.max(0.5, e * _) * c, o.beginPath(), o.moveTo(k, y), o.lineTo(d, w), o.stroke();
387
403
  }
388
404
  }
405
+ /**
406
+ * Draw an arrow wing whose geometry is recomputed in screen-pixel space at
407
+ * every frame, so diagonal arrows render with symmetric wings regardless of
408
+ * viewport aspect ratio.
409
+ *
410
+ * Stroke shape (`stroke.screenSpaceWing`):
411
+ * - fromX, fromY: tail of the main arrow line (normalized 0–1)
412
+ * - toX, toY: tip of the main arrow line (normalized 0–1)
413
+ * - headAngle: wing offset angle in radians (defaults to π/6)
414
+ * - wingSide: 'left' uses (θ - headAngle); 'right' uses (θ + headAngle)
415
+ *
416
+ * The wing is drawn as a single straight line via the canvas API (no
417
+ * RoughJS), since screen-space recomputation runs every render frame and
418
+ * regenerating a rough path each frame would be too expensive.
419
+ *
420
+ * @private
421
+ * @param {Object} stroke
422
+ * @param {number} progress - 0..1 along the wing's full extent
423
+ */
424
+ _drawScreenSpaceWingStroke(t, e) {
425
+ const { ctx: n, viewport: s } = this, i = t.screenSpaceWing;
426
+ if (!i) return;
427
+ const { fromX: r, fromY: o, toX: h, toY: a, wingSide: c } = i, f = typeof i.headAngle == "number" ? i.headAngle : Math.PI / 6;
428
+ if (typeof r != "number" || typeof o != "number" || typeof h != "number" || typeof a != "number")
429
+ return;
430
+ const p = S({ x: h, y: a }, s), u = S({ x: r, y: o }, s), l = p.x, g = p.y, k = u.x, y = u.y, d = l - k, w = g - y, _ = Math.sqrt(d * d + w * w);
431
+ if (_ === 0) return;
432
+ const P = Math.min(_ * 0.2, 0.03 * s.height), x = Math.atan2(w, d), C = c === "right" ? x + f : x - f, b = l - P * Math.cos(C), T = g - P * Math.sin(C), A = Math.max(0, Math.min(1, e)), R = l + (b - l) * A, M = g + (T - g) * A, W = s.height / v;
433
+ n.strokeStyle = t.color || "rgba(0, 0, 0, 0.5)", n.lineCap = t.lineCap || "round", n.lineJoin = "round", n.lineWidth = (t.width || 2) * W, n.beginPath(), n.moveTo(l, g), n.lineTo(R, M), n.stroke();
434
+ }
389
435
  }
390
436
  export {
391
- $ as StrokeRenderer,
392
- $ as default
437
+ v as REFERENCE_HEIGHT,
438
+ D as StrokeRenderer,
439
+ D as default
393
440
  };
394
441
  //# sourceMappingURL=index5.js.map