Skip to content

Commit 8e16c6c

Browse files
authored
Merge branch 'dev-2.0' into add-hsb-tests
2 parents eece985 + daac93f commit 8e16c6c

37 files changed

Lines changed: 1096 additions & 373 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"test/**/*.js": "eslint",
2020
"utils/**/*.{js,mjs}": "eslint"
2121
},
22-
"version": "2.2.0-rc.3",
22+
"version": "2.2.0",
2323
"dependencies": {
2424
"@davepagurek/bezier-path": "^0.0.2",
2525
"@japont/unicode-range": "^1.0.0",

preview/index.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107

108108
p.draw = function () {
109109
p.clear();
110+
p.rotateY(p.millis() * 0.001);
110111
p.push();
111112
//p.clip(() => p.rect(-50, -50, 200, 200));
112113
/*p.orbitControl();

src/color/p5.Color.js

Lines changed: 100 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,22 @@ const map = (n, start1, stop1, start2, stop2, clamp) => {
4141
return result;
4242
}
4343

44-
const serializationMap = {};
44+
const toHexComponent = (v) => {
45+
const vInt = ~~(v * 255);
46+
const hex = vInt.toString(16)
47+
if (hex.length < 2) {
48+
return '0' + hex
49+
} else {
50+
return hex
51+
}
52+
}
4553

54+
const serializationMap = new Map();
4655

4756

4857

49-
class Color {
50-
// Reference to underlying color object depending on implementation
51-
// Not meant to be used publicly unless the implementation is known for sure
52-
_color;
53-
// Color mode of the Color object, uses p5 color modes
54-
mode;
5558

59+
class Color {
5660
static colorMap = {};
5761
static #colorjsMaxes = {};
5862
static #grayscaleMap = {};
@@ -77,40 +81,47 @@ class Color {
7781

7882
constructor(vals, colorMode, colorMaxes, { clamp = false } = {}) {
7983
// This changes with the color object
80-
this.mode = colorMode || RGB;
84+
this._cachedMode = colorMode || RGB;
8185

8286
if(vals instanceof Color){
8387
// Received Color object to be used for color mode conversion
8488
const mode = colorMode ?
8589
Color.colorMap[colorMode] :
8690
Color.colorMap[vals.mode];
87-
this._color = to(vals._color, mode);
88-
this.mode = mode;
91+
this._initialize = () => {
92+
this._cachedColor = to(vals._color, mode);
93+
this._cachedMode = mode;
94+
};
8995

9096
}else if (typeof vals === 'object' && !Array.isArray(vals) && vals !== null){
9197
// Received color.js object to be used internally
9298
const mode = colorMode ?
9399
Color.colorMap[colorMode] :
94100
vals.spaceId;
95-
this._color = to(vals, mode);
96-
this.mode = colorMode || Object.entries(Color.colorMap)
97-
.find(([key, val]) => {
98-
return val === this._color.spaceId;
99-
});
101+
this._initialize = () => {
102+
this._cachedColor = to(vals, mode);
103+
this._cachedMode = colorMode || Object.entries(Color.colorMap)
104+
.find(([key, val]) => {
105+
return val === this._cachedColor.spaceId;
106+
});
107+
};
100108

101109
} else if(typeof vals[0] === 'string') {
102110
// Received string
103-
try{
104-
this._color = parse(vals[0]);
105-
const [mode] = Object.entries(Color.colorMap).find(([key, val]) => {
106-
return val === this._color.spaceId;
107-
});
108-
this.mode = mode;
109-
this._color = to(this._color, this._color.spaceId);
110-
}catch(err){
111-
// TODO: Invalid color string
112-
throw new Error('Invalid color string');
113-
}
111+
this._defaultStringValue = vals[0];
112+
this._initialize = () => {
113+
try{
114+
this._cachedColor = parse(vals[0]);
115+
const [mode] = Object.entries(Color.colorMap).find(([key, val]) => {
116+
return val === this._cachedColor.spaceId;
117+
});
118+
this._cachedMode = mode;
119+
this._cachedColor = to(this._cachedColor, this._cachedColor.spaceId);
120+
}catch(err){
121+
// TODO: Invalid color string
122+
throw new Error('Invalid color string');
123+
}
124+
};
114125

115126
}else{
116127
// Received individual channel values
@@ -119,27 +130,27 @@ class Color {
119130
if(colorMaxes){
120131
// NOTE: need to consider different number of arguments (eg. CMYK)
121132
if(vals.length === 4){
122-
mappedVals = Color.mapColorRange(vals, this.mode, colorMaxes, clamp);
133+
mappedVals = Color.mapColorRange(vals, this._cachedMode, colorMaxes, clamp);
123134
}else if(vals.length === 3){
124135
mappedVals = Color.mapColorRange(
125136
[vals[0], vals[1], vals[2]],
126-
this.mode,
137+
this._cachedMode,
127138
colorMaxes,
128139
clamp
129140
);
130141
mappedVals.push(1);
131142
}else if(vals.length === 2){
132143
// Grayscale with alpha
133-
if(Color.#grayscaleMap[this.mode]){
134-
mappedVals = Color.#grayscaleMap[this.mode](
144+
if(Color.#grayscaleMap[this._cachedMode]){
145+
mappedVals = Color.#grayscaleMap[this._cachedMode](
135146
vals[0],
136147
colorMaxes,
137148
clamp
138149
);
139150
}else{
140151
mappedVals = Color.mapColorRange(
141152
[vals[0], vals[0], vals[0]],
142-
this.mode,
153+
this._cachedMode,
143154
colorMaxes,
144155
clamp
145156
);
@@ -159,16 +170,16 @@ class Color {
159170
);
160171
}else if(vals.length === 1){
161172
// Grayscale only
162-
if(Color.#grayscaleMap[this.mode]){
163-
mappedVals = Color.#grayscaleMap[this.mode](
173+
if(Color.#grayscaleMap[this._cachedMode]){
174+
mappedVals = Color.#grayscaleMap[this._cachedMode](
164175
vals[0],
165176
colorMaxes,
166177
clamp
167178
);
168179
}else{
169180
mappedVals = Color.mapColorRange(
170181
[vals[0], vals[0], vals[0]],
171-
this.mode,
182+
this._cachedMode,
172183
colorMaxes,
173184
clamp
174185
);
@@ -180,19 +191,54 @@ class Color {
180191
}else{
181192
mappedVals = vals;
182193
}
194+
if (this._cachedMode === RGB) {
195+
if (mappedVals[3] === 1) {
196+
// Faster for the browser to parse than rgba
197+
this._defaultStringValue = '#' + toHexComponent(mappedVals[0]) + toHexComponent(mappedVals[1]) + toHexComponent(mappedVals[2]);
198+
} else {
199+
this._defaultStringValue = '#' + toHexComponent(mappedVals[0]) + toHexComponent(mappedVals[1]) + toHexComponent(mappedVals[2]) + toHexComponent(mappedVals[3]);;
200+
}
201+
}
183202

184-
const space = Color.colorMap[this.mode] || console.error('Invalid color mode');
185-
const coords = mappedVals.slice(0, 3);
203+
this._initialize = () => {
204+
const space = Color.colorMap[this._cachedMode] || console.error('Invalid color mode');
205+
const coords = mappedVals.slice(0, 3);
186206

187-
const color = {
188-
space,
189-
coords,
190-
alpha: mappedVals[3]
207+
const color = {
208+
space,
209+
coords,
210+
alpha: mappedVals[3]
211+
};
212+
this._cachedColor = to(color, space);
191213
};
192-
this._color = to(color, space);
193214
}
194215
}
195216

217+
// Color mode of the Color object, uses p5 color modes
218+
get mode() {
219+
if (this._initialize) {
220+
this._initialize();
221+
this._initialize = undefined;
222+
}
223+
return this._cachedMode;
224+
}
225+
// Reference to underlying color object depending on implementation
226+
// Not meant to be used publicly unless the implementation is known for sure
227+
get _color() {
228+
if (this._initialize) {
229+
this._initialize();
230+
this._initialize = undefined;
231+
}
232+
return this._cachedColor;
233+
}
234+
set _color(newColor) {
235+
if (this._initialize) {
236+
this._initialize();
237+
this._initialize = undefined;
238+
}
239+
this._cachedColor = newColor;
240+
}
241+
196242
// Convert from p5 color range to color.js color range
197243
static mapColorRange(origin, mode, maxes, clamp){
198244
const p5Maxes = maxes.map(max => {
@@ -319,14 +365,21 @@ class Color {
319365
* </div>
320366
*/
321367
toString(format) {
368+
if (format === undefined && this._defaultStringValue !== undefined) {
369+
return this._defaultStringValue;
370+
}
371+
322372
const key = `${this._color.space.id}-${this._color.coords.join(',')}-${this._color.alpha}-${format}`;
323-
let colorString = serializationMap[key];
373+
let colorString = serializationMap.get(key);
324374

325375
if(!colorString){
326376
colorString = serialize(this._color, {
327377
format
328378
});
329-
serializationMap[key] = colorString;
379+
if (serializationMap.size > 1000) {
380+
serializationMap.delete(serializationMap.keys().next().value)
381+
}
382+
serializationMap.set(key, colorString);
330383
}
331384
return colorString;
332385
}
@@ -487,6 +540,7 @@ class Color {
487540
* </div>
488541
*/
489542
setRed(new_red, max=[0, 1]) {
543+
this._defaultStringValue = undefined;
490544
if(!Array.isArray(max)){
491545
max = [0, max];
492546
}
@@ -542,6 +596,7 @@ class Color {
542596
* </div>
543597
*/
544598
setGreen(new_green, max=[0, 1]) {
599+
this._defaultStringValue = undefined;
545600
if(!Array.isArray(max)){
546601
max = [0, max];
547602
}
@@ -597,6 +652,7 @@ class Color {
597652
* </div>
598653
*/
599654
setBlue(new_blue, max=[0, 1]) {
655+
this._defaultStringValue = undefined;
600656
if(!Array.isArray(max)){
601657
max = [0, max];
602658
}
@@ -653,6 +709,7 @@ class Color {
653709
* </div>
654710
*/
655711
setAlpha(new_alpha, max=[0, 1]) {
712+
this._defaultStringValue = undefined;
656713
if(!Array.isArray(max)){
657714
max = [0, max];
658715
}

0 commit comments

Comments
 (0)