Skip to content

Commit

Permalink
Merge branch 'yuankunzhang:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
mrchypark authored Jul 24, 2023
2 parents c2873cb + 18c136f commit e316b14
Show file tree
Hide file tree
Showing 14 changed files with 328 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Highlights:

- Easy-to-use, declaritive API.
- Abundant chart types with rich and customizable chart themes and styles.
- Usable in WebAssembly environments.
- Ready to use in WebAssembly environments.
- Rendering to multiple formats, including HTML, SVG, PNG, JPEG, GIF, WEBP, PNM, TIFF, TGA, DDS, BMP, ICO, HDR, OPENEXR, FARBFELD, AVIF, and QOI.

## Themes
Expand Down
2 changes: 1 addition & 1 deletion charming/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "charming"
description = "A visualization library for Rust"
version = "0.2.2"
version = "0.2.4"
edition = "2021"
authors = ["Yuankun Zhang <[email protected]>"]
homepage = "https://github.com/yuankunzhang/echarts-rs"
Expand Down
2 changes: 1 addition & 1 deletion charming/src/asset/charts.html.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
{{#each gep_maps}}
echarts.registerMap('{{ this.name }}', {{{ this.opt }}});
{{/each}}
var chart = echarts.init(document.getElementById('{{ chart_id }}'){{#if theme}}, '{{ theme }}'{{/if}});
var chart = echarts.init(document.getElementById('{{ chart_id }}'), {{#if theme}}'{{ theme }}'{{else}}null{{/if}}, { renderer: '{{ canvas_type }}' });
var option = {{{ chart_option }}};
chart.setOption(option);
</script>
Expand Down
236 changes: 236 additions & 0 deletions charming/src/component/aria.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
use serde::Serialize;

use crate::{
datatype::CompositeValue,
element::{Color, Label, Symbol},
};

/**
A single decal pattern.
*/
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DecalItem {
/// The symbol type of the decal.
#[serde(skip_serializing_if = "Option::is_none")]
symbol: Option<Symbol>,

/// The size of symbol relative to decal, ranging from 0 to 1.
#[serde(skip_serializing_if = "Option::is_none")]
symbol_size: Option<f64>,

/// Whether to keep the aspect ratio of the pattern.
#[serde(skip_serializing_if = "Option::is_none")]
symbol_keep_aspect: Option<bool>,

///The color of the decal pattern. it is recommended to use a translucent
/// color, which can be superimposed on the color of the series itself.
#[serde(skip_serializing_if = "Option::is_none")]
color: Option<Color>,

/// The background color of the decal will be over the color of the series
/// itself, under the decal pattern.
#[serde(skip_serializing_if = "Option::is_none")]
background_color: Option<Color>,

/// Controls the horizontal pattern.
#[serde(skip_serializing_if = "Option::is_none")]
dash_array_x: Option<CompositeValue>,

/// Controls the vertical pattern.
#[serde(skip_serializing_if = "Option::is_none")]
dash_array_y: Option<CompositeValue>,

/// The overall rotation angle (in radians) of the pattern.
#[serde(skip_serializing_if = "Option::is_none")]
rotation: Option<f64>,

/// The upper limit of the width of the generated pattern before it is
/// duplicated.
#[serde(skip_serializing_if = "Option::is_none")]
max_tile_width: Option<f64>,

/// The upper limit of the height of the generated pattern before it is
/// duplicated.
#[serde(skip_serializing_if = "Option::is_none")]
max_tile_height: Option<f64>,
}

impl DecalItem {
pub fn new() -> DecalItem {
DecalItem {
symbol: None,
symbol_size: None,
symbol_keep_aspect: None,
color: None,
background_color: None,
dash_array_x: None,
dash_array_y: None,
rotation: None,
max_tile_width: None,
max_tile_height: None,
}
}

pub fn symbol<S: Into<Symbol>>(mut self, symbol: S) -> DecalItem {
self.symbol = Some(symbol.into());
self
}

pub fn symbol_size<F: Into<f64>>(mut self, symbol_size: F) -> DecalItem {
self.symbol_size = Some(symbol_size.into());
self
}

pub fn symbol_keep_aspect(mut self, symbol_keep_aspect: bool) -> DecalItem {
self.symbol_keep_aspect = Some(symbol_keep_aspect);
self
}

pub fn color<C: Into<Color>>(mut self, color: C) -> DecalItem {
self.color = Some(color.into());
self
}

pub fn background_color<C: Into<Color>>(mut self, background_color: C) -> DecalItem {
self.background_color = Some(background_color.into());
self
}

pub fn dash_array_x<F: Into<CompositeValue>>(mut self, dash_array_x: F) -> DecalItem {
self.dash_array_x = Some(dash_array_x.into());
self
}

pub fn dash_array_y<F: Into<CompositeValue>>(mut self, dash_array_y: F) -> DecalItem {
self.dash_array_y = Some(dash_array_y.into());
self
}

pub fn rotation<F: Into<f64>>(mut self, rotation: F) -> DecalItem {
self.rotation = Some(rotation.into());
self
}

pub fn max_tile_width<F: Into<f64>>(mut self, max_tile_width: F) -> DecalItem {
self.max_tile_width = Some(max_tile_width.into());
self
}

pub fn max_tile_height<F: Into<f64>>(mut self, max_tile_height: F) -> DecalItem {
self.max_tile_height = Some(max_tile_height.into());
self
}
}

/**
Decal patterns to be applied to series data.
*/
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Decal {
/// Whether to show decal patterns. If `decals` is not set, this option is
/// used to enable the default decal pattern.
#[serde(skip_serializing_if = "Option::is_none")]
show: Option<bool>,

/// The style of decal patterns. If multiple items are set, then each item
/// in the array will have one style and the data will be looped through
/// the array in order.
#[serde(skip_serializing_if = "Vec::is_empty")]
decals: Vec<DecalItem>,
}

impl Decal {
pub fn new() -> Decal {
Decal {
show: None,
decals: vec![],
}
}

pub fn show(mut self, show: bool) -> Decal {
self.show = Some(show);
self
}

pub fn decals<D: Into<DecalItem>>(mut self, decals: Vec<D>) -> Decal {
self.decals = decals.into_iter().map(|d| d.into()).collect();
self
}
}

/**
The WAI-ARIA (Accessible Rich Internet Applications Suite) is a W3C standard
that dedicates to make web content and web applications more accessible.
It is turned off by default, and needs to be turned on by setting `enabled` to
`true`.
Here's a simple example that enables default decal pattern on a bar chart:
```rust
use charming::{
component::{Aria, Axis, Decal},
element::AxisType,
series::Bar,
Chart,
};
Chart::new()
.x_axis(
Axis::new()
.type_(AxisType::Category)
.data(vec!["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]),
)
.y_axis(Axis::new().type_(AxisType::Value))
.aria(Aria::new().enabled(true).decal(Decal::new().show(true)))
.series(Bar::new().data(vec![120, 200, 150, 80, 70, 110, 130]))
.series(Bar::new().data(vec![20, 40, 90, 40, 30, 70, 120]))
.series(Bar::new().data(vec![140, 230, 120, 50, 30, 150, 120]));
```
*/
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct Aria {
/// Whether to enable WAI-ARIA.
#[serde(skip_serializing_if = "Option::is_none")]
enabled: Option<bool>,

/// If `enabled` is set to `true`, `label` is enabled by default. When
/// enabled, the description of the chart will be automatically and
/// intelligently generated based on the chart, data title, etc. Users can
/// also modify the description through `label`.
#[serde(skip_serializing_if = "Option::is_none")]
label: Option<Label>,

/// Decal patterns are added to series data as an additional hint other
/// than colors to help differentiate the data.
#[serde(skip_serializing_if = "Option::is_none")]
decal: Option<Decal>,
}

impl Aria {
pub fn new() -> Aria {
Aria {
enabled: None,
label: None,
decal: None,
}
}

pub fn enabled(mut self, enabled: bool) -> Aria {
self.enabled = Some(enabled);
self
}

pub fn label<L: Into<Label>>(mut self, label: L) -> Aria {
self.label = Some(label.into());
self
}

pub fn decal<D: Into<Decal>>(mut self, decal: D) -> Aria {
self.decal = Some(decal.into());
self
}
}
2 changes: 2 additions & 0 deletions charming/src/component/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod angle_axis;
pub mod aria;
pub mod axis;
pub mod axis3d;
pub mod brush;
Expand All @@ -22,6 +23,7 @@ pub mod toolbox;
pub mod visual_map;

pub use angle_axis::*;
pub use aria::*;
pub use axis::*;
pub use axis3d::*;
pub use brush::*;
Expand Down
7 changes: 7 additions & 0 deletions charming/src/component/toolbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,11 @@ impl Toolbox {
self.bottom = Some(bottom.into());
self
}

pub fn save_as_image_type(&self) -> Option<&SaveAsImageType> {
self.feature
.as_ref()
.and_then(|f| f.save_as_image.as_ref())
.and_then(|s| s.type_.as_ref())
}
}
19 changes: 17 additions & 2 deletions charming/src/element/symbol.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use serde::Serialize;

#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub enum Symbol {
Circle,
Rect,
Expand All @@ -11,4 +9,21 @@ pub enum Symbol {
Pin,
Arrow,
None,
Custom(String),
}

impl Serialize for Symbol {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self {
Symbol::Circle => serializer.serialize_str("circle"),
Symbol::Rect => serializer.serialize_str("rect"),
Symbol::RoundRect => serializer.serialize_str("roundRect"),
Symbol::Triangle => serializer.serialize_str("triangle"),
Symbol::Diamond => serializer.serialize_str("diamond"),
Symbol::Pin => serializer.serialize_str("pin"),
Symbol::Arrow => serializer.serialize_str("arrow"),
Symbol::None => serializer.serialize_str("none"),
Symbol::Custom(s) => serializer.serialize_str(s),
}
}
}
21 changes: 18 additions & 3 deletions charming/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ pub mod theme;
pub use renderer::*;

use component::{
AngleAxis, Axis, Axis3D, DataZoom, GeoMap, Grid, Grid3D, Legend, ParallelAxis,
ParallelCoordinate, PolarCoordinate, RadarCoordinate, RadiusAxis, SingleAxis, Title, Toolbox,
VisualMap,
AngleAxis, Aria, Axis, Axis3D, DataZoom, GeoMap, Grid, Grid3D, Legend, ParallelAxis,
ParallelCoordinate, PolarCoordinate, RadarCoordinate, RadiusAxis, SaveAsImageType, SingleAxis,
Title, Toolbox, VisualMap,
};
use datatype::Dataset;
use element::{process_raw_strings, AxisPointer, Color, MarkLine, Tooltip};
Expand Down Expand Up @@ -319,6 +319,9 @@ pub struct Chart {
#[serde(skip_serializing_if = "Option::is_none")]
mark_line: Option<MarkLine>,

#[serde(skip_serializing_if = "Option::is_none")]
aria: Option<Aria>,

#[serde(skip_serializing_if = "Vec::is_empty")]
series: Vec<Series>,

Expand Down Expand Up @@ -354,6 +357,7 @@ impl Chart {
color: vec![],
background_color: None,
mark_line: None,
aria: None,
series: vec![],
geo_maps: vec![],
}
Expand Down Expand Up @@ -484,6 +488,11 @@ impl Chart {
self
}

pub fn aria(mut self, aria: Aria) -> Self {
self.aria = Some(aria);
self
}

pub fn series<S: Into<Series>>(mut self, series: S) -> Self {
self.series.push(series.into());
self
Expand All @@ -493,6 +502,12 @@ impl Chart {
self.geo_maps.push(map.into());
self
}

pub fn save_as_image_type(&self) -> Option<&SaveAsImageType> {
self.toolbox
.as_ref()
.and_then(|toolbox| toolbox.save_as_image_type())
}
}

impl ToString for Chart {
Expand Down
Loading

0 comments on commit e316b14

Please sign in to comment.