html2canvas-pro 2.1.0 → 2.1.1

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 (186) hide show
  1. package/dist/html2canvas-pro.esm.js +21 -7
  2. package/dist/html2canvas-pro.esm.js.map +1 -1
  3. package/dist/html2canvas-pro.js +21 -7
  4. package/dist/html2canvas-pro.js.map +1 -1
  5. package/dist/html2canvas-pro.min.js +3 -3
  6. package/dist/lib/core/cache-storage.js +2 -2
  7. package/dist/lib/core/features.js +2 -2
  8. package/dist/lib/render/canvas/background-renderer.js +6 -0
  9. package/dist/lib/render/canvas/canvas-renderer.js +5 -1
  10. package/dist/lib/render/canvas/foreignobject-renderer.js +5 -1
  11. package/package.json +3 -11
  12. package/dist/lib/invariant.js +0 -9
  13. package/dist/types/invariant.d.ts +0 -1
  14. package/src/__tests__/index.ts +0 -99
  15. package/src/config.ts +0 -107
  16. package/src/core/__mocks__/cache-storage.ts +0 -1
  17. package/src/core/__mocks__/context.ts +0 -19
  18. package/src/core/__mocks__/features.ts +0 -8
  19. package/src/core/__mocks__/logger.ts +0 -17
  20. package/src/core/__tests__/cache-storage.test.ts +0 -205
  21. package/src/core/__tests__/cache-storage.ts +0 -278
  22. package/src/core/__tests__/logger.ts +0 -29
  23. package/src/core/__tests__/validator.ts +0 -359
  24. package/src/core/bitwise.ts +0 -1
  25. package/src/core/cache-storage.ts +0 -315
  26. package/src/core/context.ts +0 -31
  27. package/src/core/debugger.ts +0 -32
  28. package/src/core/features.ts +0 -222
  29. package/src/core/logger.ts +0 -64
  30. package/src/core/origin-checker.ts +0 -57
  31. package/src/core/performance-monitor.ts +0 -241
  32. package/src/core/render-element.ts +0 -272
  33. package/src/core/util.ts +0 -1
  34. package/src/core/validator.ts +0 -593
  35. package/src/css/index.ts +0 -427
  36. package/src/css/layout/__mocks__/bounds.ts +0 -6
  37. package/src/css/layout/bounds.ts +0 -79
  38. package/src/css/layout/text.ts +0 -161
  39. package/src/css/property-descriptor.ts +0 -49
  40. package/src/css/property-descriptors/__tests__/background-tests.ts +0 -65
  41. package/src/css/property-descriptors/__tests__/clip-path.test.ts +0 -280
  42. package/src/css/property-descriptors/__tests__/font-family.ts +0 -25
  43. package/src/css/property-descriptors/__tests__/image-rendering-integration.test.ts +0 -153
  44. package/src/css/property-descriptors/__tests__/image-rendering-performance.test.ts +0 -175
  45. package/src/css/property-descriptors/__tests__/image-rendering.test.ts +0 -72
  46. package/src/css/property-descriptors/__tests__/paint-order.ts +0 -87
  47. package/src/css/property-descriptors/__tests__/text-shadow.ts +0 -94
  48. package/src/css/property-descriptors/__tests__/transform-tests.ts +0 -18
  49. package/src/css/property-descriptors/background-clip.ts +0 -30
  50. package/src/css/property-descriptors/background-color.ts +0 -9
  51. package/src/css/property-descriptors/background-image.ts +0 -27
  52. package/src/css/property-descriptors/background-origin.ts +0 -31
  53. package/src/css/property-descriptors/background-position.ts +0 -38
  54. package/src/css/property-descriptors/background-repeat.ts +0 -44
  55. package/src/css/property-descriptors/background-size.ts +0 -27
  56. package/src/css/property-descriptors/border-color.ts +0 -13
  57. package/src/css/property-descriptors/border-radius.ts +0 -19
  58. package/src/css/property-descriptors/border-style.ts +0 -34
  59. package/src/css/property-descriptors/border-width.ts +0 -20
  60. package/src/css/property-descriptors/box-shadow.ts +0 -60
  61. package/src/css/property-descriptors/clip-path.ts +0 -271
  62. package/src/css/property-descriptors/color.ts +0 -9
  63. package/src/css/property-descriptors/content.ts +0 -26
  64. package/src/css/property-descriptors/counter-increment.ts +0 -43
  65. package/src/css/property-descriptors/counter-reset.ts +0 -36
  66. package/src/css/property-descriptors/direction.ts +0 -23
  67. package/src/css/property-descriptors/display.ts +0 -117
  68. package/src/css/property-descriptors/duration.ts +0 -14
  69. package/src/css/property-descriptors/float.ts +0 -29
  70. package/src/css/property-descriptors/font-family.ts +0 -38
  71. package/src/css/property-descriptors/font-size.ts +0 -9
  72. package/src/css/property-descriptors/font-style.ts +0 -25
  73. package/src/css/property-descriptors/font-variant.ts +0 -12
  74. package/src/css/property-descriptors/font-weight.ts +0 -26
  75. package/src/css/property-descriptors/image-rendering.ts +0 -33
  76. package/src/css/property-descriptors/letter-spacing.ts +0 -25
  77. package/src/css/property-descriptors/line-break.ts +0 -22
  78. package/src/css/property-descriptors/line-height.ts +0 -22
  79. package/src/css/property-descriptors/list-style-image.ts +0 -19
  80. package/src/css/property-descriptors/list-style-position.ts +0 -22
  81. package/src/css/property-descriptors/list-style-type.ts +0 -179
  82. package/src/css/property-descriptors/margin.ts +0 -13
  83. package/src/css/property-descriptors/mix-blend-mode.ts +0 -35
  84. package/src/css/property-descriptors/object-fit.ts +0 -39
  85. package/src/css/property-descriptors/opacity.ts +0 -15
  86. package/src/css/property-descriptors/overflow-wrap.ts +0 -22
  87. package/src/css/property-descriptors/overflow.ts +0 -34
  88. package/src/css/property-descriptors/padding.ts +0 -14
  89. package/src/css/property-descriptors/paint-order.ts +0 -42
  90. package/src/css/property-descriptors/position.ts +0 -30
  91. package/src/css/property-descriptors/quotes.ts +0 -57
  92. package/src/css/property-descriptors/rotate.ts +0 -34
  93. package/src/css/property-descriptors/text-align.ts +0 -26
  94. package/src/css/property-descriptors/text-decoration-color.ts +0 -9
  95. package/src/css/property-descriptors/text-decoration-line.ts +0 -38
  96. package/src/css/property-descriptors/text-decoration-style.ts +0 -32
  97. package/src/css/property-descriptors/text-decoration-thickness.ts +0 -30
  98. package/src/css/property-descriptors/text-overflow.ts +0 -23
  99. package/src/css/property-descriptors/text-shadow.ts +0 -52
  100. package/src/css/property-descriptors/text-transform.ts +0 -27
  101. package/src/css/property-descriptors/text-underline-offset.ts +0 -27
  102. package/src/css/property-descriptors/transform-origin.ts +0 -29
  103. package/src/css/property-descriptors/transform.ts +0 -74
  104. package/src/css/property-descriptors/visibility.ts +0 -25
  105. package/src/css/property-descriptors/webkit-line-clamp.ts +0 -30
  106. package/src/css/property-descriptors/webkit-text-stroke-color.ts +0 -8
  107. package/src/css/property-descriptors/webkit-text-stroke-width.ts +0 -15
  108. package/src/css/property-descriptors/word-break.ts +0 -25
  109. package/src/css/property-descriptors/writing-mode.ts +0 -37
  110. package/src/css/property-descriptors/z-index.ts +0 -27
  111. package/src/css/syntax/__tests__/tokernizer-tests.ts +0 -29
  112. package/src/css/syntax/parser.ts +0 -188
  113. package/src/css/syntax/tokenizer.ts +0 -822
  114. package/src/css/type-descriptor.ts +0 -7
  115. package/src/css/types/__tests__/color-tests.ts +0 -147
  116. package/src/css/types/__tests__/image-tests.ts +0 -239
  117. package/src/css/types/angle.ts +0 -86
  118. package/src/css/types/color-math.ts +0 -22
  119. package/src/css/types/color-spaces/a98.ts +0 -86
  120. package/src/css/types/color-spaces/p3.ts +0 -92
  121. package/src/css/types/color-spaces/pro-photo.ts +0 -87
  122. package/src/css/types/color-spaces/rec2020.ts +0 -90
  123. package/src/css/types/color-spaces/srgb.ts +0 -87
  124. package/src/css/types/color-utilities.ts +0 -452
  125. package/src/css/types/color.ts +0 -485
  126. package/src/css/types/functions/-prefix-linear-gradient.ts +0 -35
  127. package/src/css/types/functions/-prefix-radial-gradient.ts +0 -106
  128. package/src/css/types/functions/-webkit-gradient.ts +0 -69
  129. package/src/css/types/functions/__tests__/radial-gradient.ts +0 -69
  130. package/src/css/types/functions/counter.ts +0 -511
  131. package/src/css/types/functions/gradient.ts +0 -206
  132. package/src/css/types/functions/linear-gradient.ts +0 -28
  133. package/src/css/types/functions/radial-gradient.ts +0 -101
  134. package/src/css/types/image.ts +0 -120
  135. package/src/css/types/index.ts +0 -1
  136. package/src/css/types/length-percentage.ts +0 -137
  137. package/src/css/types/length.ts +0 -7
  138. package/src/css/types/time.ts +0 -20
  139. package/src/dom/__mocks__/document-cloner.ts +0 -22
  140. package/src/dom/__tests__/dom-normalizer.test.ts +0 -133
  141. package/src/dom/__tests__/element-container.test.ts +0 -129
  142. package/src/dom/document-cloner.ts +0 -929
  143. package/src/dom/dom-normalizer.ts +0 -133
  144. package/src/dom/element-container.ts +0 -75
  145. package/src/dom/elements/li-element-container.ts +0 -10
  146. package/src/dom/elements/ol-element-container.ts +0 -12
  147. package/src/dom/elements/select-element-container.ts +0 -10
  148. package/src/dom/elements/textarea-element-container.ts +0 -9
  149. package/src/dom/node-parser.ts +0 -177
  150. package/src/dom/node-type-guards.ts +0 -70
  151. package/src/dom/replaced-elements/canvas-element-container.ts +0 -15
  152. package/src/dom/replaced-elements/iframe-element-container.ts +0 -55
  153. package/src/dom/replaced-elements/image-element-container.ts +0 -16
  154. package/src/dom/replaced-elements/index.ts +0 -5
  155. package/src/dom/replaced-elements/input-element-container.ts +0 -105
  156. package/src/dom/replaced-elements/pseudo-elements.ts +0 -0
  157. package/src/dom/replaced-elements/svg-element-container.ts +0 -23
  158. package/src/dom/text-container.ts +0 -42
  159. package/src/global.d.ts +0 -19
  160. package/src/index.ts +0 -82
  161. package/src/invariant.ts +0 -5
  162. package/src/options.ts +0 -55
  163. package/src/render/__tests__/object-fit.test.ts +0 -85
  164. package/src/render/background.ts +0 -298
  165. package/src/render/bezier-curve.ts +0 -47
  166. package/src/render/border.ts +0 -165
  167. package/src/render/bound-curves.ts +0 -388
  168. package/src/render/box-sizing.ts +0 -31
  169. package/src/render/canvas/__tests__/background-renderer.test.ts +0 -72
  170. package/src/render/canvas/__tests__/border-renderer.test.ts +0 -24
  171. package/src/render/canvas/__tests__/effects-renderer.test.ts +0 -32
  172. package/src/render/canvas/__tests__/text-renderer.test.ts +0 -471
  173. package/src/render/canvas/background-renderer.ts +0 -271
  174. package/src/render/canvas/border-renderer.ts +0 -224
  175. package/src/render/canvas/canvas-path.ts +0 -31
  176. package/src/render/canvas/canvas-renderer.ts +0 -641
  177. package/src/render/canvas/effects-renderer.ts +0 -130
  178. package/src/render/canvas/foreignobject-renderer.ts +0 -53
  179. package/src/render/canvas/text-renderer.ts +0 -700
  180. package/src/render/effects.ts +0 -75
  181. package/src/render/font-metrics.ts +0 -72
  182. package/src/render/object-fit.ts +0 -100
  183. package/src/render/path.ts +0 -37
  184. package/src/render/renderer-interface.ts +0 -28
  185. package/src/render/stacking-context.ts +0 -386
  186. package/src/render/vector.ts +0 -19
