hand_drawn_analytics library
A bridge between analytics_toolkit (a rendering-agnostic query engine) and
hand_drawn_toolkit (sketchy chart and table widgets).
Configure a hand_drawn_toolkit chart as a styling template (with
data: null), hand it plus a typed analytics query to one of the
HandDrawnAnalytics* widgets, and the bridge runs the query, maps the
result into the toolkit's data class, and renders it — defaulting only the
values you left unset, never reinterpreting your query.
Classes
- AnalyticsScalarCard
- A self-contained card that runs a single scalar query and shows the result as a big number inside CardChrome.
- AnalyticsScope
- Carries shared bridge configuration down the widget tree for the common one-config-per-page case.
- AnalyticsScopeData
- The configuration an AnalyticsScope publishes to its descendants.
- AnalyticsWidgetBuilders
- Consumer-supplied widget builders keyed by the bridge's mapped data class.
-
AsyncData<
T> - The load completed successfully with value.
-
AsyncError<
T> - The load failed with error.
-
AsyncLoading<
T> - The load is in progress; no data or error yet.
-
AsyncValue<
T> - The tri-state of an in-flight asynchronous load: loading, data, or error.
- BridgeAnalyticsError
-
Wraps an upstream
AnalyticsError(validation or execution failure) so the bridge can carry it through the sameErrchannel as its own errors. - BridgeError
- The bridge's vocabulary for failure and async state.
- BridgeFormatters
- The single source of truth for turning typed analytics values into display strings and chart-ready numbers.
- BridgeIncompatibleValues
- The result's shape fits the widget, but its values cannot be plotted on a numeric axis. The specific cause is carried in reason — a non-numeric measure type, several series with incompatible units sharing one axis, or epoch spacing requested over non-temporal keys.
- BridgeMissingScope
-
A required piece of configuration (palette, formatters, page range, …) was
neither passed to the widget nor available from an enclosing
AnalyticsScope. missingField names what was absent. - BridgePalette
- An ordered color palette plus the bridge's coloring resolution order.
- BridgeResult
- The successful payload of a query run.
- BridgeShapeMismatch
- The result a mapper was handed does not match the shape the chosen widget can draw — e.g. a multi-series result handed to a single-series bar mapper.
- CardChrome
-
Hand-drawn framing around a dashboard widget: a
HandDrawnContainerwith optional title and an optional edit affordance. - ExecuteQueryRequest
- A plain, transport-friendly bundle of everything the executor needs.
- HandDrawnAnalyticsBarChart
-
A bar chart backed by an analytics query and styled by a
hand_drawn_toolkittemplate. - HandDrawnAnalyticsBigNumber
- A prominent single-value display backed by an analytics scalar result.
- HandDrawnAnalyticsCard
-
A spec-driven dashboard card: decodes an
AnalyticsWidgetSpec's three JSON payloads, runs the query, and renders the result by its display type inside CardChrome. - HandDrawnAnalyticsLineChart
-
A line chart backed by an analytics query and styled by a
hand_drawn_toolkittemplate. - HandDrawnAnalyticsScatterPlot
-
A scatter plot of two analytics series aligned by bucket key, styled by a
hand_drawn_toolkittemplate. - HandDrawnAnalyticsStreakLeaderboard
-
A streak leaderboard backed by a
StreakMeasurequery, styled by aHandDrawnTabletemplate. - HandDrawnAnalyticsTable
-
A table backed by an analytics query, styled by a
hand_drawn_toolkitHandDrawnTabletemplate. - HandDrawnAnalyticsWidget
-
Renders an already-computed BridgeResult according to a free-form
displayType, without running a query itself. - HandDrawnTableView
-
Renders an already-mapped TableMapping into a
HandDrawnTabletemplate, optionally with resizable columns. - PairedResult
-
The result of a paired query: an independently-computed x and y series,
aligned downstream by
BucketKeyequality. - ScatterMapping
- The result of pairedToScatter: the chart data plus how many buckets were dropped during alignment, so a widget can optionally surface the data loss (mirroring the table mapper's truncated-row count).
- SeriesView
- A uniform read-only view over the two "named series" shapes the analytics layer produces:
- SingleResult
- The result of a single (non-paired) query.
- StreakTableOptions
-
Options controlling how a streak
TableResultis laid out as a leaderboard. - TableMapping
- The bridge's stringified table projection of any analytics result.
- UnknownDisplayType
-
Returned by HandDrawnVisualizationKind.resolve when a
displayTypestring matches neither a canonical name nor a configured alias. - WidgetQueryRunner
- The one place that knows the toolkit's execution choreography: list sources → validate → project the date range → fetch records → execute. Its seams (listSources, fetchRecords, executeQuery) are injectable so the same orchestration works in tests, in-process, or across an isolate.
Enums
- BarMode
- How a multi-dimension result is laid out as bars.
- HandDrawnVisualizationKind
- The closed set of visualizations the bridge knows how to render.
- IncompatibleValuesReason
- Why a result's values cannot be drawn on a numeric chart axis.
- TemporalSpacing
- How points are positioned along a line chart's X axis.
Functions
-
assembleLineChartData(
{required List< LineSeriesData> series, required List<BucketKey> keys, required List<double> positions, required List<List< numericGrid, required BridgeFormatters formatters, required TemporalSpacing temporalSpacing, required bool integerValued, required FieldType unitType, required List<double?> >LegendEntry> legend}) → LineChartData -
Builds
LineChartDatawith computed Y/X ranges, the zero-crossing axis default, categorical labels (under uniform spacing), and a unit-suffixed Y formatter. -
bridgeShapeOf(
BridgeResult result) → ResultShape -
The
ResultShapeof a BridgeResult. Used when building a BridgeShapeMismatch so the error reports the shape that was actually produced rather than a fixed placeholder. -
defaultAxisDisplayFor(
NiceRange? range) → AxisDisplay -
The default
AxisDisplayfor a value axis spanningrange. -
defaultShouldReload(
AnalyticsChange change, Set< String> mySourceIds) → bool - The default reload policy (matches the locked change semantics):
-
epochSpacingGuard(
List< BucketKey> keys, TemporalSpacing spacing) → BridgeError? - Guards epoch-millisecond spacing against non-temporal keys.
-
isChartableFieldType(
FieldType type) → bool -
Whether
typecan be projected onto a numeric chart axis. -
isIntegerMeasure(
Measure measure, {FieldType? outputType}) → bool -
Whether
measureinherently produces integer-valued output, so a chart axis should default to integer ticks. -
mixedUnitGuard(
List< SeriesView> views) → BridgeError? - Guards against plotting series whose values carry incompatible units on a single shared axis.
-
multiMeasureToBar(
MultiMeasureSeriesResult result, {required BarMode mode, required BridgePalette palette, required BridgeFormatters formatters, SemanticColorResolver? resolver, bool integerValued = false, double? fillAlpha}) → Result< BarChartData, BridgeError> -
Maps a
MultiMeasureSeriesResultto grouped or stackedBarChartData. -
multiMeasureToLine(
MultiMeasureSeriesResult result, {required BridgePalette palette, required BridgeFormatters formatters, SemanticColorResolver? resolver, TemporalSpacing temporalSpacing = TemporalSpacing.uniform, bool integerValued = false}) → Result< LineChartData, BridgeError> -
Maps a
MultiMeasureSeriesResultto a multi-lineLineChartData— one line per measure. Rejects mixed-unit measures. -
multiSeriesToBar(
MultiSeriesResult result, {required BarMode mode, required BridgePalette palette, required BridgeFormatters formatters, SemanticColorResolver? resolver, bool integerValued = false, double? fillAlpha}) → Result< BarChartData, BridgeError> -
Maps a
MultiSeriesResultto grouped or stackedBarChartData. -
multiSeriesToLine(
MultiSeriesResult result, {required BridgePalette palette, required BridgeFormatters formatters, SemanticColorResolver? resolver, TemporalSpacing temporalSpacing = TemporalSpacing.uniform, bool integerValued = false}) → Result< LineChartData, BridgeError> -
Maps a
MultiSeriesResultto a multi-lineLineChartData— one line per secondary-group series. -
nicePaddedRange(
Iterable< double?> values) → NiceRange? -
A padded range for scatter plots: unlike niceYRange this never floors at
zero — it pads both ends so points don't sit on the axis. Returns
nullwhen there is nothing to plot. -
niceUpperBound(
double value, {bool integerValued = false}) → double -
Rounds
valueup to a visually tidy bound (1/2/2.5/5 × 10ⁿ). ForintegerValueddata the result is at least the ceiling ofvalueand is itself a whole number. -
niceYRange(
Iterable< double?> values, {bool integerValued = false}) → NiceRange? -
Computes a tidy Y range for bar/line charts from the plottable
values. -
outputTypeOf(
AnalyticsResult result) → FieldType? -
The measure output
FieldTypea chart axis should format against, ornullwhen there is no single such type. -
pairedToScatter(
SeriesResult x, SeriesResult y, {required BridgeFormatters formatters, String? xAxisLabel, String? yAxisLabel}) → Result< ScatterMapping, BridgeError> -
Aligns two series by
BucketKeyand maps the matched(x, y)pairs to a ScatterMapping. -
projectMultiSeries(
List< SeriesView> views, {required BridgeFormatters formatters}) → List<List< double?> > -
Projects the
viewsinto a denseseries × positiongrid of plottabledouble?s, usingformattersto map each typed value to a chart number. -
resolveIntegerValued(
{required bool? explicit, required List< Measure> measures, FieldType? outputType}) → bool - Resolves the effective integer-valued axis flag for a chart widget.
-
resultShapeOf(
AnalyticsResult result) → ResultShape -
The
ResultShapecorresponding to a concreteAnalyticsResult. Used when building a BridgeShapeMismatch so the error reports the actual shape. -
resultToTable(
AnalyticsResult result, {required BridgeFormatters formatters}) → Result< TableMapping, BridgeError> -
Universal intake: maps any
AnalyticsResultto a TableMapping. -
scalarToBigNumber(
AnalyticsResult result, {required BridgeFormatters formatters}) → Result< ({Color? color, String displayValue, String? label}), BridgeError> - The big-number projection of a scalar result: a display string, the measure label, and an optional color (left null — the widget decides).
-
seriesToBar(
SeriesResult result, {required BridgePalette palette, required BridgeFormatters formatters, SemanticColorResolver? resolver, bool integerValued = false, double? fillAlpha}) → Result< BarChartData, BridgeError> -
Maps a single
SeriesResulttoBarChartData: one bar per bucket. -
seriesToLine(
SeriesResult result, {required BridgePalette palette, required BridgeFormatters formatters, SemanticColorResolver? resolver, TemporalSpacing temporalSpacing = TemporalSpacing.uniform, bool integerValued = false}) → Result< LineChartData, BridgeError> -
Maps a single
SeriesResultto a one-lineLineChartData. -
streakToTable(
TableResult table, {required BridgeFormatters formatters, StreakTableOptions options = const StreakTableOptions()}) → TableMapping? -
Maps a
StreakMeasureTableResultto a readable leaderboard TableMapping (raw entity id hidden by default, wide name column, narrow streak counts). -
unchartableValueError(
FieldType type) → BridgeError -
The error returned when a measure's output
typecannot be plotted on a numeric axis. Suggests a table, which can render any value. -
unitAxisFormatter(
BridgeFormatters formatters, FieldType fieldType) → AxisValueFormatter? -
A Y-axis tick formatter that appends the measure's unit (only durations
carry one), or
nullwhen no unit annotation applies.
Typedefs
-
AnalyticsCardReloadPredicate
= bool Function(AnalyticsChange change, Set<
String> mySourceIds) -
A predicate deciding whether a widget should reload in response to an
AnalyticsChange.mySourceIdsis the set of source ids the widget reads. -
ExecuteQueryFn
= FutureOr<
Result< Function(ExecuteQueryRequest request)AnalyticsResult, AnalyticsError> > -
Executes a fully-prepared request and returns the typed result,
synchronously or asynchronously. The default runs
AnalyticsExecutor.executein-process; an async function lets a host move execution off the main isolate (e.g. by handing the request tocomputewith a top-level function that callsAnalyticsExecutor.execute). -
FetchRecordsFn
= Future<
List< Function(String sourceId, {(DateTime, DateTime)? dateBound})SourceRecord> > -
Fetches the normalized records for
sourceId, optionally bounded to a resolved[start, end)date range. The host typically composesSourceSnapshotCache.getOrFetchinto this seam; the runner does not own a cache itself. -
ListSourcesFn
= List<
SourceDef> Function() - Supplies the source catalog to validate and project against.
- NiceRange = ({double max, double min})
-
A computed
[min, max]axis range. - SemanticColorResolver = Color? Function(String? semanticTag, BucketKey? key)
- A consumer-supplied hook for assigning a color to a series, bucket, or segment from its semantic identity rather than its position.