@mathigon/core
Advanced tools
Comparing version 0.6.4 to 0.6.5
@@ -378,2 +378,15 @@ 'use strict'; | ||
} | ||
function hue2rgb(p, q, t) { | ||
if (t < 0) | ||
t += 1; | ||
if (t > 1) | ||
t -= 1; | ||
if (t < 1 / 6) | ||
return p + (q - p) * 6 * t; | ||
if (t < 1 / 2) | ||
return q; | ||
if (t < 2 / 3) | ||
return p + (q - p) * (2 / 3 - t) * 6; | ||
return p; | ||
} | ||
/** Colour generation and conversion class. */ | ||
@@ -397,3 +410,3 @@ class Color { | ||
} | ||
/** Converts this colour to an hsl string. */ | ||
/** Converts this colour to an HSL array. */ | ||
get hsl() { | ||
@@ -405,26 +418,16 @@ const r = this.r / 255; | ||
const min = Math.min(r, g, b); | ||
let h; | ||
let s; | ||
const l = (max + min) / 2; | ||
if (max === min) { | ||
h = s = 0; // achromatic | ||
} | ||
else { | ||
const d = max - min; | ||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min); | ||
switch (max) { | ||
case r: | ||
h = (g - b) / d + (g < b ? 6 : 0); | ||
break; | ||
case g: | ||
h = (b - r) / d + 2; | ||
break; | ||
default: // b | ||
h = (r - g) / d + 4; | ||
break; | ||
} | ||
h /= 6; | ||
} | ||
return 'hsl(' + [h, s, l].join(',') + ')'; | ||
const l = (min + max) / 2; | ||
const delta = max - min; | ||
if (max === min) | ||
return [0, 0, Math.round(l * 100)]; // achromatic | ||
let h = (r === max) ? (g - b) / delta : (g === max) ? 2 + (b - r) / delta : 4 + (r - g) / delta; | ||
h = Math.min(h * 60, 360); | ||
if (h < 0) | ||
h += 360; | ||
const s = (l <= 0.5) ? delta / (max + min) : delta / (2 - max - min); | ||
return [Math.round(h), Math.round(s * 100), Math.round(l * 100)]; | ||
} | ||
get chroma() { | ||
return Math.max(this.r, this.g, this.b) - Math.min(this.r, this.g, this.b); | ||
} | ||
toString() { | ||
@@ -460,2 +463,17 @@ return this.rgb; | ||
} | ||
static fromHsl(h, s, l) { | ||
h /= 360; | ||
s /= 100; | ||
l /= 100; | ||
if (s === 0) { | ||
const l1 = Math.round(l * 255); | ||
return new Color(l1, l1, l1); | ||
} | ||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s; | ||
const p = 2 * l - q; | ||
const r = hue2rgb(p, q, h + 1 / 3); | ||
const g = hue2rgb(p, q, h); | ||
const b = hue2rgb(p, q, h - 1 / 3); | ||
return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)); | ||
} | ||
/** Generates a rainbow gradient with a given number of steps. */ | ||
@@ -480,2 +498,22 @@ static rainbow(steps) { | ||
} | ||
static mixMany(colors, weights) { | ||
if (!weights) | ||
weights = colors.map(() => 1); | ||
const weight = total(weights); | ||
const hsl = colors.map(c => c.hsl); | ||
// Hue is a circle, so there are two directions in which we could merge. | ||
const hue = hsl.map(c => c[0]); | ||
const altHue = hue.map(h => h < 180 ? h + 360 : h); | ||
// We also weight the hue by its color intensity (chroma) | ||
const hueWeights = weights.map((w, i) => w * Math.sqrt(colors[i].chroma)); | ||
const hueWeight = total(hueWeights); | ||
const h1 = total(hue.map((h, i) => h * hueWeights[i])) / hueWeight; | ||
const h2 = total(altHue.map((h, i) => h * hueWeights[i])) / hueWeight; | ||
const r1 = total(hue.map((h, i) => Math.abs(h - h1) * hueWeights[i])); | ||
const r2 = total(altHue.map((h, i) => Math.abs(h - h2) * hueWeights[i])); | ||
const h = (r1 <= r2) ? h1 : h2 % 360; | ||
const s = total(hsl.map((c, i) => weights[i] * c[1])) / weight; | ||
const l = total(hsl.map((c, i) => weights[i] * c[2])) / weight; | ||
return Color.fromHsl(h, s, l); | ||
} | ||
} | ||
@@ -482,0 +520,0 @@ |
@@ -374,2 +374,15 @@ // ============================================================================= | ||
} | ||
function hue2rgb(p, q, t) { | ||
if (t < 0) | ||
t += 1; | ||
if (t > 1) | ||
t -= 1; | ||
if (t < 1 / 6) | ||
return p + (q - p) * 6 * t; | ||
if (t < 1 / 2) | ||
return q; | ||
if (t < 2 / 3) | ||
return p + (q - p) * (2 / 3 - t) * 6; | ||
return p; | ||
} | ||
/** Colour generation and conversion class. */ | ||
@@ -393,3 +406,3 @@ class Color { | ||
} | ||
/** Converts this colour to an hsl string. */ | ||
/** Converts this colour to an HSL array. */ | ||
get hsl() { | ||
@@ -401,26 +414,16 @@ const r = this.r / 255; | ||
const min = Math.min(r, g, b); | ||
let h; | ||
let s; | ||
const l = (max + min) / 2; | ||
if (max === min) { | ||
h = s = 0; // achromatic | ||
} | ||
else { | ||
const d = max - min; | ||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min); | ||
switch (max) { | ||
case r: | ||
h = (g - b) / d + (g < b ? 6 : 0); | ||
break; | ||
case g: | ||
h = (b - r) / d + 2; | ||
break; | ||
default: // b | ||
h = (r - g) / d + 4; | ||
break; | ||
} | ||
h /= 6; | ||
} | ||
return 'hsl(' + [h, s, l].join(',') + ')'; | ||
const l = (min + max) / 2; | ||
const delta = max - min; | ||
if (max === min) | ||
return [0, 0, Math.round(l * 100)]; // achromatic | ||
let h = (r === max) ? (g - b) / delta : (g === max) ? 2 + (b - r) / delta : 4 + (r - g) / delta; | ||
h = Math.min(h * 60, 360); | ||
if (h < 0) | ||
h += 360; | ||
const s = (l <= 0.5) ? delta / (max + min) : delta / (2 - max - min); | ||
return [Math.round(h), Math.round(s * 100), Math.round(l * 100)]; | ||
} | ||
get chroma() { | ||
return Math.max(this.r, this.g, this.b) - Math.min(this.r, this.g, this.b); | ||
} | ||
toString() { | ||
@@ -456,2 +459,17 @@ return this.rgb; | ||
} | ||
static fromHsl(h, s, l) { | ||
h /= 360; | ||
s /= 100; | ||
l /= 100; | ||
if (s === 0) { | ||
const l1 = Math.round(l * 255); | ||
return new Color(l1, l1, l1); | ||
} | ||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s; | ||
const p = 2 * l - q; | ||
const r = hue2rgb(p, q, h + 1 / 3); | ||
const g = hue2rgb(p, q, h); | ||
const b = hue2rgb(p, q, h - 1 / 3); | ||
return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)); | ||
} | ||
/** Generates a rainbow gradient with a given number of steps. */ | ||
@@ -476,2 +494,22 @@ static rainbow(steps) { | ||
} | ||
static mixMany(colors, weights) { | ||
if (!weights) | ||
weights = colors.map(() => 1); | ||
const weight = total(weights); | ||
const hsl = colors.map(c => c.hsl); | ||
// Hue is a circle, so there are two directions in which we could merge. | ||
const hue = hsl.map(c => c[0]); | ||
const altHue = hue.map(h => h < 180 ? h + 360 : h); | ||
// We also weight the hue by its color intensity (chroma) | ||
const hueWeights = weights.map((w, i) => w * Math.sqrt(colors[i].chroma)); | ||
const hueWeight = total(hueWeights); | ||
const h1 = total(hue.map((h, i) => h * hueWeights[i])) / hueWeight; | ||
const h2 = total(altHue.map((h, i) => h * hueWeights[i])) / hueWeight; | ||
const r1 = total(hue.map((h, i) => Math.abs(h - h1) * hueWeights[i])); | ||
const r2 = total(altHue.map((h, i) => Math.abs(h - h2) * hueWeights[i])); | ||
const h = (r1 <= r2) ? h1 : h2 % 360; | ||
const s = total(hsl.map((c, i) => weights[i] * c[1])) / weight; | ||
const l = total(hsl.map((c, i) => weights[i] * c[2])) / weight; | ||
return Color.fromHsl(h, s, l); | ||
} | ||
} | ||
@@ -478,0 +516,0 @@ |
{ | ||
"name": "@mathigon/core", | ||
"version": "0.6.4", | ||
"version": "0.6.5", | ||
"description": "TypeScript utilities library containing function wrappers, string and array helper functions, event classes and color utilities.", | ||
@@ -30,15 +30,15 @@ "keywords": [ | ||
"devDependencies": { | ||
"@rollup/plugin-typescript": "8.1.1", | ||
"@rollup/plugin-typescript": "8.2.0", | ||
"@types/tape": "4.13.0", | ||
"@typescript-eslint/eslint-plugin": "4.14.1", | ||
"@typescript-eslint/parser": "4.14.1", | ||
"eslint": "7.19.0", | ||
"@typescript-eslint/eslint-plugin": "4.15.2", | ||
"@typescript-eslint/parser": "4.15.2", | ||
"eslint": "7.21.0", | ||
"eslint-config-google": "0.14.0", | ||
"eslint-plugin-import": "2.22.1", | ||
"rollup": "2.38.2", | ||
"tape": "5.1.1", | ||
"rollup": "2.40.0", | ||
"tape": "5.2.1", | ||
"ts-node": "9.1.1", | ||
"tslib": "2.1.0", | ||
"typescript": "4.1.3" | ||
"typescript": "4.2.2" | ||
} | ||
} |
@@ -7,25 +7,20 @@ { | ||
"groupName": "lint", | ||
"automerge": true, | ||
"automergeType": "branch" | ||
"automerge": true | ||
}, { | ||
"packagePatterns": ["ts-node", "^typescript"], | ||
"groupName": "typescript", | ||
"automerge": true, | ||
"automergeType": "branch" | ||
"automerge": true | ||
}, { | ||
"packagePatterns": ["^@types/"], | ||
"groupName": "types", | ||
"automerge": true, | ||
"automergeType": "branch" | ||
"automerge": true | ||
}, { | ||
"packagePatterns": ["^rollup", "^@rollup"], | ||
"groupName": "rollup", | ||
"automerge": true, | ||
"automergeType": "branch" | ||
"automerge": true | ||
}, { | ||
"updateTypes": ["patch", "pin", "digest"], | ||
"groupName": "versions", | ||
"automerge": true, | ||
"automergeType": "branch" | ||
"automerge": true | ||
}] | ||
} |
@@ -7,3 +7,3 @@ // ============================================================================= | ||
import {last, tabulate} from './arrays'; | ||
import {last, tabulate, total} from './arrays'; | ||
@@ -33,3 +33,12 @@ | ||
function hue2rgb(p: number, q: number, t: number) { | ||
if (t < 0) t += 1; | ||
if (t > 1) t -= 1; | ||
if (t < 1/6) return p + (q - p) * 6 * t; | ||
if (t < 1/2) return q; | ||
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6; | ||
return p; | ||
} | ||
/** Colour generation and conversion class. */ | ||
@@ -54,3 +63,3 @@ export class Color { | ||
/** Converts this colour to an hsl string. */ | ||
/** Converts this colour to an HSL array. */ | ||
get hsl() { | ||
@@ -63,28 +72,20 @@ const r = this.r / 255; | ||
const min = Math.min(r, g, b); | ||
const l = (min + max) / 2; | ||
const delta = max - min; | ||
let h; let s; | ||
const l = (max + min) / 2; | ||
if (max === min) return [0, 0, Math.round(l * 100)]; // achromatic | ||
if (max === min) { | ||
h = s = 0; // achromatic | ||
} else { | ||
const d = max - min; | ||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min); | ||
switch (max) { | ||
case r: | ||
h = (g - b) / d + (g < b ? 6 : 0); | ||
break; | ||
case g: | ||
h = (b - r) / d + 2; | ||
break; | ||
default: // b | ||
h = (r - g) / d + 4; | ||
break; | ||
} | ||
h /= 6; | ||
} | ||
let h = (r === max) ? (g - b) / delta : (g === max) ? 2 + (b - r) / delta : 4 + (r - g) / delta; | ||
h = Math.min(h * 60, 360); | ||
if (h < 0) h += 360; | ||
return 'hsl(' + [h, s, l].join(',') + ')'; | ||
const s = (l <= 0.5) ? delta / (max + min) : delta / (2 - max - min); | ||
return [Math.round(h), Math.round(s * 100), Math.round(l * 100)]; | ||
} | ||
get chroma() { | ||
return Math.max(this.r, this.g, this.b) - Math.min(this.r, this.g, this.b); | ||
} | ||
toString() { | ||
@@ -130,2 +131,21 @@ return this.rgb; | ||
static fromHsl(h: number, s: number, l: number) { | ||
h /= 360; | ||
s /= 100; | ||
l /= 100; | ||
if (s === 0) { | ||
const l1 = Math.round(l * 255); | ||
return new Color(l1, l1, l1); | ||
} | ||
const q = l < 0.5 ? l * (1 + s) : l + s - l * s; | ||
const p = 2 * l - q; | ||
const r = hue2rgb(p, q, h + 1/3); | ||
const g = hue2rgb(p, q, h); | ||
const b = hue2rgb(p, q, h - 1/3); | ||
return new Color(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)); | ||
} | ||
/** Generates a rainbow gradient with a given number of steps. */ | ||
@@ -159,2 +179,27 @@ static rainbow(steps: number) { | ||
} | ||
static mixMany(colors: Color[], weights?: number[]) { | ||
if (!weights) weights = colors.map(() => 1); | ||
const weight = total(weights); | ||
const hsl = colors.map(c => c.hsl); | ||
// Hue is a circle, so there are two directions in which we could merge. | ||
const hue = hsl.map(c => c[0]); | ||
const altHue = hue.map(h => h < 180 ? h + 360 : h); | ||
// We also weight the hue by its color intensity (chroma) | ||
const hueWeights = weights.map((w, i) => w * Math.sqrt(colors[i].chroma)); | ||
const hueWeight = total(hueWeights); | ||
const h1 = total(hue.map((h, i) => h * hueWeights[i])) / hueWeight; | ||
const h2 = total(altHue.map((h, i) => h * hueWeights[i])) / hueWeight; | ||
const r1 = total(hue.map((h, i) => Math.abs(h - h1) * hueWeights[i])); | ||
const r2 = total(altHue.map((h, i) => Math.abs(h - h2) * hueWeights[i])); | ||
const h = (r1 <= r2) ? h1 : h2 % 360; | ||
const s = total(hsl.map((c, i) => weights![i] * c[1])) / weight; | ||
const l = total(hsl.map((c, i) => weights![i] * c[2])) / weight; | ||
return Color.fromHsl(h, s, l); | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
78609
25
2215