graphs now work in night mode

This commit is contained in:
Damien Elmes 2020-06-30 16:23:46 +10:00
parent 1b37398503
commit 101deb002b
13 changed files with 88 additions and 20 deletions

View file

@ -9,6 +9,7 @@ import time
import aqt import aqt
from anki.lang import _ from anki.lang import _
from aqt.qt import * from aqt.qt import *
from aqt.theme import theme_manager
from aqt.utils import ( from aqt.utils import (
addCloseShortcut, addCloseShortcut,
getSaveFile, getSaveFile,
@ -87,4 +88,8 @@ class DeckStats(QDialog):
def refresh(self): def refresh(self):
self.form.web.set_open_links_externally(False) self.form.web.set_open_links_externally(False)
self.form.web.load(QUrl(f"{self.mw.serverURL()}_anki/graphs.html")) if theme_manager.night_mode:
extra = "#night"
else:
extra = ""
self.form.web.load(QUrl(f"{self.mw.serverURL()}_anki/graphs.html"+extra))

2
ts/css.d.ts vendored
View file

@ -1 +1 @@
declare module "*.css"; declare module "*.scss";

View file

@ -31,6 +31,7 @@
"prettier": "^2.0.0", "prettier": "^2.0.0",
"prettier-plugin-svelte": "^1.1.0", "prettier-plugin-svelte": "^1.1.0",
"sass": "^1.26.9", "sass": "^1.26.9",
"sass-loader": "^8.0.2",
"style-loader": "^1.2.1", "style-loader": "^1.2.1",
"svelte": "^3.23.2", "svelte": "^3.23.2",
"svelte-loader": "^2.13.6", "svelte-loader": "^2.13.6",

View file

@ -8,6 +8,10 @@
<div id="main"></div> <div id="main"></div>
</body> </body>
<script> <script>
anki.graphs(document.getElementById("main")); const nightMode = window.location.hash == "#night";
if (nightMode) {
document.body.className = "night-mode";
}
anki.graphs(document.getElementById("main"), nightMode);
</script> </script>
</html> </html>

View file

@ -11,6 +11,7 @@
export let sourceData: pb.BackendProto.GraphsOut | null = null; export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let revlogRange: RevlogRange = RevlogRange.Month; export let revlogRange: RevlogRange = RevlogRange.Month;
export let i18n: I18n; export let i18n: I18n;
export let nightMode: boolean;
let graphData: GraphData | null = null; let graphData: GraphData | null = null;
@ -42,7 +43,14 @@
} }
$: if (graphData) { $: if (graphData) {
renderCalendar(svg as SVGElement, bounds, graphData, targetYear, i18n); renderCalendar(
svg as SVGElement,
bounds,
graphData,
targetYear,
i18n,
nightMode
);
} }
const title = i18n.tr(i18n.TR.STATISTICS_REVIEWS_TITLE); const title = i18n.tr(i18n.TR.STATISTICS_REVIEWS_TITLE);

View file

@ -1,5 +1,5 @@
<script context="module"> <script context="module">
import style from "./graphs.css"; import style from "./graphs.scss";
</script> </script>
<script lang="typescript"> <script lang="typescript">
@ -20,6 +20,7 @@
import CalendarGraph from "./CalendarGraph.svelte"; import CalendarGraph from "./CalendarGraph.svelte";
export let i18n: I18n; export let i18n: I18n;
export let nightMode: boolean;
let sourceData: pb.BackendProto.GraphsOut | null = null; let sourceData: pb.BackendProto.GraphsOut | null = null;
@ -142,7 +143,7 @@
<TodayStats {sourceData} {i18n} /> <TodayStats {sourceData} {i18n} />
<CardCounts {sourceData} {i18n} /> <CardCounts {sourceData} {i18n} />
<CalendarGraph {sourceData} {revlogRange} {i18n} /> <CalendarGraph {sourceData} {revlogRange} {i18n} {nightMode} />
<FutureDue {sourceData} {revlogRange} {i18n} /> <FutureDue {sourceData} {revlogRange} {i18n} />
<ReviewsGraph {sourceData} {revlogRange} {i18n} /> <ReviewsGraph {sourceData} {revlogRange} {i18n} />
<IntervalsGraph {sourceData} {i18n} /> <IntervalsGraph {sourceData} {i18n} />

View file

