@metabohub/mth-ui-viz
v1.4.0
Published
An open source project dedicated for graph visualisation.
Keywords
Readme
mth-ui-viz
The mth-ui-viz project allows you to set up a network visualisation tool and to choose the features you want to add to the interface by means of ‘kits’.
Breaking Changes in version 1.0.0 !
v-model for network and networkStyle
Previous API:
<VizTool :network="network" :network-style="networkStyle" />New API:
<VizTool v-model:network="network" v-model:network-style="networkStyle" />Both network and networkStyle props have been changed from regular props to v-model bindings. This enables two-way data binding, allowing the component to update these objects directly and automatically synchronizing changes with the internal store. You must now use:
v-model:networkinstead of:networkv-model:network-styleinstead of:network-style
Pinia Store Integration
This project now uses Pinia for state management.
Prerequisites for parent projects: To use this component in your project, you must have Pinia installed and initialized:
npm install pinia// main.ts in your parent project
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
const app = createApp(App);
const pinia = createPinia();
app.use(pinia); // ← Required: This Pinia instance will be shared with VizTool
app.mount('#app');Zoom Store - Shared Instance:
A Pinia store (useZoomStore) manages zoom functionality. The store instance is automatically shared between VizTool and your parent components when they use the same Pinia instance:
<template>
<div>
<VizTool v-model:network="network" v-model:network-style="style" />
<!-- Parent can control zoom directly -->
<button @click="zoomStore.rescaleNetwork()">Rescale from parent</button>
</div>
</template>
<script setup>
import { VizTool, useZoomStore } from '@metabohub/mth-ui-viz';
// This returns the SAME store instance used internally by VizTool
const zoomStore = useZoomStore();
// Available methods:
// - zoomStore.rescaleNetwork() → Fit network to viewport
// - zoomStore.graphZoomIn() → Zoom in
// - zoomStore.graphZoomOut() → Zoom out
// - zoomStore.svgProperties → Access SVG zoom instance (read-only)
</script>How it works: Pinia stores are singletons per Pinia instance. When VizTool calls useZoomStore() internally and your parent component calls useZoomStore(), they both get the same store instance because they share the same Pinia instance (the one you initialized with app.use(pinia)). This enables coordinated state management between the visualization component and your application logic.
Types
| Name | Value | | ---- | ----- | | Network | {id: string, nodes: {[key: string]: Node}, links: Array} | | GraphStyleProperties | {nodeStyle: NodeStyle, linkStyle: LinkStyle} |
For more specifications about Node, Link, NodeStyle and LinkStyle, see VizCore README.
VizTool
v-model
| Name | Description | Type | | ------------ | ---------------------------------------- | --------------------- | | network | Network object to visualise | Network | | networkStyle | Style object to apply to the network | GraphStyleProperties |
These props use Vue 3's v-model directive for two-way binding. This allows the component to both receive and update the network data and styles.
Props
| Name | Description | Type | Default | | ----------------- | --------------------------------------------- | ---------------------------------------- | ---------- | | mappingData | Mapping data for static mapping | {[key: string]: {conditions: Array, data: any}} | / | | mappingsDisplay | List of all mappings displayed in the graph | Array<{[key: string]: string}> | [] | | dynamicMapping | Mapping data for dynamic mapping | {conditions: Array, data: any} | / | | fluxMappings | Data for flux visualisation | {conditions: Array, data: {[key: string]: {[key: string]: {[key: string]: string}}}} | / | | cycleGroup | List of all cycles draw in the graph | Array | [] | | convexhulls | Information about convexhulls display or not | Convexhulls | {} | | linkClusters | Information about clusters display on links or not | Convexhulls | {} | | allowMappingInput | Enable / disable users to load mapping data | boolean | true | | allowLoadingMask | Enable / disable loading mask | boolean | true | | allowAutoAlgo | Enable / disable to start force layout at network load | boolean | false | | panelConfig | Configuration for menus and buttons | {listButtonMenu: Array, dropDownMenuLeft: {[key: string]: Array}, dropDownMenuRight: {[key: string]: Array}, switchTheme: boolean} | {listButtonMenu: [], dropDownMenuLeft: {}, dropDownMenuRight: {}, switchTheme: false} |
Events
| Name | Description | Return | | ----------- | ---------------------------------------------- | ------------------------------------ | | removeNode | Event emit when a node is removed from graph | node id as string | | loadingEnd | Event emit at end of network load | / |
Slots
contextual-panel-content
The contextual-panel-content slot allows you to customize the content displayed in the metadata panel when a user right-clicks on a node and selects "Show node information".
Slot Props:
| Name | Description | Type | | ---------- | ------------------------ | ---------------------------------------- | | nodeId | The node's ID | string | | nodeLabel | The node's label | string | | metadata | The node's metadata | {[key: string]: string | number | Array<string | number> | {[key: string]: string | number } | boolean} |
Use Case:
This slot is particularly useful when you need to:
- Display external data from an API based on the selected node
- Add custom interactions (buttons, forms) for the selected node
- Combine default metadata with additional information
- Apply custom styling or layout to the metadata display
Example:
<template>
<VizTool
v-model:network="network"
v-model:network-style="networkStyle"
:panel-config="config"
>
<template #contextual-panel-content="{ nodeId, nodeLabel, metadata }">
<!-- Custom API data section -->
<div style="padding: 16px; background-color: #f5f5f5;">
<h3>📡 External Data</h3>
<div v-if="loading">Loading...</div>
<div v-else>
<p><strong>External ID:</strong> {{ apiData.externalId }}</p>
<p><strong>Database:</strong> {{ apiData.database }}</p>
</div>
<button @click="fetchNodeData(nodeId)">
🔄 Refresh data
</button>
</div>
<!-- Default metadata section -->
<div v-if="Object.keys(metadata).length > 0" style="padding: 16px;">
<h3>📋 Local Metadata</h3>
<table>
<tr v-for="(value, key) in metadata" :key="key">
<td><strong>{{ key }}</strong></td>
<td>{{ value }}</td>
</tr>
</table>
</div>
</template>
</VizTool>
</template>
<script setup>
import { ref } from 'vue';
import { VizTool } from '@metabohub/mth-ui-viz';
const network = ref({ id: '', nodes: {}, links: [] });
const networkStyle = ref({ nodeStyles: {}, linkStyles: {} });
const apiData = ref({});
const loading = ref(false);
const fetchNodeData = async (nodeId) => {
loading.value = true;
// Fetch data from your API
const response = await fetch(`/api/nodes/${nodeId}`);
apiData.value = await response.json();
loading.value = false;
};
</script>Note: If this slot is not provided, the component will display the node's metadata in a default table format.
MultiVizTool
The MultiVizTool component is a variant of the VizTool component to display multi networks. It takes as a main input a multi (meta) network, a base network style (on top of which the multi network style will be added), a multi network report (a map which contains information on the given multi network), and an array containing the ids of the networks in the multinetwork. It also takes the panel configuration as an input. The rest of the input of the original VizTool component is planned to be added at some point.
Exported Functions
These functions are exported from the package and can be imported for use:
| Name | Description | Argument(s) | Return | | ---- | ----------- | ----------- | ------ | | saveNetworkAsJSON | Save and download network as JSONGraph or return JSON string of the object | network: Network, networkStyle: GraphStyleProperties, mappings: {[key: string]: {[key: string]: string | Array}}, mappingsDisplay: Array<{[key: string]: string}>, dynamicMapping: any, fluxMapping: any, convexhulls: Convexhulls, linkClusters: Convexhulls, cycleGroup: any, download: boolean = true | void or string | | getNetworkData | Return all network, styles and mappings in an object | / | {network: Network, networkStyle: GraphStyleProperties, mappings: {[key: string]: {[key: string]: string | Array}}, mappingsDisplay: Array<{[key: string]: string}>, dynamicMapping: any, fluxMappings: any, convexhulls: Convexhulls, linkClusters: Convexhulls, cycleGroup: any} | | importGraphFromFile | Import a network, styles and mappings object from a file (from @metabohub/mth-viz-core) | file: File | Promise<{network: Network, networkStyle: GraphStyleProperties, mappings: any, dynamicMapping: any, fluxMappings: any, convexhulls: Convexhulls, linkClusters: Convexhulls, cycleGroup: any, metadata: {[key: string]: string}}> | | importGraphFromURL | Import a network, styles and mappings object from an URL (from @metabohub/mth-viz-core) | path: string | Promise<{network: Network, networkStyle: GraphStyleProperties, mappings: any, dynamicMapping: any, fluxMappings: any, convexhulls: Convexhulls, linkClusters: Convexhulls, cycleGroup: any, metadata: {[key: string]: string}}> | | importGraphsFromFile | Import multiple networks from a file (from @metabohub/mth-viz-core) | file: File | Promise<Array<{network: Network, networkStyle: GraphStyleProperties, mappings: any, dynamicMapping: any, fluxMappings: any, convexhulls: Convexhulls, linkClusters: Convexhulls, cycleGroup: any, metadata: {[key: string]: string}}>> | | importGraphsFromURL | Import multiple networks from an URL (from @metabohub/mth-viz-core) | path: string | Promise<Array<{network: Network, networkStyle: GraphStyleProperties, mappings: any, dynamicMapping: any, fluxMappings: any, convexhulls: Convexhulls, linkClusters: Convexhulls, cycleGroup: any, metadata: {[key: string]: string}}>> |
Exported Stores
The following Pinia stores are exported and can be used in parent projects:
| Name | Description | Available Methods |
| ---- | ----------- | ----------------- |
| useZoomStore | Manages zoom functionality for the network visualization | storeZoomObject(instance), rescaleNetwork(), graphZoomIn(), graphZoomOut() |
Example usage:
import { useZoomStore } from '@metabohub/mth-ui-viz';
const zoomStore = useZoomStore();
zoomStore.rescaleNetwork(); // Fit network to viewportKits
The kits are used to define the buttons and menus that will be present in the interface. These elements must be passed in the VizTool configuration props.
Example
const config = {
"listButtonMenu": [
"undo",
...
],
"dropDownMenuLeft": {
"File": [
"loadFile",
"saveJson"
],
"Edit": [
"undo",
"redo",
"removeSC",
"removeAll",
"duplicateSC",
"verticalAlign",
"horizontalAlign"
]
},
"dropDownMenuRight": {
"Style": [
"styleManager",
"convexhulls"
],
"Mappings": [
"staticMapping",
"dynamicMapping",
"fluxMapping"
],
"Layouts": [
"forceLayout",
"hierarchicalLayout"
],
"Exploration": [
"gir"
]
},
"switchTheme": true,
}Buttons
These items must be included in the listButtonMenu argument to the configuration.
| Name | Description | | ---- | ----------- | | undo | Make an undo on graph modification | | redo | Make a redo on graph modification | | playForce | Start force layout and switch to stopForce if present in configuration | | stopForce | Stop force layout and switch to playForce if present in configuration | | rescale | Fit network to visualisation area | | curveEdge | Switch between line and curve edge(s) | | toggleLabels | Toggle display of all node labels on/off | | nodeList | Open node list panel | | zoomIn | Zoom in | | zoomOut | Zoom out |
Menu options
To define the menus present in the interface, two options are available dropDownMenuLeft and dropDownMenuRight, which define whether the menus will be on the right or left of the header. In these objects, the key will correspond to the name of the menu and the items in the list to the options available in this menu.
You can also create nested menus by grouping list options within an object.
const config = {
// List of buttons
"listButtonMenu": [
"undo",
"redo",
"playForce",
"rescale"
],
// List of menus displayed on the left
"dropDownMenuLeft": {
"File": [
"saveJson"
],
"Edit": [
"undo",
"redo",
// Nested menu example
{"subGroup": "Remove node(s)", "list": ["removeSC", "removeAll"]},
],
},
// Display toggle switch for dark / light theme
"switchTheme": false,
// Manage convexhulls panel tabs
"convexhulls": {
"attribut": {
"pathways": "reaction",
"compartments": ""
}
}
}| Name | Description | Option title | | ---- | ----------- | ------------ | | loadFile | Allows you to load a network at JSONGraph format | Load File | | loadPositionsFile | Allows you to load node positions at JSON format | Load node positions | | saveJson | Save and download network at JSONGraph format | Save as Json | | saveNodePositions | Save and download node positions at JSON format | Save node positions | | saveAsPng | Save graph and caption as PNG | Save as PNG | | saveAsSvg | Save graph and caption as SVG | Save as SVG | | undo | Make an undo on graph modification | Undo | | redo | Make a redo on graph modification | Redo | | removeSC | Remove all side compounds present in graph, if there are set | Remove side compounds | | removeAll | Remove all selected nodes | Remove All selected nodes | | duplicateSC | Duplicate all side compounds present in graph, if there are set | Duplicate side compounds | | duplicateAll | Duplicate all selected nodes | Duplicate all selected nodes | | verticalAlign | Align selected nodes vertically | Vertical align | | horizontalAlign | Align selected nodes horizontally | Horizontal align | | fixNodes | Fix positions of all selected nodes | Fix all selected nodes | | unfixNodes | Unfix positions of all selected nodes | Unfix all selected nodes | | unfixAllNodes | Unfix positions of all network nodes | Unfix all nodes | | styleManager | Open style manager panel | Style manager | | convexhulls | Open convexhulls manager panel | Display pathways / compartments | | staticMapping | Open static mapping panel manager | Static mapping | | fluxMapping | Open flux visualisation panel manager | Flux visualisation | | dynamicMapping | Open dynamic mapping panel manager | Dynamic mapping | | forceLayout | Open force layout panel manager | Force layout manager | | hierarchicalLayout | Open hierarchical layout panel manager | Hierarchical layout manager | | cycleLayout | Open cycle panel manager | Cycle layout manager | | gir | Open GIR panel manager | Guided Iterative Reconstruction (GIR) | | nodeList | Open node list panel | Display nodes list | | curveEdge | Switch between line and curve edge(s) | Curve edge |
Use example
This web component requires Vuetify.
<template>
<VizTool
v-model:network="network"
v-model:network-style="networkStyle"
:mapping-data="mappingData"
:mappings-display="mappingsDisplay"
:allow-mapping-input="false"
:allow-auto-algo="true"
:panel-config="config"
@remove-node="emitNodeID"
@loading-end="handleLoadingEnd"
/>
</template>
<script setup lang="ts">
import { VizTool } from '@metabohub/mth-ui-viz';
import type { Network, GraphStyleProperties } from '@metabohub/mth-ui-viz';
import { ref } from 'vue';
const network = ref<Network | undefined>(undefined);
const networkStyle = ref<GraphStyleProperties | undefined>(undefined);
const mappingData = ref(undefined);
const mappingsDisplay = ref([]);
function emitNodeID(nodeID: string): void {
console.log('Node removed:', nodeID);
}
function handleLoadingEnd(): void {
console.log('Network loading completed');
}
const config = {
"listButtonMenu": [
"undo",
"redo",
"playForce",
"rescale"
],
"dropDownMenuLeft": {
"File": [
"saveJson"
],
"Edit": [
"undo",
"redo",
"removeAll",
"nodeList"
],
"Layouts": [
"verticalAlign",
"horizontalAlign",
"forceLayout",
"hierarchicalLayout"
],
"Styles": [
"styleManager",
"curveEdge",
"convexhulls"
],
"Mappings": [
"staticMapping",
"dynamicMapping",
"fluxMapping"
]
},
"switchTheme": false,
"convexhulls": {
"attribut": {
"pathways": "reaction",
"compartments": ""
}
}
}
</script>
<style>
@import '@metabohub/mth-ui-viz/dist/style.css';
</style>Project Setup
npm installCompile and Hot-Reload for Development
npm run devType-Check, Compile and Minify for Production
npm run buildRun Unit Tests with Vitest
npm run test:unitCheck the coverage of the unit tests :
npm run coverageLint with ESLint
npm run lintView documentation
npm run storybookCICD pipeline
Tests
test:
image: node:latest
stage: test
before_script:
- npm install
script:
- npm run test:unitThis runs the unit tests defined in src/components/__tests__/
Deploy
.publish:
stage: deploy
before_script:
- apt-get update && apt-get install -y git default-jre
- npm install
- npm run buildThis builds the component as an npm package.
