Move dispatch logic from Histogram to individual graphs

This commit is contained in:
Henrik Giesel 2021-01-25 16:33:18 +01:00
parent f767a5e6ca
commit 759ed17963
14 changed files with 98 additions and 71 deletions

View file

@ -65,7 +65,7 @@ class DeckBrowser:
def _linkHandler(self, url):
if ":" in url:
(cmd, arg) = url.split(":")
(cmd, arg) = url.split(":", 1)
else:
cmd = url
if cmd == "open":

View file

@ -1092,7 +1092,6 @@ message GraphsOut {
uint32 scheduler_version = 5;
/// Seconds to add to UTC timestamps to get local time.
int32 local_offset_secs = 7;
bool bridge_commands_supported = 8;
}
message GraphPreferences {
@ -1104,6 +1103,7 @@ message GraphPreferences {
}
Weekday calendar_first_day_of_week = 1;
bool card_counts_separate_inactive = 2;
bool browser_links_supported = 3;
}
message RevlogEntry {

View file

@ -44,7 +44,6 @@ impl Collection {
next_day_at_secs: timing.next_day_at as u32,
scheduler_version: self.sched_ver() as u32,
local_offset_secs: local_offset_secs as i32,
bridge_commands_supported: true,
})
}
@ -52,6 +51,7 @@ impl Collection {
Ok(pb::GraphPreferences {
calendar_first_day_of_week: self.get_first_day_of_week() as i32,
card_counts_separate_inactive: self.get_card_counts_separate_inactive(),
browser_links_supported: true,
})
}

View file

@ -9,6 +9,7 @@
import HistogramGraph from "./HistogramGraph.svelte";
import GraphRangeRadios from "./GraphRangeRadios.svelte";
import TableData from "./TableData.svelte";
import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
@ -17,13 +18,15 @@
let tableData: TableDatum[] = [];
let graphRange: GraphRange = GraphRange.Month;
const dispatch = createEventDispatcher();
let addedData: GraphData | null = null;
$: if (sourceData) {
addedData = gatherData(sourceData);
}
$: if (addedData) {
[histogramData, tableData] = buildHistogram(addedData, graphRange, i18n);
[histogramData, tableData] = buildHistogram(addedData, graphRange, i18n, dispatch);
}
const title = i18n.tr(i18n.TR.STATISTICS_ADDED_TITLE);

View file

@ -11,7 +11,7 @@
export let i18n: I18n;
export let preferences: PreferenceStore;
let { cardCountsSeparateInactive } = preferences;
let { cardCountsSeparateInactive, browserLinksSupported } = preferences;
const dispatch = createEventDispatcher();
let svg = null as HTMLElement | SVGElement | null;
@ -89,7 +89,7 @@
<!-- prettier-ignore -->
<td>
<span style="color: {d.colour};">&nbsp;</span>
{#if sourceData.bridgeCommandsSupported}
{#if browserLinksSupported}
<span class="search-link" on:click={() => dispatch('search', { query: d.query })}>{d.label}</span>
{:else}
<span>{d.label}</span>

View file

@ -6,15 +6,18 @@
import type { I18n } from "anki/i18n";
import type { TableDatum } from "./graph-helpers";
import TableData from "./TableData.svelte";
import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
const dispatch = createEventDispatcher();
let histogramData = null as HistogramData | null;
let tableData: TableDatum[] = [];
$: if (sourceData) {
[histogramData, tableData] = prepareData(gatherData(sourceData), i18n);
[histogramData, tableData] = prepareData(gatherData(sourceData), i18n, dispatch);
}
const title = i18n.tr(i18n.TR.STATISTICS_CARD_EASE_TITLE);

View file

@ -9,10 +9,13 @@
import HistogramGraph from "./HistogramGraph.svelte";
import GraphRangeRadios from "./GraphRangeRadios.svelte";
import TableData from "./TableData.svelte";
import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
const dispatch = createEventDispatcher();
let graphData = null as GraphData | null;
let histogramData = null as HistogramData | null;
let tableData: TableDatum[] = [] as any;
@ -28,7 +31,8 @@
graphData,
graphRange,
backlog,
i18n
i18n,
dispatch,
));
}

View file

