Skip to main content

euv_chart/chart/
struct.rs

1use super::*;
2
3/// A chart, bound to one canvas element.
4///
5/// The chart owns its option, its layout, and its display list. Setting
6/// an option invalidates the layout; rendering rebuilds both and hands
7/// the resulting display list to the backend.
8///
9/// The backend is chosen when the chart is created: WebGPU if the host
10/// has it, WebGL2 if it does not, Canvas2D otherwise. From the outside
11/// the three behave identically — the same option produces the same
12/// picture, and the same API draws it.
13#[derive(Data)]
14pub struct Chart {
15    /// The canvas the chart draws into.
16    #[get(pub(crate))]
17    #[get_mut(pub(crate))]
18    #[set(pub(crate))]
19    pub(crate) canvas: HtmlCanvasElement,
20    /// The configuration of the chart.
21    #[get(pub(crate))]
22    #[get_mut(pub(crate))]
23    #[set(skip)]
24    pub(crate) option: ChartOption,
25    /// The rendering backend.
26    #[get(pub(crate))]
27    #[get_mut(pub(crate))]
28    #[set(pub(crate))]
29    pub(crate) backend: Box<dyn ChartBackend>,
30    /// The measurer and the glyph atlas the text is drawn with.
31    #[get(pub(crate))]
32    #[get_mut(pub(crate))]
33    #[set(pub(crate))]
34    pub(crate) shaper: TextShaper,
35    /// The layout of the chart.
36    #[get(pub(crate))]
37    #[get_mut(pub(crate))]
38    #[set(pub(crate))]
39    pub(crate) layout: ChartLayout,
40    /// The display list the backend replays.
41    #[get(pub(crate))]
42    #[get_mut(pub(crate))]
43    #[set(pub(crate))]
44    pub(crate) display_list: DisplayList,
45    /// The renderer that turns the layout into the display list.
46    #[get(pub(crate))]
47    #[get_mut(pub(crate))]
48    #[set(pub(crate))]
49    pub(crate) renderer: ChartRenderer,
50    /// The logical width of the canvas, in CSS pixels.
51    #[get(pub(crate), type(copy))]
52    #[get_mut(pub(crate))]
53    #[set(pub(crate))]
54    pub(crate) width: f64,
55    /// The logical height of the canvas, in CSS pixels.
56    #[get(pub(crate), type(copy))]
57    #[get_mut(pub(crate))]
58    #[set(pub(crate))]
59    pub(crate) height: f64,
60    /// The device pixel ratio the chart renders at.
61    #[get(pub(crate), type(copy))]
62    #[get_mut(pub(crate))]
63    #[set(pub(crate))]
64    pub(crate) dpr: f64,
65    /// Whether the layout has to be recomputed.
66    #[get(pub(crate), type(copy))]
67    #[get_mut(pub(crate))]
68    #[set(pub(crate))]
69    pub(crate) layout_dirty: bool,
70    /// Whether the display list has to be rebuilt.
71    #[get(pub(crate), type(copy))]
72    #[get_mut(pub(crate))]
73    #[set(pub(crate))]
74    pub(crate) display_dirty: bool,
75    /// The event handlers registered on the chart.
76    #[get(pub(crate))]
77    #[get_mut(pub(crate))]
78    #[set(pub(crate))]
79    pub(crate) handlers: Vec<EventRegistration>,
80    /// The animator that moves the series between two states.
81    #[get(pub(crate))]
82    #[get_mut(pub(crate))]
83    #[set(pub(crate))]
84    pub(crate) animator: Animator,
85    /// The tooltip the chart currently shows.
86    #[get(pub(crate))]
87    #[get_mut(pub(crate))]
88    #[set(pub(crate))]
89    pub(crate) tooltip: Option<TooltipState>,
90    /// The maps the chart can draw.
91    ///
92    /// The geometry of a map is far too large to live in an option: the
93    /// same map is drawn by every chart of an application, and it is
94    /// registered once.
95    #[get(pub(crate))]
96    #[get_mut(pub(crate))]
97    #[set(pub(crate))]
98    pub(crate) maps: MapRegistry,
99    /// The commands that arrived since the last frame.
100    ///
101    /// The commands travel through a signal, so an application that
102    /// holds nothing but a handle can still drive the chart.
103    #[get(pub(crate))]
104    #[get_mut(pub(crate))]
105    #[set(pub(crate))]
106    pub(crate) commands: Signal<Vec<ChartCommand>>,
107}
108
109/// A handle to a chart.
110///
111/// The handle is what an application keeps when the chart itself has
112/// to live somewhere else — in a component, in a closure, in a
113/// callback. The commands it carries travel through a signal, so the
114/// chart picks them up on its next frame, and an application that
115/// holds nothing but a signal can still drive a chart.
116///
117/// The handle is a copy: every copy talks to the same chart.
118#[derive(Clone, Copy, Data, Debug)]
119pub struct ChartHandle {
120    /// The commands waiting for the chart.
121    pub commands: Signal<Vec<ChartCommand>>,
122}
123
124/// The state of the chart's tooltip.
125///
126/// The tooltip is a first-class part of the chart: an application shows
127/// it with an action, and the chart draws it above everything else.
128#[derive(Clone, Data, Debug, Default, PartialEq)]
129pub struct TooltipState {
130    /// The index of the series the tooltip describes.
131    #[get(type(copy))]
132    pub series_index: usize,
133    /// The index of the data point the tooltip describes.
134    #[get(type(copy))]
135    pub data_index: usize,
136    /// The horizontal position of the tooltip, in canvas pixels.
137    #[get(type(copy))]
138    pub x: f64,
139    /// The vertical position of the tooltip, in canvas pixels.
140    #[get(type(copy))]
141    pub y: f64,
142    /// The lines the tooltip shows.
143    pub lines: Vec<(String, String)>,
144}
145
146/// Turns a chart's option and layout into a display list.
147///
148/// The renderer is the only place that knows how a chart is put
149/// together: the background, the grid, the axes, the series, the title,
150/// and the legend. It writes into a display list, which the backends
151/// replay — so a new backend never has to know what a chart looks like.
152///
153/// The renderer is public so that a benchmark — or a server-side render —
154/// can measure the cost of a layout without a canvas.
155#[derive(Clone, Data, Debug)]
156pub struct ChartRenderer {
157    /// The renderer that draws the series.
158    #[get(pub(crate))]
159    #[get_mut(pub(crate))]
160    #[set(pub(crate))]
161    pub(crate) series: SeriesRenderer,
162}