A lightweight, reactive typescript library for embedding and controlling EIDOS visualizations in web applications or within node processes. Built with Valtio for natural object mutations and AJV for comprehensive schema validation.
npm install @oceanum/eidos
import { EidosProvider, useEidosSpec } from "@oceanum/eidos";
// Define your EIDOS specification
const initialSpec = {
version: "0.9",
id: "my-app",
name: "My Visualization",
root: {
id: "root",
nodeType: "world",
children: [],
},
data: [],
};
function App() {
return (
<EidosProvider
initialSpec={initialSpec}
options={{
renderer: "https://render.eidos.oceanum.io",
eventListener: (event) => console.log("Event:", event),
}}
>
<YourComponents />
</EidosProvider>
);
}
// In any child component
function YourComponent() {
const spec = useEidosSpec();
const addLayer = () => {
// Mutate spec directly - changes propagate automatically to iframe
spec.root.children.push({
id: "new-layer",
nodeType: "worldlayer",
layerType: "track",
});
};
return <button onClick={addLayer}>Add Layer</button>;
}
import { render } from "@oceanum/eidos";
// Define your EIDOS specification
const spec = {
version: "0.9",
id: "my-app",
name: "My Visualization",
root: {
id: "root",
nodeType: "world",
children: [],
},
data: [],
};
// Render in a container element
const container = document.getElementById("eidos-container");
const result = await render(container, spec, {
renderer: "https://render.eidos.oceanum.io",
eventListener: (event) => {
console.log("Received event:", event);
},
});
// Mutate the spec naturally - changes propagate automatically
result.spec.name = "Updated Visualization";
result.spec.root.children.push({
id: "layer-1",
nodeType: "worldlayer",
layerType: "track",
});
// Clean up when done
result.destroy();
The React Context API allows you to easily manage multiple EIDOS instances in the same application. Each EidosProvider creates its own isolated context with its own iframe and spec.
Option 1: Multiple Providers (Recommended)
import { EidosProvider, useEidosSpec } from "@oceanum/eidos";
function App() {
return (
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
{/* Map view */}
<EidosProvider
initialSpec={mapSpec}
options={{ renderer: EIDOS_URL }}
>
<MapControls />
</EidosProvider>
{/* Chart view */}
<EidosProvider
initialSpec={chartSpec}
options={{ renderer: EIDOS_URL }}
>
<ChartControls />
</EidosProvider>
</div>
);
}
function MapControls() {
const spec = useEidosSpec(); // Gets mapSpec from nearest provider
// Mutations only affect this instance
const zoomIn = () => {
spec.root.viewState.zoom += 1;
};
return <button onClick={zoomIn}>Zoom In</button>;
}
function ChartControls() {
const spec = useEidosSpec(); // Gets chartSpec from nearest provider
// Completely isolated from MapControls
const updateData = () => {
spec.data[0].dataSpec = newData;
};
return <button onClick={updateData}>Update Data</button>;
}
Option 2: Low-Level Render API
For more control, use the render() function directly:
import { render } from "@oceanum/eidos";
import { useEffect, useRef, useState } from "react";
function MultiInstance() {
const container1 = useRef(null);
const container2 = useRef(null);
const [specs, setSpecs] = useState({ map: null, chart: null });
useEffect(() => {
const init = async () => {
const map = await render(container1.current, mapSpec, { renderer: EIDOS_URL });
const chart = await render(container2.current, chartSpec, { renderer: EIDOS_URL });
setSpecs({ map: map.spec, chart: chart.spec });
return () => {
map.destroy();
chart.destroy();
};
};
init();
}, []);
const updateMap = () => {
if (specs.map) {
specs.map.root.viewState.zoom += 1;
}
};
return (
<div>
<div ref={container1} style={{ width: '50%', height: '100%' }} />
<div ref={container2} style={{ width: '50%', height: '100%' }} />
<button onClick={updateMap}>Update Map</button>
</div>
);
}
Key Points for Multiple Instances:
useEidosSpec() always returns the spec from the nearest EidosProvider ancestorid values in your specs to avoid conflictsSee the Core API documentation for complete API details including:
render() functionEidosProvider componentuseEidosSpec() hook