@ -12,10 +12,13 @@
import HistogramGraph from "./HistogramGraph.svelte";
import type { TableDatum } from "./graph-helpers";
import TableData from "./TableData.svelte";
import { createEventDispatcher } from "svelte";
export let sourceData: pb.BackendProto.GraphsOut | null = null;
export let i18n: I18n;
const dispatch = createEventDispatcher();
let intervalData: IntervalGraphData | null = null;
let histogramData = null as HistogramData | null;
let tableData: TableDatum[] = [];
@ -26,7 +29,7 @@
}
$: if (intervalData) {
[histogramData, tableData] = prepareIntervalData(intervalData, range, i18n);
[histogramData, tableData] = prepareIntervalData(intervalData, range, i18n, dispatch);
}
const title = i18n.tr(i18n.TR.STATISTICS_INTERVALS_TITLE);

View file

@ -7,7 +7,7 @@
*/
import type pb from "anki/backend_proto";
import { extent, histogram, sum } from "d3-array";
import { extent, histogram, sum, Bin } from "d3-array";
import { scaleLinear, scaleSequential } from "d3-scale";
import type { HistogramData } from "./histogram-graph";
import { interpolateBlues } from "d3-scale-chromatic";
@ -28,10 +28,22 @@ export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
return { daysAdded };
}
function makeQuery(start: number, end: number): string {
const include = `"added:${start}"`;
if (start === 1) {
return include;
}
const exclude = `-"added:${end}"`;
return `${include} AND ${exclude}`;
}
export function buildHistogram(
data: GraphData,
range: GraphRange,
i18n: I18n
i18n: I18n,
dispatch: any,
): [HistogramData | null, TableDatum[]] {
// get min/max
const total = data.daysAdded.length;
@ -102,17 +114,11 @@ export function buildHistogram(
return `${day}:<br>${cards}<br>${total}: ${totalCards}`;
}
function makeQuery(data: HistogramData, binIdx: number): string {
const start = Math.abs(data.bins[binIdx].x0!) + 1;
const include = `"added:${start}"`;
if (start === 1) {
return include;
}
const end = Math.abs(data.bins[binIdx].x1!) + 1;
const exclude = `-"added:${end}"`;
return `${include} AND ${exclude}`;
function onClick(bin: Bin<number, number>): void {
const start = Math.abs(bin.x0!) + 1;
const end = Math.abs(bin.x1!) + 1;
const query = makeQuery(start, end);
dispatch("search", { query });
}
return [
@ -121,7 +127,7 @@ export function buildHistogram(
bins,
total: totalInPeriod,
hoverText,
makeQuery,
onClick,
colourScale,
showArea: true,
},

View file

@ -114,7 +114,6 @@ export function renderCalendar(
maxCount = count;
}
}
console.log("sourceData", sourceData, dayMap);
if (!maxCount) {
setDataAvailable(svg, false);

View file

@ -7,7 +7,7 @@
*/
import type pb from "anki/backend_proto";
import { extent, histogram, sum } from "d3-array";
import { extent, histogram, sum, Bin } from "d3-array";
import { scaleLinear, scaleSequential } from "d3-scale";
import { CardType } from "anki/cards";
import type { HistogramData } from "./histogram-graph";
@ -26,9 +26,21 @@ export function gatherData(data: pb.BackendProto.GraphsOut): GraphData {
return { eases };
}
function makeQuery(start: number, end: number): string {
if (start === end) {
return `"prop:ease=${start / 100}"`;
}
const fromQuery = `"prop:ease>=${start / 100}"`;
const tillQuery = `"prop:ease<${end / 100}"`;
return `${fromQuery} AND ${tillQuery}`;
}
export function prepareData(
data: GraphData,
i18n: I18n
i18n: I18n,
dispatch: any,
): [HistogramData | null, TableDatum[]] {
// get min/max
const allEases = data.eases;
@ -61,19 +73,11 @@ export function prepareData(
});
}
function makeQuery(data: HistogramData, binIdx: number): string {
const bin = data.bins[binIdx];
function onClick(bin: Bin<number, number>): void {
const start = bin.x0!;
const end = bin.x1! - 1;
if (start === end) {
return `"prop:ease=${start / 100}"`;
}
const fromQuery = `"prop:ease>=${start / 100}"`;
const tillQuery = `"prop:ease<${end / 100}"`;
return `${fromQuery} AND ${tillQuery}`;
const query = makeQuery(start, end);
dispatch("search", { query });
}
const xTickFormat = (num: number): string => `${num.toFixed(0)}%`;
@ -90,7 +94,7 @@ export function prepareData(
bins,
total,
hoverText,
makeQuery,
onClick,
colourScale,
showArea: false,
xTickFormat,

View file

@ -72,11 +72,23 @@ export interface FutureDueOut {
tableData: TableDatum[];
}
function makeQuery(start: number, end: number): string {
if (start === end) {
return `"prop:due=${start}"`;
}
else {
const fromQuery = `"prop:due>=${start}"`;
const tillQuery = `"prop:due<=${end}"`;
return `${fromQuery} AND ${tillQuery}`;
}
}
export function buildHistogram(
sourceData: GraphData,
range: GraphRange,
backlog: boolean,
i18n: I18n
i18n: I18n,
dispatch: any,
): FutureDueOut {
const output = { histogramData: null, tableData: [] };
// get min/max
@ -145,19 +157,11 @@ export function buildHistogram(
return `${days}:<br>${cards}<br>${totalLabel}: ${cumulative}`;
}
function makeQuery(data: HistogramData, binIdx: number): string {
const bin = data.bins[binIdx];
function onClick(bin: Bin<number, number>): void {
const start = bin.x0!;
const end = bin.x1! - 1;
if (start === end) {
return `"prop:due=${start}"`;
}
const fromQuery = `"prop:due>=${start}"`;
const tillQuery = `"prop:due<=${end}"`;
return `${fromQuery} AND ${tillQuery}`;
const query = makeQuery(start, end);
dispatch("search", { query });
}
const periodDays = xMax! - xMin!;
@ -186,7 +190,7 @@ export function buildHistogram(
bins,
total,
hoverText,
makeQuery,
onClick,
showArea: true,
colourScale,
binValue,

View file

@ -25,7 +25,7 @@ export interface HistogramData {
cumulative: number,
percent: number
) => string;
makeQuery?: (data: HistogramData, binIdx: number) => string;
onClick?: (data: Bin<number, number>) => void;
showArea: boolean;
colourScale: ScaleSequential<string>;
binValue?: (bin: Bin<any, any>) => number;
@ -36,7 +36,6 @@ export function histogramGraph(
svgElem: SVGElement,
bounds: GraphBounds,
data: HistogramData | null,
dispatch: any
): void {
const svg = select(svgElem);
const trans = svg.transition().duration(600) as any;
@ -162,11 +161,9 @@ export function histogramGraph(
})
.on("mouseout", hideTooltip);
if (data.makeQuery) {
if (data.onClick) {
hoverzone
.attr("class", "clickable")
.on("click", function (this: any, _d: any, idx: number) {
dispatch("search", { query: data.makeQuery!(data, idx) });
});
.on("click", data.onClick);
}
}

View file

@ -7,7 +7,7 @@
*/
import type pb from "anki/backend_proto";
import { extent, histogram, quantile, sum, mean } from "d3-array";
import { extent, histogram, quantile, sum, mean, Bin } from "d3-array";
import { scaleLinear, scaleSequential } from "d3-scale";
import { CardType } from "anki/cards";
import type { HistogramData } from "./histogram-graph";
@ -56,10 +56,22 @@ export function intervalLabel(
}
}
function makeQuery(start: number, end: number): string {
if (start === end) {
return `"prop:ivl=${start}"`;
}
const fromQuery = `"prop:ivl>=${start}"`;
const tillQuery = `"prop:ivl<=${end}"`;
return `${fromQuery} AND ${tillQuery}`;
}
export function prepareIntervalData(
data: IntervalGraphData,
range: IntervalRange,
i18n: I18n
i18n: I18n,
dispatch: any,
): [HistogramData | null, TableDatum[]] {
// get min/max
const allIntervals = data.intervals;
@ -134,19 +146,11 @@ export function prepareIntervalData(
return `${interval}<br>${total}: \u200e${percent.toFixed(1)}%`;
}
function makeQuery(data: HistogramData, binIdx: number): string {
const bin = data.bins[binIdx];
function onClick(bin: Bin<number, number>): void {
const start = bin.x0!;
const end = bin.x1! - 1;
if (start === end) {
return `"prop:ivl=${start}"`;
}
const fromQuery = `"prop:ivl>=${start}"`;
const tillQuery = `"prop:ivl<=${end}"`;
return `${fromQuery} AND ${tillQuery}`;
const query = makeQuery(start, end);
dispatch("search", { query });
}
const meanInterval = Math.round(mean(allIntervals) ?? 0);
@ -163,7 +167,7 @@ export function prepareIntervalData(
bins,
total: totalInPeriod,
hoverText,
makeQuery,
onClick,
colourScale,
showArea: true,
},