Skip to content

Fill layers

Edge appearance is built by compositing layers from back to front. These layers determine “how to colorize each pixel” along an edge’s path. Sigma ships with three built-in layers: layerPlain, layerDashed and layerGradient.

How layers work

Layers are declared in primitives.edges.layers. They are composited in order: earlier layers render behind later ones. When primitives.edges.layers is not set, sigma uses [layerPlain()].

All edges share the same WebGL program, so every edge runs every declared layer. To vary the look per edge, make a layer transparent for that edge so the layers below show through. For instance, layerDashed() renders transparent when its dashSize or gapSize is 0, and layerGradient() does when the edge attribute read by its enabled option is false.

Available layers

LayerPackageDescription
layerPlain()sigma/renderingSolid color fill, using the edge’s color
layerDashed()sigma/renderingDash pattern, with configurable dashes and gaps
layerGradient()sigma/renderingGradient along a list of color stops

Layer color options accept a constant color, an { attribute } reference, or an endpoint node’s color with { node: "source" } or { node: "target" }. See Edge colors for details.

Plain edges

The layerPlain() function fills the edge with a solid color. Without options, it uses the edge’s own color style. Its color option overrides it:

new Sigma(graph, container, {
primitives: {
edges: {
// Every edge wears its source node's color:
layers: [layerPlain({ color: { node: "source" } })],
},
},
});

Dashed edges

The layerDashed() function draws a dash pattern along the edge. The dashSize and gapSize options accept either a fixed { value, mode } object or an { attribute } reference to read per-edge values from graph data. Sizes are in pixels by default; set mode: "relative" to size them relative to the edge thickness. Gaps are transparent by default, so stacking layerDashed() over layerPlain() gives dashes over a solid edge body. Use gapColor to fill gaps instead.

The cap option controls the shape of dash ends: "butt" (the default) gives straight ends, while "round" gives round caps. Round-capped dashes shorter than the edge thickness degenerate to circles, so dotted edges are simply:

layerDashed({ cap: "round", dashSize: { value: 1, mode: "relative" }, gapSize: { value: 2, mode: "relative" } });

Gradient edges

The layerGradient() function fills the edge with a gradient along a list of color stops, from the source end to the target end. Each stop accepts any of the color forms above, so the typical use is blending the endpoint node colors:

new Sigma(graph, container, {
primitives: {
edges: {
layers: [layerGradient({ stops: [{ node: "source" }, { node: "target" }] })],
},
},
});

Stops follow the same positioning rules as CSS gradients: an optional offset in [0, 1] places a stop along the visible edge span, the first stop defaults to 0, the last to 1, and stops without an offset spread evenly between their positioned neighbors. Past the outermost offsets, the gradient pads with the nearest stop’s color. The offset field sits directly on { node } and { attribute } stops, and constant colors take the { color, offset } form.

// Fade through transparent halfway:
layerGradient({ stops: [{ node: "source" }, "transparent", { node: "target" }] });
// Show only a short stub leaving the source node:
layerGradient({ stops: [{ node: "source" }, { color: "transparent", offset: 0.1 }] });
// Hard switch from source to target color at the midpoint:
layerGradient({
stops: [
{ node: "source", offset: 0.5 },
{ node: "target", offset: 0.5 },
],
});

The optional enabled option reads a boolean edge attribute to toggle the gradient per edge; disabled edges fall through to the layers below.

Composing layers

Layers compose naturally. The example below stacks a plain, a gradient and a dashed layer, composited in declaration order:

import Graph from "graphology";
import Sigma, { DEFAULT_STYLES } from "sigma";
import {
extremityArrow,
layerDashed,
layerFill,
layerGradient,
layerPlain,
pathCurved,
pathCurvedS,
pathLine,
pathStepCurved,
sdfCircle,
sdfTriangle,
} from "sigma/rendering";
const container = document.getElementById("sigma-container") as HTMLElement;
const SOURCE_COLOR = "#7E3D9C";
const TARGET_COLOR = "#ED8666";
// Each row has its own path:
const PATHS = ["straight", "curved", "stepCurved", "curvedS"] as const;
// Each column shows edges fillings and extremities in its own way:
const COLUMNS = [
{ useGradient: true },
{ head: "arrow" },
{ head: "arrow", tail: "arrow", useGradient: true },
{ dashSize: 5, dashColor: "#ffffff99" },
{ head: "arrow", dashSize: 10, dashColor: "#ffffff99", useGradient: true },
];
const graph = new Graph();
PATHS.forEach((path, row) => {
COLUMNS.forEach((config, col) => {
const [x, y] = [col * 120, -row * 80];
const source = graph.addNode(`${path}-${col}-source`, { x: x - 30, y, color: SOURCE_COLOR });
const target = graph.addNode(`${path}-${col}-target`, {
x: x + 30,
y: y + 30,
color: TARGET_COLOR,
shape: "triangle",
});
graph.addEdge(source, target, { size: 6, path, curvature: path === "curved" ? 0.3 : 0, ...config });
});
});
new Sigma(graph, container, {
primitives: {
nodes: {
shapes: [sdfCircle(), sdfTriangle()],
layers: [layerFill()],
},
edges: {
variables: {
dashColor: { type: "color", default: "#000" },
dashSize: { type: "number", default: 0 },
useGradient: { type: "boolean", default: false },
},
paths: [pathLine(), pathCurved(), pathStepCurved(), pathCurvedS()],
extremities: [extremityArrow()],
layers: [
layerPlain({ color: { node: "source" } }),
layerGradient({
stops: [{ node: "source" }, { node: "target" }],
enabled: { attribute: "useGradient" },
}),
layerDashed({
dashColor: { attribute: "dashColor" },
dashSize: { attribute: "dashSize" },
gapSize: { value: 10 },
}),
],
},
},
styles: {
nodes: [DEFAULT_STYLES.nodes, { size: 12, shape: { attribute: "shape" } }],
edges: [
DEFAULT_STYLES.edges,
{ path: { attribute: "path" }, head: { attribute: "head" }, tail: { attribute: "tail" } },
],
},
settings: {
renderEdgeLabels: true,
itemSizesReference: "positions",
autoRescale: true,
},
});