plotters-rs / plotters

A rust drawing library for high quality data plotting for both WASM and native, statically and realtimely 🦀 📈🚀
https://plotters-rs.github.io/home/
MIT License
3.89k stars 281 forks source link

[Feature Request] Available in WebAssembly within web worker #482

Open lyhanburger opened 1 year ago

lyhanburger commented 1 year ago

What is the feature ?

I'd like use plotters wasm in the web worker, but the plotters/src/style/font/web.rs estimate_layout method use the window. Worker has any window context.

(Optional) Why this feature is useful and how people would use the feature ?

  1. Improving rendering efficiency when multiple charts are present.
  2. I prefer performing heavy data processing in a worker and, once the data processing is complete, invoking the chart within the worker instead of sending the chart data back to the main thread.

(Optional) Additional Information

I have implemented a simple version of it,it worked for me. (base the plotters 0.3.5)

// plotters/src/style/font/web.rs
    fn estimate_layout(&self, size: f64, text: &str) -> Result<LayoutBox, Self::ErrorType> {
        let canvas = OffscreenCanvas::new(300, 300).unwrap();
        let context = canvas
            .get_context("2d")
            .ok()
            .unwrap()
            .unwrap()
            .dyn_into::<OffscreenCanvasRenderingContext2d>()
            .unwrap();
        context.set_font(&format!("{}px {}", size, self.0));
        context.fill_text(&text, 0.0, 0.0);
        let bbox = context.measure_text(&text).unwrap();
        let width = bbox.width();
        let ascent = bbox.font_bounding_box_ascent();
        let descent = bbox.font_bounding_box_descent();
        let height = (descent - ascent).abs();
        // 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-size: {}px; position: fixed; top: 100%", self.0, 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 as i32, height as i32)))
    }
[target.'cfg(all(target_arch = "wasm32", not(target_os = "wasi")))'.dependencies.web-sys]
version = "0.3.64"
features = [
        "Document",
        "DomRect",
        "Element",
        "HtmlElement",
        "Node",
        "Window",
        "HtmlCanvasElement",
        "CanvasRenderingContext2d",
        # new add
        "OffscreenCanvas",
        "OffscreenCanvasRenderingContext2d",
        "TextMetrics",
]