@ax-design/reveal-highlight 0.3.0-alpha.7 → 0.4.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 (92) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +76 -235
  3. package/build/BaseConfig.d.ts +43 -0
  4. package/build/BaseConfig.d.ts.map +1 -0
  5. package/build/CanvasConfig.d.ts +7 -92
  6. package/build/CanvasConfig.d.ts.map +1 -1
  7. package/build/CustomElements.d.ts +20 -4
  8. package/build/CustomElements.d.ts.map +1 -1
  9. package/build/RevealBoundryStore.d.ts +50 -10
  10. package/build/RevealBoundryStore.d.ts.map +1 -1
  11. package/build/RevealStateManager.d.ts +3 -0
  12. package/build/RevealStateManager.d.ts.map +1 -1
  13. package/build/SvgConfig.d.ts +17 -0
  14. package/build/SvgConfig.d.ts.map +1 -0
  15. package/build/index.d.ts.map +1 -1
  16. package/build/main.js +169 -17
  17. package/build/utils/extractRGBValue.d.ts +2 -0
  18. package/build/utils/extractRGBValue.d.ts.map +1 -0
  19. package/build/utils/isValidateBorderDecorationType.d.ts +3 -0
  20. package/build/utils/isValidateBorderDecorationType.d.ts.map +1 -0
  21. package/build/utils/types.d.ts +103 -0
  22. package/build/utils/types.d.ts.map +1 -0
  23. package/es/BaseConfig.d.ts +43 -0
  24. package/es/BaseConfig.d.ts.map +1 -0
  25. package/es/BaseConfig.js +220 -0
  26. package/es/BaseConfig.js.map +1 -0
  27. package/es/CanvasConfig.d.ts +7 -92
  28. package/es/CanvasConfig.d.ts.map +1 -1
  29. package/es/CanvasConfig.js +35 -233
  30. package/es/CanvasConfig.js.map +1 -1
  31. package/es/CustomElements.d.ts +20 -4
  32. package/es/CustomElements.d.ts.map +1 -1
  33. package/es/CustomElements.js +130 -33
  34. package/es/CustomElements.js.map +1 -1
  35. package/es/RevealBoundryStore.d.ts +50 -10
  36. package/es/RevealBoundryStore.d.ts.map +1 -1
  37. package/es/RevealBoundryStore.js +129 -35
  38. package/es/RevealBoundryStore.js.map +1 -1
  39. package/es/RevealStateManager.d.ts +3 -0
  40. package/es/RevealStateManager.d.ts.map +1 -1
  41. package/es/RevealStateManager.js +35 -8
  42. package/es/RevealStateManager.js.map +1 -1
  43. package/es/SvgConfig.d.ts +17 -0
  44. package/es/SvgConfig.d.ts.map +1 -0
  45. package/es/SvgConfig.js +346 -0
  46. package/es/SvgConfig.js.map +1 -0
  47. package/es/index.d.ts.map +1 -1
  48. package/es/index.js +12 -18
  49. package/es/index.js.map +1 -1
  50. package/es/tsconfig.tsbuildinfo +1 -0
  51. package/es/utils/extractRGBValue.d.ts +2 -0
  52. package/es/utils/extractRGBValue.d.ts.map +1 -0
  53. package/es/utils/extractRGBValue.js +48 -0
  54. package/es/utils/extractRGBValue.js.map +1 -0
  55. package/es/utils/isValidateBorderDecorationType.d.ts +3 -0
  56. package/es/utils/isValidateBorderDecorationType.d.ts.map +1 -0
  57. package/es/utils/isValidateBorderDecorationType.js +10 -0
  58. package/es/utils/isValidateBorderDecorationType.js.map +1 -0
  59. package/es/utils/types.d.ts +103 -0
  60. package/es/utils/types.d.ts.map +1 -0
  61. package/es/utils/types.js +2 -0
  62. package/es/utils/types.js.map +1 -0
  63. package/package.json +34 -30
  64. package/src/BaseConfig.ts +311 -0
  65. package/src/CanvasConfig.ts +415 -729
  66. package/src/ComputedStyleStorage.ts +89 -89
  67. package/src/CustomElements.ts +272 -164
  68. package/src/Profiler.ts +44 -44
  69. package/src/RevealBoundryStore.ts +291 -192
  70. package/src/RevealStateManager.ts +78 -48
  71. package/src/SvgConfig.ts +422 -0
  72. package/src/config.ts +26 -26
  73. package/src/cssTypedOM.d.ts +52 -52
  74. package/src/index.ts +219 -225
  75. package/src/utils/extractRGBValue.ts +58 -0
  76. package/src/utils/isValidateBorderDecorationType.ts +8 -0
  77. package/src/utils/types.ts +106 -0
  78. package/src/variables.ts +1 -1
  79. package/.prettierrc +0 -6
  80. package/.travis.yml +0 -26
  81. package/.yarnrc.yml +0 -1
  82. package/docs/demo/debug.html +0 -75
  83. package/docs/demo/index.html +0 -1065
  84. package/docs/demo/performance-inspector.html +0 -60
  85. package/docs/demo/shapes-demo.html +0 -93
  86. package/docs/demo/single-unit.html +0 -40
  87. package/docs/logo.png +0 -0
  88. package/docs/logo.svg +0 -1
  89. package/docs/screen-record.gif +0 -0
  90. package/docs/src/logo.afdesign +0 -0
  91. package/rollup.config.js +0 -14
  92. package/tsconfig.json +0 -18