@ -154,9 +154,9 @@ export function renderButtons(
.attr("opacity", (d: Datum) => { .attr("opacity", (d: Datum) => {
switch (d.group) { switch (d.group) {
case "learning": case "learning":
return 0.3; return 0.6;
case "young": case "young":
return 0.5; return 0.8;
case "mature": case "mature":
return 1; return 1;
} }

View file

@ -53,7 +53,8 @@ export function renderCalendar(
bounds: GraphBounds, bounds: GraphBounds,
sourceData: GraphData, sourceData: GraphData,
targetYear: number, targetYear: number,
i18n: I18n i18n: I18n,
nightMode: boolean
): void { ): void {
const svg = select(svgElem); const svg = select(svgElem);
const now = new Date(); const now = new Date();
@ -101,7 +102,11 @@ export function renderCalendar(
} }
} }
const data = Array.from(dayMap.values()); const data = Array.from(dayMap.values());
const blues = scaleSequential(interpolateBlues).domain([0, maxCount]); const cappedRange = scaleLinear().range([0.2, nightMode ? 0.8 : 1]);
const blues = scaleSequential((n) => interpolateBlues(cappedRange(n))).domain([
0,
maxCount,
]);
function tooltipText(d: DayDatum): string { function tooltipText(d: DayDatum): string {
const date = d.date.toLocaleString(i18n.langs, { const date = d.date.toLocaleString(i18n.langs, {
@ -115,6 +120,10 @@ export function renderCalendar(
} }
const height = bounds.height / 10; const height = bounds.height / 10;
let emptyColour = "#eee";
if (nightMode) {
emptyColour = "#333";
}
svg.select(`g.days`) svg.select(`g.days`)
.selectAll("rect") .selectAll("rect")
.data(data) .data(data)
@ -132,7 +141,7 @@ export function renderCalendar(
.on("mouseout", hideTooltip) .on("mouseout", hideTooltip)
.attr("fill", (d) => { .attr("fill", (d) => {
if (d.count === 0) { if (d.count === 0) {
return "#eee"; return emptyColour;
} else { } else {
return blues(d.count); return blues(d.count);
} }

View file

@ -4,11 +4,11 @@
import { setupI18n } from "../i18n"; import { setupI18n } from "../i18n";
import GraphsPage from "./GraphsPage.svelte"; import GraphsPage from "./GraphsPage.svelte";
export function graphs(target: HTMLDivElement): void { export function graphs(target: HTMLDivElement, nightMode: boolean): void {
setupI18n().then((i18n) => { setupI18n().then((i18n) => {
new GraphsPage({ new GraphsPage({
target, target,
props: { i18n }, props: { i18n, nightMode },
}); });
}); });
} }

View file

@ -1,9 +1,16 @@
$day-fg: black;
$day-bg: white;
$night-fg: white;
$night-bg: #222;
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
body { body {
font-family: Arial; font-family: Arial;
background: $day-bg;
color: $day-fg;
} }
.graph-tooltip { .graph-tooltip {
@ -15,7 +22,8 @@ body {
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
transition: opacity 0.3s; transition: opacity 0.3s;
background: #fff; color: $day-fg;
background: $day-bg;
} }
.graph { .graph {
@ -37,7 +45,8 @@ body {
top: 0; top: 0;
width: 100%; width: 100%;
height: 4em; height: 4em;
background: white; color: $day-fg;
background: $day-bg;
padding: 0.5em; padding: 0.5em;
} }
@ -57,7 +66,7 @@ body {
.graph .area { .graph .area {
opacity: 0.05; opacity: 0.05;
pointer-events: none; pointer-events: none;
fill: black; fill: $day-fg;
} }
.axis-label { .axis-label {
@ -110,3 +119,23 @@ body {
.subtitle { .subtitle {
text-align: center; text-align: center;
} }
body.night-mode {
background: $night-bg;
color: $night-fg;
}
.night-mode {
.graph-tooltip {
background: $night-bg;
color: $night-fg;
}
.range-box {
background: $night-bg;
color: $night-fg;
}
.graph .area {
fill: $night-fg;
opacity: 0.1;
}
}

View file

@ -40,6 +40,13 @@ export enum RevlogRange {
All = 3, All = 3,
} }
export interface GraphsContext {
cards: pb.BackendProto.Card[];
revlog: pb.BackendProto.RevlogEntry[];
revlogRange: RevlogRange;
nightMode: boolean;
}
export interface GraphBounds { export interface GraphBounds {
width: number; width: number;
height: number; height: number;

View file

@ -74,7 +74,11 @@ export function renderHours(
.transition(trans) .transition(trans)
.call(axisBottom(x).tickSizeOuter(0)); .call(axisBottom(x).tickSizeOuter(0));
const colour = scaleSequential(interpolateBlues).domain([0, yMax]); const cappedRange = scaleLinear().range([0.1, 0.8]);
const colour = scaleSequential((n) => interpolateBlues(cappedRange(n))).domain([
0,
yMax,
]);
// y scale // y scale
@ -114,7 +118,7 @@ export function renderHours(
.attr("x", (d: Hour) => x(d.hour.toString())!) .attr("x", (d: Hour) => x(d.hour.toString())!)
.attr("y", y(0)) .attr("y", y(0))
.attr("height", 0) .attr("height", 0)
.attr("opacity", 0.7) // .attr("opacity", 0.7)
.call(updateBar), .call(updateBar),
(update) => update.call(updateBar), (update) => update.call(updateBar),
(remove) => (remove) =>

View file

@ -41,8 +41,8 @@ module.exports = {
module: { module: {
rules: [ rules: [
{ {
test: /\.css$/i, test: /\.s?css$/i,
use: ["style-loader", "css-loader"], use: ["style-loader", "css-loader", "sass-loader"],
}, },
{ {
test: /\.(svelte)$/, test: /\.(svelte)$/,