Skip to content

Commit 8290542

Browse files
committed
refactor(core): improve hexify performance with internal instance cache
1 parent 28c4110 commit 8290542

File tree

1 file changed

+41
-16
lines changed

1 file changed

+41
-16
lines changed

libs/core/src/lib/pipes/hexify.ts

Lines changed: 41 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { DOCUMENT } from '@angular/common';
22
import { inject, Pipe } from '@angular/core';
33

4+
const RGBA_REGEX = /rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*(\d*\.?\d+)?\)/;
5+
const DEFAULT_COLOR = 0x000000;
6+
47
@Pipe({ name: 'hexify', pure: true, standalone: true })
58
export class NgtHexify {
69
private document = inject(DOCUMENT, { optional: true });
710
private ctx?: CanvasRenderingContext2D | null;
11+
private cache: Record<string, number> = {};
812

913
/**
1014
* transforms a:
@@ -17,45 +21,66 @@ export class NgtHexify {
1721
* @param value
1822
*/
1923
transform(value: string): number {
20-
if (value == null) return 0x000000;
24+
if (value == null) return DEFAULT_COLOR;
2125

2226
if (value.startsWith('#')) {
23-
return this.hexStringToNumber(value);
27+
if (!this.cache[value]) {
28+
this.cache[value] = this.hexStringToNumber(value);
29+
}
30+
return this.cache[value];
2431
}
2532

2633
if (!this.ctx) {
2734
this.ctx = this.document?.createElement('canvas').getContext('2d');
2835
}
2936

30-
if (!this.ctx) return 0x000000;
37+
if (!this.ctx) {
38+
console.warn('[NGT] hexify: canvas context is not available');
39+
return DEFAULT_COLOR;
40+
}
3141

3242
this.ctx.fillStyle = value;
3343
const computedValue = this.ctx.fillStyle;
3444

3545
if (computedValue.startsWith('#')) {
36-
return this.hexStringToNumber(computedValue);
46+
if (!this.cache[computedValue]) {
47+
this.cache[computedValue] = this.hexStringToNumber(computedValue);
48+
}
49+
return this.cache[computedValue];
3750
}
3851

39-
if (!computedValue.startsWith('rgba')) return 0x000000;
52+
if (!computedValue.startsWith('rgba')) {
53+
console.warn(`[NGT] hexify: invalid color format. Expected rgba or hex, receive: ${computedValue}`);
54+
return DEFAULT_COLOR;
55+
}
4056

41-
const regex = /rgba?\((\d+),\s*(\d+),\s*(\d+),?\s*(\d*\.?\d+)?\)/;
42-
const match = computedValue.match(regex);
43-
if (!match) return 0x000000;
57+
const match = computedValue.match(RGBA_REGEX);
58+
if (!match) {
59+
console.warn(`[NGT] hexify: invalid color format. Expected rgba or hex, receive: ${computedValue}`);
60+
return DEFAULT_COLOR;
61+
}
4462

4563
const r = parseInt(match[1], 10);
4664
const g = parseInt(match[2], 10);
4765
const b = parseInt(match[3], 10);
4866
const a = match[4] ? parseFloat(match[4]) : 1.0;
4967

50-
// Convert the components to hex strings
51-
const hexR = this.componentToHex(r);
52-
const hexG = this.componentToHex(g);
53-
const hexB = this.componentToHex(b);
54-
const hexA = this.componentToHex(Math.round(a * 255));
68+
const cacheKey = `${r}:${g}:${b}:${a}`;
69+
70+
// check result from cache
71+
if (!this.cache[cacheKey]) {
72+
// Convert the components to hex strings
73+
const hexR = this.componentToHex(r);
74+
const hexG = this.componentToHex(g);
75+
const hexB = this.componentToHex(b);
76+
const hexA = this.componentToHex(Math.round(a * 255));
77+
78+
// Combine the hex components into a single hex string
79+
const hex = `#${hexR}${hexG}${hexB}${hexA}`;
80+
this.cache[cacheKey] = this.hexStringToNumber(hex);
81+
}
5582

56-
// Combine the hex components into a single hex string
57-
const hex = `#${hexR}${hexG}${hexB}${hexA}`;
58-
return this.hexStringToNumber(hex);
83+
return this.cache[cacheKey];
5984
}
6085

6186
private hexStringToNumber(hexString: string): number {

0 commit comments

Comments
 (0)