mirror of
https://github.com/ankitects/anki.git
synced 2025-09-19 14:32:22 -04:00
feat: add color blind colors to reviews graph
Signed-off-by: David Brenn <davidbrenn@t-online.de>
This commit is contained in:
parent
8d6d8dc6c8
commit
c530a024e2
3 changed files with 63 additions and 14 deletions
|
@ -22,7 +22,7 @@ import {
|
||||||
sum,
|
sum,
|
||||||
} from "d3";
|
} from "d3";
|
||||||
|
|
||||||
import type { GraphBounds } from "./graph-helpers";
|
import { colorBlindColors, type GraphBounds } from "./graph-helpers";
|
||||||
|
|
||||||
type Count = [string, number, boolean, string];
|
type Count = [string, number, boolean, string];
|
||||||
export interface GraphData {
|
export interface GraphData {
|
||||||
|
@ -36,13 +36,13 @@ let barColours;
|
||||||
if((window as any).colorBlindMode)
|
if((window as any).colorBlindMode)
|
||||||
{
|
{
|
||||||
barColours = [
|
barColours = [
|
||||||
"#88CCEE", /* new */
|
colorBlindColors.new, /* new */
|
||||||
"#44AA99", /* learn */
|
colorBlindColors.learn, /* learn */
|
||||||
"#117733", /* relearn */
|
colorBlindColors.relearn, /* relearn */
|
||||||
"#CC6677", /* young */
|
colorBlindColors.young, /* young */
|
||||||
"#882255", /* mature */
|
colorBlindColors.mature, /* mature */
|
||||||
"#DDCC77", /* suspended */
|
colorBlindColors.suspended, /* suspended */
|
||||||
"#332288", /* buried */
|
colorBlindColors.buried, /* buried */
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -105,3 +105,17 @@ export function numericMap<T>(obj: { [k: string]: T }): Map<number, T> {
|
||||||
export function getNumericMapBinValue(d: Bin<Map<number, number>, number>): number {
|
export function getNumericMapBinValue(d: Bin<Map<number, number>, number>): number {
|
||||||
return sum(d, (d) => d[1]);
|
return sum(d, (d) => d[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colorblind-friendly colors from https://davidmathlogic.com/colorblind/
|
||||||
|
*/
|
||||||
|
export const colorBlindColors = {
|
||||||
|
new: "#88CCEE",
|
||||||
|
learn: "#44AA99",
|
||||||
|
relearn: "#117733",
|
||||||
|
young: "#CC6677",
|
||||||
|
mature: "#882255",
|
||||||
|
suspended: "#DDCC77",
|
||||||
|
buried: "#332288",
|
||||||
|
filtered: "#AA4499"
|
||||||
|
};
|
||||||
|
|
|
@ -22,16 +22,20 @@ import {
|
||||||
interpolateGreens,
|
interpolateGreens,
|
||||||
interpolatePurples,
|
interpolatePurples,
|
||||||
interpolateReds,
|
interpolateReds,
|
||||||
|
interpolateRgb,
|
||||||
max,
|
max,
|
||||||
min,
|
min,
|
||||||
pointer,
|
pointer,
|
||||||
scaleLinear,
|
scaleLinear,
|
||||||
|
scaleOrdinal,
|
||||||
scaleSequential,
|
scaleSequential,
|
||||||
select,
|
select,
|
||||||
sum,
|
sum,
|
||||||
|
color,
|
||||||
|
hsl
|
||||||
} from "d3";
|
} from "d3";
|
||||||
|
|
||||||
import type { GraphBounds, TableDatum } from "./graph-helpers";
|
import { colorBlindColors, type GraphBounds, type TableDatum } from "./graph-helpers";
|
||||||
import { GraphRange, numericMap, setDataAvailable } from "./graph-helpers";
|
import { GraphRange, numericMap, setDataAvailable } from "./graph-helpers";
|
||||||
import { hideTooltip, showTooltip } from "./tooltip-utils.svelte";
|
import { hideTooltip, showTooltip } from "./tooltip-utils.svelte";
|
||||||
|
|
||||||
|
@ -188,21 +192,52 @@ export function renderReviews(
|
||||||
x.domain() as any,
|
x.domain() as any,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const colorBlindMode = (window as any).colorBlindMode;
|
||||||
|
|
||||||
|
|
||||||
|
function makeColorBlindGradient(baseHex: string, satAdjust = 0.02, lightAdjust = 0.02) {
|
||||||
|
const base = color(baseHex);
|
||||||
|
if (!base) throw new Error(`Invalid color: ${baseHex}`);
|
||||||
|
|
||||||
|
const lighter = hsl(base);
|
||||||
|
lighter.s = Math.min(1, lighter.s + satAdjust);
|
||||||
|
lighter.l = Math.min(1, lighter.l + lightAdjust);
|
||||||
|
|
||||||
|
const darker = hsl(base);
|
||||||
|
darker.s = Math.max(0, darker.s - satAdjust);
|
||||||
|
darker.l = Math.max(0, darker.l - lightAdjust);
|
||||||
|
|
||||||
|
return scaleSequential(interpolateRgb(darker.toString(), lighter.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
const colorBlindScales = {
|
||||||
|
mature: makeColorBlindGradient(colorBlindColors.mature),
|
||||||
|
learn: makeColorBlindGradient(colorBlindColors.learn),
|
||||||
|
relearn: makeColorBlindGradient(colorBlindColors.relearn),
|
||||||
|
young: makeColorBlindGradient(colorBlindColors.young),
|
||||||
|
suspended: makeColorBlindGradient(colorBlindColors.suspended),
|
||||||
|
buried: makeColorBlindGradient(colorBlindColors.buried),
|
||||||
|
filtered: makeColorBlindGradient(colorBlindColors.filtered)
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.values(colorBlindScales).forEach(scale => scale.domain(x.domain() as any));
|
||||||
|
|
||||||
function binColor(idx: BinIndex): ScaleSequential<string> {
|
function binColor(idx: BinIndex): ScaleSequential<string> {
|
||||||
switch (idx) {
|
switch (idx) {
|
||||||
case BinIndex.Mature:
|
case BinIndex.Mature:
|
||||||
return darkerGreens;
|
return colorBlindMode ? colorBlindScales.mature : darkerGreens;
|
||||||
case BinIndex.Young:
|
case BinIndex.Young:
|
||||||
return lighterGreens;
|
return colorBlindMode ? colorBlindScales.young : lighterGreens;
|
||||||
case BinIndex.Learn:
|
case BinIndex.Learn:
|
||||||
return blues;
|
return colorBlindMode ? colorBlindScales.learn : blues;
|
||||||
case BinIndex.Relearn:
|
case BinIndex.Relearn:
|
||||||
return reds;
|
return colorBlindMode ? colorBlindScales.relearn : reds;
|
||||||
case BinIndex.Filtered:
|
case BinIndex.Filtered:
|
||||||
return purples;
|
return colorBlindMode ? colorBlindScales.filtered : purples;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function valueLabel(n: number): string {
|
function valueLabel(n: number): string {
|
||||||
if (showTime) {
|
if (showTime) {
|
||||||
return timeSpan(n / 1000, false, true, TimespanUnit.Hours);
|
return timeSpan(n / 1000, false, true, TimespanUnit.Hours);
|
||||||
|
|
Loading…
Reference in a new issue