@@ -1,729 +1,415 @@
1
- import { ComputedStyleStorage, createStorage } from './ComputedStyleStorage.js';
2
- import { RevealBoundaryStore } from './RevealBoundryStore.js';
3
- import { MAGIC_DEFAULT_COLOR } from './variables.js';
4
-
5
- type BorderDecoration = 'round' | 'bevel' | 'miter';
6
-
7
- const isValidateBorderDecorationType = (x: string): x is BorderDecoration => {
8
- if (x === 'round') return true;
9
- if (x === 'bevel') return true;
10
- if (x === 'miter') return true;
11
- return false;
12
- };
13
-
14
- const extractRGBValue = (x: string) => {
15
- if (x === '') {
16
- return '';
17
- }
18
-
19
- if (x[0] === '#') {
20
- // Thanks bro:
21
- // https://stackoverflow.com/a/11508164/3931936
22
- const hexVal = parseInt(x.substring(1), 16);
23
-
24
- var r = (hexVal >> 16) & 255;
25
- var g = (hexVal >> 8) & 255;
26
- var b = hexVal & 255;
27
-
28
- return r + ',' + g + ',' + b;
29
- } else {
30
- let result = '';
31
- let beginSearch = false;
32
- let numberPointer = 0;
33
-
34
- for (let i = 0; i < x.length; i++) {
35
- const char = x[i];
36
- const charCode = char.charCodeAt(0) - 48;
37
- const charIsNumber = charCode >= 0 && charCode < 10;
38
-
39
- if (char === ' ') {
40
- continue;
41
- }
42
-
43
- if (beginSearch && !charIsNumber && char !== ',' && char !== ')') {
44
- throw new SyntaxError(`${x} is not a validate color value!`);
45
- }
46
-
47
- if (!beginSearch && char === '(') {
48
- beginSearch = true;
49
- continue;
50
- }
51
-
52
- if (numberPointer < 2 && char === ')') {
53
- throw new SyntaxError(`${x} should have at least three color channel`);
54
- }
55
-
56
- if (char === ',') {
57
- numberPointer++;
58
- }
59
-
60
- if (char === ')') {
61
- return result;
62
- }
63
-
64
- if (beginSearch) {
65
- result += char;
66
- }
67
- }
68
-
69
- return result;
70
- }
71
- };
72
-
73
- export interface CachedBoundingRect {
74
- top: number;
75
- left: number;
76
- width: number;
77
- height: number;
78
- }
79
-
80
- export interface CachedStyle {
81
- color: string;
82
- opacity: number;
83
- trueFillRadius: [number, number];
84
- borderStyle: string;
85
- borderColor: string;
86
- borderFillRadius: number;
87
- borderDecorationType: BorderDecoration;
88
- borderDecorationRadius: number;
89
- topLeftBorderDecorationRadius: number;
90
- topRightBorderDecorationRadius: number;
91
- bottomLeftBorderDecorationRadius: number;
92
- bottomRightBorderDecorationRadius: number;
93
- withLeftBorderFactor: number;
94
- withRightBorderFactor: number;
95
- withTopBorderFactor: number;
96
- withBottomBorderFactor: number;
97
- borderWidth: number;
98
- hoverLight: boolean;
99
- hoverLightColor: string;
100
- hoverLightFillMode: string;
101
- hoverLightFillRadius: number;
102
- diffuse: boolean;
103
- pressAnimation: boolean;
104
- pressAnimationFillMode: string;
105
- pressAnimationColor: string;
106
- pressAnimationSpeed: number;
107
- releaseAnimationAccelerateRate: number;
108
- }
109
-
110
- interface CachedReveal {
111
- radius: number;
112
- radiusFactor: number;
113
- color: string;
114
- opacity: number;
115
- pattern: CanvasPattern | null;
116
- }
117
-
118
- /**
119
- * Cached border and body pattern, for faster painting on the canvas.
120
- * @interface CachedRevealBitmap
121
- */
122
- export interface CachedRevealBitmap {
123
- cachedReveal: {
124
- borderReveal: CachedReveal;
125
- fillReveal: CachedReveal;
126
- };
127
- cachedCanvas: {
128
- borderReveal: HTMLCanvasElement;
129
- fillReveal: HTMLCanvasElement;
130
- };
131
- cachedCtx: {
132
- borderReveal: CanvasRenderingContext2D | null;
133
- fillReveal: CanvasRenderingContext2D | null;
134
- };
135
- }
136
-
137
- const createEmptyCanvas = () => document.createElement('canvas') as HTMLCanvasElement;
138
-
139
- export class CanvasConfig {
140
- protected _store: RevealBoundaryStore;
141
-
142
- pxRatio = window.devicePixelRatio || 1;
143
-
144
- readonly container: HTMLElement;
145
- readonly canvas: HTMLCanvasElement;
146
- ctx: CanvasRenderingContext2D | null;
147
-
148
- private readonly computedStyle: ComputedStyleStorage;
149
-
150
- paintedWidth = 0;
151
- paintedHeight = 0;
152
-
153
- protected cachedImg: CachedRevealBitmap;
154
-
155
- currentFrameId: number = -1;
156
-
157
- cachedBoundingRectFrameId: number = -2;
158
-
159
- cachedBoundingRect: CachedBoundingRect = {
160
- top: -1,
161
- left: -1,
162
- width: -1,
163
- height: -1,
164
- };
165
-
166
- cachedStyleFrameId: number = -2;
167
-
168
- cachedStyle: CachedStyle = {
169
- trueFillRadius: [0, 0],
170
- color: '',
171
- opacity: 1,
172
- borderStyle: '',
173
- borderColor: '',
174
- borderFillRadius: 0,
175
- borderDecorationType: 'miter',
176
- borderDecorationRadius: 0,
177
- topLeftBorderDecorationRadius: 0,
178
- topRightBorderDecorationRadius: 0,
179
- bottomLeftBorderDecorationRadius: 0,
180
- bottomRightBorderDecorationRadius: 0,
181
- withLeftBorderFactor: 1,
182
- withRightBorderFactor: 1,
183
- withTopBorderFactor: 1,
184
- withBottomBorderFactor: 1,
185
- borderWidth: 1,
186
- hoverLight: true,
187
- hoverLightColor: '',
188
- hoverLightFillMode: '',
189
- hoverLightFillRadius: 0,
190
- diffuse: true,
191
- pressAnimation: true,
192
- pressAnimationFillMode: '',
193
- pressAnimationColor: '',
194
- pressAnimationSpeed: 0,
195
- releaseAnimationAccelerateRate: 0,
196
- };
197
-
198
- mouseUpClientX: number | null = null;
199
- mouseUpClientY: number | null = null;
200
- mouseDownAnimateStartFrame: number | null = null;
201
- mouseDownAnimateCurrentFrame: number | null = null;
202
- mouseDownAnimateReleasedFrame: number | null = null;
203
- mouseDownAnimateLogicFrame: number | null = null;
204
- mousePressed = false;
205
-
206
- mouseReleased = false;
207
-
208
- constructor(store: RevealBoundaryStore, $canvas: HTMLCanvasElement, $container: HTMLElement) {
209
- this._store = store;
210
-
211
- this.container = $container;
212
- this.canvas = $canvas;
213
- this.ctx = $canvas.getContext('2d');
214
-
215
- const cachedCanvas = {
216
- borderReveal: createEmptyCanvas(),
217
- fillReveal: createEmptyCanvas(),
218
- };
219
-
220
- const cachedCtx = {
221
- borderReveal: cachedCanvas.borderReveal.getContext('2d'),
222
- fillReveal: cachedCanvas.fillReveal.getContext('2d'),
223
- };
224
-
225
- this.cachedImg = {
226
- cachedReveal: {
227
- borderReveal: {
228
- radiusFactor: -1,
229
- radius: -1,
230
- color: 'INVALID',
231
- opacity: 0,
232
- pattern: null,
233
- },
234
- fillReveal: {
235
- radiusFactor: -1,
236
- radius: -1,
237
- color: 'INVALID',
238
- opacity: 0,
239
- pattern: null,
240
- },
241
- },
242
- cachedCanvas,
243
- cachedCtx,
244
- };
245
-
246
- this.computedStyle = createStorage($container);
247
- }
248
-
249
- cacheBoundingRect = () => {
250
- if (this.currentFrameId === this.cachedBoundingRectFrameId) {
251
- return;
252
- }
253
-
254
- const boundingRect = this.canvas.getBoundingClientRect();
255
-
256
- this.cachedBoundingRect.top = Math.floor(boundingRect.top);
257
- this.cachedBoundingRect.left = Math.floor(boundingRect.left);
258
- this.cachedBoundingRect.width = Math.floor(boundingRect.width);
259
- this.cachedBoundingRect.height = Math.floor(boundingRect.height);
260
-
261
- this.cachedBoundingRectFrameId = this.currentFrameId;
262
- };
263
-
264
- getTrueFillRadius = (
265
- trueFillRadius = [0, 0] as [number, number],
266
- fillMode = this.computedStyle.get('--reveal-hover-light-fill-radius-mode')
267
- ) => {
268
- const b = this.cachedBoundingRect;
269
-
270
- switch (fillMode) {
271
- case 'relative':
272
- trueFillRadius[0] = Math.min(b.width, b.height);
273
- trueFillRadius[1] = Math.max(b.width, b.height);
274
- break;
275
- case 'absolute':
276
- trueFillRadius[0] = -1;
277
- trueFillRadius[1] = -1;
278
- break;
279
- default:
280
- throw new SyntaxError('The value of `--reveal-border-style` must be `relative`, `absolute`!');
281
- }
282
-
283
- this._store.updateMaxRadius(Math.max(trueFillRadius[0], trueFillRadius[1]));
284
-
285
- return trueFillRadius;
286
- };
287
-
288
- getPropFromMultipleSource = (domPropsName: string, cssPropsName: string) => {
289
- const domProps = this.container.dataset[domPropsName];
290
- if (domProps) return domProps;
291
-
292
- return this.computedStyle.get(cssPropsName);
293
- };
294
-
295
- cacheCanvasPaintingStyle = () => {
296
- if (this.currentFrameId === this.cachedStyleFrameId) {
297
- return;
298
- }
299
-
300
- if (this.computedStyle.size() === 0) {
301
- return;
302
- }
303
-
304
- const parsedBaseColor = extractRGBValue(this.computedStyle.getColor('--reveal-color')) || '0, 0, 0';
305
- const parsedBorderColor =
306
- extractRGBValue(this.computedStyle.getColor('--reveal-border-color')) || parsedBaseColor;
307
- const parsedHoverLightColor =
308
- extractRGBValue(this.computedStyle.getColor('--reveal-hover-light-color')) || parsedBaseColor;
309
- const parsedPressAnimationColor =
310
- extractRGBValue(this.computedStyle.getColor('--reveal-press-animation-color')) || parsedBaseColor;
311
-
312
- const c = this.cachedStyle;
313
-
314
- c.color = parsedBaseColor;
315
- c.opacity = this.computedStyle.getNumber('--reveal-opacity');
316
-
317
- // Border related configurations
318
- c.borderStyle = this.computedStyle.get('--reveal-border-style');
319
- c.borderColor = parsedBorderColor;
320
-
321
- c.borderFillRadius = this.computedStyle.getNumber('--reveal-border-fill-radius');
322
- c.borderDecorationType =
323
- (this.computedStyle.get('--reveal-border-decoration-type') as BorderDecoration) || 'miter';
324
- c.borderWidth = this.computedStyle.getNumber('--reveal-border-width');
325
-
326
- c.withLeftBorderFactor =
327
- this.getPropFromMultipleSource('leftBorder', '--reveal-border-left') === 'line' ? 1 : 0;
328
- c.withRightBorderFactor =
329
- this.getPropFromMultipleSource('rightBorder', '--reveal-border-right') === 'line' ? 1 : 0;
330
- c.withTopBorderFactor = this.getPropFromMultipleSource('topBorder', '--reveal-border-top') === 'line' ? 1 : 0;
331
- c.withBottomBorderFactor =
332
- this.getPropFromMultipleSource('bottomBorder', '--reveal-border-bottom') === 'line' ? 1 : 0;
333
-
334
- // Hover light related configurations
335
- c.hoverLight = this.computedStyle.get('--reveal-hover-light') === 'true';
336
- c.hoverLightColor = parsedHoverLightColor;
337
- c.hoverLightFillRadius = this.computedStyle.getNumber('--reveal-hover-light-fill-radius');
338
- c.hoverLightFillMode = this.computedStyle.get('--reveal-hover-light-fill-radius-mode');
339
-
340
- // Press animation related configurations
341
- c.diffuse = this.computedStyle.get('--reveal-diffuse') === 'true';
342
- c.pressAnimation = this.computedStyle.get('--reveal-press-animation') === 'true';
343
- c.pressAnimationFillMode = this.computedStyle.get('--reveal-press-animation-radius-mode');
344
- c.pressAnimationColor = parsedPressAnimationColor;
345
- c.pressAnimationSpeed = this.computedStyle.getNumber('--reveal-press-animation-speed');
346
- c.releaseAnimationAccelerateRate = this.computedStyle.getNumber('--reveal-release-animation-accelerate-rate');
347
-
348
- // Border decoration related configurations
349
- const r = this.computedStyle.getNumber('--reveal-border-decoration-radius');
350
- const tl = this.computedStyle.getNumber('--reveal-border-decoration-top-left-radius');
351
- const tr = this.computedStyle.getNumber('--reveal-border-decoration-top-right-radius');
352
- const bl = this.computedStyle.getNumber('--reveal-border-decoration-bottom-left-radius');
353
- const br = this.computedStyle.getNumber('--reveal-border-decoration-bottom-right-radius');
354
-
355
- c.topLeftBorderDecorationRadius = tl >= 0 ? tl : r;
356
- c.topRightBorderDecorationRadius = tr >= 0 ? tr : r;
357
- c.bottomLeftBorderDecorationRadius = bl >= 0 ? bl : r;
358
- c.bottomRightBorderDecorationRadius = br >= 0 ? br : r;
359
-
360
- this.getTrueFillRadius(c.trueFillRadius, c.hoverLightFillMode);
361
-
362
- if (!isValidateBorderDecorationType(c.borderDecorationType)) {
363
- throw new SyntaxError(
364
- 'The value of `--reveal-border-decoration-type` must be `round`, `bevel` or `miter`!'
365
- );
366
- }
367
-
368
- this.cachedStyleFrameId = this.currentFrameId;
369
- };
370
-
371
- updateCachedReveal = () => {
372
- const c = this.cachedStyle;
373
- const radius = c.trueFillRadius[1] * this.pxRatio;
374
- const size = radius * 2;
375
-
376
- const lastStyle = this.cachedImg.cachedReveal;
377
-
378
- const { borderReveal, fillReveal } = this.cachedImg.cachedCanvas;
379
- const { borderReveal: borderRevealCtx, fillReveal: fillRevealCtx } = this.cachedImg.cachedCtx;
380
-
381
- for (let i = 0; i < 2; i++) {
382
- // 0 means border, 1 means hover light.
383
- //-----------------------------------------
384
- // Last rendered style.
385
- const ls = i === 0 ? lastStyle.borderReveal : lastStyle.fillReveal;
386
- const color = i === 0 ? c.borderColor : c.hoverLightColor;
387
- const fillRadiusFactor = i === 0 ? c.borderFillRadius : c.hoverLightFillRadius;
388
-
389
- const doNotNeedUpdateReveal =
390
- color === ls.color && c.opacity === ls.opacity && fillRadiusFactor === ls.radiusFactor;
391
- if (doNotNeedUpdateReveal) return;
392
-
393
- if (doNotNeedUpdateReveal) continue;
394
-
395
- const reveal = i === 0 ? borderReveal : fillReveal;
396
- const ctx = i === 0 ? borderRevealCtx : fillRevealCtx;
397
-
398
- this.syncSizeToRevealRadius(reveal, fillRadiusFactor);
399
-
400
- if (!ctx) continue;
401
-
402
- ctx.clearRect(0, 0, reveal.width, reveal.height);
403
-
404
- const fillAlpha = i === 0 ? c.opacity : c.opacity * 0.5;
405
- const trueRadius = radius * fillRadiusFactor;
406
- const grd = ctx.createRadialGradient(trueRadius, trueRadius, 0, trueRadius, trueRadius, trueRadius);
407
-
408
- grd.addColorStop(0, `rgba(${color}, ${fillAlpha})`);
409
- grd.addColorStop(1, `rgba(${color}, 0.0)`);
410
-
411
- const trueSize = size * fillRadiusFactor;
412
- ctx.fillStyle = grd;
413
- ctx.clearRect(0, 0, trueSize, trueSize);
414
- ctx.fillRect(0, 0, trueSize, trueSize);
415
-
416
- ls.radius = trueRadius;
417
- ls.radiusFactor = fillRadiusFactor;
418
- ls.color = color;
419
- ls.opacity = c.opacity;
420
-
421
- if (!this.ctx) continue;
422
- ls.pattern = this.ctx.createPattern(reveal, 'no-repeat');
423
- }
424
- };
425
-
426
- updateCachedBitmap = () => {
427
- if (!this.ctx) return;
428
- this.updateCachedReveal();
429
- };
430
-
431
- mouseInCanvas = () => {
432
- const b = this.cachedBoundingRect;
433
-
434
- const relativeX = this._store.clientX - b.left;
435
- const relativeY = this._store.clientY - b.top;
436
-
437
- return relativeX > 0 && relativeY > 0 && relativeX < b.width && relativeY < b.height;
438
- };
439
-
440
- syncSizeToElement = (x: HTMLCanvasElement) => {
441
- const b = this.cachedBoundingRect;
442
-
443
- if (x.width !== b.width || x.height !== b.height) {
444
- x.width = b.width * this.pxRatio;
445
- x.height = b.height * this.pxRatio;
446
- x.style.width = `${b.width}px`;
447
- x.style.height = `${b.height}px`;
448
- }
449
- };
450
-
451
- syncSizeToRevealRadius = (x: HTMLCanvasElement, factor: number) => {
452
- const { trueFillRadius } = this.cachedStyle;
453
-
454
- const radius = trueFillRadius[1] || 1;
455
- const size = radius * 2 * this.pxRatio * factor;
456
-
457
- if (x.width !== size || x.height !== size) {
458
- x.width = size;
459
- x.height = size;
460
- }
461
- };
462
-
463
- updateAnimateGrd = (frame: number, grd: CanvasGradient) => {
464
- const { pressAnimationColor, opacity } = this.cachedStyle;
465
-
466
- const _innerAlpha = opacity * (0.2 - frame);
467
- const _outerAlpha = opacity * (0.1 - frame * 0.07);
468
- const _outerBorder = 0.1 + frame * 0.8;
469
-
470
- const innerAlpha = _innerAlpha < 0 ? 0 : _innerAlpha;
471
- const outerAlpha = _outerAlpha < 0 ? 0 : _outerAlpha;
472
- const outerBorder = _outerBorder > 1 ? 1 : _outerBorder;
473
-
474
- grd.addColorStop(0, `rgba(${pressAnimationColor},${innerAlpha})`);
475
- grd.addColorStop(outerBorder * 0.55, `rgba(${pressAnimationColor},${outerAlpha})`);
476
- grd.addColorStop(outerBorder, `rgba(${pressAnimationColor}, 0)`);
477
- };
478
-
479
- private drawShape = (hollow: boolean) => {
480
- if (!this.ctx) return;
481
-
482
- const b = this.cachedBoundingRect;
483
- const w = b.width * this.pxRatio;
484
- const h = b.height * this.pxRatio;
485
-
486
- const c = this.cachedStyle;
487
- const bw = c.borderWidth * this.pxRatio;
488
-
489
- const tl = c.topLeftBorderDecorationRadius * this.pxRatio;
490
- const tr = c.topRightBorderDecorationRadius * this.pxRatio;
491
- const bl = c.bottomLeftBorderDecorationRadius * this.pxRatio;
492
- const br = c.bottomRightBorderDecorationRadius * this.pxRatio;
493
-
494
- const wlf = c.withLeftBorderFactor;
495
- const wrf = c.withRightBorderFactor;
496
- const wtf = c.withTopBorderFactor;
497
- const wbf = c.withBottomBorderFactor;
498
-
499
- const tl2 = bw < tl ? tl - bw : 0;
500
- const tr2 = bw < tr ? tr - bw : 0;
501
- const bl2 = bw < bl ? bl - bw : 0;
502
- const br2 = bw < br ? br - bw : 0;
503
-
504
- this.ctx.beginPath();
505
-
506
- switch (c.borderDecorationType) {
507
- // Oh... Fuck... It's painful...
508
- case 'round':
509
- // outer
510
- this.ctx.moveTo(tl, 0);
511
- this.ctx.arcTo(w, 0, w, h, tr);
512
- this.ctx.lineTo(w, h - br);
513
- this.ctx.arcTo(w, h, br, h, br);
514
- this.ctx.lineTo(bl, h);
515
- this.ctx.arcTo(0, h, 0, br, bl);
516
- this.ctx.lineTo(0, tl);
517
- this.ctx.arcTo(0, 0, tl, 0, tl);
518
-
519
- if (hollow) {
520
- /* prettier-ignore-start */
521
- // inner
522
- /**
523
- +-①----⑧-+
524
- ② ⑦
525
- | |
526
- ③ ⑥
527
- +-④----⑤-+
528
- */
529
- // x y r p
530
- this.ctx.moveTo(tl2, bw * wtf); // ①
531
- this.ctx.arcTo(bw * wlf, bw * wtf, bw * wlf, tl2 + bw * wtf, tl2); // ②
532
- this.ctx.lineTo(bw * wlf, h - bw * wbf - bl2); // ③
533
- this.ctx.arcTo(bw * wlf, h - bw * wbf, bw * wlf + bl2, h - bw * wbf, bl2); // ④
534
- this.ctx.lineTo(w - bw * wrf - br2, h - bw * wbf); // ⑤
535
- this.ctx.arcTo(w - bw * wrf, h - bw * wbf, w - bw * wrf, h - bw * wbf - br2, br2); // ⑥
536
- this.ctx.lineTo(w - bw * wrf, bw * wtf + tr2); // ⑦
537
- this.ctx.arcTo(w - bw * wrf, bw * wtf, w - bw * wrf - tr2, bw * wtf, tr2); // ⑧
538
- this.ctx.lineTo(tl2, bw * wtf); // ①
539
- /* prettier-ignore-start */
540
- }
541
- break;
542
- case 'bevel':
543
- // outer
544
- this.ctx.moveTo(tl, 0);
545
- this.ctx.lineTo(w - tr, 0);
546
- this.ctx.lineTo(w, tr);
547
- this.ctx.lineTo(w, h - br);
548
- this.ctx.lineTo(w - br, h);
549
- this.ctx.lineTo(bl, h);
550
- this.ctx.lineTo(0, h - bl);
551
- this.ctx.lineTo(0, tl);
552
- this.ctx.lineTo(tl, 0);
553
- this.ctx.lineTo(w - tr, 0);
554
-
555
- if (hollow) {
556
- // inner
557
- /**
558
- +-①----⑧-+
559
- ② ⑦
560
- | |
561
- ③ ⑥
562
- +-④----⑤-+
563
- */
564
- // x y p
565
- this.ctx.moveTo(tl2 + bw * wlf, bw * wtf); // ①
566
- this.ctx.lineTo(bw * wlf, tl2 + bw * wtf); // ②
567
- this.ctx.lineTo(bw * wlf, h - bl2 - bw * wbf); // ③
568
- this.ctx.lineTo(bw * wlf + bl2, h - bw * wbf); // ④
569
- this.ctx.lineTo(w - br2 - bw * wrf, h - bw * wbf); // ⑤
570
- this.ctx.lineTo(w - bw * wrf, h - br2 - bw * wbf); // ⑥
571
- this.ctx.lineTo(w - bw * wrf, tr2 + bw * wtf); // ⑦
572
- this.ctx.lineTo(w - tr2 - bw * wrf, bw * wtf); // ⑧
573
- this.ctx.lineTo(tl2 + bw * wrf, bw * wtf); // ①
574
- }
575
- break;
576
- case 'miter':
577
- // outer
578
- this.ctx.moveTo(0, 0);
579
- this.ctx.lineTo(w, 0);
580
- this.ctx.lineTo(w, h);
581
- this.ctx.lineTo(0, h);
582
- this.ctx.lineTo(0, 0);
583
-
584
- if (hollow) {
585
- // inner
586
- /**
587
- ①--------④
588
- | |
589
- | |
590
- | |
591
- ②--------③
592
- */
593
- // x y p
594
- this.ctx.moveTo(bw * wlf, bw * wtf); // ①
595
- this.ctx.lineTo(bw * wlf, h - bw * wbf); // ②
596
- this.ctx.lineTo(w - bw * wrf, h - bw * wbf); // ③
597
- this.ctx.lineTo(w - bw * wrf, bw * wtf); // ④
598
- this.ctx.lineTo(bw * wlf, bw * wtf); // ①
599
- }
600
- break;
601
- default:
602
- }
603
-
604
- this.ctx.closePath();
605
- };
606
-
607
- paint = (force?: boolean, debug?: boolean): boolean => {
608
- const store = this._store;
609
-
610
- const animationPlaying = store.animationQueue.includes(this);
611
- const samePosition = store.clientX === store.paintedClientX && store.clientY === store.paintedClientY;
612
-
613
- if (samePosition && !animationPlaying && !force) {
614
- return false;
615
- }
616
-
617
- if (!this.ctx) return false;
618
-
619
- this.ctx.setTransform(1, 0, 0, 1, 0, 0);
620
- this.ctx.clearRect(0, 0, this.paintedWidth, this.paintedHeight);
621
-
622
- store.dirty = false;
623
-
624
- if (!store.mouseInBoundary && !animationPlaying) {
625
- return false;
626
- }
627
-
628
- if (!this.cachedImg.cachedReveal) {
629
- return false;
630
- }
631
-
632
- this.syncSizeToElement(this.canvas);
633
- this.cacheBoundingRect();
634
-
635
- const b = this.cachedBoundingRect;
636
-
637
- const relativeX = store.clientX - b.left;
638
- const relativeY = store.clientY - b.top;
639
-
640
- if (Number.isNaN(relativeX) || Number.isNaN(relativeY)) {
641
- return false;
642
- }
643
-
644
- const c = this.cachedStyle;
645
- this.getTrueFillRadius(c.trueFillRadius);
646
-
647
- this.paintedWidth = b.width * this.pxRatio;
648
- this.paintedHeight = b.height * this.pxRatio;
649
-
650
- const maxRadius = c.trueFillRadius[1];
651
-
652
- const inLeftBound = relativeX + maxRadius > 0;
653
- const inRightBound = relativeX - maxRadius < b.width;
654
- const inTopBound = relativeY + maxRadius > 0;
655
- const inBottomBound = relativeY - maxRadius < b.height;
656
-
657
- const mouseInRenderArea = inLeftBound && inRightBound && inTopBound && inBottomBound;
658
-
659
- if (!mouseInRenderArea && !animationPlaying) {
660
- return false;
661
- }
662
-
663
- this.cacheCanvasPaintingStyle();
664
- this.updateCachedBitmap();
665
-
666
- if (store.mouseInBoundary) {
667
- const mouseInCanvas = relativeX > 0 && relativeY > 0 && relativeX < b.width && relativeY < b.height;
668
-
669
- const fillPattern = this.cachedImg.cachedReveal.fillReveal.pattern;
670
- if (c.hoverLight && mouseInCanvas && fillPattern) {
671
- // draw fill.
672
- const radius = this.cachedImg.cachedReveal.fillReveal.radius;
673
- const putX = Math.floor(relativeX * this.pxRatio - radius);
674
- const putY = Math.floor(relativeY * this.pxRatio - radius);
675
- this.ctx.setTransform(1, 0, 0, 1, 0, 0);
676
- this.drawShape(false);
677
- this.ctx.translate(putX, putY);
678
- this.ctx.fillStyle = fillPattern;
679
- this.ctx.fill();
680
- }
681
-
682
- const diffuse = (c.diffuse && mouseInRenderArea) || mouseInCanvas;
683
- const borderPattern = this.cachedImg.cachedReveal.borderReveal.pattern;
684
- if (c.borderWidth !== 0 && borderPattern && diffuse) {
685
- // Draw border.
686
- const radius = this.cachedImg.cachedReveal.borderReveal.radius;
687
- const putX = Math.floor(relativeX * this.pxRatio - radius);
688
- const putY = Math.floor(relativeY * this.pxRatio - radius);
689
- this.ctx.setTransform(1, 0, 0, 1, 0, 0);
690
- this.drawShape(true);
691
- this.ctx.translate(putX, putY);
692
- this.ctx.fillStyle = borderPattern;
693
- this.ctx.fill();
694
- }
695
- }
696
-
697
- if (c.pressAnimation && this.mousePressed && this.mouseDownAnimateLogicFrame) {
698
- this.ctx.setTransform(1, 0, 0, 1, 0, 0);
699
- const grdRadius =
700
- c.pressAnimationFillMode === 'constrained' ? c.trueFillRadius[1] : Math.max(b.width, b.height);
701
- // prettier-ignore
702
- const animateGrd =
703
- this.mouseReleased && this.mouseUpClientX && this.mouseUpClientY
704
- ? this.ctx.createRadialGradient(
705
- (this.mouseUpClientX - b.left) * this.pxRatio,
706
- (this.mouseUpClientY - b.top) * this.pxRatio,
707
- 0,
708
- (this.mouseUpClientX - b.left) * this.pxRatio,
709
- (this.mouseUpClientY - b.top) * this.pxRatio,
710
- grdRadius * this.pxRatio
711
- )
712
- : this.ctx.createRadialGradient(
713
- relativeX * this.pxRatio,
714
- relativeY * this.pxRatio,
715
- 0,
716
- relativeX * this.pxRatio,
717
- relativeY * this.pxRatio,
718
- grdRadius * this.pxRatio
719
- );
720
- this.updateAnimateGrd(this.mouseDownAnimateLogicFrame, animateGrd);
721
-
722
- this.drawShape(false);
723
- this.ctx.fillStyle = animateGrd;
724
- this.ctx.fill();
725
- }
726
-
727
- return true;
728
- };
729
- }
1
+ import { RevealBoundaryStore } from './RevealBoundryStore.js';
2
+
3
+ import type { CachedRevealBitmap } from './utils/types.js';
4
+
5
+ import { BaseConfig } from './BaseConfig.js';
6
+
7
+ const createEmptyCanvas = () => document.createElement('canvas') as HTMLCanvasElement;
8
+
9
+ export class CanvasConfig extends BaseConfig<HTMLCanvasElement> {
10
+ ctx: CanvasRenderingContext2D | null;
11
+
12
+ protected cachedImg: CachedRevealBitmap;
13
+
14
+ constructor(store: RevealBoundaryStore, $canvas: HTMLCanvasElement, $container: HTMLElement) {
15
+ super(store, $canvas, $container);
16
+
17
+ this.ctx = $canvas.getContext('2d');
18
+
19
+ const cachedCanvas = {
20
+ borderReveal: createEmptyCanvas(),
21
+ fillReveal: createEmptyCanvas(),
22
+ };
23
+
24
+ const cachedCtx = {
25
+ borderReveal: cachedCanvas.borderReveal.getContext('2d'),
26
+ fillReveal: cachedCanvas.fillReveal.getContext('2d'),
27
+ };
28
+
29
+ this.cachedImg = {
30
+ cachedReveal: {
31
+ borderReveal: {
32
+ radiusFactor: -1,
33
+ radius: -1,
34
+ color: 'INVALID',
35
+ opacity: 0,
36
+ pattern: null,
37
+ },
38
+ fillReveal: {
39
+ radiusFactor: -1,
40
+ radius: -1,
41
+ color: 'INVALID',
42
+ opacity: 0,
43
+ pattern: null,
44
+ },
45
+ },
46
+ cachedCanvas,
47
+ cachedCtx,
48
+ };
49
+ }
50
+
51
+ updateCachedReveal = () => {
52
+ if (!this.fillDirty) return;
53
+
54
+ const c = this.cachedStyle;
55
+ const radius = c.trueFillRadius[1] * this.pxRatio;
56
+ const size = radius * 2;
57
+
58
+ const lastStyle = this.cachedImg.cachedReveal;
59
+
60
+ const { borderReveal, fillReveal } = this.cachedImg.cachedCanvas;
61
+ const { borderReveal: borderRevealCtx, fillReveal: fillRevealCtx } = this.cachedImg.cachedCtx;
62
+
63
+ this._store.updateMaxRadius(c.trueFillRadius[1] * c.borderFillRadius);
64
+
65
+ for (let i = 0; i < 2; i++) {
66
+ // 0 means border, 1 means hover light.
67
+ //-----------------------------------------
68
+ // Last rendered style.
69
+ const ls = i === 0 ? lastStyle.borderReveal : lastStyle.fillReveal;
70
+ const color = i === 0 ? c.borderColor : c.hoverLightColor;
71
+ const fillRadiusFactor = i === 0 ? c.borderFillRadius : c.hoverLightFillRadius;
72
+
73
+ const doNotNeedUpdateReveal =
74
+ color === ls.color && c.opacity === ls.opacity && fillRadiusFactor === ls.radiusFactor;
75
+
76
+ if (doNotNeedUpdateReveal) continue;
77
+
78
+ const reveal = i === 0 ? borderReveal : fillReveal;
79
+ const ctx = i === 0 ? borderRevealCtx : fillRevealCtx;
80
+
81
+ this.syncSizeToRevealRadius(reveal, fillRadiusFactor);
82
+
83
+ if (!ctx) continue;
84
+
85
+ ctx.clearRect(0, 0, reveal.width, reveal.height);
86
+
87
+ const fillAlpha = i === 0 ? c.opacity : c.opacity * 0.5;
88
+ const trueRadius = radius * fillRadiusFactor;
89
+ const grd = ctx.createRadialGradient(trueRadius, trueRadius, 0, trueRadius, trueRadius, trueRadius);
90
+
91
+ grd.addColorStop(0, `rgba(${color}, ${fillAlpha})`);
92
+ grd.addColorStop(1, `rgba(${color}, 0.0)`);
93
+
94
+ const trueSize = size * fillRadiusFactor;
95
+ ctx.fillStyle = grd;
96
+ ctx.clearRect(0, 0, trueSize, trueSize);
97
+ ctx.fillRect(0, 0, trueSize, trueSize);
98
+
99
+ ls.radius = trueRadius;
100
+ ls.radiusFactor = fillRadiusFactor;
101
+ ls.color = color;
102
+ ls.opacity = c.opacity;
103
+
104
+ if (!this.ctx) continue;
105
+ ls.pattern = this.ctx.createPattern(reveal, 'no-repeat');
106
+ }
107
+
108
+ this.fillDirty = false;
109
+ };
110
+
111
+ updateCachedBitmap = () => {
112
+ if (!this.ctx) return;
113
+ this.updateCachedReveal();
114
+ };
115
+
116
+ private updateAnimateGrd = (frame: number, grd: CanvasGradient) => {
117
+ const { pressAnimationColor, opacity } = this.cachedStyle;
118
+
119
+ const _innerAlpha = opacity * (0.2 - frame);
120
+ const _outerAlpha = opacity * (0.1 - frame * 0.07);
121
+ const _outerBorder = 0.1 + frame * 0.8;
122
+
123
+ const innerAlpha = _innerAlpha < 0 ? 0 : _innerAlpha;
124
+ const outerAlpha = _outerAlpha < 0 ? 0 : _outerAlpha;
125
+ let outerBorder = 0;
126
+ outerBorder = _outerBorder > 1 ? 1 : _outerBorder;
127
+ outerBorder = _outerBorder < 0 ? 0 : _outerBorder;
128
+
129
+ grd.addColorStop(0, `rgba(${pressAnimationColor},${innerAlpha})`);
130
+ grd.addColorStop(outerBorder * 0.55, `rgba(${pressAnimationColor},${outerAlpha})`);
131
+ grd.addColorStop(outerBorder, `rgba(${pressAnimationColor}, 0)`);
132
+ };
133
+
134
+ private drawShape = (hollow: boolean) => {
135
+ if (!this.ctx) return;
136
+
137
+ const b = this.cachedBoundingRect;
138
+ const w = b.width * this.pxRatio;
139
+ const h = b.height * this.pxRatio;
140
+
141
+ const c = this.cachedStyle;
142
+ const bw = c.borderWidth * this.pxRatio;
143
+
144
+ const tl = c.topLeftBorderDecorationRadius * this.pxRatio;
145
+ const tr = c.topRightBorderDecorationRadius * this.pxRatio;
146
+ const bl = c.bottomLeftBorderDecorationRadius * this.pxRatio;
147
+ const br = c.bottomRightBorderDecorationRadius * this.pxRatio;
148
+
149
+ const wlf = c.withLeftBorderFactor;
150
+ const wrf = c.withRightBorderFactor;
151
+ const wtf = c.withTopBorderFactor;
152
+ const wbf = c.withBottomBorderFactor;
153
+
154
+ const tl2 = bw < tl ? tl - bw : 0;
155
+ const tr2 = bw < tr ? tr - bw : 0;
156
+ const bl2 = bw < bl ? bl - bw : 0;
157
+ const br2 = bw < br ? br - bw : 0;
158
+
159
+ this.ctx.beginPath();
160
+
161
+ switch (c.borderDecorationType) {
162
+ // Oh... Fuck... It's painful...
163
+ case 'round':
164
+ // outer
165
+ this.ctx.moveTo(tl, 0);
166
+ this.ctx.arcTo(w, 0, w, h, tr);
167
+ this.ctx.lineTo(w, h - br);
168
+ this.ctx.arcTo(w, h, br, h, br);
169
+ this.ctx.lineTo(bl, h);
170
+ this.ctx.arcTo(0, h, 0, br, bl);
171
+ this.ctx.lineTo(0, tl);
172
+ this.ctx.arcTo(0, 0, tl, 0, tl);
173
+
174
+ if (hollow) {
175
+ /* prettier-ignore-start */
176
+ // inner
177
+ /**
178
+ +-①----⑧-+
179
+ ② ⑦
180
+ | |
181
+ ③ ⑥
182
+ +-④----⑤-+
183
+ */
184
+ // x y r p
185
+ this.ctx.moveTo(tl2, bw * wtf); // ①
186
+ this.ctx.arcTo(bw * wlf, bw * wtf, bw * wlf, tl2 + bw * wtf, tl2); // ②
187
+ this.ctx.lineTo(bw * wlf, h - bw * wbf - bl2); // ③
188
+ this.ctx.arcTo(bw * wlf, h - bw * wbf, bw * wlf + bl2, h - bw * wbf, bl2); // ④
189
+ this.ctx.lineTo(w - bw * wrf - br2, h - bw * wbf); // ⑤
190
+ this.ctx.arcTo(w - bw * wrf, h - bw * wbf, w - bw * wrf, h - bw * wbf - br2, br2); // ⑥
191
+ this.ctx.lineTo(w - bw * wrf, bw * wtf + tr2); // ⑦
192
+ this.ctx.arcTo(w - bw * wrf, bw * wtf, w - bw * wrf - tr2, bw * wtf, tr2); // ⑧
193
+ this.ctx.lineTo(tl2, bw * wtf); // ①
194
+ /* prettier-ignore-end */
195
+ }
196
+ break;
197
+ case 'bevel':
198
+ // outer
199
+ this.ctx.moveTo(tl, 0);
200
+ this.ctx.lineTo(w - tr, 0);
201
+ this.ctx.lineTo(w, tr);
202
+ this.ctx.lineTo(w, h - br);
203
+ this.ctx.lineTo(w - br, h);
204
+ this.ctx.lineTo(bl, h);
205
+ this.ctx.lineTo(0, h - bl);
206
+ this.ctx.lineTo(0, tl);
207
+ this.ctx.lineTo(tl, 0);
208
+ this.ctx.lineTo(w - tr, 0);
209
+
210
+ if (hollow) {
211
+ // inner
212
+ /**
213
+ +-①----⑧-+
214
+ ② ⑦
215
+ | |
216
+ ③ ⑥
217
+ +-④----⑤-+
218
+ */
219
+ // x y p
220
+ this.ctx.moveTo(tl2 + bw * wlf, bw * wtf); // ①
221
+ this.ctx.lineTo(bw * wlf, tl2 + bw * wtf); // ②
222
+ this.ctx.lineTo(bw * wlf, h - bl2 - bw * wbf); // ③
223
+ this.ctx.lineTo(bw * wlf + bl2, h - bw * wbf); // ④
224
+ this.ctx.lineTo(w - br2 - bw * wrf, h - bw * wbf); // ⑤
225
+ this.ctx.lineTo(w - bw * wrf, h - br2 - bw * wbf); // ⑥
226
+ this.ctx.lineTo(w - bw * wrf, tr2 + bw * wtf); // ⑦
227
+ this.ctx.lineTo(w - tr2 - bw * wrf, bw * wtf); // ⑧
228
+ this.ctx.lineTo(tl2 + bw * wrf, bw * wtf); // ①
229
+ }
230
+ break;
231
+ case 'miter':
232
+ // outer
233
+ this.ctx.moveTo(0, 0);
234
+ this.ctx.lineTo(w, 0);
235
+ this.ctx.lineTo(w, h);
236
+ this.ctx.lineTo(0, h);
237
+ this.ctx.lineTo(0, 0);
238
+
239
+ if (hollow) {
240
+ // inner
241
+ /**
242
+ ①--------④
243
+ | |
244
+ | |
245
+ | |
246
+ ②--------③
247
+ */
248
+ // x y p
249
+ this.ctx.moveTo(bw * wlf, bw * wtf); // ①
250
+ this.ctx.lineTo(bw * wlf, h - bw * wbf); // ②
251
+ this.ctx.lineTo(w - bw * wrf, h - bw * wbf); // ③
252
+ this.ctx.lineTo(w - bw * wrf, bw * wtf); // ④
253
+ this.ctx.lineTo(bw * wlf, bw * wtf); // ①
254
+ }
255
+ break;
256
+ default:
257
+ }
258
+
259
+ this.ctx.closePath();
260
+ };
261
+
262
+ syncSizeToElement = (x: HTMLCanvasElement) => {
263
+ const b = this.cachedBoundingRect;
264
+
265
+ if (x.width !== b.width || x.height !== b.height) {
266
+ x.width = b.width * this.pxRatio;
267
+ x.height = b.height * this.pxRatio;
268
+ x.style.width = `${b.width}px`;
269
+ x.style.height = `${b.height}px`;
270
+ }
271
+ };
272
+
273
+ clear = () => {
274
+ if (!this.ctx) return false;
275
+ if (!this.dirty) return false;
276
+
277
+ const { width, height } = this.cachedBoundingRect;
278
+
279
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
280
+ this.ctx.clearRect(
281
+ 0,
282
+ 0,
283
+ width * window.devicePixelRatio,
284
+ height * window.devicePixelRatio,
285
+ );
286
+ this.dirty = false;
287
+ return true;
288
+ }
289
+
290
+ paint = (skipSamePointerPositionCheck?: boolean): boolean => {
291
+ const store = this._store;
292
+
293
+ const animationPlaying = store.animationQueue.includes(this);
294
+ const samePosition = store.clientX === store.paintedClientX && store.clientY === store.paintedClientY;
295
+
296
+ if (samePosition && !skipSamePointerPositionCheck && !animationPlaying) {
297
+ return false;
298
+ }
299
+
300
+ if (!this.ctx) return false;
301
+
302
+ this.dirty = true;
303
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
304
+ this.ctx.clearRect(
305
+ 0, 0,
306
+ this.paintedWidth,
307
+ this.paintedHeight
308
+ );
309
+
310
+ if (!store.mouseInBoundary && !animationPlaying) {
311
+ return false;
312
+ }
313
+
314
+ if (!this.cachedImg.cachedReveal) {
315
+ return false;
316
+ }
317
+
318
+ this.syncSizeToElement(this.element);
319
+ this.cacheBoundingRect();
320
+
321
+ const b = this.cachedBoundingRect;
322
+
323
+ const relativeX = store.clientX - b.left;
324
+ const relativeY = store.clientY - b.top;
325
+
326
+ if (Number.isNaN(relativeX) || Number.isNaN(relativeY)) {
327
+ return false;
328
+ }
329
+
330
+ const c = this.cachedStyle;
331
+ this.getTrueFillRadius(c.trueFillRadius);
332
+
333
+ this.paintedWidth = b.width * this.pxRatio;
334
+ this.paintedHeight = b.height * this.pxRatio;
335
+
336
+ const maxRadius = c.trueFillRadius[1];
337
+
338
+ const inLeftBound = relativeX + maxRadius > 0;
339
+ const inRightBound = relativeX - maxRadius < b.width;
340
+ const inTopBound = relativeY + maxRadius > 0;
341
+ const inBottomBound = relativeY - maxRadius < b.height;
342
+
343
+ const mouseInRenderArea = inLeftBound && inRightBound && inTopBound && inBottomBound;
344
+
345
+ if (!mouseInRenderArea && !animationPlaying) {
346
+ return false;
347
+ }
348
+
349
+ this.cacheCanvasPaintingStyle();
350
+ this.updateCachedBitmap();
351
+
352
+ if (store.mouseInBoundary) {
353
+ const mouseInCanvas = relativeX > 0 && relativeY > 0 && relativeX < b.width && relativeY < b.height;
354
+
355
+ const fillPattern = this.cachedImg.cachedReveal.fillReveal.pattern;
356
+ if (c.hoverLight && mouseInCanvas && fillPattern) {
357
+ // draw fill.
358
+ const radius = this.cachedImg.cachedReveal.fillReveal.radius;
359
+ const putX = Math.floor(relativeX * this.pxRatio - radius);
360
+ const putY = Math.floor(relativeY * this.pxRatio - radius);
361
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
362
+ this.drawShape(false);
363
+ this.ctx.translate(putX, putY);
364
+ this.ctx.fillStyle = fillPattern;
365
+ this.ctx.fill();
366
+ }
367
+
368
+ const diffuse = (c.diffuse && mouseInRenderArea) || mouseInCanvas;
369
+ const borderPattern = this.cachedImg.cachedReveal.borderReveal.pattern;
370
+ if (c.borderWidth !== 0 && borderPattern && diffuse) {
371
+ // Draw border.
372
+ const radius = this.cachedImg.cachedReveal.borderReveal.radius;
373
+ const putX = Math.floor(relativeX * this.pxRatio - radius);
374
+ const putY = Math.floor(relativeY * this.pxRatio - radius);
375
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
376
+ this.drawShape(true);
377
+ this.ctx.translate(putX, putY);
378
+ this.ctx.fillStyle = borderPattern;
379
+ this.ctx.fill();
380
+ }
381
+ }
382
+
383
+ if (c.pressAnimation && this.mousePressed && this.mouseDownAnimateLogicFrame) {
384
+ this.ctx.setTransform(1, 0, 0, 1, 0, 0);
385
+ const grdRadius =
386
+ c.pressAnimationFillMode === 'constrained' ? c.trueFillRadius[1] : Math.max(b.width, b.height);
387
+ // prettier-ignore
388
+ const animateGrd =
389
+ this.mouseReleased && this.mouseUpClientX && this.mouseUpClientY
390
+ ? this.ctx.createRadialGradient(
391
+ (this.mouseUpClientX - b.left) * this.pxRatio,
392
+ (this.mouseUpClientY - b.top) * this.pxRatio,
393
+ 0,
394
+ (this.mouseUpClientX - b.left) * this.pxRatio,
395
+ (this.mouseUpClientY - b.top) * this.pxRatio,
396
+ grdRadius * this.pxRatio
397
+ )
398
+ : this.ctx.createRadialGradient(
399
+ relativeX * this.pxRatio,
400
+ relativeY * this.pxRatio,
401
+ 0,
402
+ relativeX * this.pxRatio,
403
+ relativeY * this.pxRatio,
404
+ grdRadius * this.pxRatio
405
+ );
406
+ this.updateAnimateGrd(this.mouseDownAnimateLogicFrame, animateGrd);
407
+
408
+ this.drawShape(false);
409
+ this.ctx.fillStyle = animateGrd;
410
+ this.ctx.fill();
411
+ }
412
+
413
+ return true;
414
+ };
415
+ }