i18n some axis labels, and support vertical CJK text

This commit is contained in:
Damien Elmes 2020-06-28 15:23:36 +10:00
parent 595c509546
commit 7e0bdb990c
14 changed files with 68 additions and 34 deletions

View file

@ -95,3 +95,6 @@ statistics-answer-buttons-title = Answer Buttons
statistics-hours-title = Hourly Breakdown
statistics-added-title = Added
statistics-card-ease-title = Card Ease
statistics-axis-label-answer-count = Answers
statistics-axis-label-card-count = Cards
statistics-axis-label-review-time = Review Time

View file

@ -36,6 +36,15 @@ export class I18n {
return `missing key: ${key}`;
}
supportsVerticalText(): boolean {
const firstLang = this.bundles[0].locales[0];
return (
firstLang.startsWith("ja") ||
firstLang.startsWith("zh") ||
firstLang.startsWith("ko")
);
}
private keyName(msg: pb.BackendProto.FluentString): string {
return this.TR[msg].toLowerCase().replace(/_/g, "-");
}

View file

@ -15,12 +15,10 @@
let addedData: GraphData | null = null;
$: if (sourceData) {
console.log("gathering data");
addedData = gatherData(sourceData);
}
$: if (addedData) {
console.log("preparing data");
histogramData = buildHistogram(addedData, range);
}
@ -29,6 +27,7 @@
const month3 = timeSpan(i18n, 3 * MONTH);
const year = timeSpan(i18n, 1 * YEAR);
const all = i18n.tr(i18n.TR.STATISTICS_RANGE_ALL_TIME);
const yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_CARD_COUNT);
</script>
{#if histogramData}
@ -54,6 +53,6 @@
</label>
</div>
<HistogramGraph data={histogramData} xText="Days" yText="Number of cards" />
<HistogramGraph data={histogramData} xText="Days" {yText} {i18n} />
</div>
{/if}

View file

@ -1,8 +1,16 @@
<script lang="typescript">
import { GraphBounds } from "./graphs";
import { I18n } from "../i18n";
export let bounds: GraphBounds;
export let xText: string;
export let yText: string;
export let i18n: I18n;
let yRotate = 180;
if (i18n.supportsVerticalText()) {
yRotate = 0;
}
</script>
<text
@ -12,6 +20,7 @@
</text>
<text
class="axis-label y-axis-label"
transform={`translate(${bounds.marginLeft / 3}, ${(bounds.height - bounds.marginBottom) / 2 + bounds.marginTop}) rotate(-180)`}>
transform={`translate(${bounds.marginLeft / 3}, ${(bounds.height - bounds.marginBottom) / 2 + bounds.marginTop})
rotate(${yRotate} 0 0)`}>
{yText}
</text>

View file

@ -11,16 +11,15 @@
const bounds = defaultGraphBounds();
const xText = "";
const yText = "Times pressed";
let svg = null as HTMLElement | SVGElement | null;
$: if (sourceData) {
console.log("gathering data");
renderButtons(svg as SVGElement, bounds, gatherData(sourceData));
}
const title = i18n.tr(i18n.TR.STATISTICS_ANSWER_BUTTONS_TITLE);
const yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_ANSWER_COUNT);
</script>
<div class="graph">
@ -30,6 +29,6 @@
<g class="bars" />
<g class="hoverzone" />
<AxisTicks {bounds} />
<AxisLabels {bounds} {xText} {yText} />
<AxisLabels {bounds} {xText} {yText} {i18n} />
</svg>
</div>

View file

@ -8,7 +8,6 @@
let cardCounts: CardCounts | null = null;
$: if (sourceData) {
console.log("gathering data");
cardCounts = gatherData(sourceData, i18n);
}
</script>

View file

