Skip to content

Commit

Permalink
Estimate text layout using an offscreen canvas
Browse files Browse the repository at this point in the history
  • Loading branch information
jwagner committed Dec 19, 2024
1 parent 3ad52da commit 52ce834
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 27 deletions.
33 changes: 20 additions & 13 deletions plotters/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,33 @@ version = "0.2.89"
[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies.web-sys]
version = "0.3.66"
features = [
"Document",
"DomRect",
"Element",
"HtmlElement",
"Node",
"Window",
"HtmlCanvasElement",
"CanvasRenderingContext2d",
"Document",
"DomRect",
"Element",
"HtmlElement",
"Node",
"Window",
"HtmlCanvasElement",
"CanvasRenderingContext2d",
"OffscreenCanvas",
"OffscreenCanvasRenderingContext2d",
"TextMetrics",
]

[features]
default = [
"bitmap_backend", "bitmap_encoder", "bitmap_gif",
"bitmap_backend",
"bitmap_encoder",
"bitmap_gif",
"svg_backend",
"chrono",
"ttf",
"image",
"deprecated_items", "all_series", "all_elements",
"deprecated_items",
"all_series",
"all_elements",
"full_palette",
"colormaps"
"colormaps",
]
all_series = ["area_series", "line_series", "point_series", "surface_series"]
all_elements = ["errorbar", "candlestick", "boxplot", "histogram"]
Expand Down Expand Up @@ -117,7 +124,8 @@ datetime = ["chrono"]
serialization = ["serde"]
evcxr = ["svg_backend"]
evcxr_bitmap = ["evcxr", "bitmap_backend", "plotters-svg/bitmap_encoder"]
deprecated_items = [] # Keep some of the deprecated items for backward compatibility
deprecated_items = [
] # Keep some of the deprecated items for backward compatibility

[dev-dependencies]
itertools = "0.10.0"
Expand All @@ -143,4 +151,3 @@ path = "benches/main.rs"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "doc_cfg"]

34 changes: 20 additions & 14 deletions plotters/src/style/font/web.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{FontData, FontFamily, FontStyle, LayoutBox};
use wasm_bindgen::JsCast;
use web_sys::{window, HtmlElement};
use web_sys::{window, HtmlElement, OffscreenCanvas, OffscreenCanvasRenderingContext2d};

#[derive(Debug, Clone)]
pub enum FontError {
Expand Down Expand Up @@ -29,18 +29,24 @@ impl FontData for FontDataInternal {
))
}
fn estimate_layout(&self, size: f64, text: &str) -> Result<LayoutBox, Self::ErrorType> {
let window = window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
let span = document.create_element("span").unwrap();
span.set_text_content(Some(text));
span.set_attribute("style", &format!("display: inline-block; font-family:{}; font-style:{}; font-size: {}px; position: fixed; top: 100%", self.0, self.1, size)).unwrap();
let span = span.into();
body.append_with_node_1(&span).unwrap();
let elem = JsCast::dyn_into::<HtmlElement>(span).unwrap();
let height = elem.offset_height() as i32;
let width = elem.offset_width() as i32;
elem.remove();
Ok(((0, 0), (width, height)))
let canvas = OffscreenCanvas::new(0, 0).expect("offscreen canvas");
let context = canvas
.get_context("2d")
.expect("getContext")
.expect("context for 2d not null")
.dyn_into::<OffscreenCanvasRenderingContext2d>()
.expect("cast");
context.set_font(&format!(
"{} {}px {}",
self.1.as_str(),
size,
self.0.as_str(),
));
let metrics = context
.measure_text(text)
.expect("measure_text to return metrics");
let width = metrics.width();
let height = metrics.font_bounding_box_ascent() + metrics.font_bounding_box_descent();
Ok(((0, 0), (width as i32, height as i32)))
}
}

0 comments on commit 52ce834

Please sign in to comment.