perspective_viewer/components/
number_series_style.rs1use web_sys::{HtmlInputElement, InputEvent};
14use yew::prelude::*;
15
16use super::modal::{ModalLink, SetModalLink};
17use crate::components::form::select_enum_field::SelectEnumField;
18use crate::config::*;
19use crate::utils::WeakScope;
20
21#[derive(Properties)]
22pub struct NumberSeriesStyleProps {
23 pub config: Option<NumberSeriesStyleConfig>,
24 pub default_config: NumberSeriesStyleDefaultConfig,
25
26 #[prop_or_default]
27 pub on_change: Callback<ColumnConfigFieldUpdate>,
28
29 #[prop_or_default]
30 pub keys: Vec<String>,
31
32 #[prop_or_default]
33 weak_link: WeakScope<NumberSeriesStyle>,
34}
35
36impl ModalLink<NumberSeriesStyle> for NumberSeriesStyleProps {
37 fn weak_link(&self) -> &'_ WeakScope<NumberSeriesStyle> {
38 &self.weak_link
39 }
40}
41
42impl PartialEq for NumberSeriesStyleProps {
43 fn eq(&self, other: &Self) -> bool {
44 self.config == other.config && self.default_config == other.default_config
45 }
46}
47
48pub enum NumberSeriesStyleMsg {
49 ChartTypeChanged(Option<ChartType>),
50 StackChanged(Option<bool>),
51}
52
53pub struct NumberSeriesStyle {
57 config: NumberSeriesStyleConfig,
58}
59
60impl Component for NumberSeriesStyle {
61 type Message = NumberSeriesStyleMsg;
62 type Properties = NumberSeriesStyleProps;
63
64 fn create(ctx: &Context<Self>) -> Self {
65 ctx.set_modal_link();
66 Self {
67 config: ctx.props().config.clone().unwrap_or_default(),
68 }
69 }
70
71 fn changed(&mut self, ctx: &Context<Self>, _old: &Self::Properties) -> bool {
72 let new_config = ctx.props().config.clone().unwrap_or_default();
73 if self.config != new_config {
74 self.config = new_config;
75 true
76 } else {
77 false
78 }
79 }
80
81 fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
82 match msg {
83 NumberSeriesStyleMsg::ChartTypeChanged(val) => {
84 self.config.chart_type = val.unwrap_or_default();
85 if !self.config.chart_type.supports_stack() {
88 self.config.stack = None;
89 }
90 self.dispatch_config(ctx);
91 true
92 },
93 NumberSeriesStyleMsg::StackChanged(val) => {
94 self.config.stack = val;
95 self.dispatch_config(ctx);
96 true
97 },
98 }
99 }
100
101 fn view(&self, ctx: &Context<Self>) -> Html {
102 let chart_type_changed = ctx.link().callback(NumberSeriesStyleMsg::ChartTypeChanged);
103
104 let stack_controls = if self.config.chart_type.supports_stack() {
105 let checked = self.config.stack.unwrap_or(true);
107 let oninput = ctx.link().callback(move |e: InputEvent| {
108 let input: HtmlInputElement = e.target_unchecked_into();
109 let next = input.checked();
110 NumberSeriesStyleMsg::StackChanged(if next { None } else { Some(false) })
113 });
114 html! {
115 <div class="row">
116 <label id="stack-label" />
117 <input type="checkbox" id="stack-checkbox" {checked} {oninput} />
118 </div>
119 }
120 } else {
121 html! {}
122 };
123
124 html! {
125 <>
126 <div id="column-style-container" class="number-series-style-container">
127 <SelectEnumField<ChartType>
128 label="chart-type"
129 on_change={chart_type_changed}
130 current_value={self.config.chart_type}
131 />
132 { stack_controls }
133 </div>
134 </>
135 }
136 }
137}
138
139impl NumberSeriesStyle {
140 fn dispatch_config(&self, ctx: &Context<Self>) {
145 let value = if self.config == NumberSeriesStyleConfig::default() {
146 serde_json::Map::new()
147 } else {
148 match serde_json::to_value(&self.config) {
149 Ok(serde_json::Value::Object(m)) => m,
150 _ => serde_json::Map::new(),
151 }
152 };
153 ctx.props().on_change.emit(ColumnConfigFieldUpdate {
154 keys: ctx.props().keys.clone(),
155 value,
156 });
157 }
158}