Skip to main content

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:

MethodProsCons
CSSClean 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 stylesAllows styling all edges of some type uniformly. Supports export to SVG. Supports path outlines.Does not support styling each edge individually.
Simple edge stylesMinimal 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 DefaultsAllows 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:

PaintStyle
Basic style definition for an edge
NameTypeDescription
dashArray?stringDefinition for stroke pattern
fill?stringFill color for the edge.
gradient?Array<[number, string]>Definition of a linear gradient to apply. Each entry is [offset, color].
outlineStroke?stringColor for the outline path
outlineWidth?numberWidth of the outline path
stroke?stringStroke color for the edge
strokeWidth?numberWidth 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 { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface [viewOptions]="viewOptions"></vjs-surface> `
})
export class AppComponent {
viewOptions = {
edges: {
redWithOutline: {
paintStyle: {
stroke: "red",
strokeWidth: 3
}
}
}
};
}

Mapping a PaintStyle in the UI defaults​

You can also set a default paint style via the defaults for some surface:

import { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface [renderOptions]="renderOptions"></vjs-surface> `
})
export class AppComponent {
renderOptions = {
defaults: {
paintStyle: {
stroke: "red",
strokeWidth: 3
}
}
};
}

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 { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface [renderOptions]="renderOptions"></vjs-surface> `
})
export class AppComponent {
renderOptions = {
defaults: {
paintStyle: {
stroke: "red",
strokeWidth: 3,
outlineStroke: "transparent",
outlineWidth: 2
}
}
};
}
Calculating the outline width

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 { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface [viewOptions]="viewOptions"></vjs-surface> `
})
export class AppComponent {
viewOptions = {
edges: {
redWithOutline: {
paintStyle: {
stroke: "red",
strokeWidth: 3,
outlineStroke: "orangered",
outlineWidth: 2
},
hoverPaintStyle: {
stroke: "green",
strokeWidth: 3,
outlineStroke: "yellowgreen",
outlineWidth: 4
}
}
}
};
}

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:

LineStyle
Defines the simple properties for an edge style.
NameTypeDescription
color?stringColor to paint the edge's path
dashArray?stringDefinition of dash pattern to use to draw the edge path
fontFamily?stringFont size to use; defaults to whatever the browser decides given the context
fontSize?numberFont size to use; defaults to whatever the browser decides given the context
fontStyle?FontStyleFont 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, color is ignored.
label?stringLabel to show on the edge
labelLocation?numberLocation for the label, defaults to 0.5
lineWidth?numberWidth of the edge path
outlineColor?stringColor to paint the edge's outline path
outlineWidth?numberWidth 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 { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface #surfaceComponent></vjs-surface> `
})
export class AppComponent {
@ViewChild('surfaceComponent') surfaceComponent: SurfaceComponent;

ngAfterViewInit() {
const surface = this.surfaceComponent.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
}
}
]
}
})
}
}

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"
})

note

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​

KeyConstantDescription
paintStyleDEFAULT_KEY_PAINT_STYLEA 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.
hoverPaintStyleDEFAULT_KEY_HOVER_PAINT_STYLEA 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 { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface [renderOptions]="renderOptions"></vjs-surface> `
})
export class AppComponent {
renderOptions = {
defaults: {
paintStyle: {
stroke: "red",
strokeWidth: 3
},
hoverPaintStyle: {
stroke: "orangered",
strokeWidth: 5
}
}
};
}

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 { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface [renderOptions]="renderOptions"></vjs-surface> `
})
export class AppComponent {
renderOptions = {
edges: {
paintOutline: false
}
};
}

You can also set the outline width and color:

import { Component, ViewChild } from '@angular/core';
import { SurfaceComponent } from '@visuallyjs/browser-ui-angular';

@Component({
selector: 'app-root',
template: ` <vjs-surface [renderOptions]="renderOptions"></vjs-surface> `
})
export class AppComponent {
renderOptions = {
edges: {
outlineWidth: 20,
outlineColor: "cadetblue"
}
};
}