forked from bvaughn/scheduling-profiler-prototype
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Chromium flamechart colors (#96)
- Loading branch information
Showing
4 changed files
with
224 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
'use strict'; | ||
|
||
import {hslaColorToString, dimmedColor, ColorGenerator} from '../colors'; | ||
|
||
describe(hslaColorToString, () => { | ||
it('should transform colors to strings', () => { | ||
expect(hslaColorToString({h: 1, s: 2, l: 3, a: 4})).toEqual( | ||
'hsl(1deg 2% 3% / 4)', | ||
); | ||
expect(hslaColorToString({h: 3.14, s: 6.28, l: 1.68, a: 100})).toEqual( | ||
'hsl(3.14deg 6.28% 1.68% / 100)', | ||
); | ||
}); | ||
}); | ||
|
||
describe(dimmedColor, () => { | ||
it('should dim luminosity using delta', () => { | ||
expect(dimmedColor({h: 1, s: 2, l: 3, a: 4}, 3)).toEqual({ | ||
h: 1, | ||
s: 2, | ||
l: 0, | ||
a: 4, | ||
}); | ||
expect(dimmedColor({h: 1, s: 2, l: 3, a: 4}, -3)).toEqual({ | ||
h: 1, | ||
s: 2, | ||
l: 6, | ||
a: 4, | ||
}); | ||
}); | ||
}); | ||
|
||
describe(ColorGenerator, () => { | ||
describe(ColorGenerator.prototype.colorForID, () => { | ||
it('should generate a color for an ID', () => { | ||
expect(new ColorGenerator().colorForID('123')).toMatchInlineSnapshot(` | ||
Object { | ||
"a": 1, | ||
"h": 190, | ||
"l": 80, | ||
"s": 67, | ||
} | ||
`); | ||
}); | ||
|
||
it('should generate colors deterministically given an ID', () => { | ||
expect(new ColorGenerator().colorForID('id1')).toEqual( | ||
new ColorGenerator().colorForID('id1'), | ||
); | ||
expect(new ColorGenerator().colorForID('id2')).toEqual( | ||
new ColorGenerator().colorForID('id2'), | ||
); | ||
}); | ||
|
||
it('should generate different colors for different IDs', () => { | ||
expect(new ColorGenerator().colorForID('id1')).not.toEqual( | ||
new ColorGenerator().colorForID('id2'), | ||
); | ||
}); | ||
|
||
it('should return colors that have been set manually', () => { | ||
const generator = new ColorGenerator(); | ||
const manualColor = {h: 1, s: 2, l: 3, a: 4}; | ||
generator.setColorForID('id with set color', manualColor); | ||
expect(generator.colorForID('id with set color')).toEqual(manualColor); | ||
expect(generator.colorForID('some other id')).not.toEqual(manualColor); | ||
}); | ||
|
||
it('should generate colors from fixed color spaces', () => { | ||
const generator = new ColorGenerator(1, 2, 3, 4); | ||
expect(generator.colorForID('123')).toEqual({h: 1, s: 2, l: 3, a: 4}); | ||
expect(generator.colorForID('234')).toEqual({h: 1, s: 2, l: 3, a: 4}); | ||
}); | ||
|
||
it('should generate colors from range color spaces', () => { | ||
const generator = new ColorGenerator( | ||
{min: 0, max: 360, count: 2}, | ||
2, | ||
3, | ||
4, | ||
); | ||
expect(generator.colorForID('123')).toEqual({h: 0, s: 2, l: 3, a: 4}); | ||
expect(generator.colorForID('234')).toEqual({h: 360, s: 2, l: 3, a: 4}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
// @flow | ||
|
||
type ColorSpace = number | {|min: number, max: number, count?: number|}; | ||
|
||
// Docstrings from https://www.w3schools.com/css/css_colors_hsl.asp | ||
type HslaColor = $ReadOnly<{| | ||
/** Hue is a degree on the color wheel from 0 to 360. 0 is red, 120 is green, and 240 is blue. */ | ||
h: number, | ||
/** Saturation is a percentage value, 0% means a shade of gray, and 100% is the full color. */ | ||
s: number, | ||
/** Lightness is a percentage, 0% is black, 50% is neither light or dark, 100% is white. */ | ||
l: number, | ||
/** Alpha is a percentage, 0% is fully transparent, and 100 is not transparent at all. */ | ||
a: number, | ||
|}>; | ||
|
||
export function hslaColorToString({h, s, l, a}: HslaColor): string { | ||
return `hsl(${h}deg ${s}% ${l}% / ${a})`; | ||
} | ||
|
||
export function dimmedColor(color: HslaColor, dimDelta: number): HslaColor { | ||
return { | ||
...color, | ||
l: color.l - dimDelta, | ||
}; | ||
} | ||
|
||
// Source: https://source.chromium.org/chromium/chromium/src/+/master:out/Debug/gen/devtools/platform/utilities.js;l=120 | ||
function hashCode(string: string): number { | ||
// Hash algorithm for substrings is described in "Über die Komplexität der Multiplikation in | ||
// eingeschränkten Branchingprogrammmodellen" by Woelfe. | ||
// http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000 | ||
const p = (1 << 30) * 4 - 5; // prime: 2^32 - 5 | ||
const z = 0x5033d967; // 32 bits from random.org | ||
const z2 = 0x59d2f15d; // random odd 32 bit number | ||
let s = 0; | ||
let zi = 1; | ||
for (let i = 0; i < string.length; i++) { | ||
const xi = string.charCodeAt(i) * z2; | ||
s = (s + zi * xi) % p; | ||
zi = (zi * z) % p; | ||
} | ||
s = (s + zi * (p - 1)) % p; | ||
return Math.abs(s | 0); | ||
} | ||
|
||
function indexToValueInSpace(index: number, space: ColorSpace): number { | ||
if (typeof space === 'number') { | ||
return space; | ||
} | ||
const count = space.count || space.max - space.min; | ||
index %= count; | ||
return ( | ||
space.min + Math.floor((index / (count - 1)) * (space.max - space.min)) | ||
); | ||
} | ||
|
||
/** | ||
* Deterministic color generator. | ||
* | ||
* Adapted from: https://source.chromium.org/chromium/chromium/src/+/master:out/Debug/gen/devtools/common/Color.js | ||
*/ | ||
export class ColorGenerator { | ||
_hueSpace: ColorSpace; | ||
_satSpace: ColorSpace; | ||
_lightnessSpace: ColorSpace; | ||
_alphaSpace: ColorSpace; | ||
_colors: Map<string, HslaColor>; | ||
|
||
constructor( | ||
hueSpace?: ColorSpace, | ||
satSpace?: ColorSpace, | ||
lightnessSpace?: ColorSpace, | ||
alphaSpace?: ColorSpace, | ||
) { | ||
this._hueSpace = hueSpace || {min: 0, max: 360}; | ||
this._satSpace = satSpace || 67; | ||
this._lightnessSpace = lightnessSpace || 80; | ||
this._alphaSpace = alphaSpace || 1; | ||
this._colors = new Map(); | ||
} | ||
|
||
setColorForID(id: string, color: HslaColor) { | ||
this._colors.set(id, color); | ||
} | ||
|
||
colorForID(id: string): HslaColor { | ||
const cachedColor = this._colors.get(id); | ||
if (cachedColor) { | ||
return cachedColor; | ||
} | ||
const color = this._generateColorForID(id); | ||
this._colors.set(id, color); | ||
return color; | ||
} | ||
|
||
_generateColorForID(id: string): HslaColor { | ||
const hash = hashCode(id); | ||
return { | ||
h: indexToValueInSpace(hash, this._hueSpace), | ||
s: indexToValueInSpace(hash >> 8, this._satSpace), | ||
l: indexToValueInSpace(hash >> 16, this._lightnessSpace), | ||
a: indexToValueInSpace(hash >> 24, this._alphaSpace), | ||
}; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
e4927cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs: