use serde::{ser::Serializer, Serialize};
use serde_repr::Serialize_repr;
#[derive(Serialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum ImageButtonFormats {
Png,
Svg,
Jpeg,
Webp,
}
#[serde_with::skip_serializing_none]
#[derive(Serialize, Debug, Default, Clone)]
pub struct ToImageButtonOptions {
format: Option<ImageButtonFormats>,
filename: Option<String>,
height: Option<usize>,
width: Option<usize>,
scale: Option<usize>,
}
impl ToImageButtonOptions {
pub fn new() -> Self {
Default::default()
}
pub fn format(mut self, format: ImageButtonFormats) -> Self {
self.format = Some(format);
self
}
pub fn filename(mut self, filename: &str) -> Self {
self.filename = Some(filename.to_string());
self
}
pub fn height(mut self, height: usize) -> Self {
self.height = Some(height);
self
}
pub fn width(mut self, width: usize) -> Self {
self.width = Some(width);
self
}
pub fn scale(mut self, scale: usize) -> Self {
self.scale = Some(scale);
self
}
}
#[derive(Debug, Clone)]
pub enum DisplayModeBar {
Hover,
True,
False,
}
impl Serialize for DisplayModeBar {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Self::Hover => serializer.serialize_str("hover"),
Self::True => serializer.serialize_bool(true),
Self::False => serializer.serialize_bool(false),
}
}
}
#[derive(Serialize, Debug, Clone)]
#[serde(rename_all = "camelCase")]
pub enum ModeBarButtonName {
Zoom2d,
Pan2d,
Select2d,
Lasso2d,
ZoomIn2d,
ZoomOut2d,
AutoScale2d,
ResetScale2d,
Zoom3d,
Pan3d,
OrbitRotation,
TableRotation,
ResetCameraDefault3d,
ResetCameraLastSave3d,
HoverClosest3d,
HoverClosestCartesian,
HoverCompareCartesian,
ZoomInGeo,
ZoomOutGeo,
ResetGeo,
HoverClosestGeo,
HoverClosestGl2d,
HoverClosestPie,
ToggleHover,
ResetViews,
ToImage,
SendDataToCloud,
ToggleSpikelines,
ResetViewMapbox,
ZoomInMapbox,
ZoomOutMapbox,
}
#[derive(Debug, Clone)]
pub enum DoubleClick {
False,
Reset,
AutoSize,
ResetAutoSize,
}
impl Serialize for DoubleClick {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Self::False => serializer.serialize_bool(false),
Self::Reset => serializer.serialize_str("reset"),
Self::AutoSize => serializer.serialize_str("autosize"),
Self::ResetAutoSize => serializer.serialize_str("reset+autosize"),
}
}
}
#[derive(Serialize_repr, Debug, Clone)]
#[repr(u8)]
pub enum PlotGLPixelRatio {
One = 1,
Two,
Three,
Four,
}
#[serde_with::skip_serializing_none]
#[derive(Serialize, Debug, Default, Clone)]
#[serde(rename_all = "camelCase")]
pub struct Configuration {
typeset_math: Option<bool>,
autosizable: Option<bool>,
scroll_zoom: Option<bool>,
fill_frame: Option<bool>,
frame_margins: Option<f64>,
editable: Option<bool>,
static_plot: Option<bool>,
to_image_button_options: Option<ToImageButtonOptions>,
display_mode_bar: Option<DisplayModeBar>,
mode_bar_buttons_to_remove: Option<Vec<ModeBarButtonName>>,
show_link: Option<bool>,
#[serde(rename = "plotlyServerURL")]
plotly_server_url: Option<String>,
#[serde(rename = "topojsonURL")]
topojson_url: Option<String>,
link_text: Option<String>,
mapbox_access_token: Option<String>,
show_edit_in_chart_studio: Option<bool>,
locale: Option<String>,
#[serde(rename = "displaylogo")]
display_logo: Option<bool>,
responsive: Option<bool>,
double_click: Option<DoubleClick>,
double_click_delay: Option<usize>,
show_axis_drag_handles: Option<bool>,
show_axis_range_entry_boxes: Option<bool>,
show_tips: Option<bool>,
send_data: Option<bool>,
watermark: Option<bool>,
#[serde(rename = "plotGlPixelRatio")]
plot_gl_pixel_ratio: Option<PlotGLPixelRatio>,
show_send_to_cloud: Option<bool>,
queue_length: Option<usize>,
}
impl Configuration {
pub fn new() -> Self {
Default::default()
}
pub fn static_plot(mut self, static_plot: bool) -> Self {
self.static_plot = Some(static_plot);
self
}
pub fn typeset_math(mut self, typeset_math: bool) -> Self {
self.typeset_math = Some(typeset_math);
self
}
pub fn plotly_server_url(mut self, plotly_server_url: &str) -> Self {
self.plotly_server_url = Some(plotly_server_url.to_string());
self
}
pub fn editable(mut self, editable: bool) -> Self {
self.editable = Some(editable);
self
}
pub fn autosizable(mut self, autosizable: bool) -> Self {
self.autosizable = Some(autosizable);
self
}
pub fn responsive(mut self, responsive: bool) -> Self {
self.responsive = Some(responsive);
self
}
pub fn fill_frame(mut self, fill_frame: bool) -> Self {
self.fill_frame = Some(fill_frame);
self
}
pub fn frame_margins(mut self, frame_margins: f64) -> Self {
self.frame_margins = Some(frame_margins);
self
}
pub fn scroll_zoom(mut self, scroll_zoom: bool) -> Self {
self.scroll_zoom = Some(scroll_zoom);
self
}
pub fn double_click(mut self, double_click: DoubleClick) -> Self {
self.double_click = Some(double_click);
self
}
pub fn double_click_delay(mut self, double_click_delay: usize) -> Self {
self.double_click_delay = Some(double_click_delay);
self
}
pub fn show_axis_drag_handles(mut self, show_axis_drag_handles: bool) -> Self {
self.show_axis_drag_handles = Some(show_axis_drag_handles);
self
}
pub fn show_axis_range_entry_boxes(mut self, show_axis_range_entry_boxes: bool) -> Self {
self.show_axis_range_entry_boxes = Some(show_axis_range_entry_boxes);
self
}
pub fn show_tips(mut self, show_tips: bool) -> Self {
self.show_tips = Some(show_tips);
self
}
pub fn show_link(mut self, show_link: bool) -> Self {
self.show_link = Some(show_link);
self
}
pub fn link_text(mut self, link_text: &str) -> Self {
self.link_text = Some(link_text.to_string());
self
}
pub fn send_data(mut self, send_data: bool) -> Self {
self.send_data = Some(send_data);
self
}
pub fn display_mode_bar(mut self, display_mode_bar: DisplayModeBar) -> Self {
self.display_mode_bar = Some(display_mode_bar);
self
}
pub fn show_send_to_cloud(mut self, show_send_to_cloud: bool) -> Self {
self.show_send_to_cloud = Some(show_send_to_cloud);
self
}
pub fn show_edit_in_chart_studio(mut self, show_edit_in_chart_studio: bool) -> Self {
self.show_edit_in_chart_studio = Some(show_edit_in_chart_studio);
self
}
pub fn mode_bar_buttons_to_remove(
mut self,
mode_bar_buttons_to_remove: Vec<ModeBarButtonName>,
) -> Self {
self.mode_bar_buttons_to_remove = Some(mode_bar_buttons_to_remove);
self
}
pub fn to_image_button_options(
mut self,
to_image_button_options: ToImageButtonOptions,
) -> Self {
self.to_image_button_options = Some(to_image_button_options);
self
}
pub fn display_logo(mut self, display_logo: bool) -> Self {
self.display_logo = Some(display_logo);
self
}
pub fn watermark(mut self, watermark: bool) -> Self {
self.watermark = Some(watermark);
self
}
pub fn plot_gl_pixel_ratio(mut self, plot_gl_pixel_ratio: PlotGLPixelRatio) -> Self {
self.plot_gl_pixel_ratio = Some(plot_gl_pixel_ratio);
self
}
pub fn topojson_url(mut self, topojson_url: &str) -> Self {
self.topojson_url = Some(topojson_url.to_string());
self
}
pub fn mapbox_access_token(mut self, mapbox_access_token: &str) -> Self {
self.mapbox_access_token = Some(mapbox_access_token.to_string());
self
}
pub fn queue_length(mut self, queue_length: usize) -> Self {
self.queue_length = Some(queue_length);
self
}
pub fn locale(mut self, locale: &str) -> Self {
self.locale = Some(locale.to_string());
self
}
}
#[cfg(test)]
mod tests {
use serde_json::{json, to_value};
use super::*;
#[test]
fn test_serialize_image_button_formats() {
assert_eq!(to_value(ImageButtonFormats::Png).unwrap(), json!("png"));
assert_eq!(to_value(ImageButtonFormats::Svg).unwrap(), json!("svg"));
assert_eq!(to_value(ImageButtonFormats::Jpeg).unwrap(), json!("jpeg"));
assert_eq!(to_value(ImageButtonFormats::Webp).unwrap(), json!("webp"));
}
#[test]
fn test_serialize_to_image_button_options() {
let options = ToImageButtonOptions::new()
.format(ImageButtonFormats::Jpeg)
.filename("filename")
.height(500)
.width(250)
.scale(2);
let expected = json!({
"format": "jpeg",
"filename": "filename",
"height": 500,
"width": 250,
"scale": 2
});
assert_eq!(to_value(options).unwrap(), expected)
}
#[test]
fn test_serialize_display_mode_bar() {
assert_eq!(to_value(DisplayModeBar::Hover).unwrap(), json!("hover"));
assert_eq!(to_value(DisplayModeBar::True).unwrap(), json!(true));
assert_eq!(to_value(DisplayModeBar::False).unwrap(), json!(false));
}
#[test]
#[rustfmt::skip]
fn test_serialize_mode_bar_button_name() {
assert_eq!(to_value(ModeBarButtonName::Zoom2d).unwrap(), json!("zoom2d"));
assert_eq!(to_value(ModeBarButtonName::Pan2d).unwrap(), json!("pan2d"));
assert_eq!(to_value(ModeBarButtonName::Select2d).unwrap(), json!("select2d"));
assert_eq!(to_value(ModeBarButtonName::Lasso2d).unwrap(), json!("lasso2d"));
assert_eq!(to_value(ModeBarButtonName::ZoomIn2d).unwrap(), json!("zoomIn2d"));
assert_eq!(to_value(ModeBarButtonName::ZoomOut2d).unwrap(), json!("zoomOut2d"));
assert_eq!(to_value(ModeBarButtonName::AutoScale2d).unwrap(), json!("autoScale2d"));
assert_eq!(to_value(ModeBarButtonName::ResetScale2d).unwrap(), json!("resetScale2d"));
assert_eq!(to_value(ModeBarButtonName::Zoom3d).unwrap(), json!("zoom3d"));
assert_eq!(to_value(ModeBarButtonName::Pan3d).unwrap(), json!("pan3d"));
assert_eq!(to_value(ModeBarButtonName::ResetCameraDefault3d).unwrap(), json!("resetCameraDefault3d"));
assert_eq!(to_value(ModeBarButtonName::ResetCameraLastSave3d).unwrap(), json!("resetCameraLastSave3d"));
assert_eq!(to_value(ModeBarButtonName::HoverClosest3d).unwrap(), json!("hoverClosest3d"));
assert_eq!(to_value(ModeBarButtonName::OrbitRotation).unwrap(), json!("orbitRotation"));
assert_eq!(to_value(ModeBarButtonName::TableRotation).unwrap(), json!("tableRotation"));
assert_eq!(to_value(ModeBarButtonName::HoverClosestCartesian).unwrap(), json!("hoverClosestCartesian"));
assert_eq!(to_value(ModeBarButtonName::HoverCompareCartesian).unwrap(), json!("hoverCompareCartesian"));
assert_eq!(to_value(ModeBarButtonName::ZoomInGeo).unwrap(), json!("zoomInGeo"));
assert_eq!(to_value(ModeBarButtonName::ZoomOutGeo).unwrap(), json!("zoomOutGeo"));
assert_eq!(to_value(ModeBarButtonName::ResetGeo).unwrap(), json!("resetGeo"));
assert_eq!(to_value(ModeBarButtonName::HoverClosestGeo).unwrap(), json!("hoverClosestGeo"));
assert_eq!(to_value(ModeBarButtonName::HoverClosestGl2d).unwrap(), json!("hoverClosestGl2d"));
assert_eq!(to_value(ModeBarButtonName::HoverClosestPie).unwrap(), json!("hoverClosestPie"));
assert_eq!(to_value(ModeBarButtonName::ToggleHover).unwrap(), json!("toggleHover"));
assert_eq!(to_value(ModeBarButtonName::ResetViews).unwrap(), json!("resetViews"));
assert_eq!(to_value(ModeBarButtonName::ToImage).unwrap(), json!("toImage"));
assert_eq!(to_value(ModeBarButtonName::SendDataToCloud).unwrap(), json!("sendDataToCloud"));
assert_eq!(to_value(ModeBarButtonName::ToggleSpikelines).unwrap(), json!("toggleSpikelines"));
assert_eq!(to_value(ModeBarButtonName::ResetViewMapbox).unwrap(), json!("resetViewMapbox"));
assert_eq!(to_value(ModeBarButtonName::ZoomInMapbox).unwrap(), json!("zoomInMapbox"));
assert_eq!(to_value(ModeBarButtonName::ZoomOutMapbox).unwrap(), json!("zoomOutMapbox"));
}
#[test]
#[rustfmt::skip]
fn test_serialize_double_click() {
assert_eq!(to_value(DoubleClick::False).unwrap(), json!(false));
assert_eq!(to_value(DoubleClick::Reset).unwrap(), json!("reset"));
assert_eq!(to_value(DoubleClick::AutoSize).unwrap(), json!("autosize"));
assert_eq!(to_value(DoubleClick::ResetAutoSize).unwrap(), json!("reset+autosize"));
}
#[test]
fn test_serialize_plot_gl_pixel_ratio() {
assert_eq!(to_value(PlotGLPixelRatio::One).unwrap(), json!(1));
assert_eq!(to_value(PlotGLPixelRatio::Two).unwrap(), json!(2));
assert_eq!(to_value(PlotGLPixelRatio::Three).unwrap(), json!(3));
assert_eq!(to_value(PlotGLPixelRatio::Four).unwrap(), json!(4));
}
#[test]
fn test_serialize_configuration() {
let config = Configuration::new()
.static_plot(true)
.typeset_math(true)
.plotly_server_url("server_url")
.editable(false)
.autosizable(false)
.responsive(true)
.fill_frame(false)
.frame_margins(2.0)
.scroll_zoom(false)
.double_click(DoubleClick::ResetAutoSize)
.double_click_delay(50)
.show_axis_drag_handles(false)
.show_axis_range_entry_boxes(true)
.show_tips(false)
.show_link(true)
.link_text("link text")
.send_data(false)
.display_mode_bar(DisplayModeBar::Hover)
.show_send_to_cloud(true)
.show_edit_in_chart_studio(false)
.mode_bar_buttons_to_remove(vec![ModeBarButtonName::Zoom2d])
.to_image_button_options(ToImageButtonOptions::new())
.display_logo(false)
.watermark(true)
.plot_gl_pixel_ratio(PlotGLPixelRatio::Four)
.topojson_url("topojson_url")
.mapbox_access_token("123")
.queue_length(100)
.locale("en");
let expected = json!({
"staticPlot": true,
"typesetMath": true,
"plotlyServerURL": "server_url",
"editable": false,
"autosizable": false,
"responsive": true,
"fillFrame": false,
"frameMargins": 2.0,
"scrollZoom": false,
"doubleClick": "reset+autosize",
"doubleClickDelay": 50,
"showAxisDragHandles": false,
"showAxisRangeEntryBoxes": true,
"showTips": false,
"showLink": true,
"linkText": "link text",
"sendData": false,
"displayModeBar": "hover",
"showSendToCloud": true,
"showEditInChartStudio": false,
"modeBarButtonsToRemove": ["zoom2d"],
"toImageButtonOptions": {},
"displaylogo": false,
"watermark": true,
"plotGlPixelRatio": 4,
"topojsonURL": "topojson_url",
"mapboxAccessToken": "123",
"queueLength": 100,
"locale": "en"
});
assert_eq!(to_value(config).unwrap(), expected);
}
}