Skip to content

Commit edc563e

Browse files
authored
Merge pull request #34 from azriel91/feature/33/support-images
2 parents 3290398 + 2149105 commit edc563e

File tree

17 files changed

+832
-181
lines changed

17 files changed

+832
-181
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Changelog
22

3+
## unreleased
4+
5+
* Support inline images ([#33]).
6+
7+
8+
[#33]: https://github.com/azriel91/dot_ix/issues/33
9+
10+
311
## 0.8.0 (2024-08-08)
412

513
* Add `TextEditor` in playground which uses [monaco][monaco] / [rust-monaco][rust-monaco].

crate/model/src/common.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ pub use self::{
99
edges::Edges,
1010
graphviz_attrs::GraphvizAttrs,
1111
graphviz_dot_theme::GraphvizDotTheme,
12+
image_id::{ImageId, ImageIdInvalidFmt},
13+
images::Images,
1214
node_descs::NodeDescs,
1315
node_emojis::NodeEmojis,
1416
node_hierarchy::NodeHierarchy,
1517
node_id::{NodeId, NodeIdInvalidFmt},
18+
node_images::NodeImages,
1619
node_names::NodeNames,
1720
node_tags_set::NodeTagsSet,
1821
tag_id::{TagId, TagIdInvalidFmt},
@@ -21,21 +24,24 @@ pub use self::{
2124
tag_styles::TagStyles,
2225
};
2326

27+
pub mod dot_src_and_styles;
2428
pub mod graphviz_attrs;
2529
pub mod graphviz_dot_theme;
2630

2731
mod any_id;
28-
mod dot_src_and_styles;
2932
mod edge;
3033
mod edge_descs;
3134
mod edge_id;
3235
mod edge_tags_set;
3336
mod edges;
3437
mod id_newtype;
38+
mod image_id;
39+
mod images;
3540
mod node_descs;
3641
mod node_emojis;
3742
mod node_hierarchy;
3843
mod node_id;
44+
mod node_images;
3945
mod node_names;
4046
mod node_tags_set;
4147
mod tag_id;

crate/model/src/common/dot_src_and_styles.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,36 @@ use serde::{Deserialize, Serialize};
22

33
use crate::theme::ThemeWarnings;
44

5+
pub use self::{graphviz_image::GraphvizImage, graphviz_opts::GraphvizOpts};
6+
7+
mod graphviz_image;
8+
mod graphviz_opts;
9+
510
/// Graphviz dot source and CSS styles.
611
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
712
pub struct DotSrcAndStyles {
813
/// Graphviz dot source to run in `dot`.
914
pub dot_src: String,
1015
/// Tailwind CSS styles to put into `<styles>..</styles>`.
1116
pub styles: String,
17+
/// Options to pass to graphviz when rendering.
18+
pub opts: GraphvizOpts,
1219
/// Warnings detected while computing CSS utility classes.
1320
pub theme_warnings: ThemeWarnings,
1421
}
1522

1623
impl DotSrcAndStyles {
1724
/// Returns a new `DotSrcAndStyles` object.
18-
pub fn new(dot_src: String, styles: String, theme_warnings: ThemeWarnings) -> Self {
25+
pub fn new(
26+
dot_src: String,
27+
styles: String,
28+
opts: GraphvizOpts,
29+
theme_warnings: ThemeWarnings,
30+
) -> Self {
1931
Self {
2032
dot_src,
2133
styles,
34+
opts,
2235
theme_warnings,
2336
}
2437
}
@@ -33,6 +46,11 @@ impl DotSrcAndStyles {
3346
&self.styles
3447
}
3548

49+
/// Returns the options to pass to graphviz when rendering.
50+
pub fn opts(&self) -> &GraphvizOpts {
51+
&self.opts
52+
}
53+
3654
/// Returns the warnings detected while computing CSS utility classes.
3755
pub fn theme_warnings(&self) -> &ThemeWarnings {
3856
&self.theme_warnings
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
/// Defines the path, width, and height of an image for GraphViz.
4+
///
5+
/// Without this, the `<image>` element is not rendered for a node.
6+
///
7+
/// See [`Image`].
8+
///
9+
/// [`Image`]: https://hpcc-systems.github.io/hpcc-js-wasm/graphviz/interfaces/Image.html
10+
#[derive(Clone, Debug, PartialEq, Eq, Deserialize, Serialize)]
11+
pub struct GraphvizImage {
12+
/// URL to the image. This may be a data URL.
13+
///
14+
/// # Examples
15+
///
16+
/// Hyperlinked image:
17+
///
18+
/// ```text
19+
/// https://example.com/image.png
20+
/// ```
21+
///
22+
/// Inline image:
23+
///
24+
/// ```text
25+
/// data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZBAMAAAA2x5hQAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAADUExURUeK/z7BOdMAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAOSURBVCjPYxgFNAMMDAABXgABAvs87wAAAABJRU5ErkJggg==
26+
/// ```
27+
pub path: String,
28+
/// Width that GraphViz scales the image, e.g. `"50px"`.
29+
pub width: String,
30+
/// Height that GraphViz scales the image, e.g. `"50px"`.
31+
pub height: String,
32+
}
33+
34+
impl GraphvizImage {
35+
/// Returns a new `GraphvizImage`.
36+
pub fn new(path: String, width: String, height: String) -> Self {
37+
Self {
38+
path,
39+
width,
40+
height,
41+
}
42+
}
43+
44+
/// Returns the URL to the image. This may be a data URL.
45+
///
46+
/// # Examples
47+
///
48+
/// Hyperlinked image:
49+
///
50+
/// ```text
51+
/// https://example.com/image.png
52+
/// ```
53+
///
54+
/// Inline image:
55+
///
56+
/// ```text
57+
/// data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZBAMAAAA2x5hQAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAADUExURUeK/z7BOdMAAAAJcEhZcwAADsIAAA7CARUoSoAAAAAOSURBVCjPYxgFNAMMDAABXgABAvs87wAAAABJRU5ErkJggg==
58+
/// ```
59+
pub fn path(&self) -> &str {
60+
&self.path
61+
}
62+
63+
/// Returns the width that GraphViz scales the image, e.g. `"50px"`.
64+
pub fn width(&self) -> &str {
65+
&self.width
66+
}
67+
68+
/// Returns the height that GraphViz scales the image, e.g. `"50px"`.
69+
pub fn height(&self) -> &str {
70+
&self.height
71+
}
72+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
use crate::common::dot_src_and_styles::GraphvizImage;
4+
5+
/// Options to pass to graphviz when rendering.
6+
///
7+
/// Currently this is used to pass inline images.
8+
///
9+
/// See [`Options`].
10+
///
11+
/// [`Options`]: https://hpcc-systems.github.io/hpcc-js-wasm/graphviz/interfaces/Options.html
12+
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
13+
#[serde(default)]
14+
pub struct GraphvizOpts {
15+
/// The list of [`images`] to pass to `graphviz.layout`.
16+
///
17+
/// [`images`]: https://hpcc-systems.github.io/hpcc-js-wasm/graphviz/interfaces/Image.html
18+
pub images: Vec<GraphvizImage>,
19+
}
20+
21+
impl GraphvizOpts {
22+
/// Returns a new `GraphvizOpts` object.
23+
pub fn new(images: Vec<GraphvizImage>) -> Self {
24+
Self { images }
25+
}
26+
27+
/// Returns the list of [`images`] to pass to `graphviz.layout`.
28+
///
29+
/// [`images`]: https://hpcc-systems.github.io/hpcc-js-wasm/graphviz/interfaces/Image.html
30+
pub fn images(&self) -> &[GraphvizImage] {
31+
&self.images
32+
}
33+
}

crate/model/src/common/image_id.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
use std::borrow::Cow;
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
use crate::common::AnyId;
6+
7+
/// Unique identifier for an image, `Cow<'static, str>` newtype.
8+
///
9+
/// Must begin with a letter or underscore, and contain only letters, numbers,
10+
/// and underscores.
11+
///
12+
/// # Examples
13+
///
14+
/// The following are all examples of valid `ImageId`s:
15+
///
16+
/// ```rust
17+
/// # use dot_ix::model::{image_id, ImageId};
18+
/// #
19+
/// let _snake = image_id!("snake_case");
20+
/// let _camel = image_id!("camelCase");
21+
/// let _pascal = image_id!("PascalCase");
22+
/// ```
23+
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
24+
pub struct ImageId(Cow<'static, str>);
25+
26+
crate::common::id_newtype!(ImageId, ImageIdInvalidFmt, image_id);
27+
28+
impl From<AnyId> for ImageId {
29+
fn from(any_id: AnyId) -> Self {
30+
let id = any_id.into_inner();
31+
32+
Self(id)
33+
}
34+
}

crate/model/src/common/images.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
use std::ops::{Deref, DerefMut};
2+
3+
use indexmap::IndexMap;
4+
use serde::{Deserialize, Serialize};
5+
6+
use crate::common::{dot_src_and_styles::GraphvizImage, ImageId};
7+
8+
/// Images available for . `IndexMap<ImageId, GraphvizImage>` newtype.
9+
///
10+
/// # Examples
11+
///
12+
/// Each URL should either be a hyperlink to an image, or a base64 encoded
13+
/// data URL:
14+
///
15+
/// ```yaml
16+
/// hierarchy:
17+
/// dove: {}
18+
/// blue: {}
19+
///
20+
/// images:
21+
/// dove_svg:
22+
/// path: "https://peace.mk/img/dove.svg"
23+
/// width: "50px"
24+
/// height: "50px"
25+
///
26+
/// blue_inline:
27+
/// path: >-
28+
/// data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAZBAMAAAA2x5hQAAAAAX
29+
/// NSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAADUExURUeK/z7BOdMAAAAJcEhZcwAADsIAAA
30+
/// 7CARUoSoAAAAAOSURBVCjPYxgFNAMMDAABXgABAvs87wAAAABJRU5ErkJggg==
31+
/// width: "50px"
32+
/// height: "50px"
33+
///
34+
/// node_images:
35+
/// dove: dove_svg
36+
/// blue: blue_inline
37+
/// ```
38+
#[derive(Clone, Debug, Default, PartialEq, Eq, Deserialize, Serialize)]
39+
pub struct Images(IndexMap<ImageId, GraphvizImage>);
40+
41+
impl Images {
42+
/// Returns a new `Images` map.
43+
pub fn new() -> Self {
44+
Self::default()
45+
}
46+
47+
/// Returns a new `Images` map with the given preallocated
48+
/// capacity.
49+
pub fn with_capacity(capacity: usize) -> Self {
50+
Self(IndexMap::with_capacity(capacity))
51+
}
52+
53+
/// Returns the underlying map.
54+
pub fn into_inner(self) -> IndexMap<ImageId, GraphvizImage> {
55+
self.0
56+
}
57+
}
58+
59+
impl Deref for Images {
60+
type Target = IndexMap<ImageId, GraphvizImage>;
61+
62+
fn deref(&self) -> &Self::Target {
63+
&self.0
64+
}
65+
}
66+
67+
impl DerefMut for Images {
68+
fn deref_mut(&mut self) -> &mut Self::Target {
69+
&mut self.0
70+
}
71+
}
72+
73+
impl From<IndexMap<ImageId, GraphvizImage>> for Images {
74+
fn from(inner: IndexMap<ImageId, GraphvizImage>) -> Self {
75+
Self(inner)
76+
}
77+
}
78+
79+
impl FromIterator<(ImageId, GraphvizImage)> for Images {
80+
fn from_iter<I: IntoIterator<Item = (ImageId, GraphvizImage)>>(iter: I) -> Self {
81+
Self(IndexMap::from_iter(iter))
82+
}
83+
}

0 commit comments

Comments
 (0)