Class Chart<W extends Chart<W>>
- Direct Known Subclasses:
CartesianChart,DonutChart
BarChart, LineChart and
DonutChart add the marks and the axes.
A chart is usable with nothing configured: colors come from the palette that matches
the active Theme, the scale rounds itself, the legend appears when there is more
than one thing to name, and values animate in. Everything past that is a setter.
BarChart chart = new BarChart();
chart.setLabels("Mon", "Tue", "Wed", "Thu", "Fri");
chart.addSeries(ChartSeries.of("Signups", 12, 19, 3, 5, 22));
chart.addSeries(ChartSeries.of("Churn", 2, 3, 1, 4, 2));
chart.setStacked(true);
chart.onPointClick(point -> open(point.label()));
Animation. Values interpolate, not pixels: on the first appearance a series
grows out of the axis baseline, and afterwards it eases from the number on screen to the
number it was just given, so a live chart re-pushed every second reads as one moving
shape rather than as a slideshow. setAnimationDuration(double) with 0
turns it off, which is also what a chart with no scene does: a headless test or a
screenshot sees final values, never an in-between frame.
Interaction. Hovering reports the datum under the pointer; the tooltip follows
it and stays inside the chart. A chart with more than one series reports every series at
the hovered category at once (Chart.TooltipMode.INDEX), which is what makes two lines
comparable at a glance. Clicking calls onPointClick(Consumer) with the same
datum. Clicking a legend entry hides and shows its series, animating the scale and any
stack around it.
Charts are painted, not composed: a chart has no child widgets, with one exception:
DonutChart.setCenter(Widget) puts a real widget in the hole, so the middle of a
donut can hold a label, an icon or a button.
On chaining. The setters here return Chart, so a chain that starts on a
subclass cannot continue into one of that subclass's own setters:
new BarChart().setTitle("x").setStacked(true) does not compile. Configure a chart
in statements (which is how the demo scenes read anyway) or start from
BarChart.of(java.util.List<java.lang.String>, limn.components.chart.ChartSeries...), LineChart.of(java.util.List<java.lang.String>, limn.components.chart.ChartSeries...) and DonutChart.of(java.util.List<java.lang.String>, double...), which take the labels
and the series together. The alternative, redeclaring every setter in all three
subclasses purely to narrow its return type, buys one expression shape at the price of
forty methods whose documentation could only repeat their signatures.
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprotected static final recordOne row of the legend: a swatch, a name, and whether its data is currently drawn.static enumWhere the legend sits relative to the plot.static enumHow much a hover reports. -
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final floatHands a dimension back to the default size, theProgressBar.UNSETidiom. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionaddSeries(ChartSeries newSeries) Adds a series.protected doubleThe value a series grows out of when it first appears, and collapses to when it is hidden: where the axis crosses the plot, which is zero on any scale that contains it and the nearer end otherwise.doubleLength of the entry and value-change animation, in seconds.@Nullable ColorThe panel color behind the chart, ornullwhen it paints on what is below.final intHow many categories the chart spans: the labels, or the longest series.Removes every series.Takes the title away, assetTitle(null)would: that call does not compile, becausenullfits more than one of the overloads.protected final floatHeight of the region left after the title and the legend.protected final floatWidth of the region left after the title and the legend.protected final floatLeft edge of the region left after the title and the legend.protected final floatTop edge of the region left after the title and the legend.protected final voidDamages whatever the hover draws right now, without erasing anywhere it has been.protected final intBumped by every change to the data or to what is visible in it.protected final doubledrawnValue(int seriesIndex, int index) The value seriesseriesIndexis drawn at right now, animation included.protected final floatelementProgress(int index, int count) protected final Stringtextshortened with an ellipsis until it fitsmaxWidth, or""when not even the ellipsis fits.protected voidhandleUserChange(Change.Aspect aspect) Both handlers readhoveredPoint(), which is assigned before either announcement, so neither needs a payload the channel does not carry.@Nullable ChartPointThe datum under the pointer, ornull.protected @Nullable RecthoverRegion(ChartPoint point) The region of this chart that changes whenpointis the datum under the pointer: lit marks, a crosshair, a band, a popped slice.booleanWhether clicking a legend entry hides and shows its data.booleanWhether hovering shows a tooltip.label(int index) The label forindex, or""when there are fewer labels than values.labels()The category labels as they currently read, in order.labelSource(int index) The localizable value behindlabel(int), orI18nString.EMPTYpast the end: what a language change re-resolves.protected final voidDrops the legend's cached entries, for a chart whose legend is not the series list.protected List<Chart.LegendEntry> One entry per series, in palette order.protected final voidlegendEntryBounds(int index, Accessibility a) Places the node being described at legend entryindex's box, in this chart's own coordinates: the same rectangle a click on the legend is tested against, so the published box and the operable box are one array.protected final intHow many legend entries are drawn right now, with their boxes brought up to date first:0whenever the legend is not drawn, which folds inChart.LegendPosition.NONE,Chart.LegendPosition.AUTOwith fewer than two entries and a chart with nothing to name.Where the legend sits.protected final TextMetricsMeasures a single line with the layout ruler (agrees with whatdrawTextdraws).protected voidCalled when this widget enters a scene (attached to the tree).protected voidonHoverChanged(@Nullable ChartPoint picked) Called when the datum under the pointer changes,nullwhen there is none: the hook for a chart that animates something on hover.protected voidonLayout()Recomputes the regions whenever the box is laid out, so that the legend's boxes are current for the tree published between this pass and the paint.protected SizeonMeasure(Constraints constraints) Reports the size this widget wants withinconstraints.protected voidonMouseEvent(MouseEvent event) Mouse events (bubbling); callevent.consume()when handled.protected voidWidget's own background/content, in local coordinates.protected voidonPaintOverlay(Canvas canvas) Painted after children (scrollbars, focus rings…).onPointClick(@Nullable Consumer<ChartPoint> listener) Called with the datum under the pointer on a left click.onPointHover(@Nullable Consumer<@Nullable ChartPoint> listener) Called whenever the hovered datum changes, withnullwhen the pointer leaves the marks.protected voidonSeriesAdded(ChartSeries added) Called with a series that has just joined the chart, before anything is animated.protected abstract voidpaintContent(Canvas canvas, float x, float y, float w, float h) Paints the marks inside the region left after the title and the legend, in the chart's own coordinates.palette()The palette in force: the one that was set, or the built-in one for this theme.protected abstract @Nullable ChartPointpickAt(float localX, float localY) The datum under a point in the chart's local coordinates, ornullwhen the pointer is not over the marks.protected final ChartPointpointFor(int seriesIndex, int index, double share, float x, float y) Builds aChartPointfor a datum, with the anchor the caller measured.protected final floatprogress()Overall animation progress in[0,1]; 1 means the data as it stands.removeSeries(ChartSeries victim) Removes a series; a no-op when it is not in this chart.Replays the entry animation from the axis baseline.series()The series, in the order they were added (paint and palette order).protected final ChartSeriesseries(int index) The series atindex, without copying the list, the accessor the painting and hit-testing paths use, sinceseries()allocates and both run per frame.protected final floatseriesAlpha(int index) The alpha a series is currently drawn at, folding in its hide/show fade.final ColorseriesColor(int index) The color of seriesindex: its own, or its palette slot.protected final intHow many series the chart holds, visible or not.setAnimationDuration(double seconds) Sets the animation length in seconds;0draws every change immediately.setAnimationEasing(Easing easing) Sets the animation curve (defaultEasing.EASE_OUT).setBackground(@Nullable Color color) Fills the chart's box withcolorbefore anything else, rounded like a card;null(the default) paints nothing, letting the chart sit on the surface it was placed on.Sets the category labels: the x axis of a bar or line chart, the slices of a donut.setLabels(String...)from a list; the list is copied.setLabels(I18nString... values) Sets category labels that follow the UI language.setLegendInteractive(boolean value) Enables or disables hide/show on legend clicks (on by default).setLegendPosition(Chart.LegendPosition position) Moves the legend, or takes it away withChart.LegendPosition.NONE.setPalette(@Nullable ChartPalette value) Pins the palette;nullhands it back toChartPalette.defaultFor(limn.components.Theme), which follows the active theme's light/dark mode.setPreferredSize(float width, float height) Overrides the natural size (360.0f x 220.0f);UNSETon either axis restores it.setSeries(ChartSeries... newSeries) Replaces every series at once.Sets a title drawn above the plot (nullfor none).setTitle(@Nullable I18nString value) Sets a title that follows the UI language (nullfor none).setTooltipEnabled(boolean value) Turns the hover tooltip on or off (on by default).setTooltipFormat(@Nullable Function<ChartPoint, String> format) Replaces the text of a tooltip row.Sets whether a hover reports the whole category or only the mark under the pointer.setValueFormat(DoubleFunction<String> format) Sets the tooltip value format; seeNumberFormatsfor ready-made ones.protected floatHow far apart consecutive elements start, as a fraction of the animation: a wipe rather than a single pop.protected final doubleHow long a state fade lasts (hiding a series, popping a hovered mark), in seconds.@Nullable Stringtitle()The chart title as it currently reads, ornullwhen there is none.@Nullable I18nStringThe localizable value behindtitle(), ornull.protected voidtoggleLegendEntry(int index) Hides or shows what legend entryindexstands for.protected final SizeTokenstokens()The tokens for the step resolved on this chart; resolve once per pass, never in a field.How much of the data a hover reports.protected ColorThe swatch color for a tooltip row.protected StringtooltipRowName(ChartPoint row) The name a tooltip row carries where reading starts, the series name by default.protected List<ChartPoint> tooltipRows(ChartPoint picked) The rows a tooltip shows forpicked.protected StringThe value a tooltip row carries where reading ends.protected StringtooltipTitle(ChartPoint picked) The heading over the tooltip rows; the category label by default.protected final voidRecomputes the title/legend/plot split.How values are written in tooltips and in the names a screen reader hears for each mark: grouped digits by default (1,234.5), and scientific notation with up to three decimals from1e15up (1.235E20).Methods inherited from class limn.scene.Widget
acceptsTextInput, accessibleLabelAccessKey, accessibleLabelTarget, accessibleLabelText, add, add, announceChange, backdropReach, baselineOffset, baselineOffsetOf, caretRect, children, clipboard, clipHeight, clipsChildren, clipWidth, clipX, clipY, controlSize, cursor, declaredControlSize, declaredLayoutDirection, declaredLocale, focusArrivedBackward, focusArrivedByTraversal, height, hitTest, hitTestChild, id, imageCursor, inheritanceHost, invalidate, invalidate, invalidateAccessible, isEnabled, isFocusable, isFocused, isRightToLeft, isSelfEnabled, isShowing, isVisible, isVisibleByItsOwnFlag, layoutBox, layoutDirection, locale, localToScene, localToSceneBounds, markNeedsContainedLayout, markNeedsLayout, markNeedsLayoutInPlace, maxHeight, maxWidth, measure, minHeight, minWidth, moveChild, moveChild, moveChild, neutralBase, notifyChange, notifyTextEdit, observeChanges, onAccessibility, onAccessibilityAction, onAccessibilityChild, onAccessibilityChildAction, onAccessibilityChildIdentity, onCanEdit, onCharTyped, onDetached, onDragExit, onDragOver, onDragStart, onDrop, onEdit, onFocusGained, onFocusLost, onHitTest, onKeyEvent, onPreedit, onSyntheticAction, overlayPassesPointer, paintChildren, paintOutset, paintsDecoration, paintsFromBackdrop, paintWidget, parent, remove, remove, requestFocus, requestFocus, revealInView, revealInView, runHandler, scene, sceneNanos, sceneToLocal, self, setAccessibleDescribedBy, setAccessibleDescription, setAccessibleDescription, setAccessibleIgnored, setAccessibleLabelledBy, setAccessibleName, setAccessibleName, setAccessibleRole, setControlSize, setCursor, setEnabled, setFocusable, setId, setImageCursor, setInheritanceHost, setLayoutDirection, setLocale, setMaxHeight, setMaxWidth, setMinHeight, setMinWidth, setPresentedElsewhere, setTooltip, setTooltip, setVisible, shapeText, textRuler, tooltip, tooltipSource, width, x, y
-
Field Details
-
UNSET
public static final float UNSETHands a dimension back to the default size, theProgressBar.UNSETidiom.- See Also:
-
-
Constructor Details
-
Chart
public Chart()
-
-
Method Details
-
labels
The category labels as they currently read, in order. -
label
The label forindex, or""when there are fewer labels than values. -
labelSource
The localizable value behindlabel(int), orI18nString.EMPTYpast the end: what a language change re-resolves. -
setLabels
Sets the category labels: the x axis of a bar or line chart, the slices of a donut. -
setLabels
Sets category labels that follow the UI language. There is noListform of it (List<String>andList<I18nString>erase to the same signature), so hand a list over aslist.toArray(new I18nString[0]). -
setLabels
setLabels(String...)from a list; the list is copied. -
series
The series, in the order they were added (paint and palette order). -
addSeries
Adds a series. It takes the next palette slot unless it names its own color.- Throws:
IllegalStateException- if the series already belongs to a chart
-
onSeriesAdded
Called with a series that has just joined the chart, before anything is animated. Charts with per-series defaults of their own apply them here, so a series added after the default was set is styled like the ones that were already there. -
setSeries
Replaces every series at once. -
removeSeries
Removes a series; a no-op when it is not in this chart. -
clearSeries
Removes every series. -
series
The series atindex, without copying the list, the accessor the painting and hit-testing paths use, sinceseries()allocates and both run per frame. -
seriesCount
protected final int seriesCount()How many series the chart holds, visible or not. -
dataGeneration
protected final int dataGeneration()Bumped by every change to the data or to what is visible in it. Derived structures that are expensive to rebuild (a stack-key list walked once per bar) cache against it instead of rebuilding per frame. -
contentLeft
protected final float contentLeft()Left edge of the region left after the title and the legend. -
contentTop
protected final float contentTop()Top edge of the region left after the title and the legend. -
contentBoxWidth
protected final float contentBoxWidth()Width of the region left after the title and the legend. -
contentBoxHeight
protected final float contentBoxHeight()Height of the region left after the title and the legend. -
categoryCount
public final int categoryCount()How many categories the chart spans: the labels, or the longest series. -
palette
The palette in force: the one that was set, or the built-in one for this theme. -
setPalette
Pins the palette;nullhands it back toChartPalette.defaultFor(limn.components.Theme), which follows the active theme's light/dark mode. -
seriesColor
The color of seriesindex: its own, or its palette slot. -
title
The chart title as it currently reads, ornullwhen there is none. -
titleSource
The localizable value behindtitle(), ornull. -
setTitle
Sets a title drawn above the plot (nullfor none). -
setTitle
Sets a title that follows the UI language (nullfor none). -
clearTitle
Takes the title away, assetTitle(null)would: that call does not compile, becausenullfits more than one of the overloads.- Returns:
- this chart
-
background
The panel color behind the chart, ornullwhen it paints on what is below. -
setBackground
Fills the chart's box withcolorbefore anything else, rounded like a card;null(the default) paints nothing, letting the chart sit on the surface it was placed on. -
legendPosition
Where the legend sits. -
setLegendPosition
Moves the legend, or takes it away withChart.LegendPosition.NONE. -
isLegendInteractive
public boolean isLegendInteractive()Whether clicking a legend entry hides and shows its data. -
setLegendInteractive
Enables or disables hide/show on legend clicks (on by default). -
setPreferredSize
Overrides the natural size (360.0f x 220.0f);UNSETon either axis restores it. A chart in anExpandedor a stretchedColumntakes the space it is given regardless; this is the fallback for an unconstrained parent. -
valueFormat
How values are written in tooltips and in the names a screen reader hears for each mark: grouped digits by default (1,234.5), and scientific notation with up to three decimals from1e15up (1.235E20). -
setValueFormat
Sets the tooltip value format; seeNumberFormatsfor ready-made ones. -
isTooltipEnabled
public boolean isTooltipEnabled()Whether hovering shows a tooltip. -
setTooltipEnabled
Turns the hover tooltip on or off (on by default). -
tooltipMode
How much of the data a hover reports. -
setTooltipMode
Sets whether a hover reports the whole category or only the mark under the pointer. -
setTooltipFormat
Replaces the text of a tooltip row. The default lays each row out in two columns (the series name where reading starts, the formatted value where it ends, so both columns swap in a chart that reads right to left), which is what makes a multi-series tooltip scannable; a formatter set here produces the whole row as one string instead.nullrestores the default. -
animationDuration
public double animationDuration()Length of the entry and value-change animation, in seconds. -
setAnimationDuration
Sets the animation length in seconds;0draws every change immediately. -
setAnimationEasing
Sets the animation curve (defaultEasing.EASE_OUT). -
replayAnimation
Replays the entry animation from the axis baseline. -
onPointClick
Called with the datum under the pointer on a left click. InChart.TooltipMode.INDEXa click anywhere in a category reports that category's nearest mark, so a thin line is as clickable as a fat bar.One handler at a time:
nullclears it, and setting a second while one is set throwsIllegalStateException. -
onPointHover
Called whenever the hovered datum changes, withnullwhen the pointer leaves the marks. Fires on changes only, not on every pointer move.One handler at a time:
nullclears it, and setting a second while one is set throwsIllegalStateException. -
handleUserChange
Both handlers readhoveredPoint(), which is assigned before either announcement, so neither needs a payload the channel does not carry.- Overrides:
handleUserChangein classWidget<W extends Chart<W>>- Parameters:
aspect- what changed; the origin isUSERor this is not called
-
hoveredPoint
The datum under the pointer, ornull. -
paintContent
Paints the marks inside the region left after the title and the legend, in the chart's own coordinates. Grid, axes and everything data-shaped belong here. -
pickAt
The datum under a point in the chart's local coordinates, ornullwhen the pointer is not over the marks. Called for hover and for clicks, so it decides both. -
tooltipRows
The rows a tooltip shows forpicked. The default isChart.TooltipMode.INDEX-aware: every visible series at the same index, or just the picked datum inChart.TooltipMode.POINT. -
tooltipTitle
The heading over the tooltip rows; the category label by default. -
tooltipRowName
The name a tooltip row carries where reading starts, the series name by default. -
tooltipRowValue
The value a tooltip row carries where reading ends. -
tooltipRowColor
The swatch color for a tooltip row. -
legendEntries
One entry per series, in palette order. Overridden by charts whose legend is not that. -
toggleLegendEntry
protected void toggleLegendEntry(int index) Hides or shows what legend entryindexstands for. -
legendChanged
protected final void legendChanged()Drops the legend's cached entries, for a chart whose legend is not the series list. -
onHoverChanged
Called when the datum under the pointer changes,nullwhen there is none: the hook for a chart that animates something on hover. The application-facing callback isonPointHover(Consumer); this is for subclasses. -
updateRegions
protected final void updateRegions()Recomputes the title/legend/plot split. For a subclass laying out inonLayout. -
legendEntryCount
protected final int legendEntryCount()How many legend entries are drawn right now, with their boxes brought up to date first:0whenever the legend is not drawn, which folds inChart.LegendPosition.NONE,Chart.LegendPosition.AUTOwith fewer than two entries and a chart with nothing to name.For the describe hook, which runs after the layout pass and before the paint. The boxes are written by the region pass, and that pass runs before every paint and every pointer test but not before the tree is published, so a hook that read them as they stood would publish the previous frame's rectangles — or none at all on the first frame. The pass is re-run here only when the legend's own cache says its entries changed since the last one, or the UI language moved, because under a ruler that does not memoize its shaping the pass allocates, and a quiet damaged frame must not.
-
legendEntryBounds
Places the node being described at legend entryindex's box, in this chart's own coordinates: the same rectangle a click on the legend is tested against, so the published box and the operable box are one array.- Parameters:
index- an entry belowlegendEntryCount(), which must have been asked first in the same pass so that the boxes are currenta- the builder with the entry's synthetic child open- Throws:
IndexOutOfBoundsException- if there is no such entry
-
animationBaseline
protected double animationBaseline()The value a series grows out of when it first appears, and collapses to when it is hidden: where the axis crosses the plot, which is zero on any scale that contains it and the nearer end otherwise. -
staggerFraction
protected float staggerFraction()How far apart consecutive elements start, as a fraction of the animation: a wipe rather than a single pop.0(the default) starts everything at once, which is what a line wants: staggering the points of a line animates a wave through it. -
progress
protected final float progress()Overall animation progress in[0,1]; 1 means the data as it stands. -
elementProgress
protected final float elementProgress(int index, int count) Animation progress for elementindexofcount, withstaggerFraction()applied. Elements past the first start later and finish later, and every one of them reaches 1 by the timeprogress()does. -
seriesAlpha
protected final float seriesAlpha(int index) The alpha a series is currently drawn at, folding in its hide/show fade. -
drawnValue
protected final double drawnValue(int seriesIndex, int index) The value seriesseriesIndexis drawn at right now, animation included. -
pointFor
Builds aChartPointfor a datum, with the anchor the caller measured. -
tokens
The tokens for the step resolved on this chart; resolve once per pass, never in a field. -
measure
Measures a single line with the layout ruler (agrees with whatdrawTextdraws). -
ellipsize
textshortened with an ellipsis until it fitsmaxWidth, or""when not even the ellipsis fits. Category labels are application data: they are as long as they are, and a chart that lets them collide is unreadable.Shaped once and cut where
ShapedText.fitEnd(int, float)says, then re-shaped once or twice, the wayLabeldoes it. The obvious loop (drop a character, measure, repeat) made a label that overflows by forty characters cost forty shapings a paint, and a chart paints every frame of a value transition; worse, each candidate was a distinct string in the ruler's memo, so a few long labels evicted every other widget's text from it and everything on screen re-shaped each frame. -
onAttached
protected void onAttached()Description copied from class:WidgetCalled when this widget enters a scene (attached to the tree).Widget.scene()is the scene it just joined. Fires top-down, so a parent runs before its children. Default no-op.- Overrides:
onAttachedin classWidget<W extends Chart<W>>
-
onMeasure
Description copied from class:WidgetReports the size this widget wants withinconstraints. Called once per layout pass, and the result is cached against the constraints and the resolved axes (size step, layout direction, locale), so it must be a pure function of them and of this widget's own state.Resolve the
ControlSizeand theLayoutDirectiononce each here and thread them down; never read either in a constructor. The locale needs no threading: it is in scope, andI18n.locale()answers it wherever text is resolved. -
onLayout
protected void onLayout()Recomputes the regions whenever the box is laid out, so that the legend's boxes are current for the tree published between this pass and the paint. A subclass that lays out a child of its own calls this first. -
onPaint
Description copied from class:WidgetWidget's own background/content, in local coordinates. -
onPaintOverlay
Description copied from class:WidgetPainted after children (scrollbars, focus rings…).- Overrides:
onPaintOverlayin classWidget<W extends Chart<W>>
-
hoverRegion
The region of this chart that changes whenpointis the datum under the pointer: lit marks, a crosshair, a band, a popped slice.nullmeans "unknown", and the whole chart is repainted.A subclass owns this because only it knows what its hover draws, and the answers differ in kind: a cartesian chart lights a category across the plot, a donut pops one slice out of a ring. An answer that is too small leaves stale pixels, which is the one failure of partial rendering no assertion can see, so answer generously or answer
null. The tooltip panel is not part of it — this class adds that.- Parameters:
point- the hovered datum, nevernull- Returns:
- the region in widget coordinates, or
nullfor "all of it"
-
damageHoverInPlace
protected final void damageHoverInPlace()Damages whatever the hover draws right now, without erasing anywhere it has been.What a fade wants: the panel and the marks are where the last frame left them, so repainting them in place is the whole of it. A subclass whose own animation runs on the hover — a slice popping out of a ring — points its transition here.
-
onMouseEvent
Description copied from class:WidgetMouse events (bubbling); callevent.consume()when handled.- Overrides:
onMouseEventin classWidget<W extends Chart<W>>
-
stateFadeSeconds
protected final double stateFadeSeconds()How long a state fade lasts (hiding a series, popping a hovered mark), in seconds. Short, because it is feedback rather than data movement, and0wheneversetAnimationDuration(double)turned animation off, so "off" means all of it.
-