Merge pull request #81 from microsoft/cleanup-color-compute
Cleanup color compute
This commit is contained in:
Коммит
cd2c001643
|
@ -0,0 +1,8 @@
|
|||
releases:
|
||||
"@thematic/color": major
|
||||
"@thematic/core": major
|
||||
"@thematic/d3": patch
|
||||
"@thematic/fluent": major
|
||||
"@thematic/react": patch
|
||||
"@thematic/vega": major
|
||||
"@thematic/webapp": major
|
|
@ -7,13 +7,9 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
hsl(): {
|
||||
h: number;
|
||||
s: number;
|
||||
l: number;
|
||||
};
|
||||
hsl(): Hsl;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
{ h: number; s: number; l: number; }
|
||||
[Hsl](./color.hsl.md)
|
||||
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
hsluv(): [number, number, number];
|
||||
hsluv(): HslVector;
|
||||
```
|
||||
<b>Returns:</b>
|
||||
|
||||
\[number, number, number\]
|
||||
[HslVector](./color.hslvector.md)
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rgbav(alpha?: number): [number, number, number, number];
|
||||
rgbav(alpha?: number): RGBAV;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -18,5 +18,5 @@ rgbav(alpha?: number): [number, number, number, number];
|
|||
|
||||
<b>Returns:</b>
|
||||
|
||||
\[number, number, number, number\]
|
||||
[RGBAV](./color.rgbav.md)
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ export declare enum ColorSpace
|
|||
| --- | --- | --- |
|
||||
| CSS | <code>"css"</code> | Encode the color using any CSS-compatible color string. The default due to its wide applicability, and the format colors use in theme JSON. https://www.w3.org/TR/css-color-3/\#colorunits |
|
||||
| HEX | <code>"hex"</code> | Encode as a standard hexadecimal color. |
|
||||
| HSL | <code>"hsl"</code> | HSL color space, { h, s, l }<!-- -->. |
|
||||
| HSLUV | <code>"hsluv"</code> | HSLuv, which is a perceptually balanced space. \[h, s, l\]. https://www.hsluv.org/ |
|
||||
| RGB | <code>"rgb"</code> | Encode as an object with r, g, b properies, scaled 0-255 each. |
|
||||
| RGBA | <code>"rgba"</code> | Encode as an object with r, g, b properies, scaled 0-255 each, along with an alpha prop scaled 0-1 |
|
||||
| RGBA\_NUMBER | <code>"rgbaint"</code> | This is raw JavaScript number representing the RGBA color. It is calculated by bitshifting R, G, B, and A values into a 32-bit space. (i.e., r, g <<!-- -->< 8, b <<!-- -->< 16, a <<!-- -->< 24) |
|
||||
|
|
|
@ -9,7 +9,7 @@ Convert a standard CSS-compatible string to \[h, s, l\] array
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function css2hsluv(css: string): [number, number, number];
|
||||
export declare function css2hsluv(css: string): HslVector;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -20,5 +20,5 @@ export declare function css2hsluv(css: string): [number, number, number];
|
|||
|
||||
<b>Returns:</b>
|
||||
|
||||
\[number, number, number\]
|
||||
[HslVector](./color.hslvector.md)
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ Convert a standard CSS-compatible string to \[l, c, h\] array
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function css2lch(css: string): [number, number, number];
|
||||
export declare function css2lch(css: string): HslVector;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
@ -20,5 +20,5 @@ export declare function css2lch(css: string): [number, number, number];
|
|||
|
||||
<b>Returns:</b>
|
||||
|
||||
\[number, number, number\]
|
||||
[HslVector](./color.hslvector.md)
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [css2rgbaNumber](./color.css2rgbanumber.md)
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [css2rgbaint](./color.css2rgbaint.md)
|
||||
|
||||
## css2rgbaNumber() function
|
||||
## css2rgbaint() function
|
||||
|
||||
Convert a standard CSS string to an integer number. This is commonly used in GL code.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function css2rgbaNumber(css: string, alpha?: number): number;
|
||||
export declare function css2rgbaint(css: string, alpha?: number): number;
|
||||
```
|
||||
|
||||
## Parameters
|
|
@ -1,15 +1,15 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [css2rgbaVector](./color.css2rgbavector.md)
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [css2rgbav](./color.css2rgbav.md)
|
||||
|
||||
## css2rgbaVector() function
|
||||
## css2rgbav() function
|
||||
|
||||
Convert a standard CSS string to vector of \[r, g, b, a\] values scaled from 0-1. This is typically used in WebGl.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function css2rgbaVector(css: string, alpha?: number): [number, number, number, number];
|
||||
export declare function css2rgbav(css: string, alpha?: number): [number, number, number, number];
|
||||
```
|
||||
|
||||
## Parameters
|
|
@ -4,15 +4,18 @@
|
|||
|
||||
## defaultParams variable
|
||||
|
||||
Default set of params useful for initializing new themes with our "standard look".
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
defaultParams: {
|
||||
accentHue: number;
|
||||
accentSaturation: number;
|
||||
accentLuminance: number;
|
||||
backgroundHueShift: number;
|
||||
backgroundLevel: number;
|
||||
nominalHueStep: number;
|
||||
accentLightness: number;
|
||||
scaleSaturation: number;
|
||||
scaleLightness: number;
|
||||
greyHue: number;
|
||||
greySaturation: number;
|
||||
}
|
||||
```
|
||||
|
|
|
@ -4,22 +4,26 @@
|
|||
|
||||
## getScheme() function
|
||||
|
||||
Takes a set of core params and generates all of the scale computes required for a Schema, using HSLuv color space for even perceptual qualities.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function getScheme(params: Params, nominalItemCount: number, sequentialItemCount: number, light: boolean): Scheme;
|
||||
export declare function getScheme(params: SchemeParams, nominalItemCount: number, sequentialItemCount: number, light: boolean, tuning?: Partial<TuningParameters>): Scheme;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| params | [Params](./color.params.md) | |
|
||||
| params | [SchemeParams](./color.schemeparams.md) | |
|
||||
| nominalItemCount | number | |
|
||||
| sequentialItemCount | number | |
|
||||
| light | boolean | |
|
||||
| tuning | Partial<[TuningParameters](./color.tuningparameters.md)<!-- -->> | <i>(Optional)</i> |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[Scheme](./color.scheme.md)
|
||||
|
||||
|
||||
|
|
|
@ -7,16 +7,14 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function hsluv2hex(h: number, s: number, l: number): string;
|
||||
export declare function hsluv2hex(hsluv: HslVector): string;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| h | number | |
|
||||
| s | number | |
|
||||
| l | number | |
|
||||
| hsluv | [HslVector](./color.hslvector.md) | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [hsluv2hsl](./color.hsluv2hsl.md)
|
||||
|
||||
## hsluv2hsl() function
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function hsluv2hsl(hsluv: HslVector): HslVector;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| hsluv | [HslVector](./color.hslvector.md) | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
[HslVector](./color.hslvector.md)
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [HslVector](./color.hslvector.md)
|
||||
|
||||
## HslVector type
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type HslVector = [number, number, number];
|
||||
```
|
|
@ -32,12 +32,13 @@
|
|||
| [css2lch(css)](./color.css2lch.md) | Convert a standard CSS-compatible string to \[l, c, h\] array |
|
||||
| [css2rgb(css, \_alpha)](./color.css2rgb.md) | Converts a standard CSS color to an {<!-- -->r, g, b<!-- -->} object |
|
||||
| [css2rgba(css, alpha)](./color.css2rgba.md) | Converts a standard CSS color to an { r, g, b, a } object. |
|
||||
| [css2rgbaNumber(css, alpha)](./color.css2rgbanumber.md) | Convert a standard CSS string to an integer number. This is commonly used in GL code. |
|
||||
| [css2rgbaVector(css, alpha)](./color.css2rgbavector.md) | Convert a standard CSS string to vector of \[r, g, b, a\] values scaled from 0-1. This is typically used in WebGl. |
|
||||
| [css2rgbaint(css, alpha)](./color.css2rgbaint.md) | Convert a standard CSS string to an integer number. This is commonly used in GL code. |
|
||||
| [css2rgbav(css, alpha)](./color.css2rgbav.md) | Convert a standard CSS string to vector of \[r, g, b, a\] values scaled from 0-1. This is typically used in WebGl. |
|
||||
| [darken(css, value)](./color.darken.md) | Darken a standard CSS color |
|
||||
| [getNamedSchemeColor(scheme, path)](./color.getnamedschemecolor.md) | Extracts a thematic Color using its scheme "path". |
|
||||
| [getScheme(params, nominalItemCount, sequentialItemCount, light)](./color.getscheme.md) | |
|
||||
| [hsluv2hex(h, s, l)](./color.hsluv2hex.md) | |
|
||||
| [getScheme(params, nominalItemCount, sequentialItemCount, light, tuning)](./color.getscheme.md) | Takes a set of core params and generates all of the scale computes required for a Schema, using HSLuv color space for even perceptual qualities. |
|
||||
| [hsluv2hex(hsluv)](./color.hsluv2hex.md) | |
|
||||
| [hsluv2hsl(hsluv)](./color.hsluv2hsl.md) | |
|
||||
| [isNominal(name)](./color.isnominal.md) | |
|
||||
| [lch2hex(l, c, h)](./color.lch2hex.md) | Convert a set of l, c, and h values to a standard CSS-comptible hex string |
|
||||
| [lighten(css, value)](./color.lighten.md) | Lighten a standard CSS color |
|
||||
|
@ -52,14 +53,22 @@
|
|||
| [ColorBlindnessMeta](./color.colorblindnessmeta.md) | Interface for meta container about color blindness. Note that incidence is the reported number for males, as female color blindness is very rare in comparison (overall 1 in 12 males, 1 in 200 females) |
|
||||
| [Hsl](./color.hsl.md) | |
|
||||
| [Hsv](./color.hsv.md) | |
|
||||
| [Params](./color.params.md) | This is the core set of parameters for generating schemes using the ColorPicker |
|
||||
| [Rgb](./color.rgb.md) | |
|
||||
| [Rgba](./color.rgba.md) | |
|
||||
| [Scheme](./color.scheme.md) | Core color properties for a computed color scheme. Note the values are all strings - our color default representation uses hex codes. |
|
||||
| [SchemeParams](./color.schemeparams.md) | This is the core set of parameters for generating schemes using the ColorPicker |
|
||||
| [TuningParameters](./color.tuningparameters.md) | Detailed tuning for the scale generation algorithms. |
|
||||
|
||||
## Variables
|
||||
|
||||
| Variable | Description |
|
||||
| --- | --- |
|
||||
| [defaultParams](./color.defaultparams.md) | |
|
||||
| [defaultParams](./color.defaultparams.md) | Default set of params useful for initializing new themes with our "standard look". |
|
||||
|
||||
## Type Aliases
|
||||
|
||||
| Type Alias | Description |
|
||||
| --- | --- |
|
||||
| [HslVector](./color.hslvector.md) | |
|
||||
| [RGBAV](./color.rgbav.md) | |
|
||||
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Params](./color.params.md) > [accentHue](./color.params.accenthue.md)
|
||||
|
||||
## Params.accentHue property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
accentHue: number;
|
||||
```
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Params](./color.params.md) > [accentLuminance](./color.params.accentluminance.md)
|
||||
|
||||
## Params.accentLuminance property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
accentLuminance: number;
|
||||
```
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Params](./color.params.md) > [accentSaturation](./color.params.accentsaturation.md)
|
||||
|
||||
## Params.accentSaturation property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
accentSaturation: number;
|
||||
```
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Params](./color.params.md) > [backgroundHueShift](./color.params.backgroundhueshift.md)
|
||||
|
||||
## Params.backgroundHueShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
backgroundHueShift: number;
|
||||
```
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Params](./color.params.md) > [backgroundLevel](./color.params.backgroundlevel.md)
|
||||
|
||||
## Params.backgroundLevel property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
backgroundLevel: number;
|
||||
```
|
|
@ -1,25 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Params](./color.params.md)
|
||||
|
||||
## Params interface
|
||||
|
||||
This is the core set of parameters for generating schemes using the ColorPicker
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface Params
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Modifiers | Type | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [accentHue](./color.params.accenthue.md) | | number | |
|
||||
| [accentLuminance](./color.params.accentluminance.md) | | number | |
|
||||
| [accentSaturation](./color.params.accentsaturation.md) | | number | |
|
||||
| [backgroundHueShift](./color.params.backgroundhueshift.md) | | number | |
|
||||
| [backgroundLevel](./color.params.backgroundlevel.md) | | number | |
|
||||
| [nominalHueStep](./color.params.nominalhuestep.md) | | number | |
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Params](./color.params.md) > [nominalHueStep](./color.params.nominalhuestep.md)
|
||||
|
||||
## Params.nominalHueStep property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
nominalHueStep: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [RGBAV](./color.rgbav.md)
|
||||
|
||||
## RGBAV type
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare type RGBAV = [number, number, number, number];
|
||||
```
|
|
@ -7,14 +7,14 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export declare function rgbav2hex(rgbav: [number, number, number, number]): string;
|
||||
export declare function rgbav2hex(rgbav: RGBAV): string;
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| rgbav | \[number, number, number, number\] | |
|
||||
| rgbav | [RGBAV](./color.rgbav.md) | |
|
||||
|
||||
<b>Returns:</b>
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Scheme](./color.scheme.md) > [dataPrimary](./color.scheme.dataprimary.md)
|
||||
|
||||
## Scheme.dataPrimary property
|
||||
|
||||
Primary data color, derived from the accent.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
dataPrimary: string;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Scheme](./color.scheme.md) > [dataPrimaryBold](./color.scheme.dataprimarybold.md)
|
||||
|
||||
## Scheme.dataPrimaryBold property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
dataPrimaryBold: string;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Scheme](./color.scheme.md) > [dataPrimaryMuted](./color.scheme.dataprimarymuted.md)
|
||||
|
||||
## Scheme.dataPrimaryMuted property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
dataPrimaryMuted: string;
|
||||
```
|
|
@ -18,6 +18,9 @@ export interface Scheme
|
|||
| --- | --- | --- | --- |
|
||||
| [accent](./color.scheme.accent.md) | | string | |
|
||||
| [background](./color.scheme.background.md) | | string | |
|
||||
| [dataPrimary](./color.scheme.dataprimary.md) | | string | Primary data color, derived from the accent. |
|
||||
| [dataPrimaryBold](./color.scheme.dataprimarybold.md) | | string | |
|
||||
| [dataPrimaryMuted](./color.scheme.dataprimarymuted.md) | | string | |
|
||||
| [diverging](./color.scheme.diverging.md) | | string\[\] | |
|
||||
| [diverging2](./color.scheme.diverging2.md) | | string\[\] | |
|
||||
| [error](./color.scheme.error.md) | | string | |
|
||||
|
@ -33,6 +36,7 @@ export interface Scheme
|
|||
| [nominalBold](./color.scheme.nominalbold.md) | | string\[\] | |
|
||||
| [nominalMuted](./color.scheme.nominalmuted.md) | | string\[\] | |
|
||||
| [offsetBackground](./color.scheme.offsetbackground.md) | | string | |
|
||||
| [rainbow](./color.scheme.rainbow.md) | | string\[\] | |
|
||||
| [sequential](./color.scheme.sequential.md) | | string\[\] | |
|
||||
| [sequential2](./color.scheme.sequential2.md) | | string\[\] | |
|
||||
| [warning](./color.scheme.warning.md) | | string | |
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [Scheme](./color.scheme.md) > [rainbow](./color.scheme.rainbow.md)
|
||||
|
||||
## Scheme.rainbow property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rainbow: string[];
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md) > [accentHue](./color.schemeparams.accenthue.md)
|
||||
|
||||
## SchemeParams.accentHue property
|
||||
|
||||
HSL hue component for the accent. Valid range is 0-360 (degrees).
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
accentHue: number;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md) > [accentLightness](./color.schemeparams.accentlightness.md)
|
||||
|
||||
## SchemeParams.accentLightness property
|
||||
|
||||
HSL lightness component for the accent. Valid range is 0-100.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
accentLightness: number;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md) > [accentSaturation](./color.schemeparams.accentsaturation.md)
|
||||
|
||||
## SchemeParams.accentSaturation property
|
||||
|
||||
HSL saturation component for the accent. Valid range is 0-100.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
accentSaturation: number;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md) > [greyHue](./color.schemeparams.greyhue.md)
|
||||
|
||||
## SchemeParams.greyHue property
|
||||
|
||||
Optional hue to mix some of warm or cool into grey scales.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
greyHue?: number;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md) > [greySaturation](./color.schemeparams.greysaturation.md)
|
||||
|
||||
## SchemeParams.greySaturation property
|
||||
|
||||
Optional saturation to mix some of warm or cool into grey scales.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
greySaturation?: number;
|
||||
```
|
|
@ -0,0 +1,26 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md)
|
||||
|
||||
## SchemeParams interface
|
||||
|
||||
This is the core set of parameters for generating schemes using the ColorPicker
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface SchemeParams
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Modifiers | Type | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [accentHue](./color.schemeparams.accenthue.md) | | number | HSL hue component for the accent. Valid range is 0-360 (degrees). |
|
||||
| [accentLightness](./color.schemeparams.accentlightness.md) | | number | HSL lightness component for the accent. Valid range is 0-100. |
|
||||
| [accentSaturation](./color.schemeparams.accentsaturation.md) | | number | HSL saturation component for the accent. Valid range is 0-100. |
|
||||
| [greyHue?](./color.schemeparams.greyhue.md) | | number | <i>(Optional)</i> Optional hue to mix some of warm or cool into grey scales. |
|
||||
| [greySaturation?](./color.schemeparams.greysaturation.md) | | number | <i>(Optional)</i> Optional saturation to mix some of warm or cool into grey scales. |
|
||||
| [scaleLightness?](./color.schemeparams.scalelightness.md) | | number | <i>(Optional)</i> Sets the default lightness for nominal scales. Muted and bold scales are a fixed lightness +- |
|
||||
| [scaleSaturation?](./color.schemeparams.scalesaturation.md) | | number | <i>(Optional)</i> Sets the default saturation for nominal scales. Muted and bold scales are a fixed saturation +- |
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md) > [scaleLightness](./color.schemeparams.scalelightness.md)
|
||||
|
||||
## SchemeParams.scaleLightness property
|
||||
|
||||
Sets the default lightness for nominal scales. Muted and bold scales are a fixed lightness +-
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
scaleLightness?: number;
|
||||
```
|
|
@ -0,0 +1,13 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [SchemeParams](./color.schemeparams.md) > [scaleSaturation](./color.schemeparams.scalesaturation.md)
|
||||
|
||||
## SchemeParams.scaleSaturation property
|
||||
|
||||
Sets the default saturation for nominal scales. Muted and bold scales are a fixed saturation +-
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
scaleSaturation?: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [analogousRange](./color.tuningparameters.analogousrange.md)
|
||||
|
||||
## TuningParameters.analogousRange property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
analogousRange: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [backgroundHueShift](./color.tuningparameters.backgroundhueshift.md)
|
||||
|
||||
## TuningParameters.backgroundHueShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
backgroundHueShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [backgroundLevel](./color.tuningparameters.backgroundlevel.md)
|
||||
|
||||
## TuningParameters.backgroundLevel property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
backgroundLevel: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [complementaryRange](./color.tuningparameters.complementaryrange.md)
|
||||
|
||||
## TuningParameters.complementaryRange property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
complementaryRange: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [darkBackgroundLightnessShift](./color.tuningparameters.darkbackgroundlightnessshift.md)
|
||||
|
||||
## TuningParameters.darkBackgroundLightnessShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
darkBackgroundLightnessShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [darkestGrey](./color.tuningparameters.darkestgrey.md)
|
||||
|
||||
## TuningParameters.darkestGrey property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
darkestGrey: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [darkMaxLightnessOffet](./color.tuningparameters.darkmaxlightnessoffet.md)
|
||||
|
||||
## TuningParameters.darkMaxLightnessOffet property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
darkMaxLightnessOffet: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [darkTextLightness](./color.tuningparameters.darktextlightness.md)
|
||||
|
||||
## TuningParameters.darkTextLightness property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
darkTextLightness: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [lightBackgroundLightnessShift](./color.tuningparameters.lightbackgroundlightnessshift.md)
|
||||
|
||||
## TuningParameters.lightBackgroundLightnessShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
lightBackgroundLightnessShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [lightestGrey](./color.tuningparameters.lightestgrey.md)
|
||||
|
||||
## TuningParameters.lightestGrey property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
lightestGrey: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [lightMaxLightnessOffset](./color.tuningparameters.lightmaxlightnessoffset.md)
|
||||
|
||||
## TuningParameters.lightMaxLightnessOffset property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
lightMaxLightnessOffset: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [lightTextLightness](./color.tuningparameters.lighttextlightness.md)
|
||||
|
||||
## TuningParameters.lightTextLightness property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
lightTextLightness: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [lowContrastBackgroundShift](./color.tuningparameters.lowcontrastbackgroundshift.md)
|
||||
|
||||
## TuningParameters.lowContrastBackgroundShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
lowContrastBackgroundShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [maxBackgroundChroma](./color.tuningparameters.maxbackgroundchroma.md)
|
||||
|
||||
## TuningParameters.maxBackgroundChroma property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
maxBackgroundChroma: number;
|
||||
```
|
|
@ -0,0 +1,43 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md)
|
||||
|
||||
## TuningParameters interface
|
||||
|
||||
Detailed tuning for the scale generation algorithms.
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
export interface TuningParameters
|
||||
```
|
||||
|
||||
## Properties
|
||||
|
||||
| Property | Modifiers | Type | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [analogousRange](./color.tuningparameters.analogousrange.md) | | number | |
|
||||
| [backgroundHueShift](./color.tuningparameters.backgroundhueshift.md) | | number | |
|
||||
| [backgroundLevel](./color.tuningparameters.backgroundlevel.md) | | number | |
|
||||
| [complementaryRange](./color.tuningparameters.complementaryrange.md) | | number | |
|
||||
| [darkBackgroundLightnessShift](./color.tuningparameters.darkbackgroundlightnessshift.md) | | number | |
|
||||
| [darkestGrey](./color.tuningparameters.darkestgrey.md) | | number | |
|
||||
| [darkMaxLightnessOffet](./color.tuningparameters.darkmaxlightnessoffet.md) | | number | |
|
||||
| [darkTextLightness](./color.tuningparameters.darktextlightness.md) | | number | |
|
||||
| [lightBackgroundLightnessShift](./color.tuningparameters.lightbackgroundlightnessshift.md) | | number | |
|
||||
| [lightestGrey](./color.tuningparameters.lightestgrey.md) | | number | |
|
||||
| [lightMaxLightnessOffset](./color.tuningparameters.lightmaxlightnessoffset.md) | | number | |
|
||||
| [lightTextLightness](./color.tuningparameters.lighttextlightness.md) | | number | |
|
||||
| [lowContrastBackgroundShift](./color.tuningparameters.lowcontrastbackgroundshift.md) | | number | |
|
||||
| [maxBackgroundChroma](./color.tuningparameters.maxbackgroundchroma.md) | | number | |
|
||||
| [minNominalLightness](./color.tuningparameters.minnominallightness.md) | | number | |
|
||||
| [minNominalSaturation](./color.tuningparameters.minnominalsaturation.md) | | number | |
|
||||
| [nominalBoldLightnessShift](./color.tuningparameters.nominalboldlightnessshift.md) | | number | |
|
||||
| [nominalBoldSaturationShift](./color.tuningparameters.nominalboldsaturationshift.md) | | number | |
|
||||
| [nominalHueStep](./color.tuningparameters.nominalhuestep.md) | | number | |
|
||||
| [nominalMutedLightnessShift](./color.tuningparameters.nominalmutedlightnessshift.md) | | number | |
|
||||
| [nominalMutedSaturationShift](./color.tuningparameters.nominalmutedsaturationshift.md) | | number | |
|
||||
| [offsetBackgroundLightnessShift](./color.tuningparameters.offsetbackgroundlightnessshift.md) | | number | |
|
||||
| [polynomialExponent](./color.tuningparameters.polynomialexponent.md) | | number | |
|
||||
| [reservedDataColors](./color.tuningparameters.reserveddatacolors.md) | | number | |
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [minNominalLightness](./color.tuningparameters.minnominallightness.md)
|
||||
|
||||
## TuningParameters.minNominalLightness property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
minNominalLightness: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [minNominalSaturation](./color.tuningparameters.minnominalsaturation.md)
|
||||
|
||||
## TuningParameters.minNominalSaturation property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
minNominalSaturation: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [nominalBoldLightnessShift](./color.tuningparameters.nominalboldlightnessshift.md)
|
||||
|
||||
## TuningParameters.nominalBoldLightnessShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
nominalBoldLightnessShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [nominalBoldSaturationShift](./color.tuningparameters.nominalboldsaturationshift.md)
|
||||
|
||||
## TuningParameters.nominalBoldSaturationShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
nominalBoldSaturationShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [nominalHueStep](./color.tuningparameters.nominalhuestep.md)
|
||||
|
||||
## TuningParameters.nominalHueStep property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
nominalHueStep: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [nominalMutedLightnessShift](./color.tuningparameters.nominalmutedlightnessshift.md)
|
||||
|
||||
## TuningParameters.nominalMutedLightnessShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
nominalMutedLightnessShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [nominalMutedSaturationShift](./color.tuningparameters.nominalmutedsaturationshift.md)
|
||||
|
||||
## TuningParameters.nominalMutedSaturationShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
nominalMutedSaturationShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [offsetBackgroundLightnessShift](./color.tuningparameters.offsetbackgroundlightnessshift.md)
|
||||
|
||||
## TuningParameters.offsetBackgroundLightnessShift property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
offsetBackgroundLightnessShift: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [polynomialExponent](./color.tuningparameters.polynomialexponent.md)
|
||||
|
||||
## TuningParameters.polynomialExponent property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
polynomialExponent: number;
|
||||
```
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/color](./color.md) > [TuningParameters](./color.tuningparameters.md) > [reservedDataColors](./color.tuningparameters.reserveddatacolors.md)
|
||||
|
||||
## TuningParameters.reservedDataColors property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
reservedDataColors: number;
|
||||
```
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -14,20 +14,16 @@ export class Color {
|
|||
// (undocumented)
|
||||
hex(alpha?: number): string;
|
||||
// (undocumented)
|
||||
hsl(): {
|
||||
h: number;
|
||||
s: number;
|
||||
l: number;
|
||||
};
|
||||
hsl(): Hsl;
|
||||
// (undocumented)
|
||||
hsluv(): [number, number, number];
|
||||
hsluv(): HslVector;
|
||||
get raw(): string;
|
||||
// (undocumented)
|
||||
rgba(alpha?: number): Rgba;
|
||||
// (undocumented)
|
||||
rgbaint(alpha?: number): number;
|
||||
// (undocumented)
|
||||
rgbav(alpha?: number): [number, number, number, number];
|
||||
rgbav(alpha?: number): RGBAV;
|
||||
// (undocumented)
|
||||
toString(): string;
|
||||
}
|
||||
|
@ -72,6 +68,8 @@ export enum ColorBlindnessMode {
|
|||
export enum ColorSpace {
|
||||
CSS = "css",
|
||||
HEX = "hex",
|
||||
HSL = "hsl",
|
||||
HSLUV = "hsluv",
|
||||
RGB = "rgb",
|
||||
RGBA = "rgba",
|
||||
RGBA_NUMBER = "rgbaint",
|
||||
|
@ -101,7 +99,7 @@ export function css2hsl(css: string, _alpha?: number): Hsl;
|
|||
// Warning: (ae-missing-release-tag) "css2hsluv" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export function css2hsluv(css: string): [number, number, number];
|
||||
export function css2hsluv(css: string): HslVector;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "css2hsv" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -111,7 +109,7 @@ export function css2hsv(css: string, _alpha?: number): Hsv;
|
|||
// Warning: (ae-missing-release-tag) "css2lch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export function css2lch(css: string): [number, number, number];
|
||||
export function css2lch(css: string): HslVector;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "css2rgb" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -123,15 +121,15 @@ export function css2rgb(css: string, _alpha?: number): Rgb;
|
|||
// @public
|
||||
export function css2rgba(css: string, alpha?: number): Rgba;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "css2rgbaNumber" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
// Warning: (ae-missing-release-tag) "css2rgbaint" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export function css2rgbaNumber(css: string, alpha?: number): number;
|
||||
export function css2rgbaint(css: string, alpha?: number): number;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "css2rgbaVector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
// Warning: (ae-missing-release-tag) "css2rgbav" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export function css2rgbaVector(css: string, alpha?: number): [number, number, number, number];
|
||||
export function css2rgbav(css: string, alpha?: number): [number, number, number, number];
|
||||
|
||||
// Warning: (ae-missing-release-tag) "darken" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -140,14 +138,15 @@ export function darken(css: string, value?: number): string;
|
|||
|
||||
// Warning: (ae-missing-release-tag) "defaultParams" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
// @public
|
||||
export const defaultParams: {
|
||||
accentHue: number;
|
||||
accentSaturation: number;
|
||||
accentLuminance: number;
|
||||
backgroundHueShift: number;
|
||||
backgroundLevel: number;
|
||||
nominalHueStep: number;
|
||||
accentLightness: number;
|
||||
scaleSaturation: number;
|
||||
scaleLightness: number;
|
||||
greyHue: number;
|
||||
greySaturation: number;
|
||||
};
|
||||
|
||||
// Warning: (ae-missing-release-tag) "getNamedSchemeColor" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
@ -157,8 +156,8 @@ export function getNamedSchemeColor(scheme: Scheme, path?: string): Color;
|
|||
|
||||
// Warning: (ae-missing-release-tag) "getScheme" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function getScheme(params: Params, nominalItemCount: number, sequentialItemCount: number, light: boolean): Scheme;
|
||||
// @public
|
||||
export function getScheme(params: SchemeParams, nominalItemCount: number, sequentialItemCount: number, light: boolean, tuning?: Partial<TuningParameters>): Scheme;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Hsl" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -175,7 +174,17 @@ export interface Hsl {
|
|||
// Warning: (ae-missing-release-tag) "hsluv2hex" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function hsluv2hex(h: number, s: number, l: number): string;
|
||||
export function hsluv2hex(hsluv: HslVector): string;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "hsluv2hsl" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function hsluv2hsl(hsluv: HslVector): HslVector;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "HslVector" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type HslVector = [number, number, number];
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Hsv" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -209,24 +218,6 @@ export function lighten(css: string, value?: number): string;
|
|||
// @public
|
||||
export function nearest(input: Color, list: Color[]): Color;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Params" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export interface Params {
|
||||
// (undocumented)
|
||||
accentHue: number;
|
||||
// (undocumented)
|
||||
accentLuminance: number;
|
||||
// (undocumented)
|
||||
accentSaturation: number;
|
||||
// (undocumented)
|
||||
backgroundHueShift: number;
|
||||
// (undocumented)
|
||||
backgroundLevel: number;
|
||||
// (undocumented)
|
||||
nominalHueStep: number;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Rgb" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
|
@ -252,10 +243,15 @@ export interface Rgba extends Rgb {
|
|||
// @public (undocumented)
|
||||
export function rgba2hex(rgba: Rgba): string;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "RGBAV" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export type RGBAV = [number, number, number, number];
|
||||
|
||||
// Warning: (ae-missing-release-tag) "rgbav2hex" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public (undocumented)
|
||||
export function rgbav2hex(rgbav: [number, number, number, number]): string;
|
||||
export function rgbav2hex(rgbav: RGBAV): string;
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Scheme" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -265,6 +261,11 @@ export interface Scheme {
|
|||
accent: string;
|
||||
// (undocumented)
|
||||
background: string;
|
||||
dataPrimary: string;
|
||||
// (undocumented)
|
||||
dataPrimaryBold: string;
|
||||
// (undocumented)
|
||||
dataPrimaryMuted: string;
|
||||
// (undocumented)
|
||||
diverging: string[];
|
||||
// (undocumented)
|
||||
|
@ -296,6 +297,8 @@ export interface Scheme {
|
|||
// (undocumented)
|
||||
offsetBackground: string;
|
||||
// (undocumented)
|
||||
rainbow: string[];
|
||||
// (undocumented)
|
||||
sequential: string[];
|
||||
// (undocumented)
|
||||
sequential2: string[];
|
||||
|
@ -303,6 +306,73 @@ export interface Scheme {
|
|||
warning: string;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "SchemeParams" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export interface SchemeParams {
|
||||
accentHue: number;
|
||||
accentLightness: number;
|
||||
accentSaturation: number;
|
||||
greyHue?: number;
|
||||
greySaturation?: number;
|
||||
scaleLightness?: number;
|
||||
scaleSaturation?: number;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "TuningParameters" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
// @public
|
||||
export interface TuningParameters {
|
||||
// (undocumented)
|
||||
analogousRange: number;
|
||||
// (undocumented)
|
||||
backgroundHueShift: number;
|
||||
// (undocumented)
|
||||
backgroundLevel: number;
|
||||
// (undocumented)
|
||||
complementaryRange: number;
|
||||
// (undocumented)
|
||||
darkBackgroundLightnessShift: number;
|
||||
// (undocumented)
|
||||
darkestGrey: number;
|
||||
// (undocumented)
|
||||
darkMaxLightnessOffet: number;
|
||||
// (undocumented)
|
||||
darkTextLightness: number;
|
||||
// (undocumented)
|
||||
lightBackgroundLightnessShift: number;
|
||||
// (undocumented)
|
||||
lightestGrey: number;
|
||||
// (undocumented)
|
||||
lightMaxLightnessOffset: number;
|
||||
// (undocumented)
|
||||
lightTextLightness: number;
|
||||
// (undocumented)
|
||||
lowContrastBackgroundShift: number;
|
||||
// (undocumented)
|
||||
maxBackgroundChroma: number;
|
||||
// (undocumented)
|
||||
minNominalLightness: number;
|
||||
// (undocumented)
|
||||
minNominalSaturation: number;
|
||||
// (undocumented)
|
||||
nominalBoldLightnessShift: number;
|
||||
// (undocumented)
|
||||
nominalBoldSaturationShift: number;
|
||||
// (undocumented)
|
||||
nominalHueStep: number;
|
||||
// (undocumented)
|
||||
nominalMutedLightnessShift: number;
|
||||
// (undocumented)
|
||||
nominalMutedSaturationShift: number;
|
||||
// (undocumented)
|
||||
offsetBackgroundLightnessShift: number;
|
||||
// (undocumented)
|
||||
polynomialExponent: number;
|
||||
// (undocumented)
|
||||
reservedDataColors: number;
|
||||
}
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
||||
|
|
|
@ -69,11 +69,12 @@
|
|||
"css2lch": "function",
|
||||
"css2rgb": "function",
|
||||
"css2rgba": "function",
|
||||
"css2rgbaNumber": "function",
|
||||
"css2rgbaVector": "function",
|
||||
"css2rgbaint": "function",
|
||||
"css2rgbav": "function",
|
||||
"rgba2hex": "function",
|
||||
"rgbav2hex": "function",
|
||||
"hsluv2hex": "function",
|
||||
"hsluv2hsl": "function",
|
||||
"lch2hex": "function",
|
||||
"nearest": "function"
|
||||
},
|
||||
|
|
|
@ -8,10 +8,10 @@ import {
|
|||
css2hsl,
|
||||
css2hsluv,
|
||||
css2rgba,
|
||||
css2rgbaNumber,
|
||||
css2rgbaVector,
|
||||
css2rgbaint,
|
||||
css2rgbav,
|
||||
} from './chroma.js'
|
||||
import type { Rgba } from './types.js'
|
||||
import type { Hsl, HslVector, Rgba, RGBAV } from './types.js'
|
||||
|
||||
/**
|
||||
* This class represents an instance of a color.
|
||||
|
@ -41,19 +41,19 @@ export class Color {
|
|||
css(alpha?: number): string {
|
||||
return css2css(this._raw, alpha || this._alpha)
|
||||
}
|
||||
rgbav(alpha?: number): [number, number, number, number] {
|
||||
return css2rgbaVector(this._raw, alpha || this._alpha)
|
||||
rgbav(alpha?: number): RGBAV {
|
||||
return css2rgbav(this._raw, alpha || this._alpha)
|
||||
}
|
||||
rgbaint(alpha?: number): number {
|
||||
return css2rgbaNumber(this._raw, alpha || this._alpha)
|
||||
return css2rgbaint(this._raw, alpha || this._alpha)
|
||||
}
|
||||
rgba(alpha?: number): Rgba {
|
||||
return css2rgba(this._raw, alpha)
|
||||
}
|
||||
hsluv(): [number, number, number] {
|
||||
hsluv(): HslVector {
|
||||
return css2hsluv(this._raw)
|
||||
}
|
||||
hsl(): { h: number; s: number; l: number } {
|
||||
hsl(): Hsl {
|
||||
return css2hsl(this._raw)
|
||||
}
|
||||
toString(): string {
|
||||
|
|
|
@ -2,81 +2,82 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import { ColorMaker, polynomial_scale } from '../scheme/HsluvColorLogic.js'
|
||||
import { defaultParams } from '../index.js'
|
||||
import { getScheme, validateParams } from '../scheme/HsluvColorLogic.js'
|
||||
|
||||
const GREYS = [
|
||||
[50, 0, 92],
|
||||
[50, 0, 84],
|
||||
[50, 0, 76],
|
||||
[50, 0, 68],
|
||||
[50, 0, 60],
|
||||
[50, 0, 52],
|
||||
[50, 0, 44],
|
||||
[50, 0, 36.000000000000007],
|
||||
[50, 0, 28],
|
||||
[50, 0, 20],
|
||||
const NEUTRAL_GREYS = [
|
||||
'#f5f5f5',
|
||||
'#dddddd',
|
||||
'#c5c5c5',
|
||||
'#aeaeae',
|
||||
'#979797',
|
||||
'#818181',
|
||||
'#6c6c6c',
|
||||
'#575757',
|
||||
'#434343',
|
||||
'#303030',
|
||||
]
|
||||
|
||||
const SEQUENTIAL1 = [
|
||||
[50, 0, 92],
|
||||
[50, 25, 81.5],
|
||||
[50, 50, 71],
|
||||
[50, 75, 60.5],
|
||||
[50, 100, 50],
|
||||
const TINTED_GREYS = [
|
||||
'#f6f5f3',
|
||||
'#e0ddd5',
|
||||
'#c8c5be',
|
||||
'#b0aea7',
|
||||
'#999791',
|
||||
'#83817c',
|
||||
'#6d6c67',
|
||||
'#585754',
|
||||
'#444340',
|
||||
'#31302e',
|
||||
]
|
||||
|
||||
const SEQUENTIAL2 = [
|
||||
[58.57142857142857, 0, 92],
|
||||
[58.57142857142857, 25, 81.5],
|
||||
[58.57142857142857, 50, 71],
|
||||
[58.57142857142857, 75, 60.5],
|
||||
[58.57142857142857, 100, 50],
|
||||
]
|
||||
const SEQUENTIAL1 = ['#f5f5f5', '#dfd2c6', '#d4ad85', '#ba8c54', '#9d6e22']
|
||||
|
||||
const SEQUENTIAL2 = ['#f5f5f5', '#d9d1de', '#c5aad7', '#ba7cdd', '#b92fec']
|
||||
|
||||
const DIVERGING = [
|
||||
[140, 100, 50],
|
||||
[140, 71.55417527999329, 61.947246382402824],
|
||||
[140, 46.47580015448901, 72.48016393511462],
|
||||
[140, 25.29822128134704, 81.37474706183424],
|
||||
[140, 8.944271909999161, 88.24340579780035],
|
||||
[50, 8.944271909999161, 88.24340579780035],
|
||||
[50, 25.29822128134704, 81.37474706183424],
|
||||
[50, 46.47580015448901, 72.48016393511462],
|
||||
[50, 71.55417527999329, 61.947246382402824],
|
||||
[50, 100, 50],
|
||||
'#238850',
|
||||
'#5ba978',
|
||||
'#8dc59f',
|
||||
'#badcc4',
|
||||
'#e3ebe5',
|
||||
'#ebe9e7',
|
||||
'#dfd1c6',
|
||||
'#d7b28c',
|
||||
'#be915a',
|
||||
'#9d6e22',
|
||||
]
|
||||
|
||||
describe('ColorMaker', () => {
|
||||
test('can be instantiated', () => {
|
||||
expect(() => new ColorMaker([50, 50, 50], 50, 50, 50, true)).not.toThrow()
|
||||
// TODO: test light v dark
|
||||
|
||||
describe('getScheme', () => {
|
||||
test('creates neutral grey scales (no saturation)', () => {
|
||||
const scheme = getScheme(
|
||||
{
|
||||
accentHue: 50,
|
||||
accentSaturation: 50,
|
||||
accentLightness: 50,
|
||||
greySaturation: 0,
|
||||
},
|
||||
10,
|
||||
10,
|
||||
true,
|
||||
)
|
||||
expect(scheme.greys).toEqual(NEUTRAL_GREYS)
|
||||
})
|
||||
|
||||
test('can create grey scales', () => {
|
||||
const colorMaker = new ColorMaker([50, 50, 50], 50, 50, 50, true)
|
||||
const greys = colorMaker.grey(10)
|
||||
expect(greys).toEqual(GREYS)
|
||||
})
|
||||
|
||||
test('can create sequential scales', () => {
|
||||
const colorMaker = new ColorMaker([50, 50, 50], 50, 50, 50, true)
|
||||
const sequential1 = colorMaker.sequential(5)
|
||||
const sequential2 = colorMaker.sequential(5, 1)
|
||||
expect(sequential1).toEqual(SEQUENTIAL1)
|
||||
expect(sequential2).toEqual(SEQUENTIAL2)
|
||||
})
|
||||
|
||||
test('can create diverging scales', () => {
|
||||
const colorMaker = new ColorMaker([50, 50, 50], 50, 50, 50, true)
|
||||
const diverging = colorMaker.diverging(10)
|
||||
expect(diverging).toEqual(DIVERGING)
|
||||
})
|
||||
|
||||
test('has polynomial scales', () => {
|
||||
const scale1 = polynomial_scale(1, 0, 10, 11).map(x => Math.round(x))
|
||||
expect(scale1).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
|
||||
const scale2 = polynomial_scale(2, 0, 64, 8).map(x => Math.round(x))
|
||||
expect(scale2).toEqual([0, 1, 5, 12, 21, 33, 47, 64])
|
||||
test('creates tinted grey scales (default)', () => {
|
||||
const scheme = getScheme(
|
||||
{
|
||||
accentHue: 50,
|
||||
accentSaturation: 50,
|
||||
accentLightness: 50,
|
||||
},
|
||||
10,
|
||||
10,
|
||||
true,
|
||||
)
|
||||
expect(scheme.greys).toEqual(TINTED_GREYS)
|
||||
})
|
||||
|
||||
describe('nominal count matches requested size', () => {
|
||||
|
@ -84,21 +85,96 @@ describe('ColorMaker', () => {
|
|||
// but this can result in mismatched final counts
|
||||
// ensure that the resulting nominal scales are trimmed correctly
|
||||
test('default hue step (10)', () => {
|
||||
const colorMaker = new ColorMaker([50, 50, 50], 50, 50, 10, true)
|
||||
const scale = colorMaker.nominal(1)
|
||||
expect(scale.size).toBe(1)
|
||||
const scheme = getScheme(
|
||||
{
|
||||
accentHue: 50,
|
||||
accentSaturation: 50,
|
||||
accentLightness: 50,
|
||||
},
|
||||
1,
|
||||
10,
|
||||
true,
|
||||
)
|
||||
expect(scheme.nominal).toHaveLength(1)
|
||||
})
|
||||
|
||||
test('hue step < 10 (3)', () => {
|
||||
const colorMaker = new ColorMaker([50, 50, 50], 50, 50, 3, true)
|
||||
const scale = colorMaker.nominal(1)
|
||||
expect(scale.size).toBe(1)
|
||||
const scheme = getScheme(
|
||||
{
|
||||
accentHue: 50,
|
||||
accentSaturation: 50,
|
||||
accentLightness: 50,
|
||||
},
|
||||
1,
|
||||
10,
|
||||
true,
|
||||
{
|
||||
nominalHueStep: 3,
|
||||
},
|
||||
)
|
||||
expect(scheme.nominal).toHaveLength(1)
|
||||
})
|
||||
|
||||
test('hue step > 10 (14)', () => {
|
||||
const colorMaker = new ColorMaker([50, 50, 50], 50, 50, 14, true)
|
||||
const scale = colorMaker.nominal(2)
|
||||
expect(scale.size).toBe(2)
|
||||
const scheme = getScheme(
|
||||
{
|
||||
accentHue: 50,
|
||||
accentSaturation: 50,
|
||||
accentLightness: 50,
|
||||
},
|
||||
2,
|
||||
10,
|
||||
true,
|
||||
{
|
||||
nominalHueStep: 14,
|
||||
},
|
||||
)
|
||||
expect(scheme.nominal).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('sequential scales', () => {
|
||||
test('creates sequential scales', () => {
|
||||
const scheme = getScheme(
|
||||
{
|
||||
accentHue: 50,
|
||||
accentSaturation: 50,
|
||||
accentLightness: 50,
|
||||
},
|
||||
10,
|
||||
5,
|
||||
true,
|
||||
)
|
||||
expect(scheme.sequential).toEqual(SEQUENTIAL1)
|
||||
expect(scheme.sequential2).toEqual(SEQUENTIAL2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('diverging scales', () => {
|
||||
test('creates diverging scales', () => {
|
||||
const scheme = getScheme(
|
||||
{
|
||||
accentHue: 50,
|
||||
accentSaturation: 50,
|
||||
accentLightness: 50,
|
||||
},
|
||||
10,
|
||||
10,
|
||||
true,
|
||||
)
|
||||
expect(scheme.diverging).toEqual(DIVERGING)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('validateParams', () => {
|
||||
test('fill in defaults', () => {
|
||||
const params = validateParams({
|
||||
accentHue: 100,
|
||||
accentLightness: 100,
|
||||
accentSaturation: 100,
|
||||
})
|
||||
expect(params.greyHue).toBe(defaultParams.greyHue)
|
||||
expect(params.greySaturation).toBe(defaultParams.greySaturation)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import { css2css, css2rgbaNumber, css2rgbaVector } from '../chroma.js'
|
||||
import { css2css, css2rgbaint, css2rgbav } from '../chroma.js'
|
||||
|
||||
describe('color conversion functions', () => {
|
||||
describe('css2css', () => {
|
||||
|
@ -14,48 +14,48 @@ describe('color conversion functions', () => {
|
|||
|
||||
describe('css => rgba vector', () => {
|
||||
test('default opacity in hex string', () => {
|
||||
const value = css2rgbaVector('#1f77b4')
|
||||
const value = css2rgbav('#1f77b4')
|
||||
expect(value).toEqual([
|
||||
0.12156862745098039, 0.4666666666666667, 0.7058823529411765, 1,
|
||||
])
|
||||
})
|
||||
|
||||
test('override opacity with alpha param', () => {
|
||||
const value = css2rgbaVector('#1f77b4', 0.5)
|
||||
const value = css2rgbav('#1f77b4', 0.5)
|
||||
expect(value).toEqual([
|
||||
0.12156862745098039, 0.4666666666666667, 0.7058823529411765, 0.5,
|
||||
])
|
||||
})
|
||||
|
||||
test('css "none" value', () => {
|
||||
const value = css2rgbaVector('none')
|
||||
const value = css2rgbav('none')
|
||||
expect(value).toEqual([0, 0, 0, 0])
|
||||
})
|
||||
})
|
||||
|
||||
describe('css => rgba number', () => {
|
||||
test('full opacity black', () => {
|
||||
const value = css2rgbaNumber('black')
|
||||
const value = css2rgbaint('black')
|
||||
expect(value).toBe(-16777216)
|
||||
})
|
||||
|
||||
test('zero opacity black', () => {
|
||||
const value = css2rgbaNumber('black', 0)
|
||||
const value = css2rgbaint('black', 0)
|
||||
expect(value).toBe(0)
|
||||
})
|
||||
|
||||
test('full opacity red', () => {
|
||||
const value = css2rgbaNumber('red', 1)
|
||||
const value = css2rgbaint('red', 1)
|
||||
expect(value).toBe(-16776961)
|
||||
})
|
||||
|
||||
test('zero opacity red', () => {
|
||||
const value = css2rgbaNumber('red', 0)
|
||||
const value = css2rgbaint('red', 0)
|
||||
expect(value).toBe(255)
|
||||
})
|
||||
|
||||
test('css "none" value', () => {
|
||||
const value = css2rgbaNumber('none')
|
||||
const value = css2rgbaint('none')
|
||||
expect(value).toBe(0)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('nearest', () => {
|
|||
test('orange', () => {
|
||||
const color = new Color('orange')
|
||||
const match = nearest(color, colors)
|
||||
expect(match.hex()).toBe('#ce9e3f')
|
||||
expect(match.hex()).toBe('#e7973c')
|
||||
})
|
||||
|
||||
test('yellow', () => {
|
||||
|
@ -127,7 +127,7 @@ describe('nearest', () => {
|
|||
test('indigo', () => {
|
||||
const color = new Color('indigo')
|
||||
const match = nearest(color, colors)
|
||||
expect(match.hex()).toBe('#d291f7')
|
||||
expect(match.hex()).toBe('#b197f3')
|
||||
})
|
||||
|
||||
test('violet', () => {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import { polynomialSequence } from '../scheme/utils.js'
|
||||
|
||||
describe('schema compute utils', () => {
|
||||
describe('polynomialSequence', () => {
|
||||
test('default linear', () => {
|
||||
const scale1 = polynomialSequence(0, 10, 11).map(x => Math.round(x))
|
||||
expect(scale1).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
|
||||
})
|
||||
|
||||
test('squared', () => {
|
||||
const scale2 = polynomialSequence(0, 64, 8, 2).map(x => Math.round(x))
|
||||
expect(scale2).toEqual([0, 1, 5, 12, 21, 33, 47, 64])
|
||||
})
|
||||
})
|
||||
})
|
|
@ -6,7 +6,7 @@
|
|||
import chroma from 'chroma-js'
|
||||
import { Hsluv } from 'hsluv'
|
||||
|
||||
import type { Hsl, Hsv, Rgb, Rgba } from './types.js'
|
||||
import type { Hsl, HslVector, Hsv, Rgb, Rgba, RGBAV } from './types.js'
|
||||
|
||||
/**
|
||||
* This is a variety of color utilities to minimize additional direct dependencies
|
||||
|
@ -18,34 +18,36 @@ import type { Hsl, Hsv, Rgb, Rgba } from './types.js'
|
|||
*
|
||||
* @param css - the css color hex string
|
||||
*/
|
||||
export function css2hsluv(css: string): [number, number, number] {
|
||||
export function css2hsluv(css: string): HslVector {
|
||||
const conv = new Hsluv()
|
||||
conv.hex = chroma(css).hex()
|
||||
conv.hexToHsluv()
|
||||
|
||||
return [conv.hsluv_h, conv.hsluv_s, conv.hsluv_l].map((v: number) =>
|
||||
Math.round(v),
|
||||
) as [number, number, number]
|
||||
) as HslVector
|
||||
}
|
||||
|
||||
export function hsluv2hex(h: number, s: number, l: number): string {
|
||||
export function hsluv2hex(hsluv: HslVector): string {
|
||||
const conv = new Hsluv()
|
||||
conv.hsluv_h = h
|
||||
conv.hsluv_s = s
|
||||
conv.hsluv_l = l
|
||||
conv.hsluv_h = hsluv[0]
|
||||
conv.hsluv_s = hsluv[1]
|
||||
conv.hsluv_l = hsluv[2]
|
||||
conv.hsluvToHex()
|
||||
return conv.hex
|
||||
}
|
||||
|
||||
export function hsluv2hsl(hsluv: HslVector): HslVector {
|
||||
return chroma(hsluv2hex(hsluv)).hsl()
|
||||
}
|
||||
/**
|
||||
* Convert a standard CSS-compatible string to [l, c, h] array
|
||||
*
|
||||
* @param css - the css color hex string
|
||||
*/
|
||||
export function css2lch(css: string): [number, number, number] {
|
||||
export function css2lch(css: string): HslVector {
|
||||
return chroma(css)
|
||||
.lch()
|
||||
.map((v: number) => Math.round(v)) as [number, number, number]
|
||||
.map((v: number) => Math.round(v)) as HslVector
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -227,7 +229,7 @@ export function css2hex(css: string, alpha?: number): string {
|
|||
* @param css - the css color hex string
|
||||
* @param alpha - optional alpha override from 0-1. Not all CSS strings include alpha, so you can provide it if needed.
|
||||
*/
|
||||
export function css2rgbaVector(
|
||||
export function css2rgbav(
|
||||
css: string,
|
||||
alpha?: number,
|
||||
): [number, number, number, number] {
|
||||
|
@ -246,7 +248,7 @@ export function css2rgbaVector(
|
|||
* @param css - the css color hex string
|
||||
* @param alpha - the alpha value to use [0-1]
|
||||
*/
|
||||
export function css2rgbaNumber(css: string, alpha?: number): number {
|
||||
export function css2rgbaint(css: string, alpha?: number): number {
|
||||
if (css === 'none') {
|
||||
return 0
|
||||
}
|
||||
|
@ -260,6 +262,6 @@ export function css2rgbaNumber(css: string, alpha?: number): number {
|
|||
return color
|
||||
}
|
||||
|
||||
export function rgbav2hex(rgbav: [number, number, number, number]): string {
|
||||
export function rgbav2hex(rgbav: RGBAV): string {
|
||||
return chroma(rgbav).hex()
|
||||
}
|
||||
|
|
|
@ -9,12 +9,15 @@ export * from './nearest.js'
|
|||
export * from './scheme.js'
|
||||
export * from './types.js'
|
||||
|
||||
// TODO: best would be to update the scheme compute to accept undefined or baseline params and handle an "empty" case, which is maybe grayscale
|
||||
/**
|
||||
* Default set of params useful for initializing new themes with our "standard look".
|
||||
*/
|
||||
export const defaultParams = {
|
||||
accentHue: 252,
|
||||
accentSaturation: 89,
|
||||
accentLuminance: 50,
|
||||
backgroundHueShift: 50,
|
||||
backgroundLevel: 95,
|
||||
nominalHueStep: 10,
|
||||
accentLightness: 50,
|
||||
scaleSaturation: 90,
|
||||
scaleLightness: 67,
|
||||
greyHue: 72,
|
||||
greySaturation: 7,
|
||||
}
|
||||
|
|
|
@ -15,11 +15,11 @@ import type { Color } from './Color.js'
|
|||
* @param list
|
||||
*/
|
||||
export function nearest(input: Color, list: Color[]): Color {
|
||||
const hsl = input.hsl()
|
||||
const hsl = input.hsluv()
|
||||
const distances = list.map(color => {
|
||||
const hsl2 = color.hsl()
|
||||
const left = hsl.h
|
||||
const right = hsl2.h
|
||||
const hsl2 = color.hsluv()
|
||||
const left = hsl[0]
|
||||
const right = hsl2[0]
|
||||
let delta1 = Math.abs(left - right)
|
||||
if (delta1 > 180) {
|
||||
delta1 = 360 - delta1
|
||||
|
|
|
@ -2,449 +2,365 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import chroma from 'chroma-js'
|
||||
|
||||
import { hsluv2hex } from '../chroma.js'
|
||||
import type { Params, Scheme } from '../types'
|
||||
import { defaultParams } from '../index.js'
|
||||
import type {
|
||||
HslVector,
|
||||
Scheme,
|
||||
SchemeParams,
|
||||
TuningParameters,
|
||||
} from '../types'
|
||||
import {
|
||||
getAnnotations,
|
||||
getBackgroundHsl,
|
||||
getDivergingSequence,
|
||||
getForegroundHsl,
|
||||
getGreyLightness,
|
||||
getNominalHues,
|
||||
getNominalRainbowSequence,
|
||||
getNominalSequence,
|
||||
getNominalShiftedSequence,
|
||||
getOffsetBackgroundHsl,
|
||||
getSequentialSequence,
|
||||
greySequence,
|
||||
} from './functions.js'
|
||||
|
||||
const lightTextLuminance = 95
|
||||
const darkTextLuminance = 20
|
||||
const lightScaleLuminance = 70
|
||||
const darkScaleLuminance = 70
|
||||
const maxSaturation = 100
|
||||
const maxLightLuminanceOffset = 5
|
||||
const maxDarkLuminanceOffset = 10
|
||||
const maxBackgroundChroma = 4 // absolute
|
||||
const lightScaleBackgroundLuminanceShift = 10
|
||||
const darkScaleBackgroundLuminanceShift = 3
|
||||
const analogousRange = 60
|
||||
const complementaryRange = 60
|
||||
const nominalSaturation = 90
|
||||
const nominalLighterShift = 15
|
||||
const nominalDarkerShift = 30
|
||||
const boldSaturationShift = 10
|
||||
const mutedSaturationShift = 55
|
||||
const minNominalSaturation = 10
|
||||
const minNominalLuminance = 50
|
||||
const linearExponent = 1
|
||||
const polynomialExponent = 1.5
|
||||
const lowContrastBackgroundShift = 20
|
||||
const darkestGrey = 20
|
||||
const lightestGrey = 90
|
||||
const offsetBackgroundLuminanceShift = 1
|
||||
function getDefaultTuning(
|
||||
tuning?: Partial<TuningParameters>,
|
||||
): Required<TuningParameters> {
|
||||
return {
|
||||
analogousRange: 60,
|
||||
complementaryRange: 60,
|
||||
|
||||
export interface NominalHueSequence {
|
||||
bold: [number, number, number][]
|
||||
std: [number, number, number][]
|
||||
muted: [number, number, number][]
|
||||
hues: number[]
|
||||
size: number
|
||||
}
|
||||
lightTextLightness: 95,
|
||||
lightMaxLightnessOffset: 5,
|
||||
lightBackgroundLightnessShift: 10,
|
||||
|
||||
export function polynomial_scale(
|
||||
exp: number,
|
||||
start: number,
|
||||
end: number,
|
||||
size: number,
|
||||
): number[] {
|
||||
const base = 1 / (size - 1)
|
||||
const interval = end - start
|
||||
const result: number[] = []
|
||||
for (let i = 0; i < size; i++) {
|
||||
result.push(start + interval * (i * base) ** exp)
|
||||
}
|
||||
return result
|
||||
}
|
||||
darkTextLightness: 20,
|
||||
darkMaxLightnessOffet: 10,
|
||||
darkBackgroundLightnessShift: 3,
|
||||
|
||||
export type HSLVector = [number, number, number]
|
||||
backgroundLevel: 95,
|
||||
backgroundHueShift: 50,
|
||||
|
||||
export function polynomial_hsl_scale(
|
||||
exp: number,
|
||||
[sh, ss, sl]: HSLVector,
|
||||
[eh, es, el]: HSLVector,
|
||||
size: number,
|
||||
): HSLVector[] {
|
||||
const hues = polynomial_scale(exp, sh, eh, size)
|
||||
const saturations = polynomial_scale(exp, ss, es, size)
|
||||
const luminances = polynomial_scale(exp, sl, el, size)
|
||||
const hexvalues: HSLVector[] = []
|
||||
for (let i = 0; i < size; i++) {
|
||||
hexvalues.push([
|
||||
hues[i] as number,
|
||||
saturations[i] as number,
|
||||
luminances[i] as number,
|
||||
])
|
||||
}
|
||||
return hexvalues
|
||||
}
|
||||
nominalHueStep: 10,
|
||||
minNominalSaturation: 10,
|
||||
minNominalLightness: 50,
|
||||
|
||||
// Based on a maximum hue shift of 100 (from the slider)
|
||||
function getOffsetHue([h]: HSLVector, hueShift: number) {
|
||||
if (hueShift >= 25 && hueShift <= 75) {
|
||||
// analogous range
|
||||
const delta = (analogousRange * (hueShift - 50)) / 25
|
||||
return (h + delta) % 360
|
||||
} else if (hueShift > 75) {
|
||||
// clockwise complementary range
|
||||
const delta = 180 - (complementaryRange * (100 - hueShift)) / 25
|
||||
return (h + delta) % 360
|
||||
} else {
|
||||
// anticlockwise complementary range
|
||||
const delta = 180 + (complementaryRange * hueShift) / 25
|
||||
return (h + delta) % 360
|
||||
nominalMutedSaturationShift: -55,
|
||||
nominalMutedLightnessShift: 15,
|
||||
|
||||
nominalBoldSaturationShift: 10,
|
||||
nominalBoldLightnessShift: -30,
|
||||
|
||||
maxBackgroundChroma: 4,
|
||||
lowContrastBackgroundShift: 20,
|
||||
offsetBackgroundLightnessShift: 1,
|
||||
lightestGrey: 90,
|
||||
darkestGrey: 20,
|
||||
polynomialExponent: 1.5,
|
||||
reservedDataColors: 1,
|
||||
...tuning,
|
||||
}
|
||||
}
|
||||
|
||||
function getBackgroundSaturationaAndLuminance(
|
||||
hue: number,
|
||||
backgroundLevel: number,
|
||||
light: boolean,
|
||||
): [number, number] {
|
||||
function normalizeSaturation(_h: number, l: number) {
|
||||
let satGivingMaxChroma = 100
|
||||
let c = chroma.hex(hsluv2hex(hue, 100, l)).hcl()[1]
|
||||
while (c > maxBackgroundChroma && satGivingMaxChroma >= 0) {
|
||||
satGivingMaxChroma -= 1
|
||||
c = chroma.hex(hsluv2hex(hue, satGivingMaxChroma, l)).hcl()[1]
|
||||
}
|
||||
return satGivingMaxChroma
|
||||
}
|
||||
if (light) {
|
||||
if (backgroundLevel < 50) {
|
||||
const l = 100 - maxLightLuminanceOffset
|
||||
return [(backgroundLevel * normalizeSaturation(hue, l)) / 50, l]
|
||||
} else {
|
||||
const l =
|
||||
100 - maxLightLuminanceOffset * (1 - (backgroundLevel - 50) / 50)
|
||||
return [normalizeSaturation(hue, l), l]
|
||||
}
|
||||
} else {
|
||||
if (backgroundLevel < 50) {
|
||||
const l = maxDarkLuminanceOffset
|
||||
return [(backgroundLevel * normalizeSaturation(hue, l)) / 50, l]
|
||||
} else {
|
||||
const l = maxDarkLuminanceOffset * (1 - (backgroundLevel - 50) / 50)
|
||||
return [normalizeSaturation(hue, l), l]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ColorMaker {
|
||||
public readonly textLuminance: number
|
||||
public readonly scaleLuminance: number
|
||||
public readonly backgroundHsl: [number, number, number]
|
||||
public readonly offsetbackgroundHsl: [number, number, number]
|
||||
public readonly foregroundHsl: [number, number, number]
|
||||
public readonly faintAnnotationHsl: [number, number, number]
|
||||
public readonly lowContrastAnnotationHsl: [number, number, number]
|
||||
public readonly lowMidContrastAnnotationHsl: [number, number, number]
|
||||
public readonly midContrastAnnotationHsl: [number, number, number]
|
||||
public readonly midHighContrastAnnotationHsl: [number, number, number]
|
||||
public readonly highContrastAnnotationHsl: [number, number, number]
|
||||
public readonly greyLuminance: number
|
||||
|
||||
private cachedNominalSequence: NominalHueSequence | undefined
|
||||
|
||||
public constructor(
|
||||
public readonly accentHsl: [number, number, number],
|
||||
public readonly backgroundLevel: number,
|
||||
public readonly backgroundHueShift: number,
|
||||
public readonly nominalHueStep: number,
|
||||
public readonly light: boolean,
|
||||
) {
|
||||
this.textLuminance = light ? darkTextLuminance : lightTextLuminance
|
||||
this.scaleLuminance = light ? darkScaleLuminance : lightScaleLuminance
|
||||
|
||||
const h = getOffsetHue(this.accentHsl, this.backgroundHueShift)
|
||||
const [s, l] = getBackgroundSaturationaAndLuminance(
|
||||
h,
|
||||
this.backgroundLevel,
|
||||
this.light,
|
||||
)
|
||||
this.backgroundHsl = [h, s, l]
|
||||
const offsetBackgroundLuminance = light
|
||||
? Math.min(100, l + offsetBackgroundLuminanceShift)
|
||||
: Math.max(0, l - offsetBackgroundLuminanceShift)
|
||||
this.offsetbackgroundHsl = [h, s, offsetBackgroundLuminance]
|
||||
this.foregroundHsl = [0, 0, this.textLuminance]
|
||||
|
||||
this.greyLuminance = this.light
|
||||
? this.backgroundHsl[2] - darkScaleBackgroundLuminanceShift
|
||||
: this.backgroundHsl[2] + lightScaleBackgroundLuminanceShift
|
||||
const mutedGreyLuminance = this.light
|
||||
? this.backgroundHsl[2] - lowContrastBackgroundShift
|
||||
: this.backgroundHsl[2] + lowContrastBackgroundShift
|
||||
|
||||
const boldGreyLuminance = this.light ? darkestGrey : lightestGrey
|
||||
const greys = this.explicitGrey(5, mutedGreyLuminance, boldGreyLuminance)
|
||||
this.lowContrastAnnotationHsl = greys[0] as HSLVector
|
||||
this.lowMidContrastAnnotationHsl = greys[1] as HSLVector
|
||||
this.midContrastAnnotationHsl = greys[2] as HSLVector
|
||||
this.midHighContrastAnnotationHsl = greys[3] as HSLVector
|
||||
this.highContrastAnnotationHsl = greys[4] as HSLVector
|
||||
// halfway to the background from the darkest/lightest
|
||||
const faintLuminance = this.light
|
||||
? (100 - lightestGrey) / 2 + lightestGrey
|
||||
: darkestGrey / 2
|
||||
this.faintAnnotationHsl = [this.accentHsl[0], 0, faintLuminance]
|
||||
}
|
||||
|
||||
public grey(size: number): HSLVector[] {
|
||||
const boldGreyLuminance = this.light ? darkestGrey : lightestGrey
|
||||
return this.explicitGrey(size, this.greyLuminance, boldGreyLuminance)
|
||||
}
|
||||
|
||||
public nominal(size: number): NominalHueSequence {
|
||||
if (
|
||||
!this.cachedNominalSequence ||
|
||||
this.cachedNominalSequence.size !== size
|
||||
) {
|
||||
const { nominalBold, nominal, nominalMuted, nominalHues } =
|
||||
this.getNominalHueSequences(size)
|
||||
this.cachedNominalSequence = {
|
||||
bold: nominalBold,
|
||||
std: nominal,
|
||||
muted: nominalMuted,
|
||||
hues: nominalHues,
|
||||
size: nominal.length,
|
||||
}
|
||||
}
|
||||
return this.cachedNominalSequence
|
||||
}
|
||||
|
||||
private explicitGrey(
|
||||
size: number,
|
||||
startLuminance: number,
|
||||
endLuminance: number,
|
||||
) {
|
||||
const greyFrom: HSLVector = [this.accentHsl[0], 0, startLuminance]
|
||||
const greyTo: HSLVector = [this.accentHsl[0], 0, endLuminance]
|
||||
return polynomial_hsl_scale(linearExponent, greyFrom, greyTo, size)
|
||||
}
|
||||
|
||||
private getAccentsAndComplements(
|
||||
size: number,
|
||||
offset: number,
|
||||
): {
|
||||
greyAccent: HSLVector
|
||||
greyComplement: HSLVector
|
||||
maxSaturationAccent: HSLVector
|
||||
maxSaturationComplement: HSLVector
|
||||
} {
|
||||
const { hues: nominalHues } = this.nominal(size)
|
||||
|
||||
const accentHue = nominalHues[offset % nominalHues.length] as number
|
||||
|
||||
const colorLuminance = this.accentHsl[2]
|
||||
const greyLuminance = this.greyLuminance
|
||||
const complementHue = (accentHue + 90) % 360
|
||||
const greyAccent: HSLVector = [accentHue, 0, greyLuminance]
|
||||
const greyComplement: HSLVector = [complementHue, 0, greyLuminance]
|
||||
const maxSaturationAccent: HSLVector = [
|
||||
accentHue,
|
||||
maxSaturation,
|
||||
colorLuminance,
|
||||
]
|
||||
const maxSaturationComplement: HSLVector = [
|
||||
complementHue,
|
||||
maxSaturation,
|
||||
colorLuminance,
|
||||
]
|
||||
|
||||
return {
|
||||
greyAccent,
|
||||
greyComplement,
|
||||
maxSaturationAccent,
|
||||
maxSaturationComplement,
|
||||
}
|
||||
}
|
||||
|
||||
public sequential(size: number, offset = 0): HSLVector[] {
|
||||
const { greyAccent, maxSaturationAccent } = this.getAccentsAndComplements(
|
||||
size,
|
||||
offset,
|
||||
)
|
||||
return polynomial_hsl_scale(
|
||||
linearExponent,
|
||||
greyAccent,
|
||||
maxSaturationAccent,
|
||||
size,
|
||||
)
|
||||
}
|
||||
|
||||
public sequentialComplement(size: number, offset = 0): HSLVector[] {
|
||||
const { greyAccent, maxSaturationComplement } =
|
||||
this.getAccentsAndComplements(size, offset)
|
||||
return polynomial_hsl_scale(
|
||||
linearExponent,
|
||||
greyAccent,
|
||||
maxSaturationComplement,
|
||||
size,
|
||||
)
|
||||
}
|
||||
|
||||
public diverging(size: number, offset = 0): HSLVector[] {
|
||||
const {
|
||||
greyAccent,
|
||||
greyComplement,
|
||||
maxSaturationAccent,
|
||||
maxSaturationComplement,
|
||||
} = this.getAccentsAndComplements(size, offset)
|
||||
|
||||
const half = Math.round(size / 2)
|
||||
const cut = size % 2 === 0 ? half + 1 : half
|
||||
|
||||
let diverging = polynomial_hsl_scale(
|
||||
polynomialExponent,
|
||||
greyComplement,
|
||||
maxSaturationComplement,
|
||||
cut,
|
||||
)
|
||||
.slice(1)
|
||||
.reverse()
|
||||
|
||||
let toAdd = polynomial_hsl_scale(
|
||||
polynomialExponent,
|
||||
greyAccent,
|
||||
maxSaturationAccent,
|
||||
cut,
|
||||
)
|
||||
if (size % 2 === 0) {
|
||||
toAdd = toAdd.slice(1, cut)
|
||||
}
|
||||
diverging = diverging.concat(toAdd)
|
||||
return diverging
|
||||
}
|
||||
|
||||
private getNominalHueSequences(size: number) {
|
||||
const nominal: HSLVector[] = []
|
||||
const nominalBold: HSLVector[] = []
|
||||
const nominalMuted: HSLVector[] = []
|
||||
const nominalHues: number[] = []
|
||||
let hues: number[] = []
|
||||
const h = this.accentHsl[0]
|
||||
|
||||
const initialHues =
|
||||
this.nominalHueStep <= 10
|
||||
? 13 - this.nominalHueStep
|
||||
: this.nominalHueStep - 8
|
||||
|
||||
const hueDirection = this.nominalHueStep <= 10 ? -1 : 1
|
||||
|
||||
let hueStep = 360.0 / initialHues
|
||||
|
||||
for (let i = 0; i < initialHues; i += 1) {
|
||||
hues.push((h + i * hueDirection * hueStep) % 360)
|
||||
}
|
||||
|
||||
while (hues.length < size) {
|
||||
hueStep = hueStep / 2
|
||||
const newHues: number[] = []
|
||||
for (const existingHue of hues) {
|
||||
newHues.push((existingHue + hueDirection * hueStep) % 360)
|
||||
if (hues.length + newHues.length === size) {
|
||||
break
|
||||
}
|
||||
}
|
||||
hues = hues.concat(newHues)
|
||||
}
|
||||
|
||||
// trim the core hues to match requested size
|
||||
// this acounts for initialHues calculation
|
||||
// which can result in minimum counts higher than requested
|
||||
hues = hues.slice(0, size)
|
||||
|
||||
let baseSaturation = nominalSaturation
|
||||
let baseLuminance = this.scaleLuminance
|
||||
|
||||
const addHue = (hue: number) => {
|
||||
nominal.push([hue, baseSaturation, baseLuminance])
|
||||
nominalBold.push([
|
||||
hue,
|
||||
0.5 * (nominalSaturation + baseSaturation) + boldSaturationShift,
|
||||
0.5 * (this.scaleLuminance + baseLuminance) - nominalDarkerShift,
|
||||
])
|
||||
nominalMuted.push([
|
||||
hue,
|
||||
0.5 * (nominalSaturation + baseSaturation) - mutedSaturationShift,
|
||||
0.5 * (this.scaleLuminance + baseLuminance) + nominalLighterShift,
|
||||
])
|
||||
nominalHues.push(hue)
|
||||
if (nominal.length % 3 === 0) {
|
||||
baseSaturation = Math.max(baseSaturation - 1, minNominalSaturation)
|
||||
}
|
||||
if (nominal.length % 6 === 0) {
|
||||
baseLuminance = Math.max(baseLuminance - 1, minNominalLuminance)
|
||||
}
|
||||
}
|
||||
|
||||
for (const finalHue of hues) {
|
||||
addHue(finalHue)
|
||||
}
|
||||
|
||||
return {
|
||||
nominal,
|
||||
nominalBold,
|
||||
nominalMuted,
|
||||
nominalHues,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function hsluv_to_hex(values: HSLVector[]): string[] {
|
||||
return values.map(([h, s, l]) => hsluv2hex(h, s, l))
|
||||
}
|
||||
|
||||
// TODO: this should probably throw errors if out-of-bounds values are submitted OR, wrap around the geometry if that's always valid
|
||||
/**
|
||||
* Takes a set of core params and generates all of the scale computes required for a Schema,
|
||||
* using HSLuv color space for even perceptual qualities.
|
||||
* @param params
|
||||
* @param nominalItemCount
|
||||
* @param sequentialItemCount
|
||||
* @param light
|
||||
* @returns
|
||||
*/
|
||||
export function getScheme(
|
||||
params: Params,
|
||||
params: SchemeParams,
|
||||
nominalItemCount: number,
|
||||
sequentialItemCount: number,
|
||||
light: boolean,
|
||||
tuning?: Partial<TuningParameters>,
|
||||
): Scheme {
|
||||
const {
|
||||
accentHue,
|
||||
accentSaturation,
|
||||
accentLuminance,
|
||||
backgroundLevel,
|
||||
backgroundHueShift,
|
||||
nominalHueStep,
|
||||
} = params
|
||||
accentLightness,
|
||||
scaleSaturation,
|
||||
scaleLightness,
|
||||
greyHue,
|
||||
greySaturation,
|
||||
} = validateParams(params)
|
||||
|
||||
const colorMaker = new ColorMaker(
|
||||
[accentHue, accentSaturation, accentLuminance],
|
||||
const {
|
||||
analogousRange,
|
||||
complementaryRange,
|
||||
nominalHueStep,
|
||||
maxBackgroundChroma,
|
||||
lightMaxLightnessOffset,
|
||||
darkMaxLightnessOffet,
|
||||
lightTextLightness,
|
||||
darkTextLightness,
|
||||
lightBackgroundLightnessShift,
|
||||
darkBackgroundLightnessShift,
|
||||
backgroundLevel,
|
||||
backgroundHueShift,
|
||||
nominalHueStep,
|
||||
nominalMutedLightnessShift,
|
||||
nominalBoldLightnessShift,
|
||||
nominalMutedSaturationShift,
|
||||
nominalBoldSaturationShift,
|
||||
minNominalSaturation,
|
||||
minNominalLightness,
|
||||
lowContrastBackgroundShift,
|
||||
offsetBackgroundLightnessShift,
|
||||
lightestGrey,
|
||||
darkestGrey,
|
||||
reservedDataColors,
|
||||
polynomialExponent,
|
||||
} = getDefaultTuning(tuning)
|
||||
|
||||
const foregroundHsl = getForegroundHsl(
|
||||
lightTextLightness,
|
||||
darkTextLightness,
|
||||
light,
|
||||
)
|
||||
|
||||
const nominalSequences = colorMaker.nominal(nominalItemCount)
|
||||
const backgroundHsl = getBackgroundHsl(
|
||||
accentHue,
|
||||
backgroundLevel,
|
||||
backgroundHueShift,
|
||||
lightMaxLightnessOffset,
|
||||
darkMaxLightnessOffet,
|
||||
maxBackgroundChroma,
|
||||
analogousRange,
|
||||
complementaryRange,
|
||||
light,
|
||||
)
|
||||
|
||||
const backgroundLightness = backgroundHsl[2]
|
||||
|
||||
const offsetbackgroundHsl = getOffsetBackgroundHsl(
|
||||
backgroundHsl,
|
||||
offsetBackgroundLightnessShift,
|
||||
light,
|
||||
)
|
||||
|
||||
const boldGreyLightness = light ? darkestGrey : lightestGrey
|
||||
const greyLightness = getGreyLightness(
|
||||
backgroundLightness,
|
||||
lightBackgroundLightnessShift,
|
||||
darkBackgroundLightnessShift,
|
||||
light,
|
||||
)
|
||||
|
||||
const greys = greySequence(
|
||||
greyHue,
|
||||
greySaturation,
|
||||
greyLightness,
|
||||
boldGreyLightness,
|
||||
sequentialItemCount,
|
||||
)
|
||||
|
||||
const {
|
||||
faintAnnotationHsl,
|
||||
lowContrastAnnotationHsl,
|
||||
lowMidContrastAnnotationHsl,
|
||||
midContrastAnnotationHsl,
|
||||
midHighContrastAnnotationHsl,
|
||||
highContrastAnnotationHsl,
|
||||
} = getAnnotations(
|
||||
greyHue,
|
||||
backgroundLightness,
|
||||
boldGreyLightness,
|
||||
lowContrastBackgroundShift,
|
||||
lightestGrey,
|
||||
darkestGrey,
|
||||
greySaturation,
|
||||
light,
|
||||
)
|
||||
|
||||
const nominalHues = getNominalHues(
|
||||
accentHue,
|
||||
nominalHueStep,
|
||||
nominalItemCount + reservedDataColors,
|
||||
)
|
||||
const nominal = getNominalSequence(
|
||||
nominalHues,
|
||||
scaleSaturation,
|
||||
minNominalSaturation,
|
||||
scaleLightness,
|
||||
minNominalLightness,
|
||||
)
|
||||
const nominalMuted = getNominalShiftedSequence(
|
||||
nominalHues,
|
||||
scaleSaturation,
|
||||
minNominalSaturation,
|
||||
scaleLightness,
|
||||
minNominalLightness,
|
||||
nominalMutedSaturationShift,
|
||||
nominalMutedLightnessShift,
|
||||
)
|
||||
const nominalBold = getNominalShiftedSequence(
|
||||
nominalHues,
|
||||
scaleSaturation,
|
||||
minNominalSaturation,
|
||||
scaleLightness,
|
||||
minNominalLightness,
|
||||
nominalBoldSaturationShift,
|
||||
nominalBoldLightnessShift,
|
||||
)
|
||||
|
||||
const sequential1 = getSequentialSequence(
|
||||
nominalHues,
|
||||
scaleSaturation,
|
||||
accentLightness,
|
||||
greyLightness,
|
||||
sequentialItemCount,
|
||||
0,
|
||||
)
|
||||
const sequential2 = getSequentialSequence(
|
||||
nominalHues,
|
||||
scaleSaturation,
|
||||
accentLightness,
|
||||
greyLightness,
|
||||
sequentialItemCount,
|
||||
1,
|
||||
)
|
||||
|
||||
const diverging1 = getDivergingSequence(
|
||||
nominalHues,
|
||||
scaleSaturation,
|
||||
accentLightness,
|
||||
greyLightness,
|
||||
polynomialExponent,
|
||||
sequentialItemCount,
|
||||
0,
|
||||
)
|
||||
const diverging2 = getDivergingSequence(
|
||||
nominalHues,
|
||||
scaleSaturation,
|
||||
accentLightness,
|
||||
greyLightness,
|
||||
polynomialExponent,
|
||||
sequentialItemCount,
|
||||
1,
|
||||
)
|
||||
|
||||
const rainbow = getNominalRainbowSequence(
|
||||
accentHue,
|
||||
scaleSaturation,
|
||||
scaleLightness,
|
||||
)
|
||||
return {
|
||||
background: hsluv2hex(...colorMaker.backgroundHsl),
|
||||
offsetBackground: hsluv2hex(...colorMaker.offsetbackgroundHsl),
|
||||
foreground: hsluv2hex(...colorMaker.foregroundHsl),
|
||||
accent: hsluv2hex(...colorMaker.accentHsl),
|
||||
lowContrastAnnotation: hsluv2hex(...colorMaker.lowContrastAnnotationHsl),
|
||||
lowMidContrastAnnotation: hsluv2hex(
|
||||
...colorMaker.lowMidContrastAnnotationHsl,
|
||||
),
|
||||
midContrastAnnotation: hsluv2hex(...colorMaker.midContrastAnnotationHsl),
|
||||
midHighContrastAnnotation: hsluv2hex(
|
||||
...colorMaker.midHighContrastAnnotationHsl,
|
||||
),
|
||||
highContrastAnnotation: hsluv2hex(...colorMaker.highContrastAnnotationHsl),
|
||||
faintAnnotation: hsluv2hex(...colorMaker.faintAnnotationHsl),
|
||||
sequential: hsluv_to_hex(colorMaker.sequential(sequentialItemCount, 0)),
|
||||
sequential2: hsluv_to_hex(colorMaker.sequential(sequentialItemCount, 1)),
|
||||
diverging: hsluv_to_hex(colorMaker.diverging(sequentialItemCount, 0)),
|
||||
diverging2: hsluv_to_hex(colorMaker.diverging(sequentialItemCount, 1)),
|
||||
nominalBold: hsluv_to_hex(nominalSequences.bold),
|
||||
nominal: hsluv_to_hex(nominalSequences.std),
|
||||
nominalMuted: hsluv_to_hex(nominalSequences.muted),
|
||||
greys: hsluv_to_hex(colorMaker.grey(sequentialItemCount)),
|
||||
background: hsluv2hex(backgroundHsl),
|
||||
offsetBackground: hsluv2hex(offsetbackgroundHsl),
|
||||
foreground: hsluv2hex(foregroundHsl),
|
||||
accent: hsluv2hex([accentHue, accentSaturation, accentLightness]),
|
||||
dataPrimary: hsluv2hex(nominal[0]!),
|
||||
dataPrimaryMuted: hsluv2hex(nominalMuted[0]!),
|
||||
dataPrimaryBold: hsluv2hex(nominalBold[0]!),
|
||||
lowContrastAnnotation: hsluv2hex(lowContrastAnnotationHsl),
|
||||
lowMidContrastAnnotation: hsluv2hex(lowMidContrastAnnotationHsl),
|
||||
midContrastAnnotation: hsluv2hex(midContrastAnnotationHsl),
|
||||
midHighContrastAnnotation: hsluv2hex(midHighContrastAnnotationHsl),
|
||||
highContrastAnnotation: hsluv2hex(highContrastAnnotationHsl),
|
||||
faintAnnotation: hsluv2hex(faintAnnotationHsl),
|
||||
sequential: hsluvList2hexList(sequential1),
|
||||
sequential2: hsluvList2hexList(sequential2),
|
||||
diverging: hsluvList2hexList(diverging1),
|
||||
diverging2: hsluvList2hexList(diverging2),
|
||||
nominalBold: hsluvList2hexList(nominalBold.slice(reservedDataColors)),
|
||||
nominal: hsluvList2hexList(nominal.slice(reservedDataColors)),
|
||||
nominalMuted: hsluvList2hexList(nominalMuted.slice(reservedDataColors)),
|
||||
greys: hsluvList2hexList(greys),
|
||||
rainbow: hsluvList2hexList(rainbow),
|
||||
warning: '#ff8c00',
|
||||
error: '#d13438',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a list of HSLuv vectors to hex strings.
|
||||
* @param values
|
||||
* @returns
|
||||
*/
|
||||
function hsluvList2hexList(hsluvs: HslVector[]): string[] {
|
||||
return hsluvs.map(hsluv2hex)
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the param limits, and returns a clean set or throws if unadjustable.
|
||||
* @param params
|
||||
*/
|
||||
export function validateParams(params: SchemeParams): Required<SchemeParams> {
|
||||
const {
|
||||
accentHue,
|
||||
accentSaturation,
|
||||
accentLightness,
|
||||
scaleSaturation,
|
||||
scaleLightness,
|
||||
greyHue,
|
||||
greySaturation,
|
||||
} = params
|
||||
|
||||
const scaleSat =
|
||||
scaleSaturation === undefined
|
||||
? defaultParams.scaleSaturation
|
||||
: scaleSaturation
|
||||
const scaleLt =
|
||||
scaleLightness === undefined ? defaultParams.scaleLightness : scaleLightness
|
||||
const grey = greyHue === undefined ? defaultParams.greyHue : greyHue
|
||||
const greySat =
|
||||
greySaturation === undefined ? defaultParams.greySaturation : greySaturation
|
||||
|
||||
if (accentHue === undefined) {
|
||||
throw new Error(
|
||||
'Must supply an accent hue from 0-360. <undefined> was supplied.',
|
||||
)
|
||||
}
|
||||
|
||||
if (accentLightness === undefined) {
|
||||
throw new Error(
|
||||
'Must supply an accent lightness from 0-100. <undefined> was supplied.',
|
||||
)
|
||||
}
|
||||
|
||||
if (accentSaturation === undefined) {
|
||||
throw new Error(
|
||||
'Must supply an accent saturation from 0-100. <undefined> was supplied.',
|
||||
)
|
||||
}
|
||||
|
||||
if (accentLightness < 0 || accentLightness > 100) {
|
||||
throw new Error(
|
||||
`accentLightness ${accentLightness} is out of valid range: 0-100`,
|
||||
)
|
||||
}
|
||||
|
||||
if (accentSaturation < 0 || accentSaturation > 100) {
|
||||
throw new Error(
|
||||
`accentSaturation ${accentSaturation} is out of valid range: 0-100`,
|
||||
)
|
||||
}
|
||||
|
||||
if (scaleSat < 0 || scaleSat > 100) {
|
||||
throw new Error(`scaleSaturation ${scaleSat} is out of valid range: 0-100`)
|
||||
}
|
||||
|
||||
if (scaleLt < 0 || scaleLt > 100) {
|
||||
throw new Error(`scaleLightness ${scaleLt} is out of valid range: 0-100`)
|
||||
}
|
||||
|
||||
if (greySat < 0 || greySat > 100) {
|
||||
throw new Error(`greySaturation ${greySat} is out of valid range: 0-100`)
|
||||
}
|
||||
|
||||
return {
|
||||
accentHue,
|
||||
accentLightness,
|
||||
accentSaturation,
|
||||
scaleSaturation: scaleSat,
|
||||
scaleLightness: scaleLt,
|
||||
greyHue: grey,
|
||||
greySaturation: greySat,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,508 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
|
||||
import { hsluv2hsl } from '../chroma.js'
|
||||
import type { HslVector } from '../types.js'
|
||||
import { polynomialHslSequence } from './utils.js'
|
||||
|
||||
/**
|
||||
* Gets an offset hue based on the hue shift param.
|
||||
* This is used to tint the background color slightly.
|
||||
* Note that the shift parameter is arbitrarily binned using the 0-100 range:
|
||||
* 0-25 counterclockwise complementary, 25-75 analogous, 75+ clockwise complementary.
|
||||
* @param hue
|
||||
* @param shift
|
||||
* @param analagousRange
|
||||
* @param complementaryRange
|
||||
* @returns
|
||||
*/
|
||||
function getOffsetHue(
|
||||
hue: number,
|
||||
shift: number,
|
||||
analogousRange: number,
|
||||
complementaryRange: number,
|
||||
) {
|
||||
if (shift >= 25 && shift <= 75) {
|
||||
// analogous range
|
||||
const delta = (analogousRange * (shift - 50)) / 25
|
||||
return (hue + delta) % 360
|
||||
} else if (shift > 75) {
|
||||
// clockwise complementary range
|
||||
const delta = 180 - (complementaryRange * (100 - shift)) / 25
|
||||
return (hue + delta) % 360
|
||||
} else {
|
||||
// anticlockwise complementary range
|
||||
const delta = 180 + (complementaryRange * shift) / 25
|
||||
return (hue + delta) % 360
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Choose a background lightness based on the "level" and light/dark mode.
|
||||
* @param level
|
||||
* @param lightMaxOffset
|
||||
* @param darkMaxOffset
|
||||
* @param light
|
||||
* @returns
|
||||
*/
|
||||
function getBackgroundLightness(
|
||||
level: number,
|
||||
lightMaxOffset: number,
|
||||
darkMaxOffset: number,
|
||||
light: boolean,
|
||||
) {
|
||||
if (light) {
|
||||
if (level < 50) {
|
||||
return 100 - lightMaxOffset
|
||||
}
|
||||
return 100 - lightMaxOffset * (1 - (level - 50) / 50)
|
||||
} else {
|
||||
if (level < 50) {
|
||||
return darkMaxOffset
|
||||
} else {
|
||||
return darkMaxOffset * (1 - (level - 50) / 50)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a saturation value that maximizes chroma for a given hue.
|
||||
* HSLuv has relative saturation, so we find this using HSL and map it back.
|
||||
* @param hue
|
||||
* @param lightness
|
||||
* @param maxBackgroundChroma
|
||||
* @returns
|
||||
*/
|
||||
function normalizeSaturation(
|
||||
hue: number,
|
||||
lightness: number,
|
||||
maxChroma: number,
|
||||
) {
|
||||
let satGivingMaxChroma = 100
|
||||
let c = hsluv2hsl([hue, 100, lightness])[1]
|
||||
while (c > maxChroma && satGivingMaxChroma >= 0) {
|
||||
satGivingMaxChroma -= 1
|
||||
c = hsluv2hsl([hue, satGivingMaxChroma, lightness])[1]
|
||||
}
|
||||
return satGivingMaxChroma
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the ideal saturation for a given background config.
|
||||
* @param hue
|
||||
* @param lightness
|
||||
* @param level
|
||||
* @param maxChroma
|
||||
* @returns
|
||||
*/
|
||||
function getBackgroundSaturation(
|
||||
hue: number,
|
||||
lightness: number,
|
||||
level: number,
|
||||
maxChroma: number,
|
||||
): number {
|
||||
if (level < 50) {
|
||||
return (level * normalizeSaturation(hue, lightness, maxChroma)) / 50
|
||||
} else {
|
||||
return normalizeSaturation(hue, lightness, maxChroma)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the background HSL color based on our hue params and shifts.
|
||||
* @param hue
|
||||
* @param level
|
||||
* @param shift
|
||||
* @param lightMaxLightnessOffset
|
||||
* @param darkMaxLightnessOffet
|
||||
* @param maxChroma
|
||||
* @param analogousRange
|
||||
* @param complementaryRange
|
||||
* @param light
|
||||
* @returns
|
||||
*/
|
||||
export function getBackgroundHsl(
|
||||
hue: number,
|
||||
level: number,
|
||||
shift: number,
|
||||
lightMaxLightnessOffset: number,
|
||||
darkMaxLightnessOffet: number,
|
||||
maxChroma: number,
|
||||
analogousRange: number,
|
||||
complementaryRange: number,
|
||||
light: boolean,
|
||||
): HslVector {
|
||||
const h = getOffsetHue(hue, shift, analogousRange, complementaryRange)
|
||||
const l = getBackgroundLightness(
|
||||
level,
|
||||
lightMaxLightnessOffset,
|
||||
darkMaxLightnessOffet,
|
||||
light,
|
||||
)
|
||||
const s = getBackgroundSaturation(h, l, level, maxChroma)
|
||||
return [h, s, l]
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given set of nominal hues, find the accents and complement set.
|
||||
* Accent is established by configuring an offset within the hues array,
|
||||
* complement is 90deg from that in the hue space.
|
||||
* @param hues
|
||||
* @param accentHsl
|
||||
* @param greyLightness
|
||||
* @param offset
|
||||
* @returns
|
||||
*/
|
||||
export function getAccentsAndComplements(
|
||||
hues: number[],
|
||||
saturation: number,
|
||||
lightness: number,
|
||||
greyLightness: number,
|
||||
offset: number,
|
||||
): {
|
||||
greyAccent: HslVector
|
||||
greyComplement: HslVector
|
||||
accent: HslVector
|
||||
complement: HslVector
|
||||
} {
|
||||
const accentHue = hues[offset % hues.length] as number
|
||||
const complementHue = (accentHue + 90) % 360
|
||||
const greyAccent: HslVector = [accentHue, 0, greyLightness]
|
||||
const greyComplement: HslVector = [complementHue, 0, greyLightness]
|
||||
const accent: HslVector = [accentHue, saturation, lightness]
|
||||
const complement: HslVector = [complementHue, saturation, lightness]
|
||||
|
||||
return {
|
||||
greyAccent,
|
||||
greyComplement,
|
||||
accent,
|
||||
complement,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a sequence of hue components using the specified step starting from an initial hue.
|
||||
* Attempts to cycle in a way that is predictable but does not result in similar neighbor colors.
|
||||
* Note that there is a standard cycle for the most common 10 hue scales, and then it randomizes more.
|
||||
* @param start
|
||||
* @param step
|
||||
* @param size
|
||||
* @returns
|
||||
*/
|
||||
export function getNominalHues(start: number, step: number, size: number) {
|
||||
const initialHues = step <= 11 ? 13 - step : step - 8
|
||||
const hueDirection = step <= 11 ? -1 : 1
|
||||
|
||||
let hues: number[] = []
|
||||
let hueStep = 360.0 / initialHues
|
||||
|
||||
for (let i = 0; i < initialHues; i += 1) {
|
||||
hues.push((start + i * hueDirection * hueStep) % 360)
|
||||
}
|
||||
|
||||
while (hues.length < size) {
|
||||
hueStep = hueStep / 2
|
||||
const newHues: number[] = []
|
||||
for (const existingHue of hues) {
|
||||
newHues.push((existingHue + hueDirection * hueStep) % 360)
|
||||
if (hues.length + newHues.length === size) {
|
||||
break
|
||||
}
|
||||
}
|
||||
hues = hues.concat(newHues)
|
||||
}
|
||||
|
||||
// trim the core hues to match requested size
|
||||
// this accounts for initialHues calculation
|
||||
// which can result in minimum counts higher than requested
|
||||
return hues.slice(0, size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a nominal sequence with even perception based on a core hue set.
|
||||
* In order to maintain some differentiation, at greater quantities
|
||||
* the colors are shifted in saturation and lightness.
|
||||
* @param hues
|
||||
* @param saturation
|
||||
* @param minSaturation
|
||||
* @param lightness
|
||||
* @param minLightness
|
||||
* @returns
|
||||
*/
|
||||
export function getNominalSequence(
|
||||
hues: number[],
|
||||
saturation: number,
|
||||
minSaturation: number,
|
||||
lightness: number,
|
||||
minLightness: number,
|
||||
) {
|
||||
const minS = Math.min(saturation, minSaturation)
|
||||
const minL = Math.min(lightness, minLightness)
|
||||
let baseSaturation = saturation
|
||||
let baseLightness = lightness
|
||||
return hues.map((hue, idx) => {
|
||||
const hsl = [hue, baseSaturation, baseLightness] as HslVector
|
||||
if (idx > 9 && (idx + 1) % 3 === 0) {
|
||||
baseSaturation = Math.max(baseSaturation - 1, minS)
|
||||
}
|
||||
if (idx > 9 && (idx + 1) % 6 === 0) {
|
||||
baseLightness = Math.max(baseLightness - 1, minL)
|
||||
}
|
||||
return hsl
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the muted/bold nominal sequence by shifting the saturation and lightness
|
||||
* @param hues
|
||||
* @param saturation
|
||||
* @param minSaturation
|
||||
* @param lightness
|
||||
* @param minLightness
|
||||
* @param saturationShift
|
||||
* @param nominalShift
|
||||
* @returns
|
||||
*/
|
||||
export function getNominalShiftedSequence(
|
||||
hues: number[],
|
||||
saturation: number,
|
||||
minSaturation: number,
|
||||
lightness: number,
|
||||
minLightness: number,
|
||||
saturationShift: number,
|
||||
lightnessShift: number,
|
||||
) {
|
||||
let baseSaturation = saturation
|
||||
let baseLightness = lightness
|
||||
|
||||
return hues.map((hue, idx) => {
|
||||
const shiftedS = 0.5 * (saturation + baseSaturation) + saturationShift
|
||||
const shiftedL = 0.5 * (lightness + baseLightness) + lightnessShift
|
||||
// correct for valid bounds
|
||||
const correctedS = Math.min(Math.max(0, shiftedS), 100)
|
||||
const correctedL = Math.min(Math.max(0, shiftedL), 100)
|
||||
const hsl = [hue, correctedS, correctedL] as HslVector
|
||||
if (idx > 9 && (idx + 1) % 3 === 0) {
|
||||
baseSaturation = Math.max(baseSaturation - 1, minSaturation)
|
||||
}
|
||||
if (idx > 9 && (idx + 1) % 6 === 0) {
|
||||
baseLightness = Math.max(baseLightness - 1, minLightness)
|
||||
}
|
||||
return hsl
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Just gets every hue, with consistent saturation and lightness.
|
||||
* @param start
|
||||
* @param saturation
|
||||
* @param lightness
|
||||
* @returns
|
||||
*/
|
||||
export function getNominalRainbowSequence(
|
||||
start: number,
|
||||
saturation: number,
|
||||
lightness: number,
|
||||
) {
|
||||
return new Array(360)
|
||||
.fill(1)
|
||||
.map((_a, i) => [i + start, saturation, lightness] as HslVector)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sequence of greys from a {start} to {end} lightness.
|
||||
* Note the optional saturation - by default this is 0 for pure greys,
|
||||
* but if you want some of the hue mixed in to warm or cool the sequence
|
||||
* you can bump this and the hue will emerge.
|
||||
* @param hue
|
||||
* @param size
|
||||
* @param startLightness
|
||||
* @param endLightness
|
||||
* @param saturation
|
||||
* @returns
|
||||
*/
|
||||
export function greySequence(
|
||||
hue: number,
|
||||
saturation: number,
|
||||
startLightness: number,
|
||||
endLightness: number,
|
||||
size: number,
|
||||
) {
|
||||
const greyFrom: HslVector = [hue, saturation, startLightness]
|
||||
const greyTo: HslVector = [hue, saturation, endLightness]
|
||||
return polynomialHslSequence(greyFrom, greyTo, size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the sequential scale sequence from grey to the offset hue color.
|
||||
* @param hues
|
||||
* @param saturation
|
||||
* @param lightness
|
||||
* @param greyLightness
|
||||
* @param size
|
||||
* @param offset
|
||||
* @returns
|
||||
*/
|
||||
export function getSequentialSequence(
|
||||
hues: number[],
|
||||
saturation: number,
|
||||
lightness: number,
|
||||
greyLightness: number,
|
||||
size: number,
|
||||
offset: number,
|
||||
) {
|
||||
const { greyAccent, accent } = getAccentsAndComplements(
|
||||
hues,
|
||||
saturation,
|
||||
lightness,
|
||||
greyLightness,
|
||||
offset,
|
||||
)
|
||||
return polynomialHslSequence(greyAccent, accent, size)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the diverging scale sequence from a complement on one end to the offset hue on the other, with near-white in the middle.
|
||||
* @param hues
|
||||
* @param saturation
|
||||
* @param lightness
|
||||
* @param greyLightness
|
||||
* @param polynomialExponent
|
||||
* @param size
|
||||
* @param offset
|
||||
* @returns
|
||||
*/
|
||||
export function getDivergingSequence(
|
||||
hues: number[],
|
||||
saturation: number,
|
||||
lightness: number,
|
||||
greyLightness: number,
|
||||
polynomialExponent: number,
|
||||
size: number,
|
||||
offset: number,
|
||||
) {
|
||||
const { greyAccent, greyComplement, accent, complement } =
|
||||
getAccentsAndComplements(hues, saturation, lightness, greyLightness, offset)
|
||||
|
||||
const half = Math.round(size / 2)
|
||||
const cut = size % 2 === 0 ? half + 1 : half
|
||||
|
||||
const diverging = polynomialHslSequence(
|
||||
greyComplement,
|
||||
complement,
|
||||
cut,
|
||||
polynomialExponent,
|
||||
)
|
||||
.slice(1)
|
||||
.reverse()
|
||||
|
||||
let toAdd = polynomialHslSequence(greyAccent, accent, cut, polynomialExponent)
|
||||
if (size % 2 === 0) {
|
||||
toAdd = toAdd.slice(1, cut)
|
||||
}
|
||||
return diverging.concat(toAdd)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the collection of greyscale annotations for text colors.
|
||||
* @param accentHue
|
||||
* @param backgroundLightness
|
||||
* @param boldGreyLightness
|
||||
* @param lowContrastbackgroundShift
|
||||
* @param lightestGrey
|
||||
* @param darkestGrey
|
||||
* @param greySaturation
|
||||
* @param light
|
||||
* @returns
|
||||
*/
|
||||
export function getAnnotations(
|
||||
accentHue: number,
|
||||
backgroundLightness: number,
|
||||
boldGreyLightness: number,
|
||||
lowContrastbackgroundShift: number,
|
||||
lightestGrey: number,
|
||||
darkestGrey: number,
|
||||
greySaturation: number,
|
||||
light: boolean,
|
||||
) {
|
||||
const mutedGreyLightness = light
|
||||
? backgroundLightness - lowContrastbackgroundShift
|
||||
: backgroundLightness + lowContrastbackgroundShift
|
||||
|
||||
const annotations = greySequence(
|
||||
accentHue,
|
||||
greySaturation,
|
||||
mutedGreyLightness,
|
||||
boldGreyLightness,
|
||||
5,
|
||||
)
|
||||
const lowContrastAnnotationHsl = annotations[0] as HslVector
|
||||
const lowMidContrastAnnotationHsl = annotations[1] as HslVector
|
||||
const midContrastAnnotationHsl = annotations[2] as HslVector
|
||||
const midHighContrastAnnotationHsl = annotations[3] as HslVector
|
||||
const highContrastAnnotationHsl = annotations[4] as HslVector
|
||||
// halfway to the background from the darkest/lightest
|
||||
const faintLightness = light
|
||||
? (100 - lightestGrey) / 2 + lightestGrey
|
||||
: darkestGrey / 2
|
||||
const faintAnnotationHsl: HslVector = [accentHue, 0, faintLightness]
|
||||
|
||||
return {
|
||||
faintAnnotationHsl,
|
||||
lowContrastAnnotationHsl,
|
||||
lowMidContrastAnnotationHsl,
|
||||
midContrastAnnotationHsl,
|
||||
midHighContrastAnnotationHsl,
|
||||
highContrastAnnotationHsl,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the primary foreground (text) color.
|
||||
* @param lightTextLightness
|
||||
* @param darkTextLightness
|
||||
* @param light
|
||||
* @returns
|
||||
*/
|
||||
export function getForegroundHsl(
|
||||
lightTextLightness: number,
|
||||
darkTextLightness: number,
|
||||
light: boolean,
|
||||
): HslVector {
|
||||
const textLightness = light ? darkTextLightness : lightTextLightness
|
||||
return [0, 0, textLightness]
|
||||
}
|
||||
/**
|
||||
* Gets the offset background - this is used for data plot area for example,
|
||||
* so it stands out slightly from the regular application background.
|
||||
* @param backgroundHsl
|
||||
* @param lightnessShift
|
||||
* @param light
|
||||
* @returns
|
||||
*/
|
||||
|
||||
export function getOffsetBackgroundHsl(
|
||||
backgroundHsl: HslVector,
|
||||
lightnessShift: number,
|
||||
light: boolean,
|
||||
): HslVector {
|
||||
const [hue, saturation, lightness] = backgroundHsl
|
||||
const offsetLightness = light
|
||||
? Math.min(100, lightness + lightnessShift)
|
||||
: Math.max(0, lightness - lightnessShift)
|
||||
|
||||
return [hue, saturation, offsetLightness]
|
||||
}
|
||||
|
||||
export function getGreyLightness(
|
||||
backgroundLightness: number,
|
||||
lightBackgroundLightnessShift: number,
|
||||
darkBackgroundLightnessShift: number,
|
||||
light: boolean,
|
||||
) {
|
||||
return light
|
||||
? backgroundLightness - darkBackgroundLightnessShift
|
||||
: backgroundLightness + lightBackgroundLightnessShift
|
||||
}
|
|
@ -2,4 +2,4 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
export * from './HsluvColorLogic.js'
|
||||
export { getScheme } from './HsluvColorLogic.js'
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*!
|
||||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import type { HslVector } from '../types.js'
|
||||
|
||||
/**
|
||||
* Creates a polynomial number sequence of {size} entries from {start} to {end}.
|
||||
* @param start
|
||||
* @param end
|
||||
* @param size
|
||||
* @param exponent
|
||||
* @returns
|
||||
*/
|
||||
export function polynomialSequence(
|
||||
start: number,
|
||||
end: number,
|
||||
size: number,
|
||||
exponent = 1,
|
||||
): number[] {
|
||||
const base = 1 / (size - 1)
|
||||
const interval = end - start
|
||||
const result: number[] = []
|
||||
for (let i = 0; i < size; i++) {
|
||||
result.push(start + interval * (i * base) ** exponent)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a sequence of HSL values interpolated from {start} to {end}
|
||||
* @param start
|
||||
* @param end
|
||||
* @param size
|
||||
* @param exp
|
||||
* @returns
|
||||
*/
|
||||
export function polynomialHslSequence(
|
||||
start: HslVector,
|
||||
end: HslVector,
|
||||
size: number,
|
||||
exp = 1,
|
||||
): HslVector[] {
|
||||
const [sh, ss, sl] = start
|
||||
const [eh, es, el] = end
|
||||
const hues = polynomialSequence(sh, eh, size, exp)
|
||||
const saturations = polynomialSequence(ss, es, size, exp)
|
||||
const luminances = polynomialSequence(sl, el, size, exp)
|
||||
const hexvalues: HslVector[] = []
|
||||
for (let i = 0; i < size; i++) {
|
||||
hexvalues.push([
|
||||
hues[i] as number,
|
||||
saturations[i] as number,
|
||||
luminances[i] as number,
|
||||
])
|
||||
}
|
||||
return hexvalues
|
||||
}
|
|
@ -6,13 +6,81 @@
|
|||
/**
|
||||
* This is the core set of parameters for generating schemes using the ColorPicker
|
||||
*/
|
||||
export interface Params {
|
||||
export interface SchemeParams {
|
||||
/**
|
||||
* HSL hue component for the accent.
|
||||
* Valid range is 0-360 (degrees).
|
||||
*/
|
||||
accentHue: number
|
||||
/**
|
||||
* HSL saturation component for the accent.
|
||||
* Valid range is 0-100.
|
||||
*/
|
||||
accentSaturation: number
|
||||
accentLuminance: number
|
||||
backgroundHueShift: number
|
||||
backgroundLevel: number
|
||||
/**
|
||||
* HSL lightness component for the accent.
|
||||
* Valid range is 0-100.
|
||||
*/
|
||||
accentLightness: number
|
||||
/**
|
||||
* Sets the default saturation for nominal scales.
|
||||
* Muted and bold scales are a fixed saturation +-
|
||||
*/
|
||||
scaleSaturation?: number
|
||||
/**
|
||||
* Sets the default lightness for nominal scales.
|
||||
* Muted and bold scales are a fixed lightness +-
|
||||
*/
|
||||
scaleLightness?: number
|
||||
/**
|
||||
* Optional hue to mix some of warm or cool into grey scales.
|
||||
*/
|
||||
greyHue?: number
|
||||
/**
|
||||
* Optional saturation to mix some of warm or cool into grey scales.
|
||||
*/
|
||||
greySaturation?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Detailed tuning for the scale generation algorithms.
|
||||
*/
|
||||
export interface TuningParameters {
|
||||
analogousRange: number
|
||||
complementaryRange: number
|
||||
|
||||
nominalHueStep: number
|
||||
|
||||
lightTextLightness: number
|
||||
lightMaxLightnessOffset: number
|
||||
lightBackgroundLightnessShift: number
|
||||
|
||||
darkTextLightness: number
|
||||
darkMaxLightnessOffet: number
|
||||
darkBackgroundLightnessShift: number
|
||||
|
||||
backgroundLevel: number
|
||||
backgroundHueShift: number
|
||||
|
||||
minNominalSaturation: number
|
||||
minNominalLightness: number
|
||||
|
||||
nominalMutedSaturationShift: number
|
||||
nominalMutedLightnessShift: number
|
||||
|
||||
nominalBoldLightnessShift: number
|
||||
nominalBoldSaturationShift: number
|
||||
|
||||
maxBackgroundChroma: number
|
||||
lowContrastBackgroundShift: number
|
||||
offsetBackgroundLightnessShift: number
|
||||
|
||||
lightestGrey: number
|
||||
darkestGrey: number
|
||||
|
||||
reservedDataColors: number
|
||||
|
||||
polynomialExponent: number
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -26,6 +94,12 @@ export interface Scheme {
|
|||
accent: string
|
||||
warning: string
|
||||
error: string
|
||||
/**
|
||||
* Primary data color, derived from the accent.
|
||||
*/
|
||||
dataPrimary: string
|
||||
dataPrimaryMuted: string
|
||||
dataPrimaryBold: string
|
||||
faintAnnotation: string
|
||||
lowContrastAnnotation: string
|
||||
lowMidContrastAnnotation: string
|
||||
|
@ -40,6 +114,7 @@ export interface Scheme {
|
|||
nominal: string[]
|
||||
nominalMuted: string[]
|
||||
greys: string[]
|
||||
rainbow: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -129,6 +204,15 @@ export enum ColorSpace {
|
|||
* (i.e., r, g \<\< 8, b \<\< 16, a \<\< 24)
|
||||
*/
|
||||
RGBA_NUMBER = 'rgbaint',
|
||||
/**
|
||||
* HSL color space, { h, s, l }.
|
||||
*/
|
||||
HSL = 'hsl',
|
||||
/**
|
||||
* HSLuv, which is a perceptually balanced space. [h, s, l].
|
||||
* https://www.hsluv.org/
|
||||
*/
|
||||
HSLUV = 'hsluv',
|
||||
}
|
||||
|
||||
export interface Rgb {
|
||||
|
@ -152,3 +236,7 @@ export interface Hsl {
|
|||
s: number
|
||||
l: number
|
||||
}
|
||||
|
||||
export type RGBAV = [number, number, number, number]
|
||||
|
||||
export type HslVector = [number, number, number]
|
||||
|
|
|
@ -20,6 +20,7 @@ export interface ColorScales
|
|||
| [nominal](./core.colorscales.nominal.md) | | (sizeOrDomain?: number \| string\[\] \| number\[\]) => [NominalColorScaleFunction](./core.nominalcolorscalefunction.md) | |
|
||||
| [nominalBold](./core.colorscales.nominalbold.md) | | (sizeOrDomain?: number \| string\[\] \| number\[\]) => [NominalColorScaleFunction](./core.nominalcolorscalefunction.md) | |
|
||||
| [nominalMuted](./core.colorscales.nominalmuted.md) | | (sizeOrDomain?: number \| string\[\] \| number\[\]) => [NominalColorScaleFunction](./core.nominalcolorscalefunction.md) | |
|
||||
| [rainbow](./core.colorscales.rainbow.md) | | (domain?: number\[\], scaleType?: [ScaleType](./core.scaletype.md)<!-- -->, quantiles?: number) => [ContinuousColorScaleFunction](./core.continuouscolorscalefunction.md) | |
|
||||
| [sequential](./core.colorscales.sequential.md) | | (domain?: number\[\], scaleType?: [ScaleType](./core.scaletype.md)<!-- -->, quantiles?: number) => [ContinuousColorScaleFunction](./core.continuouscolorscalefunction.md) | Constructs a sequential numeric scale based on the input domain and specified ScaleType The input domain should be an array of values. For linear or log scales, the behavior mimics d3-scale. For quantile scales, the domain values are used to construct a quantile division using the requested number of quantile bins |
|
||||
| [sequential2](./core.colorscales.sequential2.md) | | (domain?: number\[\], scaleType?: [ScaleType](./core.scaletype.md)<!-- -->, quantiles?: number) => [ContinuousColorScaleFunction](./core.continuouscolorscalefunction.md) | |
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/core](./core.md) > [ColorScales](./core.colorscales.md) > [rainbow](./core.colorscales.rainbow.md)
|
||||
|
||||
## ColorScales.rainbow property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
rainbow: (domain?: number[], scaleType?: ScaleType, quantiles?: number) => ContinuousColorScaleFunction;
|
||||
```
|
|
@ -36,7 +36,7 @@ export interface Theme
|
|||
| [name](./core.theme.name.md) | | string | |
|
||||
| [nearest](./core.theme.nearest.md) | | (color: string, scale?: [NominalColorScaleFunction](./core.nominalcolorscalefunction.md)<!-- -->) => Color | Returns a theme color that's the closest to a CSS color string we can find. Note that by default this uses the standard nominal scale with 20 entries so there is plenty of variety to choose from. Pass in a different scale instance if you want something else to choose from. |
|
||||
| [node](./core.theme.node.md) | | [MarkFunction](./core.markfunction.md)<!-- --><[Node](./core.node.md)<!-- -->> | |
|
||||
| [params](./core.theme.params.md) | | Params | |
|
||||
| [params](./core.theme.params.md) | | SchemeParams | |
|
||||
| [plotArea](./core.theme.plotarea.md) | | [ChromeFunction](./core.chromefunction.md)<!-- --><[PlotArea](./core.plotarea.md)<!-- -->> | |
|
||||
| [process](./core.theme.process.md) | | [MarkFunction](./core.markfunction.md)<!-- --><[Process](./core.process.md)<!-- -->> | |
|
||||
| [rect](./core.theme.rect.md) | | [MarkFunction](./core.markfunction.md)<!-- --><[Rect](./core.rect.md)<!-- -->> | |
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
params: Params;
|
||||
params: SchemeParams;
|
||||
```
|
||||
|
|
|
@ -41,7 +41,7 @@ export declare class Theme implements ITheme
|
|||
| [link](./core.themeimpl.link.md) | | (markConfig?: [MarkConfig](./core.markconfig.md)<!-- -->) => [Link](./core.link.md) | |
|
||||
| [name](./core.themeimpl.name.md) | <code>readonly</code> | string | |
|
||||
| [node](./core.themeimpl.node.md) | | (markConfig?: [MarkConfig](./core.markconfig.md)<!-- -->) => [Node](./core.node.md) | |
|
||||
| [params](./core.themeimpl.params.md) | <code>readonly</code> | Params | |
|
||||
| [params](./core.themeimpl.params.md) | <code>readonly</code> | SchemeParams | |
|
||||
| [plotArea](./core.themeimpl.plotarea.md) | | () => [PlotArea](./core.plotarea.md) | |
|
||||
| [process](./core.themeimpl.process.md) | | (markConfig?: [MarkConfig](./core.markconfig.md)<!-- -->) => [Process](./core.process.md) | |
|
||||
| [rect](./core.themeimpl.rect.md) | | (markConfig?: [MarkConfig](./core.markconfig.md)<!-- -->) => [Rect](./core.rect.md) | |
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
get params(): Params;
|
||||
get params(): SchemeParams;
|
||||
```
|
||||
|
|
|
@ -19,5 +19,6 @@ export interface ThemeSpec
|
|||
| [dark?](./core.themespec.dark.md) | | Scheme | <i>(Optional)</i> |
|
||||
| [light?](./core.themespec.light.md) | | Scheme | <i>(Optional)</i> |
|
||||
| [name?](./core.themespec.name.md) | | string | <i>(Optional)</i> |
|
||||
| [params?](./core.themespec.params.md) | | Params | <i>(Optional)</i> |
|
||||
| [params?](./core.themespec.params.md) | | SchemeParams | <i>(Optional)</i> |
|
||||
| [tuning?](./core.themespec.tuning.md) | | TuningParameters | <i>(Optional)</i> |
|
||||
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
params?: Params;
|
||||
params?: SchemeParams;
|
||||
```
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||
|
||||
[Home](./index.md) > [@thematic/core](./core.md) > [ThemeSpec](./core.themespec.md) > [tuning](./core.themespec.tuning.md)
|
||||
|
||||
## ThemeSpec.tuning property
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
tuning?: TuningParameters;
|
||||
```
|
|
@ -2620,6 +2620,47 @@
|
|||
"endIndex": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "PropertySignature",
|
||||
"canonicalReference": "@thematic/core!ColorScales#rainbow:member",
|
||||
"docComment": "",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "rainbow: "
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "(domain?: number[], scaleType?: "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "ScaleType",
|
||||
"canonicalReference": "@thematic/core!ScaleType:enum"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ", quantiles?: number) => "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "ContinuousColorScaleFunction",
|
||||
"canonicalReference": "@thematic/core!ContinuousColorScaleFunction:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isReadonly": false,
|
||||
"isOptional": false,
|
||||
"releaseTag": "Public",
|
||||
"name": "rainbow",
|
||||
"propertyTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "PropertySignature",
|
||||
"canonicalReference": "@thematic/core!ColorScales#sequential:member",
|
||||
|
@ -6367,8 +6408,8 @@
|
|||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "Params",
|
||||
"canonicalReference": "@thematic/color!Params:interface"
|
||||
"text": "SchemeParams",
|
||||
"canonicalReference": "@thematic/color!SchemeParams:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -8509,8 +8550,8 @@
|
|||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "Params",
|
||||
"canonicalReference": "@thematic/color!Params:interface"
|
||||
"text": "SchemeParams",
|
||||
"canonicalReference": "@thematic/color!SchemeParams:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -9255,8 +9296,8 @@
|
|||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "Params",
|
||||
"canonicalReference": "@thematic/color!Params:interface"
|
||||
"text": "SchemeParams",
|
||||
"canonicalReference": "@thematic/color!SchemeParams:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
|
@ -9271,6 +9312,34 @@
|
|||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"kind": "PropertySignature",
|
||||
"canonicalReference": "@thematic/core!ThemeSpec#tuning:member",
|
||||
"docComment": "",
|
||||
"excerptTokens": [
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": "tuning?: "
|
||||
},
|
||||
{
|
||||
"kind": "Reference",
|
||||
"text": "TuningParameters",
|
||||
"canonicalReference": "@thematic/color!TuningParameters:interface"
|
||||
},
|
||||
{
|
||||
"kind": "Content",
|
||||
"text": ";"
|
||||
}
|
||||
],
|
||||
"isReadonly": false,
|
||||
"isOptional": true,
|
||||
"releaseTag": "Public",
|
||||
"name": "tuning",
|
||||
"propertyTypeTokenRange": {
|
||||
"startIndex": 1,
|
||||
"endIndex": 2
|
||||
}
|
||||
}
|
||||
],
|
||||
"extendsTokenRanges": []
|
||||
|
|
|
@ -6,8 +6,9 @@
|
|||
|
||||
import { Color } from '@thematic/color';
|
||||
import { ColorBlindnessMode } from '@thematic/color';
|
||||
import type { Params } from '@thematic/color';
|
||||
import type { Scheme } from '@thematic/color';
|
||||
import type { SchemeParams } from '@thematic/color';
|
||||
import type { TuningParameters } from '@thematic/color';
|
||||
|
||||
// Warning: (ae-missing-release-tag) "Application" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
//
|
||||
|
@ -248,6 +249,8 @@ export interface ColorScales {
|
|||
nominalBold: (sizeOrDomain?: number | string[] | number[]) => NominalColorScaleFunction;
|
||||
// (undocumented)
|
||||
nominalMuted: (sizeOrDomain?: number | string[] | number[]) => NominalColorScaleFunction;
|
||||
// (undocumented)
|
||||
rainbow: (domain?: number[], scaleType?: ScaleType, quantiles?: number) => ContinuousColorScaleFunction;
|
||||
sequential: (domain?: number[], scaleType?: ScaleType, quantiles?: number) => ContinuousColorScaleFunction;
|
||||
// (undocumented)
|
||||
sequential2: (domain?: number[], scaleType?: ScaleType, quantiles?: number) => ContinuousColorScaleFunction;
|
||||
|
@ -662,7 +665,7 @@ export interface Theme {
|
|||
// (undocumented)
|
||||
node: MarkFunction<Node>;
|
||||
// (undocumented)
|
||||
params: Params;
|
||||
params: SchemeParams;
|
||||
// (undocumented)
|
||||
plotArea: ChromeFunction<PlotArea>;
|
||||
// (undocumented)
|
||||
|
@ -797,7 +800,7 @@ export class ThemeImpl implements Theme {
|
|||
// (undocumented)
|
||||
node: (markConfig?: MarkConfig) => Node;
|
||||
// (undocumented)
|
||||
get params(): Params;
|
||||
get params(): SchemeParams;
|
||||
// (undocumented)
|
||||
plotArea: () => PlotArea;
|
||||
// (undocumented)
|
||||
|
@ -848,7 +851,9 @@ export interface ThemeSpec {
|
|||
// (undocumented)
|
||||
name?: string;
|
||||
// (undocumented)
|
||||
params?: Params;
|
||||
params?: SchemeParams;
|
||||
// (undocumented)
|
||||
tuning?: TuningParameters;
|
||||
}
|
||||
|
||||
// Warning: (ae-missing-release-tag) "ThemeVariant" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import type { Params, Scheme } from '@thematic/color'
|
||||
import type { Scheme, SchemeParams } from '@thematic/color'
|
||||
import { Color, ColorBlindnessMode, nearest } from '@thematic/color'
|
||||
import merge from 'lodash-es/merge.js'
|
||||
|
||||
|
@ -80,9 +80,8 @@ export class Theme implements ITheme {
|
|||
private _spec: ThemeSpec
|
||||
private _themeDefinition: ThemeDefinition
|
||||
private _config: ThemeConfig
|
||||
private _params: Params
|
||||
private _params: SchemeParams
|
||||
private _scheme: Scheme
|
||||
private _schemeCache: { [size: number]: Scheme }
|
||||
|
||||
/**
|
||||
* Creates a new Theme instance using the params defined in the spec.
|
||||
|
@ -92,7 +91,6 @@ export class Theme implements ITheme {
|
|||
*/
|
||||
public constructor(spec: ThemeSpec, config?: ThemeConfig) {
|
||||
const conf = merge({}, defaultConfig, config)
|
||||
this._schemeCache = {}
|
||||
const scheme = createScheme(spec, conf.dark, conf.colorBlindnessMode)
|
||||
this._scheme = scheme
|
||||
this._spec = applyScheme(spec)
|
||||
|
@ -152,7 +150,7 @@ export class Theme implements ITheme {
|
|||
public get config(): ThemeConfig {
|
||||
return this._config
|
||||
}
|
||||
public get params(): Params {
|
||||
public get params(): SchemeParams {
|
||||
return this._params
|
||||
}
|
||||
public get scheme(): Scheme {
|
||||
|
@ -238,6 +236,14 @@ export class Theme implements ITheme {
|
|||
const scheme = this.getScheme(100)
|
||||
return continuous(scheme.greys, domain, scaleType, quantiles)
|
||||
},
|
||||
rainbow: (
|
||||
domain: number[] = [0, 1],
|
||||
scaleType?: ScaleType,
|
||||
quantiles?: number,
|
||||
) => {
|
||||
const scheme = this.getScheme(360)
|
||||
return continuous(scheme.rainbow, domain, scaleType, quantiles)
|
||||
},
|
||||
}
|
||||
}
|
||||
public application = (): Application => {
|
||||
|
@ -304,28 +310,20 @@ export class Theme implements ITheme {
|
|||
const c = new Color(color)
|
||||
const colors = scale
|
||||
? scale.toColors()
|
||||
: this.scales().nominal().toColors(20)
|
||||
: this.scales().nominal(30).toColors()
|
||||
return nearest(c, colors)
|
||||
}
|
||||
/**
|
||||
* Gets the scheme with the appropriate size
|
||||
* @param size - The number of elements in the scheme
|
||||
*/
|
||||
// TODO: this cache overcomes slow scale computes, but they shouldn't be slow
|
||||
private getScheme(size = 0) {
|
||||
if (!this._schemeCache[size]) {
|
||||
this._schemeCache[size] = createScheme(
|
||||
this._spec,
|
||||
this._config.dark,
|
||||
this._config.colorBlindnessMode,
|
||||
size,
|
||||
size,
|
||||
)
|
||||
}
|
||||
const result = this._schemeCache[size]
|
||||
if (!result) {
|
||||
throw new Error(`could not locate schema with size ${size}`)
|
||||
}
|
||||
return result
|
||||
return createScheme(
|
||||
this._spec,
|
||||
this._config.dark,
|
||||
this._config.colorBlindnessMode,
|
||||
size,
|
||||
size,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,9 +30,9 @@ const lightConfig = {
|
|||
// TODO: mock this out better so it isn't unstable
|
||||
|
||||
const SCALE_VECTOR = [
|
||||
0.9725490196078431, 0.5490196078431373, 0.5529411764705883, 1.0,
|
||||
0.21568627450980393, 0.7058823529411765, 0.7058823529411765, 1.0,
|
||||
]
|
||||
const SCALE_NUMBER = -7500552
|
||||
const SCALE_NUMBER = -4934601
|
||||
|
||||
// these are variants from the mock theme config above
|
||||
const STROKE_VECTOR = [
|
||||
|
|
|
@ -6,17 +6,14 @@ import { load } from '../loader.js'
|
|||
import { ThemeVariant } from '../types/index.js'
|
||||
|
||||
describe('load', () => {
|
||||
// these are variants from the theme json for arc.stroke - they could change if we change the json!
|
||||
const STROKE_CSS = '#c5c5c5'
|
||||
|
||||
test('zero-config load (light theme)', () => {
|
||||
const theme = load()
|
||||
expect(theme.name).toBe('Default')
|
||||
expect(theme.variant).toBe(ThemeVariant.Light)
|
||||
expect(theme.dark).toBe(false)
|
||||
expect(theme.chart().backgroundColor().hex()).toBe('none')
|
||||
expect(theme.arc().stroke().hex()).toBe(STROKE_CSS)
|
||||
expect(theme.text().fill().hex()).toBe('#303030')
|
||||
expect(theme.arc().stroke().hex()).toBe('#c8c5be')
|
||||
expect(theme.text().fill().hex()).toBe('#31302e')
|
||||
})
|
||||
|
||||
test('load dark theme', () => {
|
||||
|
@ -27,7 +24,7 @@ describe('load', () => {
|
|||
expect(theme.variant).toBe(ThemeVariant.Dark)
|
||||
expect(theme.dark).toBe(true)
|
||||
expect(theme.chart().backgroundColor().hex()).toBe('none')
|
||||
expect(theme.arc().stroke().hex()).toBe('#323232')
|
||||
expect(theme.text().fill().hex()).toBe('#e2e2e2')
|
||||
expect(theme.arc().stroke().hex()).toBe('#333230')
|
||||
expect(theme.text().fill().hex()).toBe('#e5e2db')
|
||||
})
|
||||
})
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import type { Scheme } from '@thematic/color'
|
||||
|
||||
import { computeDefinition } from '../scheme.js'
|
||||
|
||||
const definition = {}
|
||||
|
||||
const scheme = {
|
||||
const scheme: Scheme = {
|
||||
background: '#111111',
|
||||
offsetBackground: '#222222',
|
||||
foreground: '#333333',
|
||||
|
@ -25,6 +27,9 @@ const scheme = {
|
|||
greys: ['lightgrey', 'darkgrey'],
|
||||
warning: 'orange',
|
||||
error: 'red',
|
||||
dataPrimary: '#999999',
|
||||
dataPrimaryMuted: '#99999e',
|
||||
dataPrimaryBold: '#99999f',
|
||||
}
|
||||
describe('scheme overlays', () => {
|
||||
describe('computeDefinition', () => {
|
||||
|
@ -35,13 +40,13 @@ describe('scheme overlays', () => {
|
|||
})
|
||||
|
||||
test('scale-based props', () => {
|
||||
expect(def.rect!.fill).toBe(scheme.nominal[0])
|
||||
expect(def.rect!.fill).toBe(scheme.dataPrimary)
|
||||
})
|
||||
|
||||
test('signal props', () => {
|
||||
expect(def.rect!.hovered!.fill).toBe(scheme.nominalBold[0])
|
||||
expect(def.rect!.selected!.fill).toBe(scheme.nominalBold[0])
|
||||
expect(def.rect!.suppressed!.fill).toBe(scheme.nominalMuted[0])
|
||||
expect(def.rect!.suppressed!.fill).toBe(scheme.dataPrimaryMuted)
|
||||
expect(def.rect!.hovered!.fill).toBe(scheme.dataPrimaryBold)
|
||||
expect(def.rect!.selected!.fill).toBe(scheme.dataPrimaryBold)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -30,11 +30,11 @@ const themes = {
|
|||
export const defaultThemes: ThemeListing[] = Object.entries(themes).map(
|
||||
entry => {
|
||||
const [key, value] = entry
|
||||
const { accentHue, accentSaturation, accentLuminance } = value.params
|
||||
const { accentHue, accentSaturation, accentLightness } = value.params
|
||||
return {
|
||||
id: key,
|
||||
name: value.name,
|
||||
accent: hsluv2hex(accentHue, accentSaturation, accentLuminance),
|
||||
accent: hsluv2hex([accentHue, accentSaturation, accentLightness]),
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import type { ColorBlindnessMode, Params, Scheme } from '@thematic/color'
|
||||
import type { ColorBlindnessMode, Scheme, SchemeParams } from '@thematic/color'
|
||||
import { colorBlindness, defaultParams, getScheme } from '@thematic/color'
|
||||
import merge from 'lodash-es/merge.js'
|
||||
import set from 'lodash-es/set.js'
|
||||
|
@ -20,23 +20,19 @@ type Config = {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a completed Params block from a ThemeDefinition, making sure missing optional fields are populated.
|
||||
* Creates a completed SchemeParams block from a ThemeDefinition, making sure missing optional fields are populated.
|
||||
* @param themeDefinition
|
||||
*/
|
||||
export function applyParams(spec: ThemeSpec): Params {
|
||||
const { params = defaultParams } = spec
|
||||
export function applyParams(spec: ThemeSpec): SchemeParams {
|
||||
const { params } = spec
|
||||
return {
|
||||
accentHue: params.accentHue,
|
||||
accentSaturation: params.accentSaturation,
|
||||
accentLuminance: params.accentLuminance,
|
||||
backgroundHueShift: params.backgroundHueShift,
|
||||
backgroundLevel: params.backgroundLevel,
|
||||
nominalHueStep: params.nominalHueStep,
|
||||
...defaultParams,
|
||||
...params,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a computed scheme from a ThemeDefinition (specifically, the Params in the definition).
|
||||
* Creates a computed scheme from a ThemeDefinition (specifically, the SchemeParams in the definition).
|
||||
* Note that this creates scales with 10 items as a default, useful for saving to file, etc.
|
||||
* If more gradations are desired, a new scheme should be created at point-of-use.
|
||||
* TODO: separate the scale bisection using Scheme functions that allow request of different
|
||||
|
@ -51,7 +47,13 @@ export function createScheme(
|
|||
sequentialItemCount: number = DEFAULT_SEQUENTIAL_ITEMS,
|
||||
): Scheme {
|
||||
const params = applyParams(spec)
|
||||
const scheme = getScheme(params, nominalItemCount, sequentialItemCount, !dark)
|
||||
const scheme = getScheme(
|
||||
params,
|
||||
nominalItemCount,
|
||||
sequentialItemCount,
|
||||
!dark,
|
||||
spec.tuning,
|
||||
)
|
||||
return colorBlindness(scheme, colorBlindnessMode)
|
||||
}
|
||||
|
||||
|
@ -120,7 +122,7 @@ export function computeDefinition(
|
|||
paths: ['application.error'],
|
||||
},
|
||||
{
|
||||
value: scheme.nominal[0] as string,
|
||||
value: scheme.dataPrimary,
|
||||
paths: [
|
||||
'rect.fill',
|
||||
'area.fill',
|
||||
|
@ -133,7 +135,7 @@ export function computeDefinition(
|
|||
{
|
||||
// very light grey, for subtle borders and backgrounds
|
||||
value: scheme.faintAnnotation,
|
||||
paths: ['application.faint'],
|
||||
paths: ['application.faint', 'gridLines.stroke'],
|
||||
},
|
||||
{
|
||||
// low contrast grey, so they don't occupy lots of visual attention
|
||||
|
@ -143,7 +145,6 @@ export function computeDefinition(
|
|||
'plotArea.stroke',
|
||||
'axisLine.stroke',
|
||||
'axisTicks.stroke',
|
||||
'gridLines.stroke',
|
||||
'arc.stroke',
|
||||
'application.border',
|
||||
'application.lowContrast',
|
||||
|
@ -191,7 +192,7 @@ export function computeDefinition(
|
|||
|
||||
const signalConfigs: Config[] = [
|
||||
{
|
||||
value: scheme.nominalBold[0] as string,
|
||||
value: scheme.dataPrimaryBold,
|
||||
paths: [
|
||||
'rect.hovered.fill',
|
||||
'area.hovered.fill',
|
||||
|
@ -208,7 +209,7 @@ export function computeDefinition(
|
|||
],
|
||||
},
|
||||
{
|
||||
value: scheme.nominalMuted[0] as string,
|
||||
value: scheme.dataPrimaryMuted,
|
||||
paths: [
|
||||
'rect.suppressed.fill',
|
||||
'area.suppressed.fill',
|
||||
|
|
|
@ -7,10 +7,11 @@ const autumnTheme = {
|
|||
params: {
|
||||
accentHue: 50,
|
||||
accentSaturation: 86,
|
||||
accentLuminance: 67,
|
||||
backgroundLevel: 95,
|
||||
backgroundHueShift: 50,
|
||||
nominalHueStep: 10,
|
||||
accentLightness: 67,
|
||||
scaleSaturation: 90,
|
||||
scaleLightness: 67,
|
||||
greyHue: 50,
|
||||
greySaturation: 10,
|
||||
},
|
||||
}
|
||||
export default autumnTheme
|
||||
|
|
|
@ -7,10 +7,11 @@ const defaultTheme = {
|
|||
params: {
|
||||
accentHue: 252,
|
||||
accentSaturation: 78,
|
||||
accentLuminance: 49,
|
||||
backgroundLevel: 95,
|
||||
backgroundHueShift: 50,
|
||||
nominalHueStep: 10,
|
||||
accentLightness: 49,
|
||||
scaleSaturation: 90,
|
||||
scaleLightness: 67,
|
||||
greyHue: 72,
|
||||
greySaturation: 7,
|
||||
},
|
||||
}
|
||||
export default defaultTheme
|
||||
|
|
|
@ -7,10 +7,11 @@ const metalTheme = {
|
|||
params: {
|
||||
accentHue: 242,
|
||||
accentSaturation: 46,
|
||||
accentLuminance: 45,
|
||||
backgroundLevel: 98,
|
||||
backgroundHueShift: 100,
|
||||
nominalHueStep: 21,
|
||||
accentLightness: 45,
|
||||
scaleSaturation: 90,
|
||||
scaleLightness: 67,
|
||||
greyHue: 242,
|
||||
greySaturation: 20,
|
||||
},
|
||||
}
|
||||
export default metalTheme
|
||||
|
|
|
@ -7,10 +7,11 @@ const oceanTheme = {
|
|||
params: {
|
||||
accentHue: 215,
|
||||
accentSaturation: 95,
|
||||
accentLuminance: 61,
|
||||
backgroundLevel: 90,
|
||||
backgroundHueShift: 40,
|
||||
nominalHueStep: 0,
|
||||
accentLightness: 61,
|
||||
scaleSaturation: 90,
|
||||
scaleLightness: 67,
|
||||
greyHue: 100,
|
||||
greySaturation: 7,
|
||||
},
|
||||
}
|
||||
export default oceanTheme
|
||||
|
|
|
@ -2,7 +2,12 @@
|
|||
* Copyright (c) Microsoft. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE file in the project.
|
||||
*/
|
||||
import type { Color, ColorBlindnessMode, Params, Scheme } from '@thematic/color'
|
||||
import type {
|
||||
Color,
|
||||
ColorBlindnessMode,
|
||||
Scheme,
|
||||
SchemeParams,
|
||||
} from '@thematic/color'
|
||||
|
||||
import type { ScaleType, SelectionState, ThemeVariant } from './enums.js'
|
||||
import type { ThemeConfig } from './ThemeConfig.js'
|
||||
|
@ -192,6 +197,11 @@ export interface ColorScales {
|
|||
scaleType?: ScaleType,
|
||||
quantiles?: number,
|
||||
) => ContinuousColorScaleFunction
|
||||
rainbow: (
|
||||
domain?: number[],
|
||||
scaleType?: ScaleType,
|
||||
quantiles?: number,
|
||||
) => ContinuousColorScaleFunction
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -263,7 +273,7 @@ export interface Theme {
|
|||
name: string
|
||||
dark: boolean
|
||||
variant: ThemeVariant
|
||||
params: Params
|
||||
params: SchemeParams
|
||||
scheme: Scheme
|
||||
spec: ThemeSpec
|
||||
config: ThemeConfig
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче