Crate d3_geo_rs

source ·
Expand description

A port of d3/d3-geo into rust_d3_geo.

A library with a wide range of geographic projections, spherical shapes and spherical trigonometry.

Features :-

  • Each projection builder supports - scaling, rotating and translation to yield the desired map view.

  • Large datasets can be resampled to reduce compute.

  • As well as displaying to a CANVAS element or SVG, various metric can be computed on the geometry such as Area, Centroids, and Bounds on polygons and lines.

TODO add note about stream pipelines and endpoints.

Available projections

Each projection has default builder, which can be programmed.

Stereographic for example

use geo_types::Coord;
use d3_geo_rs::projection::Build;
use d3_geo_rs::projection::RawBase as ProjectionRawBase;
use d3_geo_rs::projection::stereographic::Stereographic;
use d3_geo_rs::projection::ClipAngleAdjust;
use d3_geo_rs::projection::PrecisionAdjust;
use d3_geo_rs::projection::ScaleSet;
use d3_geo_rs::projection::TranslateSet;
use d3_geo_rs::stream::DrainStub;

    let stereographic = Stereographic::<DrainStub<f64>, f64>::builder()
      .scale_set(100_f64)
      .translate_set(&Coord {
         x: 300_f64,
         y: 300_f64,
      })
      .clip_angle(90_f64)
      .precision_set(&10_f64)
      .build();

Examples

The examples directory contains a large selection of applications demmonstration web applications rendering to a CANVAS or SVG elemments. It serves as a migration guide examples/projection shows each projction in turn, with the javascript and rust version drawn side by side.

examples/globe - demonstrates that this library can process larger datasets than is possible which javascript The javascript version operate on a 110m dataset of the globe while, the RUST version use a denser 50m dataset.

Here is code snippet from example/projection/globe/ showing the rendering of a globe.


extern crate js_sys;
extern crate rust_topojson_client;
extern crate topojson;
extern crate web_sys;

use geo_types::Coord;
use geo::Geometry;
use geo::MultiLineString;
use topojson::Topology;
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsCast;
use gloo_utils::format::JsValueSerdeExt;
use wasm_bindgen_futures::JsFuture;
use web_sys::Document;
use web_sys::*;

use d3_geo_rs::graticule::generate_mls;
use d3_geo_rs::path::builder::Builder as PathBuilder;
use d3_geo_rs::path::context::Context;
use d3_geo_rs::projection::orthographic::Orthographic;
use d3_geo_rs::projection::Build;
use d3_geo_rs::projection::RawBase as ProjectionRawBase;
use d3_geo_rs::projection::RotateSet;
use d3_geo_rs::projection::ScaleSet;
use d3_geo_rs::projection::TranslateSet;
use rust_topojson_client::feature::feature_from_name;

fn document() -> Result<Document, JsValue> {
    let window = web_sys::window().unwrap();
    Ok(window.document().unwrap())
}

/// Entry point
#[wasm_bindgen(start)]
pub async fn start() -> Result<(), JsValue> {
    let document = document()?;
    let window = web_sys::window().expect("Failed to get window");

    // Get data from world map.
    let mut opts = RequestInit::new();
    opts.method("GET");
    opts.mode(RequestMode::Cors);
    let request = Request::new_with_str_and_init("/world-atlas/world/50m.json", &opts)?;

    let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
    let resp: Response = resp_value.dyn_into().unwrap();

    let json = JsFuture::from(resp.json()?).await?;

    let topology =
        JsValueSerdeExt::into_serde::<Topology>(&json).expect("Did not get a valid Topology");

    // Grab canvas.
    let canvas = document
        .get_element_by_id("c")
        .unwrap()
        .dyn_into::<web_sys::HtmlCanvasElement>()?;

    let context_raw = canvas
        .get_context("2d")?
        .unwrap()
        .dyn_into::<web_sys::CanvasRenderingContext2d>()?;

    let width: f64 = canvas.width().into();
    let height: f64 = canvas.height().into();

    let countries = feature_from_name(&topology, "countries").expect("Did not extract geometry");

    let context = Context::new(context_raw.clone());
    let pb = PathBuilder::new(context);

    let ortho = Orthographic::builder()
        .scale_set(width as f64 / 1.3_f64 / std::f64::consts::PI)
        .translate_set(&Coord {
            x: width / 2_f64,
            y: height / 2_f64,
        })
        .rotate2_set(&[270_f64, 00_f64])
        .build();

    let mut path = pb.build(ortho);
    context_raw.set_stroke_style(&"#333".into());
    context_raw.set_line_width(0.5);
    path.object(&countries);
    context_raw.stroke();

    // Graticule
    let graticule =
        generate_mls::<f64>();
    context_raw.begin_path();
    context_raw.set_stroke_style(&"#ccc".into());
    path.object(&graticule);
    context_raw.stroke();

    Ok(())
}

Modules

Area Stream.
Vector arithmatic operations on 3-D vectors.
Use to calculate the centroid point for a given object.
Related to the injection of circles into a stream.
Projectors can clip, remove point computed to be outside the projection.
Streamable Data obejcts.
Used to calculate distances on a sphereical surface.
A graticule is a network of lines used for plotting, scaling.
A stream pipeline stage.
Testing and debug helpers.
Used to calculate of object lengths.
Mathematical constants.
Stream end point: Calculation of paths to a string or rendering context.
A stripped down version of path
Determines when points are located inside data objects.
Holds proctions and associated builders.
Generates range of T values from start to stop by step.
Rotation transforms.
Stream related helper functions.

Traits

2-D Transform common to projections and, rotations.