Styling edges
There are a few approaches you can take when it comes to styling your edges - VisuallyJs provides an out of the box mapping from edge data to basic properties such as edge width, color etc, via the concept of Simple edge styles. You can also use CSS, or you can map a PaintStyle to your edges via a view or in the UI defaults. That's a lot of choice, so here we present a quick pros and cons for each option:
| Method | Pros | Cons |
|---|---|---|
| CSS | Clean separation of presentation from code. Allows usage of various SVG CSS effects. Allows styling all edges of some type uniformly. | Does not support export to SVG, PNG or JPG. Does not support styling each edge individually. Does not support path outlines. |
| Paint styles | Allows styling all edges of some type uniformly. Supports export to SVG. Supports path outlines. | Does not support styling each edge individually. |
| Simple edge styles | Minimal setup. Allows each edge to be styled individually. Seamlessly integrated with update and undo/redo. Supports path outlines. Supports export to SVG. | Each edge needs its own styles declared in the backing data. Limited set of configurable properties. |
| UI Defaults | Allows configuration of default styles value which will apply, in the absence of some other value, to all edges. Supports export to SVG. Supports path outlines. | Does not support styling each edge individually. Applies to all types (but you can override on a per-type basis via Paint styles). |
Styling with CSS
Since VisuallyJs uses SVG to render edges, you can target the artifacts that VisuallyJs adds to the DOM via CSS. VisuallyJs uses a class of vjs-connector on the SVG element it uses for each edge, and the edge itself is written as one or more path elements inside of that, which each have a class according to their function:
<svg class="vjs-connector">
<path d="..." class="vjs-connector-outline"></path>
<path d="..." class="vjs-connector-path"></path>
</svg>
Targeting the edge's SVG element
To target the parent element for some path, for instance to assign z-index, you need a rule like this:
.vjs-connector {
z-index:50;
}
Targeting the SVG path
To target the element used to render the path, you need a rule like this:
.vjs-connector-path {
stroke-width:2;
stroke:cadetblue;
stroke-dasharray: 2;
}
Hover styles
To change the appearance of an edge on hover, use the :hover css meta class:
.vjs-connector-path:hover {
stroke:orangered;
}
Note that the above example targets the path element on hover, but you can also target the parent SVG element of course:
.vjs-connector:hover {
outline:1px solid orangered;
}
Marching ants effect
It's simple to get this 'marching ants' effect via CSS with VisuallyJs:
1. Define the CSS animation
Define a CSS animation with a single keyframe that sets the dash offset:
@keyframes dashdraw {
0% {
stroke-dashoffset:10;
}
}
2. Map the animation to a CSS rule
.animated-edge {
stroke-dasharray:5;
animation: dashdraw .5s linear infinite;
}
3. Use the cssClass property in an edge definition to map to this class (optional)
We said that (3) is optional because if you just want to apply it to every edge in your dataset you can change the CSS rule shown in (2) to target every edge:
.vjs-connector-path {
stroke-dasharray:5;
animation: dashdraw .5s linear infinite;
}
Selected edges
When an edge is in the model's current selection, it has the CSS class vjs-selected-connection applied to it. You can target this class to change the appearance of either the connector's parent element:
.vjs-selected-connection {
outline:2px solid orangered;
}
or the path element representing the edge:
.vjs-selected-connection .vjs-connector-path {
stroke:orangered;
}
Styling with PaintStyles
A PaintStyle is an object containing various properties to apply to a given type of edge. The definition is:
| Name | Type | Description |
|---|---|---|
| dashArray? | string | Definition for stroke pattern |
| fill? | string | Fill color for the edge. |
| gradient? | Array<[number, string]> | Definition of a linear gradient to apply. Each entry is [offset, color]. |
| outlineStroke? | string | Color for the outline path |
| outlineWidth? | number | Width of the outline path |
| stroke? | string | Stroke color for the edge |
| strokeWidth? | number | Width of the stroke |
All properties are optional; VisuallyJs will use an default value where properties are not specified. To setup an outline path, you must provide both outlineStroke and outlineWidth.
Mapping a PaintStyle in a view
You can map a PaintStyle to some specific edge type inside a view:
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const viewOptions = {
edges: {
redWithOutline: {
paintStyle: {
stroke: "red",
strokeWidth: 3
}
}
}
}
return <SurfaceComponent viewOptions={viewOptions}/>
}
Mapping a PaintStyle in the UI defaults
You can also set a default paint style via the defaults for some surface:
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const renderOptions = {
defaults: {
paintStyle: {
stroke: "red",
strokeWidth: 3
}
}
}
return <SurfaceComponent renderOptions={renderOptions}/>
}
Controlling the hit zone
By default, VisuallyJs paints a single path element for each edge. If you want your users to be able to interact with your edges but your edges have a stroke width of only a couple of pixels, this can be difficult. To manage this with a paintStyles we recommend using the outlineWidth and outlineStroke paint style properties to setup a hit zone:
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const renderOptions = {
defaults: {
paintStyle: {
stroke: "red",
strokeWidth: 3,
outlineStroke: "transparent",
outlineWidth: 2
}
}
}
return <SurfaceComponent renderOptions={renderOptions}/>
}
When you provide outlineWidth and outlineStroke properties in a PaintStyle, the visible width of the outline is computed as:
w = strokeWidth + (2 * outlineWidth)
which is to say that the outlineWidth value you provide is applied to each side of the connector's path.
In this example we've used "transparent" for the outline color, which gives us the expanded hit zone without altering the appearance of each edge. You can, of course, use any color you like.
Hover styles
You can also provide a hoverPaintStyle property in your view, which VisuallyJs will use to paint the edge when the mouse is hovering over it:
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const viewOptions = {
edges: {
redWithOutline: {
paintStyle: {
stroke: "red",
strokeWidth: 3,
outlineStroke: "orangered",
outlineWidth: 2
},
hoverPaintStyle: {
stroke: "green",
strokeWidth: 3,
outlineStroke: "yellowgreen",
outlineWidth: 4
}
}
}
}
return <SurfaceComponent viewOptions={viewOptions}/>
}
Simple edge styles
Simple edge styles allow you to map values from an edge's backing data to its appearance. The LineStyle interface defines the supported properties:
| Name | Type | Description |
|---|---|---|
| color? | string | Color to paint the edge's path |
| dashArray? | string | Definition of dash pattern to use to draw the edge path |
| fontFamily? | string | Font size to use; defaults to whatever the browser decides given the context |
| fontSize? | number | Font size to use; defaults to whatever the browser decides given the context |
| fontStyle? | FontStyle | Font style to use; defaults to whatever the browser decides given the context |
| gradient? | Array<[number, string]> | An array of color stops to use as a linear gradient for the edge path. When this is set, is ignored. |
| label? | string | Label to show on the edge |
| labelLocation? | number | Location for the label, defaults to 0.5 |
| lineWidth? | number | Width of the edge path |
| outlineColor? | string | Color to paint the edge's outline path |
| outlineWidth? | number | Width to draw the edge's outline path |
None of these properties are mandatory. VisuallyJs will fall back to its defaults for these via the paintStyle mechanism if your edge data does not contain any of these properties.
Example
import {useRef, useEffect} from "react"
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const surfaceRef = useRef(null)
const initialized = useRef(false)
useEffect(() => {
if(!initialized.current) {
initialized.current = true
const surface = surfaceRef.current.surface
const model = surface.model
model.load({
type:"json",
data:{
nodes:[
{ id:"1" }, { id:"2" }
],
edges:[
{
source:"1",
target:"2",
data:{
color:"cadetblue",
lineWidth:3,
outlineColor:"pink",
outlineWidth:5
}
}
]
}
})
}
})
return <SurfaceComponent/>
}
In this example the edge in our dataset will have a color of "cadetblue" and a stroke width of 3 pixels. It will also have an outline of 5 pixels each side, and the color of the outline will be pink. I think we can all agree it will look pretty fetching indeed.
We'll render an edge with this backing data:
{
color:"cadetblue",
lineWidth:3,
outlineColor:"pink",
outlineWidth:5,
id:"edge"
}
(we gave it an id because we want to access it when you press a button in a moment; id is not a mandatory property).
If you now , we'll set these new values, and you'll see the edge update:
model.updateEdge("edge", {
color:"black",
outlineColor:"yellow",
lineWidth:2,
outlineWidth:3,
label:"New label"
})
Simple edge styles are switched on by default. If you do not want this behaviour in your app, you can save yourself some CPU cycles by setting simpleEdgeStyles:false in your render options.
Gradient Example
In this example the edge in our dataset will have a stroke width of 5 pixels, and will be painted with a linear gradient from "lightblue" to "forestgreen".
Let's render that example from above. We'll render an edge with this backing data:
{
gradient:[[0,"lightblue"],[100, "forestgreen"]],
lineWidth:5
}
Styling with UI Defaults
The UI defaults supports two keys that allow you to configure default paint styles for your edges:
Supported properties
| Key | Constant | Description |
|---|---|---|
paintStyle | DEFAULT_KEY_PAINT_STYLE | A PaintStyle object as discussed above, whose values will be used for all edges unless a more specific type mapping is found in the view. Defaults to a stroke width of 2 pixels and a stroke color of #456. |
hoverPaintStyle | DEFAULT_KEY_HOVER_PAINT_STYLE | A PaintStyle object as discussed above, whose values will be used for all edges when the mouse is hovering over it unless a more specific type mapping is found in the view. Defaults to null. |
Example
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const renderOptions = {
defaults: {
paintStyle: {
stroke: "red",
strokeWidth: 3
},
hoverPaintStyle: {
stroke: "orangered",
strokeWidth: 5
}
}
}
return <SurfaceComponent renderOptions={renderOptions}/>
}
Controlling the hit zone
VisuallyJs paints a single path element for each edge. It also paints an outline element behind each path, which, by default, extends to 10 pixels either side of the edge path, and has a transparent stroke. You can switch this mechanism off if you wish:
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const renderOptions = {
edges: {
paintOutline: false
}
}
return <SurfaceComponent renderOptions={renderOptions}/>
}
You can also set the outline width and color:
import { SurfaceComponent } from "@visuallyjs/browser-ui-react"
export default function MyComponent() {
const renderOptions = {
edges: {
outlineWidth: 20,
outlineColor: "cadetblue"
}
}
return <SurfaceComponent renderOptions={renderOptions}/>
}