1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! `vowl-wasm` — an ontology visualisation engine in Rust, compiled to WebAssembly.
//!
//! This crate turns an OWL ontology into something a browser can draw: it parses
//! the ontology, builds a typed graph out of it, settles that graph with a
//! force-directed layout, and hands the result to JavaScript. It is a clean-room
//! Rust reimplementation of the **VOWL** visual notation defined by
//! [VisualDataWeb/WebVOWL](https://github.com/VisualDataWeb/WebVOWL) (MIT,
//! © 2014–2019 Vincent Link, Steffen Lohmann, Eduard Marbach, Stefan Negru,
//! Vitalis Wiens). No upstream JavaScript, fixtures, or assets are vendored here;
//! only the notation and the on-the-wire JSON shape are shared.
//!
//! # The two entry points
//!
//! [`WebVowl`](bindings::WebVowl) is the general-purpose surface: load an
//! ontology, run the simulation, read the graph back. It is always available.
//!
//! [`NggExplorer`](bindings::explorer::NggExplorer) is a narrower, allocation-free
//! surface for a rendering worker: it loads a pre-baked binary tier and exposes
//! the live position buffer as a pointer into WASM linear memory, so JavaScript
//! can build a zero-copy `Float32Array` over it and never pay a per-frame
//! serialisation cost. It requires the `ngg1` feature.
//!
//! # Example
//!
//! Parse a small ontology, settle it, and read the result. This is the same API
//! JavaScript sees, minus the `camelCase` renaming applied at the WASM boundary.
//!
//! ```
//! use vowl_wasm::bindings::WebVowl;
//!
//! let mut vowl = WebVowl::new();
//!
//! // WebVOWL-shaped ontology JSON: classes and the properties between them.
//! vowl.load_ontology(r#"{
//! "class": [
//! { "id": "c1", "label": "Person", "type": "owl:Class" },
//! { "id": "c2", "label": "Organisation", "type": "owl:Class" }
//! ],
//! "property": [
//! { "id": "p1", "label": "worksFor", "type": "owl:ObjectProperty",
//! "domain": "c1", "range": "c2" }
//! ]
//! }"#).expect("valid ontology");
//!
//! assert_eq!(vowl.get_node_count(), 2);
//!
//! // Settle the layout: seed the simulation, then anneal it.
//! vowl.init_simulation().expect("graph is loaded");
//! vowl.run_simulation(120).expect("graph is loaded");
//!
//! // Alpha decays as the layout cools.
//! assert!(vowl.get_alpha() < 1.0);
//! ```
//!
//! # The JavaScript API
//!
//! Every method below is exported to JavaScript under the `js_name` shown. This
//! is the **frozen 0.1.0 surface**: names and signatures will not change without
//! a major version bump. Later 0.1.x releases only add to it — `getNodeIds`,
//! `getNodePositions` and `writePositionsInto` arrived in 0.1.1.
//!
//! ## Reading positions
//!
//! [`get_node_positions`](bindings::WebVowl::get_node_positions) is the
//! always-available way to get coordinates out after a
//! [`tick`](bindings::WebVowl::tick). Node **index order is stable for the
//! lifetime of a loaded graph** — ticking, pinning, filtering and folding never
//! reorder or remove nodes — so pair it once with
//! [`get_node_ids`](bindings::WebVowl::get_node_ids) and then read only floats
//! per frame:
//!
//! ```javascript
//! const ids = vowl.getNodeIds(); // once, after loadOntology
//! vowl.tick();
//! const xy = vowl.getNodePositions(); // ids[i] <-> xy[2i], xy[2i + 1]
//! ```
//!
//! `getGraphData()` remains the way to read labels, types and edges, and stays
//! behind `debug-serde`.
//!
//! ## `WebVowl` — always available
//!
//! | JavaScript | Rust | Purpose |
//! |---|---|---|
//! | `new WebVowl()` | [`WebVowl::new`](bindings::WebVowl::new) | Construct an empty instance |
//! | `loadOntology(json)` | [`load_ontology`](bindings::WebVowl::load_ontology) | Parse and build the graph |
//! | `initSimulation()` | [`init_simulation`](bindings::WebVowl::init_simulation) | Seed the force simulation |
//! | `runSimulation(n)` | [`run_simulation`](bindings::WebVowl::run_simulation) | Advance `n` steps |
//! | `tick()` | [`tick`](bindings::WebVowl::tick) | Advance one step |
//! | `isFinished()` | [`is_finished`](bindings::WebVowl::is_finished) | Has the layout settled? |
//! | `getAlpha()` | [`get_alpha`](bindings::WebVowl::get_alpha) | Annealing temperature |
//! | `setCenter(x, y)` | [`set_center`](bindings::WebVowl::set_center) | Move the layout centre |
//! | `setLinkDistance(d)` | [`set_link_distance`](bindings::WebVowl::set_link_distance) | Spring rest length |
//! | `setChargeStrength(s)` | [`set_charge_strength`](bindings::WebVowl::set_charge_strength) | Repulsion strength |
//! | `getNodeCount()` | [`get_node_count`](bindings::WebVowl::get_node_count) | Node count |
//! | `getEdgeCount()` | [`get_edge_count`](bindings::WebVowl::get_edge_count) | Edge count |
//! | `getNodeIds()` | [`get_node_ids`](bindings::WebVowl::get_node_ids) | Node ids, in index order |
//! | `getNodePositions()` | [`get_node_positions`](bindings::WebVowl::get_node_positions) | Live `x, y` per node as a `Float32Array` |
//! | `writePositionsInto(buf)` | [`write_positions_into`](bindings::WebVowl::write_positions_into) | Copy those positions into a caller-owned buffer |
//! | `getStatistics()` | [`get_statistics`](bindings::WebVowl::get_statistics) | Degree, components, OWL2 metrics |
//! | `getMetadata()` | [`get_metadata`](bindings::WebVowl::get_metadata) | Ontology header (IRI, version, title) |
//!
//! Filtering, pinning and folding (`filterByDegree`, `toggleDatatypes`,
//! `toggleSetOperators`, `resetVisibility`, `filterHierarchy`, `pinNode`,
//! `unpinNode`, `isPinned`, `resetPins`, `getPinnedCount`, `getNodeDegree`) are
//! also always available; see [`bindings::WebVowl`] for the full list.
//!
//! ## Feature-gated
//!
//! | JavaScript | Feature | Purpose |
//! |---|---|---|
//! | `getGraphData()` | `debug-serde` | Full-graph serde export, for diagnostics |
//! | `checkNodeClick(origin, dir)` | `interaction` | Ray-sphere node hit testing |
//! | `new NggExplorer()` and its methods | `ngg1` | Zero-copy worker physics |
//!
//! # Features
//!
//! All optional features are **off by default**; the general-purpose engine —
//! OWL/JSON parsing, the graph model, force layout (Barnes-Hut quadtree and the
//! CSR simulation), pinning and statistics — is always compiled.
//!
//! - **`ngg1`** — the NGG1 binary tier format (a re-export of the
//! [`ontomark-ngg1`](https://docs.rs/ontomark-ngg1) codec) and the
//! [`NggExplorer`](bindings::explorer::NggExplorer) binding.
//! - **`interaction`** — ray-sphere hit testing for click and selection.
//! - **`debug-serde`** — the legacy full-graph serde export.
//! - **`parallel`** — data-parallel ontology loading via rayon. Native only.
//! - **`simd`** — WASM SIMD128 force accumulation. Needs the `simd128` target
//! feature.
//!
//! # Licence
//!
//! MIT. See `LICENSE`, which carries both the upstream WebVOWL notice and
//! DreamLab-AI's.
pub use ;
use *;
/// WASM module entry point, run once when the module is instantiated.
///
/// `wasm-bindgen` calls this automatically; there is no need to invoke it from
/// JavaScript. It is currently a no-op, reserved for panic-hook installation.
/// The crate version, as reported to JavaScript.
///
/// Returns the `CARGO_PKG_VERSION` this module was compiled from — useful for
/// asserting that the loaded `.wasm` matches the JavaScript glue shipped with it.
///
/// ```
/// assert_eq!(vowl_wasm::version(), env!("CARGO_PKG_VERSION"));
/// ```