Inspectors
An inspector is a form that can be used to edit the properties of some object, or set of objects, in the VisuallyJs dataset. Inspectors listen to selection events from the underlying model and then draw a suitable UI for editing the selected object(s) based upon the configuration you provide.
In the canvas below we've setup a simple inspector and selected a vertex to begin with. You can edit the various fields in the form on the left. Note that with the text input, changes are persisted on blur and when the enter key is pressed, but for the textarea changes are only persisted on blur.
Setup
Create a React component that renders an InspectorComponent, and pass a function to its body that renders content based on the current selected object.
import { useState } from "react"
import { InspectorComponent} from "@visuallyjs/browser-ui-react"
import { Node, Edge } from "@visuallyjs/browser-ui"
export default function MyInspectorComponent(props) {
return <InspectorComponent>
{(current) => {
{ current.objectType === Node.objectType &&
<div className="node-inspector">
<div>Text</div>
<input type="text" vjs-att="text" vjs-focus="true"/>
<div>Fill</div>
<input type="color" vjs-att="fill"/>
</div>
}
{ current.objectType === Edge.objectType &&
<div className="edge-inspector">
<div>Label</div>
<input type="text" vjs-att="label"/>
<div>Color</div>
<input type="color" vjs-att="color"/>
</div>
}
}}
</InspectorComponent>
}
Empty inspector
To render something when the inspector has no current selection, pass a function to the renderEmptyContent prop:
import { useState } from "react"
import { InspectorComponent} from "@visuallyjs/browser-ui-react"
import { Node, Edge } from "@visuallyjs/browser-ui"
export default function MyInspectorComponent(props) {
function nothingSelected() {
return <h3>Select a node to inspect its properties</h3>
}
return <InspectorComponent renderEmptyContent={nothingSelected}>
{(current) => {
...
}}
</InspectorComponent>
}
SurfaceComponent or SurfaceProvider:
import { SurfaceComponent, SurfaceProvider} from "@visuallyjs/browser-ui-react"
import MyInspectorComponent from "./MyInspector.jsx"
export function MyApp() {
return <SurfaceProvider>
<SurfaceComponent .../>
<MyInspectorComponent/>
</SurfaceProvider>
}
The InspectorComponent is discussed in detail in the reference docs on this page.
Binding data
Fields in your data objects are bound to HTML elements via an vjs-att attribute. For instance, here's the form we use in the example canvas above:
<input type="text" vjs-att="label">
<textarea vjs-att="description" rows="10" cols="10"></textarea>
<select vjs-att="someNumber">
<option value="1">1</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
Each of the vjs-att attributes in the HTML above maps to a property in the backing data of the object(s) being inspected:
{
label:"My Object",
description:"This is my object, with a label and a description and some number",
someNumber:5
}
Supported input types
This is the list of supported input types. We show a simple example for each type, but keep in mind you can use all the available attributes on these in your markup - for instance, for a number field, perhaps you want to limit the allowed values. Or you could supply a regular expression to a text input, etc.
Text Input
<input type='text' vjs-att="someProperty">
Radio Button
<input type='radio' vjs-att="someProperty" value="radioValue" name="someProperty">
Checkbox(es)
<input type='checkbox' vjs-att="someProperty">
The inspector supports rendering multiple checkboxes with the same vjs-att, for example:
<div class="my-inspector">
<input type='checkbox' vjs-att="someProperty" value="type1">
<input type='checkbox' vjs-att="someProperty" value="type2">
</div>
You need to be using an array in your data to support this:
{
id:"my-vertex",
someProperty:["type1", "type2"]
}
Number Input
<input type='number' vjs-att="someProperty">
Textarea
<textarea vjs-att="someProperty" rows="10" cols="5">
Select
<select vjs-att="someProperty">
<option value="someValue">Some Value</option>
<option value="someOtherValue">Some Other Value</option>
</select>
Color Input
<input type='color' vjs-att="someProperty">
Hidden Input
<input type='hidden' vjs-att="someProperty" value="someValue">
Non-string datatypes
By default, HTML element values are strings, which may not be ideal for your data model. You can instruct VisuallyJs to cast the value of certain elements to a number, by declaring a vjs-datatype attribute in your inspector template:
<div>
<select vjs-att="threshold" vjs-datatype="integer">
<option value="5">5</option>
<option value="10">10</option>
<option value="15">15</option>
</select>
</div>
In this example, VisuallyJs will attempt to cast the value to an integer. Currently, supported values for vjs-datatype are:
- integer Cast the value to an integer
- float Cast the value to a float, eg 1.5, 2.0, etc.
The vjs-datatype attribute is supported on:
<select.../><input type="radio" .../><input type="text" .../>
If you're using an input of type text and you want a number, it's probably better to use an input of type number - see MDN's discussion here.
Edge Property Mappings
Edge Property Mappings are a means for you to group several pieces of information about an edge's appearance and link them to a named property. If you want to provide your users with a graphical picker to assist them in choosing edge type, include EdgePropertyMappingsInspector in your inspector and show it when an edge is selected. It builds its form from the edge property mappings declared on the UI.
import { InspectorComponent, EdgePropertyMappingsInspector } from "@visuallyjs/browser-ui-react"
export default function MyInspector() {
return (
<InspectorComponent>
{(current) =>
current?.objectType === "Edge"
? <EdgePropertyMappingsInspector />
: null
}
</InspectorComponent>
)
}
For a full discussion, see the React reference.
Shape Properties
To let users edit a node's shape properties, include ShapePropertiesInspector in your inspector and show it when a node is selected. It renders the properties defined by that shape in the active shape library, so pass it the selected vertex.
import { InspectorComponent, ShapePropertiesInspector } from "@visuallyjs/browser-ui-react"
import { Vertex } from "@visuallyjs/browser-ui"
export default function MyInspector() {
return (
<InspectorComponent>
{(current) =>
current?.objectType === Vertex.objectType
? <ShapePropertiesInspector vertex={current} />
: null
}
</InspectorComponent>
)
}
For a full discussion, see the React reference.
Multiple selections
By default, an inspector supports selections containing multiple objects. When multiple objects are being edited, the inspector calculates a set of "common data", ie. the set of keys for which every object in the inspector has a value. For text inputs and text areas, if every value for some given key is the same across all the managed objects, that value is shown and can be edited, resulting in a change to all the managed objects. Otherwise, if not every value is the same, the text input or text area will display a blank value. If the user types in the input field then that change will be propagated to all the managed objects.
To switch off multiple selections you can do this:
import { useState } from "react"
import { InspectorComponent} from "@visuallyjs/browser-ui-react"
import { Node, Edge } from "@visuallyjs/browser-ui"
export default function MyInspectorComponent(props) {
const [currentType, setCurrentType] = useState('')
const renderEmptyContainer = () => setCurrentType('')
// a Node, Edge, Group or Port
const refresh= (obj, cb) => {
setCurrentType(obj.objectType)
}
return <InspectorComponent refresh={refresh}
multipleSelections={false}
renderEmptyContainer={renderEmptyContainer}>
...
</InspectorComponent>
}