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