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}