@@ -1,271 +0,0 @@
1
- /**
2
- * Background Renderer
3
- *
4
- * Handles rendering of element backgrounds including:
5
- * - Background colors
6
- * - Background images (URL)
7
- * - Linear gradients
8
- * - Radial gradients
9
- * - Background patterns and repeats
10
- */
11
-
12
- import { Context } from '../../core/context';
13
- import { ElementContainer } from '../../dom/element-container';
14
- import { Path } from '../path';
15
- import {
16
- CSSImageType,
17
- CSSLinearGradientImage,
18
- CSSRadialGradientImage,
19
- CSSURLImage,
20
- isLinearGradient,
21
- isRadialGradient
22
- } from '../../css/types/image';
23
- import { calculateBackgroundRendering } from '../background';
24
- import { calculateGradientDirection, calculateRadius, processColorStops } from '../../css/types/functions/gradient';
25
- import { FIFTY_PERCENT, getAbsoluteValue } from '../../css/types/length-percentage';
26
- import { asString } from '../../css/types/color-utilities';
27
- import { IMAGE_RENDERING } from '../../css/property-descriptors/image-rendering';
28
- import { createCanvasPath } from './canvas-path';
29
-
30
- /**
31
- * Dependencies required for BackgroundRenderer
32
- */
33
- export interface BackgroundRendererDependencies {
34
- ctx: CanvasRenderingContext2D;
35
- context: Context;
36
- canvas: HTMLCanvasElement;
37
- options: {
38
- width: number;
39
- height: number;
40
- scale: number;
41
- };
42
- }
43
-
44
- /**
45
- * Background Renderer
46
- *
47
- * Specialized renderer for element backgrounds.
48
- * Extracted from CanvasRenderer to improve code organization and maintainability.
49
- */
50
- export class BackgroundRenderer {
51
- private readonly ctx: CanvasRenderingContext2D;
52
- private readonly context: Context;
53
- private readonly canvas: HTMLCanvasElement;
54
-
55
- constructor(deps: BackgroundRendererDependencies) {
56
- this.ctx = deps.ctx;
57
- this.context = deps.context;
58
- this.canvas = deps.canvas;
59
- // Options stored in deps but not needed as instance property
60
- }
61
-
62
- /**
63
- * Render background images for a container
64
- * Supports URL images, linear gradients, and radial gradients
65
- *
66
- * @param container - Element container with background styles
67
- */
68
- async renderBackgroundImage(container: ElementContainer): Promise<void> {
69
- let index = container.styles.backgroundImage.length - 1;
70
- for (const backgroundImage of container.styles.backgroundImage.slice(0).reverse()) {
71
- if (backgroundImage.type === CSSImageType.URL) {
72
- await this.renderBackgroundURLImage(container, backgroundImage as CSSURLImage, index);
73
- } else if (isLinearGradient(backgroundImage)) {
74
- this.renderLinearGradient(container, backgroundImage, index);
75
- } else if (isRadialGradient(backgroundImage)) {
76
- this.renderRadialGradient(container, backgroundImage, index);
77
- }
78
- index--;
79
- }
80
- }
81
-
82
- /**
83
- * Render a URL-based background image
84
- */
85
- private async renderBackgroundURLImage(
86
- container: ElementContainer,
87
- backgroundImage: CSSURLImage,
88
- index: number
89
- ): Promise<void> {
90
- let image;
91
- const url = backgroundImage.url;
92
- try {
93
- image = await this.context.cache.match(url);
94
- } catch (e) {
95
- this.context.logger.error(`Error loading background-image ${url}`);
96
- }
97
-
98
- if (image) {
99
- const imageWidth = isNaN(image.width) || image.width === 0 ? 1 : image.width;
100
- const imageHeight = isNaN(image.height) || image.height === 0 ? 1 : image.height;
101
- const [path, x, y, width, height] = calculateBackgroundRendering(container, index, [
102
- imageWidth,
103
- imageHeight,
104
- imageWidth / imageHeight
105
- ]);
106
- const pattern = this.ctx.createPattern(
107
- this.resizeImage(image as HTMLImageElement, width, height, container.styles.imageRendering),
108
- 'repeat'
109
- ) as CanvasPattern;
110
- this.renderRepeat(path, pattern, x, y);
111
- }
112
- }
113
-
114
- /**
115
- * Render a linear gradient background
116
- */
117
- private renderLinearGradient(
118
- container: ElementContainer,
119
- backgroundImage: CSSLinearGradientImage,
120
- index: number
121
- ): void {
122
- const [path, x, y, width, height] = calculateBackgroundRendering(container, index, [null, null, null]);
123
- const [lineLength, x0, x1, y0, y1] = calculateGradientDirection(backgroundImage.angle, width, height);
124
-
125
- const ownerDocument = this.canvas.ownerDocument ?? document;
126
- const canvas = ownerDocument.createElement('canvas');
127
- canvas.width = width;
128
- canvas.height = height;
129
- const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
130
- const gradient = ctx.createLinearGradient(x0, y0, x1, y1);
131
-
132
- processColorStops(backgroundImage.stops, lineLength || 1).forEach((colorStop) =>
133
- gradient.addColorStop(colorStop.stop, asString(colorStop.color))
134
- );
135
-
136
- ctx.fillStyle = gradient;
137
- ctx.fillRect(0, 0, width, height);
138
- if (width > 0 && height > 0) {
139
- const pattern = this.ctx.createPattern(canvas, 'repeat') as CanvasPattern;
140
- this.renderRepeat(path, pattern, x, y);
141
- }
142
- }
143
-
144
- /**
145
- * Render a radial gradient background
146
- */
147
- private renderRadialGradient(
148
- container: ElementContainer,
149
- backgroundImage: CSSRadialGradientImage,
150
- index: number
151
- ): void {
152
- const [path, left, top, width, height] = calculateBackgroundRendering(container, index, [null, null, null]);
153
- const position = backgroundImage.position.length === 0 ? [FIFTY_PERCENT] : backgroundImage.position;
154
- const x = getAbsoluteValue(position[0], width);
155
- const y = getAbsoluteValue(position[position.length - 1], height);
156
-
157
- let [rx, ry] = calculateRadius(backgroundImage, x, y, width, height);
158
- // Handle edge case where radial gradient size is 0
159
- // Use a minimum value of 0.01 to ensure gradient is still rendered
160
- if (rx === 0 || ry === 0) {
161
- rx = Math.max(rx, 0.01);
162
- ry = Math.max(ry, 0.01);
163
- }
164
- if (rx > 0 && ry > 0) {
165
- const radialGradient = this.ctx.createRadialGradient(left + x, top + y, 0, left + x, top + y, rx);
166
-
167
- processColorStops(backgroundImage.stops, rx * 2).forEach((colorStop) =>
168
- radialGradient.addColorStop(colorStop.stop, asString(colorStop.color))
169
- );
170
-
171
- this.path(path);
172
- this.ctx.fillStyle = radialGradient;
173
- if (rx !== ry) {
174
- // transforms for elliptical radial gradient
175
- const midX = container.bounds.left + 0.5 * container.bounds.width;
176
- const midY = container.bounds.top + 0.5 * container.bounds.height;
177
- const f = ry / rx;
178
- const invF = 1 / f;
179
-
180
- this.ctx.save();
181
- this.ctx.translate(midX, midY);
182
- this.ctx.transform(1, 0, 0, f, 0, 0);
183
- this.ctx.translate(-midX, -midY);
184
-
185
- this.ctx.fillRect(left, invF * (top - midY) + midY, width, height * invF);
186
- this.ctx.restore();
187
- } else {
188
- this.ctx.fill();
189
- }
190
- }
191
- }
192
-
193
- /**
194
- * Render a repeating pattern with offset
195
- *
196
- * @param path - Path to fill
197
- * @param pattern - Canvas pattern or gradient
198
- * @param offsetX - X offset for pattern
199
- * @param offsetY - Y offset for pattern
200
- */
201
- private renderRepeat(
202
- path: Path[],
203
- pattern: CanvasPattern | CanvasGradient,
204
- offsetX: number,
205
- offsetY: number
206
- ): void {
207
- this.path(path);
208
- this.ctx.fillStyle = pattern;
209
- this.ctx.translate(offsetX, offsetY);
210
- this.ctx.fill();
211
- this.ctx.translate(-offsetX, -offsetY);
212
- }
213
-
214
- /**
215
- * Resize an image to target dimensions
216
- *
217
- * @param image - Source image
218
- * @param width - Target width
219
- * @param height - Target height
220
- * @param imageRendering - CSS image-rendering property value
221
- * @returns Resized canvas or original image
222
- */
223
- private resizeImage(
224
- image: HTMLImageElement,
225
- width: number,
226
- height: number,
227
- imageRendering: IMAGE_RENDERING
228
- ): HTMLCanvasElement | HTMLImageElement {
229
- // https://github.com/niklasvh/html2canvas/pull/2911
230
- // if (image.width === width && image.height === height) {
231
- // return image;
232
- // }
233
-
234
- const ownerDocument = this.canvas.ownerDocument ?? document;
235
- const canvas = ownerDocument.createElement('canvas');
236
- canvas.width = Math.max(1, width);
237
- canvas.height = Math.max(1, height);
238
- const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
239
-
240
- // Apply image smoothing based on CSS image-rendering property
241
- if (imageRendering === IMAGE_RENDERING.PIXELATED || imageRendering === IMAGE_RENDERING.CRISP_EDGES) {
242
- this.context.logger.debug(`Disabling image smoothing for background image due to CSS image-rendering`);
243
- ctx.imageSmoothingEnabled = false;
244
- } else if (imageRendering === IMAGE_RENDERING.SMOOTH) {
245
- this.context.logger.debug(
246
- `Enabling image smoothing for background image due to CSS image-rendering: smooth`
247
- );
248
- ctx.imageSmoothingEnabled = true;
249
- } else {
250
- // AUTO: inherit from main renderer context
251
- ctx.imageSmoothingEnabled = this.ctx.imageSmoothingEnabled;
252
- }
253
-
254
- // Inherit quality setting
255
- if (this.ctx.imageSmoothingQuality) {
256
- ctx.imageSmoothingQuality = this.ctx.imageSmoothingQuality;
257
- }
258
-
259
- ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, width, height);
260
- return canvas;
261
- }
262
-
263
- /**
264
- * Create a canvas path from path array
265
- *
266
- * @param paths - Array of path points
267
- */
268
- private path(paths: Path[]): void {
269
- createCanvasPath(this.ctx, paths);
270
- }
271
- }
@@ -1,224 +0,0 @@
1
- /**
2
- * Border Renderer
3
- *
4
- * Handles rendering of element borders including:
5
- * - Solid borders
6
- * - Double borders
7
- * - Dashed borders
8
- * - Dotted borders
9
- */
10
-
11
- import { Color } from '../../css/types/color';
12
- import { asString } from '../../css/types/color-utilities';
13
- import { BoundCurves } from '../bound-curves';
14
- import { BORDER_STYLE } from '../../css/property-descriptors/border-style';
15
- import {
16
- parsePathForBorder,
17
- parsePathForBorderDoubleInner,
18
- parsePathForBorderDoubleOuter,
19
- parsePathForBorderStroke
20
- } from '../border';
21
- import { isBezierCurve, BezierCurve } from '../bezier-curve';
22
- import { Vector } from '../vector';
23
- import { Path } from '../path';
24
-
25
- /**
26
- * Dependencies required for BorderRenderer
27
- */
28
- export interface BorderRendererDependencies {
29
- ctx: CanvasRenderingContext2D;
30
- }
31
-
32
- /**
33
- * Path creation callbacks
34
- * The main CanvasRenderer retains path() and formatPath() methods,
35
- * so we inject them as callbacks to avoid duplication
36
- */
37
- export interface PathCallbacks {
38
- path(paths: Path[]): void;
39
- formatPath(paths: Path[]): void;
40
- }
41
-
42
- /**
43
- * Border Renderer
44
- *
45
- * Specialized renderer for element borders.
46
- * Extracted from CanvasRenderer to improve code organization and maintainability.
47
- */
48
- export class BorderRenderer {
49
- private readonly ctx: CanvasRenderingContext2D;
50
- private pathCallbacks: PathCallbacks;
51
-
52
- constructor(deps: BorderRendererDependencies, pathCallbacks: PathCallbacks) {
53
- this.ctx = deps.ctx;
54
- this.pathCallbacks = pathCallbacks;
55
- }
56
-
57
- /**
58
- * Render a solid border
59
- *
60
- * @param color - Border color
61
- * @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
62
- * @param curvePoints - Border curve points
63
- */
64
- async renderSolidBorder(color: Color, side: number, curvePoints: BoundCurves): Promise<void> {
65
- this.pathCallbacks.path(parsePathForBorder(curvePoints, side));
66
- this.ctx.fillStyle = asString(color);
67
- this.ctx.fill();
68
- }
69
-
70
- /**
71
- * Render a double border
72
- * Falls back to solid border if width is too small
73
- *
74
- * @param color - Border color
75
- * @param width - Border width
76
- * @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
77
- * @param curvePoints - Border curve points
78
- */
79
- async renderDoubleBorder(color: Color, width: number, side: number, curvePoints: BoundCurves): Promise<void> {
80
- if (width < 3) {
81
- await this.renderSolidBorder(color, side, curvePoints);
82
- return;
83
- }
84
-
85
- const outerPaths = parsePathForBorderDoubleOuter(curvePoints, side);
86
- this.pathCallbacks.path(outerPaths);
87
- this.ctx.fillStyle = asString(color);
88
- this.ctx.fill();
89
- const innerPaths = parsePathForBorderDoubleInner(curvePoints, side);
90
- this.pathCallbacks.path(innerPaths);
91
- this.ctx.fill();
92
- }
93
-
94
- /**
95
- * Render a dashed or dotted border
96
- *
97
- * @param color - Border color
98
- * @param width - Border width
99
- * @param side - Border side (0=top, 1=right, 2=bottom, 3=left)
100
- * @param curvePoints - Border curve points
101
- * @param style - Border style (DASHED or DOTTED)
102
- */
103
- async renderDashedDottedBorder(
104
- color: Color,
105
- width: number,
106
- side: number,
107
- curvePoints: BoundCurves,
108
- style: BORDER_STYLE
109
- ): Promise<void> {
110
- this.ctx.save();
111
-
112
- const strokePaths = parsePathForBorderStroke(curvePoints, side);
113
- const boxPaths = parsePathForBorder(curvePoints, side);
114
-
115
- if (style === BORDER_STYLE.DASHED) {
116
- this.pathCallbacks.path(boxPaths);
117
- this.ctx.clip();
118
- }
119
-
120
- // Extract start and end coordinates
121
- let startX, startY, endX, endY;
122
- if (isBezierCurve(boxPaths[0])) {
123
- startX = (boxPaths[0] as BezierCurve).start.x;
124
- startY = (boxPaths[0] as BezierCurve).start.y;
125
- } else {
126
- startX = (boxPaths[0] as Vector).x;
127
- startY = (boxPaths[0] as Vector).y;
128
- }
129
- if (isBezierCurve(boxPaths[1])) {
130
- endX = (boxPaths[1] as BezierCurve).end.x;
131
- endY = (boxPaths[1] as BezierCurve).end.y;
132
- } else {
133
- endX = (boxPaths[1] as Vector).x;
134
- endY = (boxPaths[1] as Vector).y;
135
- }
136
-
137
- // Calculate border length
138
- let length;
139
- if (side === 0 || side === 2) {
140
- length = Math.abs(startX - endX);
141
- } else {
142
- length = Math.abs(startY - endY);
143
- }
144
-
145
- this.ctx.beginPath();
146
- if (style === BORDER_STYLE.DOTTED) {
147
- this.pathCallbacks.formatPath(strokePaths);
148
- } else {
149
- this.pathCallbacks.formatPath(boxPaths.slice(0, 2));
150
- }
151
-
152
- // Calculate dash and space lengths
153
- let dashLength = width < 3 ? width * 3 : width * 2;
154
- let spaceLength = width < 3 ? width * 2 : width;
155
- if (style === BORDER_STYLE.DOTTED) {
156
- dashLength = width;
157
- spaceLength = width;
158
- }
159
-
160
- // Adjust dash pattern for border length
161
- let useLineDash = true;
162
- if (length <= dashLength * 2) {
163
- useLineDash = false;
164
- } else if (length <= dashLength * 2 + spaceLength) {
165
- const multiplier = length / (2 * dashLength + spaceLength);
166
- dashLength *= multiplier;
167
- spaceLength *= multiplier;
168
- } else {
169
- const numberOfDashes = Math.floor((length + spaceLength) / (dashLength + spaceLength));
170
- const minSpace = (length - numberOfDashes * dashLength) / (numberOfDashes - 1);
171
- const maxSpace = (length - (numberOfDashes + 1) * dashLength) / numberOfDashes;
172
- spaceLength =
173
- maxSpace <= 0 || Math.abs(spaceLength - minSpace) < Math.abs(spaceLength - maxSpace)
174
- ? minSpace
175
- : maxSpace;
176
- }
177
-
178
- // Apply line dash pattern
179
- if (useLineDash) {
180
- if (style === BORDER_STYLE.DOTTED) {
181
- this.ctx.setLineDash([0, dashLength + spaceLength]);
182
- } else {
183
- this.ctx.setLineDash([dashLength, spaceLength]);
184
- }
185
- }
186
-
187
- // Set line style and stroke
188
- if (style === BORDER_STYLE.DOTTED) {
189
- this.ctx.lineCap = 'round';
190
- this.ctx.lineWidth = width;
191
- } else {
192
- this.ctx.lineWidth = width * 2 + 1.1;
193
- }
194
- this.ctx.strokeStyle = asString(color);
195
- this.ctx.stroke();
196
- this.ctx.setLineDash([]);
197
-
198
- // Fill dashed round edge gaps
199
- if (style === BORDER_STYLE.DASHED) {
200
- if (isBezierCurve(boxPaths[0])) {
201
- const path1 = boxPaths[3] as BezierCurve;
202
- const path2 = boxPaths[0] as BezierCurve;
203
- this.ctx.beginPath();
204
- this.pathCallbacks.formatPath([
205
- new Vector(path1.end.x, path1.end.y),
206
- new Vector(path2.start.x, path2.start.y)
207
- ]);
208
- this.ctx.stroke();
209
- }
210
- if (isBezierCurve(boxPaths[1])) {
211
- const path1 = boxPaths[1] as BezierCurve;
212
- const path2 = boxPaths[2] as BezierCurve;
213
- this.ctx.beginPath();
214
- this.pathCallbacks.formatPath([
215
- new Vector(path1.end.x, path1.end.y),
216
- new Vector(path2.start.x, path2.start.y)
217
- ]);
218
- this.ctx.stroke();
219
- }
220
- }
221
-
222
- this.ctx.restore();
223
- }
224
- }
@@ -1,31 +0,0 @@
1
- import { isBezierCurve } from '../bezier-curve';
2
- import { Path } from '../path';
3
- import { Vector } from '../vector';
4
-
5
- export const formatCanvasPath = (ctx: CanvasRenderingContext2D, paths: Path[]): void => {
6
- paths.forEach((point, index) => {
7
- const start: Vector = isBezierCurve(point) ? point.start : point;
8
- if (index === 0) {
9
- ctx.moveTo(start.x, start.y);
10
- } else {
11
- ctx.lineTo(start.x, start.y);
12
- }
13
-
14
- if (isBezierCurve(point)) {
15
- ctx.bezierCurveTo(
16
- point.startControl.x,
17
- point.startControl.y,
18
- point.endControl.x,
19
- point.endControl.y,
20
- point.end.x,
21
- point.end.y
22
- );
23
- }
24
- });
25
- };
26
-
27
- export const createCanvasPath = (ctx: CanvasRenderingContext2D, paths: Path[]): void => {
28
- ctx.beginPath();
29
- formatCanvasPath(ctx, paths);
30
- ctx.closePath();
31
- };