{"id":16849696,"url":"https://github.com/martinfrances107/rust_d3_geo","last_synced_at":"2025-04-08T04:17:17.242Z","repository":{"id":39569699,"uuid":"282274438","full_name":"martinfrances107/rust_d3_geo","owner":"martinfrances107","description":"A port of d3-geo into RUST.","archived":false,"fork":false,"pushed_at":"2025-02-17T18:53:37.000Z","size":1089806,"stargazers_count":23,"open_issues_count":9,"forks_count":1,"subscribers_count":1,"default_branch":"v3.x-dev","last_synced_at":"2025-03-24T06:53:33.602Z","etag":null,"topics":["d3","d3js","library","rust","rustlang"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/martinfrances107.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-07-24T17:02:56.000Z","updated_at":"2025-03-22T10:27:22.000Z","dependencies_parsed_at":"2022-07-04T10:54:10.276Z","dependency_job_id":"43713106-5cb5-4544-be6e-b126b0b0d43c","html_url":"https://github.com/martinfrances107/rust_d3_geo","commit_stats":{"total_commits":1645,"total_committers":2,"mean_commits":822.5,"dds":0.0006079027355623268,"last_synced_commit":"21cf8c0737ab1ff57239f1f03deaa279921c39ff"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrances107%2Frust_d3_geo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrances107%2Frust_d3_geo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrances107%2Frust_d3_geo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/martinfrances107%2Frust_d3_geo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/martinfrances107","download_url":"https://codeload.github.com/martinfrances107/rust_d3_geo/tar.gz/refs/heads/v3.x-dev","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247773721,"owners_count":20993639,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["d3","d3js","library","rust","rustlang"],"created_at":"2024-10-13T13:17:08.029Z","updated_at":"2025-04-08T04:17:17.215Z","avatar_url":"https://github.com/martinfrances107.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n# Rust D3 Geo\n\nRust 2021 Edition.\n\u003cdiv align=\"center\"\u003e\n\n\u003ca href=\"https://crates.io/crates/d3_geo_rs\"\u003e\u003cimg alt=\"crates.io\" src=\"https://img.shields.io/crates/v/d3_geo_rs.svg\"/\u003e\u003c/a\u003e\n\u003ca href=\"https://docs.rs/d3_geo_rs\" rel=\"nofollow noopener noreferrer\"\u003e\u003cimg src=\"https://docs.rs/d3_geo_rs/badge.svg\" alt=\"Documentation\"\u003e\u003c/a\u003e\n\u003ca href=\"https://crates.io/crates/d3_geo_rs\"\u003e\u003cimg src=\"https://img.shields.io/crates/d/d3_geo_rs.svg\" alt=\"Download\" /\u003e\u003c/a\u003e\n\n\u003c/div\u003e\n\nThis is a port [d3-geo](https://github.com/d3/d3-geo) into RUST. It is part of a family of ported d3-modules\n\n* d3_geo_rs\n* [d3_delaunay_rs](https://crates.io/crates/d3_delaunay_rs)\n* [d3_geo_voronoi_rs](https://crates.io/crates/d3_geo_voronoi_rs)\n\nThis library allows the development of custom maps. It provides a comprehensive set\n of projections along with the means to scale rotate and translate the final image.\n The projector processes polygons, lines and points in the form of\n [GeoJSON](https://en.wikipedia.org/wiki/GeoJSON) objects. Additionally this\n library can be used to calculate lengths, areas and the centroid of such objects\n\n[CHANGELOG.md](https://github.com/martinfrances107/rust_d3_geo/blob/v3.x-dev/CHANGELOG.md) contains a summary of breaking changes between v1.x, 2.x and 3.x\n\nVersion 3.0.0 adds support for WGPU\n\n\u003e \"WGPU is a pure-rust graphics API. It runs natively on Vulkan, Metal, D3D12, and OpenGL; and on top of WebGL2 and WebGPU on wasm.\" [\\[wgpu\\]](https://crates.io/crates/wgpu)\n\n## When to use the rust version of the library\n\nThe limits of the javascript library become obvious when developing interactive applications that process large datasets.\nFor example the examples/globe applications operate on a highly detailed ( 1:50M resolution ) map of the earth. On a laptop this is beyond the javascript version.\n\n | Available Projections |   |   |\n | --------------------- | - | - |\n | Albers | ConicEqualArea | Gnomic|\n | AlbersUsa | Equidistant | Orthographic |\n | AzimuthalEqualArea | Equirectangular | Mercator |\n | AzimuthalEquiDistant | EqualArea | MercatorTransverse |\n | Conformal | EqualEarth | Stereographic |\n\n## Examples\n\nThese Examples are provided to help developers convert their existing javascript to rust. They can be found in the github repository associated with this crate.\n\n\u003ctable\u003e\n\u003cthead\u003e\n\u003ctr\u003e\n\u003cth align=\"left\" colspan=\"2\" \u003eDescription\u003c/th\u003e\n\u003c/tr\u003e\n\u003c/thead\u003e\n\u003ctbody align=\"left\" style=\"vertical-align:top;\"\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cstrong\u003eexamples/globe/rotating_50m\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n\nThis is a port into rust of this d3-geo example\n\n[www.d3indepth.com/geographic/](https://www.d3indepth.com/geographic/)\n\nThe javascript version compromises by using a low resolution map. Here no such compromise is required.\n\nThis globe is rendered to a HTML CANVAS element.\n\nFor performance reasons this example is best viewed by running \"npm run  build\" and then \"npm run serve\" which compiles the rust code using the --release flag.\n\n(Scale 1:50M)\n\n\u003c/td\u003e\n\n\u003ctd width=\"50%\"\u003e\n  \u003cimage src=\"https://raw.githubusercontent.com/martinfrances107/rust_d3_geo/v3.x-dev/images/rotating.png\"\u003e\n\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd width=\"50%\"\u003e\n\u003cstrong\u003eexamples/globe/rotating_WGPU\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n\n[WGPU](https://gpuweb.github.io/gpuweb/) support in the browser is partial and currently hidden behind experimental flags. See the browser-WGPU Implementation [Status](https://github.com/gpuweb/gpuweb/wiki/Implementation-Status). For now development in this library uses the [winit](https://crates.io/crates/winit) crate to make cross platform application.\n\nThe promise of this approach is to bypass the bottleneck in passing bulk data from RUST memory space, into javascript, and finally into GPU memory.\n\nGeoJson Geometry is streamed through this libraries rendering pipeline into a new **PolyLinesWPGU** endpoint.\n\nThis endpoint's output is a (vertex_buffer,index_buffer) pair in the form of blocks of contiguous memory which can be passed directly to the GPU.\n\nA thin vertex and fragment shader is then responsible for rendering.\n\nThe render speed is approximately 3 times faster than the example above.\n\n(Scale 1:50M)\n\n\u003c/td\u003e\n\n\u003ctd width=\"50%\"\u003e\n\u003cimage src=\"https://raw.githubusercontent.com/martinfrances107/rust_d3_geo/v3.x-dev/images/rotating_wgpu.png\"\u003e\n\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003ctr\u003e\n\n\u003ctd\u003e\n\u003cstrong\u003eexamples/globe/svg\u003c/strong\u003e\u003cbr\u003e\u003cbr\u003e\n\nThe globe is rendered as a SVG image.\n\nSVG are useful when the semantic meaning of the data needs to be preserved. The example shows how to load/parse/display the globe as individual SVG PATH elements.\n\nIt also includes code samples that generates SVG graticules.\n\n(Scale 1:50M)\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimage src=\"https://raw.githubusercontent.com/martinfrances107/rust_d3_geo/v3.x-dev/images/globe.svg\"\u003e\n\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003ctr\u003e\n\n\u003ctd\u003e\u003cstrong\u003eexamples/globe/drag_and_zoom\u003c/strong\u003e \u003cbr/\u003e\u003cbr/\u003e\n\nThis globe is rendered to a HTML CANVAS element\n\nIt deliberately mixes typescript methods with rust.\nThe typescript is responsible for handling the mouse events and manipulating the quaternion used to calculate the appropriate change in rotation. In a typescript render loop calls to a rust function render the globe.\n\u003cbr/\u003e\n\u003cbr/\u003e\nThis example is currently undergoing rapid development.\n\n(Scale 1:50M)\n\u003c/td\u003e\n\n\u003ctd\u003e\n\u003cimage src=\"https://raw.githubusercontent.com/martinfrances107/rust_d3_geo/v3.x-dev/images/drag_and_zoom.png\"\u003e\n\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003ctr\u003e\n\n\u003ctd\u003e\n\u003cstrong\u003eexamples/projections\u003c/strong\u003e \u003cbr/\u003e\u003cbr/\u003e\n\nAll available projections are rendered to a HTML CANVAS element\n\nAs a confidence building exercise, this demo\nshows a side by side comparison of the all the projections rendered by in both \u003cstrong\u003ejavascript\u003c/strong\u003e and \u003cstrong\u003erust\u003c/strong\u003e.\n\n(Scale 1:50M)\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimage src=\"https://raw.githubusercontent.com/martinfrances107/rust_d3_geo/v3.x-dev/images/projection.png\"\u003e\n\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003ctr\u003e\n\n\u003ctd\u003e\u003cstrong\u003eexamples/globe/albers_usa\u003c/strong\u003e \u003cbr\u003e\u003cbr\u003e\n\nThis show all the counties in the USA.\n\nAlbersUSA is unlike the other projections. Alaska and Hawaii are rendered as insets.\nAs can be seen in the code a Multi-drain must be used to gather the three projections.\n\n(Scale of 1:10M)\n\n\u003c/td\u003e\n\u003ctd\u003e\u003cimage src=\"https://raw.githubusercontent.com/martinfrances107/rust_d3_geo/v3.x-dev/images/albers_usa.svg\"\u003e\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003ctr\u003e\n\n\u003ctd\u003e\n\u003cstrong\u003eexamples/ring\u003c/strong\u003e\u003cbr/\u003e\u003cbr/\u003e\nSVG example\n\nSample code in both RUST and javascript that renders a complex multi-polygon. ( Orthographic and Stereographic )\n\n\u003c/td\u003e\n\u003ctd\u003e\n\u003cimage src=\"https://raw.githubusercontent.com/martinfrances107/rust_d3_geo/v3.x-dev/images/ring.png\"\u003e\n\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003ctr\u003e\n\n\u003ctd\u003e\n\u003cstrong\u003eexamples/multi_threaded\u003c/strong\u003e\u003cbr/\u003e\u003cbr/\u003e\nMulti threading support is being developed on the v3.x branch\nIt is still highly experimental.\n\nThis code is intended to be used as a template for native\napplications ( i.e. *NOT* for web environments )\n\nEach of the 6 stages runs on a new thread\nMessages like PolygonStart/LineStart and Point are transmiited\ninto the first stage.\n\nAfter the stream is complete a request in transmitted into the input\nand a copy of the endpoint is transmitted out of the final stage.\n\n\u003c/td\u003e\n\u003ctd\u003e\nIMGAE TBD\n\u003c/td\u003e\n\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003ctable\u003e\n\n\u003cbr/\u003e\n\n### An outline of the common steps found in all the examples\n\n1) For a given projection, use its default projection builder, make changes to the scale, translation .. etc, then call build() to construct a projector.\n\n    ```rust\n    let projector = Stereographic::\u003cf64\u003e::builder()\n      .scale_set(100_f64)\n      .translate_set(\u0026Coord {\n         x: 300_f64,\n         y: 300_f64,\n      })\n      .clip_angle(90_f64)\n      .precision_set(\u002610_f64)\n      .build();\n    ````\n\n2) Construct a PathBuilder\n\n    A Path is a collection of nodes where each step on the path transforms the geometry object in some manner.\n\n    An object is then streamed along the path.\n\n    Here is an overview of the key nodes.\n\n     **Clipping**: Two strategies are used \"Antimeridian\" and \"ClipAngle\" [See clip_angle_set() and clip_angle_reset()]\n\n     **Resampling**: Dense geometry can be reduced by declaring a separation distance under which points, used to describe polygons and lines, are considered indistinguishable [See precision_set()]\n\n     **Bounding**: A projection space box can be set, and only geometry within this extent will be displayed. Polygons partially inside the box are restructured to conform to the edges of the box. [See clip_extent_set() clip_extent_clear()]\n\n      **Endpoints** are special path nodes which hold the result of a calculation. A variety of endpoint are available Area, Centroid, Length which can be use to compute properties about polygons or lines. These examples only show endpoints that render to a HTML canvas element or a SVG path element.\n\n    When rendering to a HTML canvas the endpoint holds Path2D \"rendering context\"\n\n      ```rust\n       // Construct a PathBuilder linked to Path2d\n       // rendering context.\n       let path2d = Path2d::new()?;\n       let endpoint = PathBuilder::new(path2d);\n       let pb = PathBuilder::new(endpoint);\n       let path = pb.build();\n      ```\n\n    When generating a SVG image, the endpoint holds a string value from which a PATH element can be constructed.\n\n      ```rust\n        let pb = PathBuilder::pathstring();\n        let path = pb.build();\n      ```\n\n3) Please see the different examples, but the common next step is to\n   construct a PathBuilder object and then to stream a geometry object into it :-\n\n      ```rust\n         // 'countries' is a geometry extracted from\n         // a world map json file.\n         path.stream(\u0026countries)\n      ```\n\n### Requirements (running the examples)\n\n* node and npm [installation guide](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm)\n\n* wasm-pack [installation guide](https://rustwasm.github.io/wasm-pack/installer/)\n\n\u003cbr/\u003e\n\nTo view an example application either create a development build, or construct a static-web site as follows\n\n### Examples: Start And Run A Development Build\n\n ```bash\n git clone https://github.com/martinfrances107/rust_d3_geo.git\n cd rust_d3_geo/examples/ring/\n npm install\n npm run start\n ```\n\nThe last command \"npm run start\" will automatically open your default browser at http:://localhost::8080\n\n### Performance: Examples Building A Static Site\n\nMuch better performance can be achieved by building a static web site and viewing that directly. At the expense of longer build times the RUST portions of the code a build using the \"--release\" tags\n\n```bash\n  git clone https://github.com/martinfrances107/rust_d3_geo.git\n  cd rust_d3_geo/examples/ring\n  npm install\n  npm run build\n  npm run serve\n```\n\n## Feature List\n\n* **web** (default) This feature allows rendering to a HTML CANVAS element. For CLI binary applications this can be removed to reduce the dependency count.\n\n* **wgpu** Allow an endpoint that outputs points and poly-lines as \"Array Buffer\". This buffer can then be fed direcly in a the GPU reducing the amount system calls. This feature is highly experimental.\n\n## Benchmarking\n\nThere are two distinct compute environments\n\n  1. The browser: Is a highly constrained environment.\n  Here are two equivalent benchmarks, one for rust\n  [rust_d3_geo_voronoi](https://github.com/martinfrances107/rust_d3_geo_voronoi)\n  and one for javascript [d3-geo-voronoi](https://github.com/Fil/d3-geo-voronoi).\n  Rust runs as a service worker with no direct control the DOM. Passing objects as JsValue\n  between threads has negative performance impacts despite this benchmark runs **twice** as fast.\n\n  2. Node like environments:\n  The github repository associated with crate has two \"profile targets\" and two \"benches\"\n  which can be used to to spot bottlenecks in this environment. The benches are [Criterion.rs](https://crates.io/crates/criterion) based micro benchmarks.\n\n## Flamegraph\n\nA profile_target is binary that outputs a HTML page containing a SVG image showing the globe with graticule markings.\n\nA flame-graph can be created by entering a particular profile targets directory and running :-\n\n```bash\ncd profile_target/albers_usa\nsudo CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph\n```\n\nThe complexity of rendering 240 countries/polygons provides a good view in memory allocation issues.\n\n## Coding Standard\n\n* Idiomatic RUST, as defined by cargo clippy where possible.\n* No booleans as arguments to functions/methods, use two state enums instead.\n\n   See \"Reflect\" as an example.\n\n   ```rust\n   pub trait ReflectSet {\n       /// f64 or f32.\n       type T;\n      /// Set the projection builder to invert the x-coordinate.\n       fn reflect_x_set(\u0026mut self, reflect: Reflect) -\u003e \u0026mut Self;\n      /// Set the projection builder to invert the y-coordinate.\n       fn reflect_y_set(\u0026mut self, reflect: Reflect) -\u003e \u0026mut Self;\n   }\n   ```\n\n   This allows for a clearer statement of intent :-\n\n   ```rust\n   builder.reflect_y_set(Reflect::Flipped);\n   ```\n\n* [\"Type-Driven API Design\"](https://www.youtube.com/watch?v=bnnacleqg6k) is the\n     preferred way of constructing state machines.\n\n     In the example below, when assembling a stream pipeline, connect() can only be called\n     when the state is \"Unconnected\". The output type's STATE is \"Connected\\\u003cSINK\\\u003e\".\n\n    ```rust\n    impl StreamTransformRadians\u003cUnconnected\u003e {\n      #[inline]\n      /// Connect this node to the next element in the pipeline.\n      pub const fn connect\u003cEP, SINK, T\u003e(self, sink: SINK) -\u003e StreamTransformRadians\u003cConnected\u003cSINK\u003e\u003e\n      where\n        SINK: Clone,\n      {\n        StreamTransformRadians(Connected { sink })\n      }\n    }\n     ```\n\n     The \"Stream\" trait is only implemented when the STATE is \"Connected\\\u003cSINK\\\u003e\".\n     By design, all code is prevented from calling line_start() or point() unless the object\n     has been connected to another pipeline stage.\n\n\u003cbr/\u003e\n\n## Future 3.0 upgrades\n\n\"Semantic Versioning\" guidelines :-\n\n* Increment the major number when a breaking change occurs.\n* Increment the minor number when a new feature is added, @deprecated notes added to outdated functions,\n* Increment the patch number for tightly focused security fixes.\n\nFuture Work.\n\n* Since I ported this code ... the javascript has added a digits() function to control the\n  precision of numbers as they are output as strings. ( I need to implement this upgrade )\n\n* [rayon](https://docs.rs/rayon/latest/rayon/index.html) is rust's crate for multithread support. Since this crate is focused on web development and so incoperating [wasm-bindgen-rayon](https://crates.io/crates/wasm-bindgen-rayon). wasm-bindgen_rayon recommends using nightly - and so it far from production read. I have made extensive use of iterators when porting the code and rayon support the easy conversion of single threaded iterators to multithread iterators.\n\n## Architecture discussion\n\nThere is an aspect of the design that needs review. It related to the best way to implement a doubly-linked list which has cross links between nodes.\n\nThe clipping algorithm in clip/rejoin/mod.rs needs to be refactored.\nsee [The intersection Problem.](/intersection_problem.md)\nTest coverage in that area is high so the algorithms is working but the data structures make extensive use of vectors ( heap objects ) containing references to other heap objects ```Vec\u003cOptions\u003cRc\u003cRefCell\u003c_Intersection_\u003e\u003e\u003e\u003e``` which is not performant.\n\n A full discussion can be found [here](/intersection_problem.md)\n\n### Unimplemented sections of the library\n\nSupport for a custom projection is not yet supported.\n\nFor an example of this see the test labelled \"projection.fitExtent(…) custom projection\"\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinfrances107%2Frust_d3_geo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmartinfrances107%2Frust_d3_geo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmartinfrances107%2Frust_d3_geo/lists"}