@ -12,17 +12,17 @@
let histogramData = null as HistogramData | null;
$: if (sourceData) {
console.log("gathering data");
histogramData = prepareData(gatherData(sourceData));
}
const title = i18n.tr(i18n.TR.STATISTICS_CARD_EASE_TITLE);
const yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_CARD_COUNT);
</script>
{#if histogramData}
<div class="graph">
<h1>{title}</h1>
<HistogramGraph data={histogramData} xText="Ease (%)" yText="Number of cards" />
<HistogramGraph data={histogramData} xText="Ease (%)" {yText} {i18n} />
</div>
{/if}

View file

@ -23,12 +23,10 @@
let range = FutureDueRange.Month;
$: if (sourceData) {
console.log("gathering data");
graphData = gatherData(sourceData);
}
$: if (graphData) {
console.log("preparing data");
histogramData = buildHistogram(graphData, range);
}
@ -37,6 +35,7 @@
const month3 = timeSpan(i18n, 3 * MONTH);
const year = timeSpan(i18n, 1 * YEAR);
const all = i18n.tr(i18n.TR.STATISTICS_RANGE_ALL_TIME);
const yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_CARD_COUNT);
</script>
{#if histogramData}
@ -44,6 +43,10 @@
<div class="graph">
<h1>{title}</h1>
<div class="range-box-inner">
The number of cards studied each day, relative to today.
</div>
<div class="range-box-inner">
<label>
<input type="radio" bind:group={range} value={FutureDueRange.Month} />
@ -63,10 +66,7 @@
</label>
</div>
<HistogramGraph
data={histogramData}
xText="Days from now"
yText="Number of cards" />
<HistogramGraph data={histogramData} xText="" {yText} {i18n} />
</div>
{/if}

View file

@ -3,8 +3,10 @@
import AxisLabels from "./AxisLabels.svelte";
import AxisTicks from "./AxisTicks.svelte";
import { defaultGraphBounds } from "./graphs";
import { I18n } from "../i18n";
export let data: HistogramData | null = null;
export let i18n: I18n;
export let xText: string;
export let yText: string;
@ -21,5 +23,5 @@
<g class="hoverzone" />
<path class="area" />
<AxisTicks {bounds} />
<AxisLabels {bounds} {xText} {yText} />
<AxisLabels {bounds} {xText} {yText} {i18n} />
</svg>

View file

@ -11,16 +11,15 @@
const bounds = defaultGraphBounds();
const xText = "";
const yText = "Times pressed";
let svg = null as HTMLElement | SVGElement | null;
$: if (sourceData) {
console.log("gathering data");
renderHours(svg as SVGElement, bounds, gatherData(sourceData));
}
const title = i18n.tr(i18n.TR.STATISTICS_HOURS_TITLE);
const yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_ANSWER_COUNT);
</script>
<div class="graph">
@ -31,6 +30,6 @@
<path class="area" />
<g class="hoverzone" />
<AxisTicks {bounds} />
<AxisLabels {bounds} {xText} {yText} />
<AxisLabels {bounds} {xText} {yText} {i18n} />
</svg>
</div>

View file

@ -21,18 +21,17 @@
let range = IntervalRange.Percentile95;
$: if (sourceData) {
console.log("gathering data");
intervalData = gatherIntervalData(sourceData);
}
$: if (intervalData) {
console.log("preparing data");
histogramData = prepareIntervalData(intervalData, range);
}
const title = i18n.tr(i18n.TR.STATISTICS_INTERVALS_TITLE);
const month = timeSpan(i18n, 1 * MONTH);
const all = i18n.tr(i18n.TR.STATISTICS_RANGE_ALL_TIME);
const yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_CARD_COUNT);
</script>
{#if histogramData}
@ -71,9 +70,6 @@
</label>
</div>
<HistogramGraph
data={histogramData}
xText="Interval (days)"
yText="Number of cards" />
<HistogramGraph data={histogramData} xText="Interval (days)" {yText} {i18n} />
</div>
{/if}

View file

@ -32,21 +32,27 @@
}
const xText = "";
const yText = "Times pressed";
$: if (sourceData) {
console.log("gathering data");
graphData = gatherData(sourceData);
}
$: if (graphData) {
renderReviews(svg as SVGElement, bounds, graphData, range, showTime);
renderReviews(svg as SVGElement, bounds, graphData, range, showTime, i18n);
}
const title = i18n.tr(i18n.TR.STATISTICS_REVIEWS_TITLE);
const month = timeSpan(i18n, 1 * MONTH);
const month3 = timeSpan(i18n, 3 * MONTH);
const year = timeSpan(i18n, 1 * YEAR);
const all = i18n.tr(i18n.TR.STATISTICS_RANGE_ALL_TIME);
let yText: string;
$: if (showTime) {
yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_REVIEW_TIME);
} else {
yText = i18n.tr(i18n.TR.STATISTICS_AXIS_LABEL_ANSWER_COUNT);
}
</script>
<div class="graph">
@ -75,7 +81,7 @@
{#if revlogRange === RevlogRange.All}
<label>
<input type="radio" bind:group={range} value={ReviewRange.AllTime} />
All time
{all}
</label>
{/if}
</div>
@ -87,7 +93,7 @@
<path class="area" />
<g class="hoverzone" />
<AxisTicks {bounds} />
<AxisLabels {bounds} {xText} {yText} />
<AxisLabels {bounds} {xText} {yText} {i18n} />
</svg>
</div>

View file

@ -81,8 +81,7 @@
}
.y-axis-label {
writing-mode: vertical-rl;
rotate: 180;
writing-mode: vertical-lr;
}
.hoverzone rect {

View file

@ -21,6 +21,8 @@ import { showTooltip, hideTooltip } from "./tooltip";
import { GraphBounds } from "./graphs";
import { area, curveBasis } from "d3-shape";
import { min, histogram, sum, max, Bin, cumsum } from "d3-array";
import { timeSpan } from "../time";
import { I18n } from "../i18n";
interface Reviews {
mature: number;
@ -111,7 +113,8 @@ export function renderReviews(
bounds: GraphBounds,
sourceData: GraphData,
range: ReviewRange,
showTime: boolean
showTime: boolean,
i18n: I18n
): void {
const xMax = 0;
let xMin = 0;
@ -161,6 +164,17 @@ export function renderReviews(
axisLeft(y)
.ticks(bounds.height / 80)
.tickSizeOuter(0)
.tickFormat(((n: number): string => {
if (showTime) {
return timeSpan(i18n, n / 1000);
} else {
if (Math.round(n) != n) {
return "";
} else {
return n.toString();
}
}
}) as any)
);
// x bars