Skip to content

Commit ecff275

Browse files
committed
[sigma] Drafts nodes/edges depths
This commit is related to #1427.
1 parent 3107e21 commit ecff275

File tree

4 files changed

+55
-43
lines changed

4 files changed

+55
-43
lines changed

packages/sigma/src/rendering/program.ts

+18-6
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
} from "./utils";
2323

2424
const PICKING_PREFIX = `#define PICKING_MODE\n`;
25+
const Z_INDEXING_PREFIX = `#define Z_INDEXING\n`;
2526

2627
const SIZE_FACTOR_PER_ATTRIBUTE_TYPE: Record<number, number> = {
2728
[WebGL2RenderingContext.BOOL]: 1,
@@ -76,6 +77,7 @@ export abstract class Program<
7677
pickProgram: ProgramInfo | null;
7778

7879
isInstanced: boolean;
80+
isZIndexing: boolean;
7981

8082
abstract getDefinition(): ProgramDefinition<Uniform> | InstancedProgramDefinition<Uniform>;
8183

@@ -84,11 +86,16 @@ export abstract class Program<
8486
pickingBuffer: WebGLFramebuffer | null,
8587
renderer: Sigma<N, E, G>,
8688
) {
89+
this.renderer = renderer;
90+
this.isZIndexing = !!renderer.getSetting("zIndex");
91+
92+
const zIndexingPrefix = this.isZIndexing ? Z_INDEXING_PREFIX : "";
93+
8794
// Reading and caching program definition
8895
const def = this.getDefinition();
8996
this.VERTICES = def.VERTICES;
90-
this.VERTEX_SHADER_SOURCE = def.VERTEX_SHADER_SOURCE;
91-
this.FRAGMENT_SHADER_SOURCE = def.FRAGMENT_SHADER_SOURCE;
97+
this.VERTEX_SHADER_SOURCE = zIndexingPrefix + def.VERTEX_SHADER_SOURCE;
98+
this.FRAGMENT_SHADER_SOURCE = zIndexingPrefix + def.FRAGMENT_SHADER_SOURCE;
9299
this.UNIFORMS = def.UNIFORMS;
93100
this.ATTRIBUTES = def.ATTRIBUTES;
94101
this.METHOD = def.METHOD;
@@ -102,14 +109,19 @@ export abstract class Program<
102109
this.STRIDE = this.VERTICES * this.ATTRIBUTES_ITEMS_COUNT;
103110

104111
// Members
105-
this.renderer = renderer;
106-
this.normalProgram = this.getProgramInfo("normal", gl, def.VERTEX_SHADER_SOURCE, def.FRAGMENT_SHADER_SOURCE, null);
112+
this.normalProgram = this.getProgramInfo(
113+
"normal",
114+
gl,
115+
this.VERTEX_SHADER_SOURCE,
116+
this.FRAGMENT_SHADER_SOURCE,
117+
null,
118+
);
107119
this.pickProgram = pickingBuffer
108120
? this.getProgramInfo(
109121
"pick",
110122
gl,
111-
PICKING_PREFIX + def.VERTEX_SHADER_SOURCE,
112-
PICKING_PREFIX + def.FRAGMENT_SHADER_SOURCE,
123+
PICKING_PREFIX + this.VERTEX_SHADER_SOURCE,
124+
PICKING_PREFIX + this.FRAGMENT_SHADER_SOURCE,
113125
pickingBuffer,
114126
)
115127
: null;

packages/sigma/src/sigma.ts

+32-33
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ export default class Sigma<
143143
private nodesWithForcedLabels: Set<string> = new Set<string>();
144144
private edgesWithForcedLabels: Set<string> = new Set<string>();
145145
private nodeExtent: { x: Extent; y: Extent } = { x: [0, 1], y: [0, 1] };
146-
private nodeZExtent: [number, number] = [Infinity, -Infinity];
147-
private edgeZExtent: [number, number] = [Infinity, -Infinity];
146+
private nodeDepths: Record<string, number> = {};
147+
private edgeDepths: Record<string, number> = {};
148148

149149
private matrix: Float32Array = identity();
150150
private invMatrix: Float32Array = identity();
@@ -631,13 +631,13 @@ export default class Sigma<
631631
private bindGraphHandlers(): this {
632632
const graph = this.graph;
633633

634-
const LAYOUT_IMPACTING_FIELDS = new Set(["x", "y", "zIndex", "type"]);
634+
const LAYOUT_IMPACTING_FIELDS = new Set(["x", "y", "type"]);
635635
this.activeListeners.eachNodeAttributesUpdatedGraphUpdate = (e: { hints?: { attributes?: string[] } }) => {
636636
const updatedFields = e.hints?.attributes;
637637
// we process all nodes
638638
this.graph.forEachNode((node) => this.updateNode(node));
639639

640-
// if coord, type or zIndex have changed, we need to schedule a render
640+
// if coord or type have changed, we need to schedule a render
641641
// (zIndex for the programIndex)
642642
const layoutChanged = !updatedFields || updatedFields.some((f) => LAYOUT_IMPACTING_FIELDS.has(f));
643643
this.refresh({ partialGraph: { nodes: graph.nodes() }, skipIndexation: !layoutChanged, schedule: true });
@@ -647,7 +647,7 @@ export default class Sigma<
647647
const updatedFields = e.hints?.attributes;
648648
// we process all edges
649649
this.graph.forEachEdge((edge) => this.updateEdge(edge));
650-
const layoutChanged = updatedFields && ["zIndex", "type"].some((f) => updatedFields?.includes(f));
650+
const layoutChanged = updatedFields?.includes("type");
651651
this.refresh({ partialGraph: { edges: graph.edges() }, skipIndexation: !layoutChanged, schedule: true });
652652
};
653653

@@ -816,7 +816,7 @@ export default class Sigma<
816816
const itemIDsIndex: typeof this.itemIDsIndex = {};
817817
let incrID = 1;
818818

819-
let nodes = graph.nodes();
819+
const nodes = graph.nodes();
820820

821821
// Do some indexation on the whole graph
822822
for (let i = 0, l = nodes.length; i < l; i++) {
@@ -849,13 +849,16 @@ export default class Sigma<
849849
}
850850

851851
// Order nodes by zIndex before to add them to program
852-
if (this.settings.zIndex && this.nodeZExtent[0] !== this.nodeZExtent[1])
853-
nodes = zIndexOrdering<string>(
854-
this.nodeZExtent,
852+
this.nodeDepths = {};
853+
if (this.settings.zIndex) {
854+
const sortedNodes = zIndexOrdering<string>(
855855
(node: string): number => this.nodeDataCache[node].zIndex,
856-
nodes,
856+
nodes.slice(0),
857857
);
858858

859+
for (let i = 0, l = sortedNodes.length; i < l; i++) this.nodeDepths[sortedNodes[i]] = l - 1 - i;
860+
}
861+
859862
// Add data to programs
860863
for (let i = 0, l = nodes.length; i < l; i++) {
861864
const node = nodes[i];
@@ -873,7 +876,7 @@ export default class Sigma<
873876
//
874877

875878
const edgesPerPrograms: Record<string, number> = {};
876-
let edges = graph.edges();
879+
const edges = graph.edges();
877880

878881
// Allocate memory to programs
879882
for (let i = 0, l = edges.length; i < l; i++) {
@@ -883,13 +886,16 @@ export default class Sigma<
883886
}
884887

885888
// Order edges by zIndex before to add them to program
886-
if (this.settings.zIndex && this.edgeZExtent[0] !== this.edgeZExtent[1])
887-
edges = zIndexOrdering<string>(
888-
this.edgeZExtent,
889+
this.edgeDepths = {};
890+
if (this.settings.zIndex) {
891+
const sortedEdges = zIndexOrdering<string>(
889892
(edge: string): number => this.edgeDataCache[edge].zIndex,
890-
edges,
893+
edges.slice(0),
891894
);
892895

896+
for (let i = 0, l = sortedEdges.length; i < l; i++) this.edgeDepths[sortedEdges[i]] = l - 1 - i;
897+
}
898+
893899
for (const type in this.edgePrograms) {
894900
if (!hasOwnProperty.call(this.edgePrograms, type)) {
895901
throw new Error(`Sigma: could not find a suitable program for edge type "${type}"!`);
@@ -930,8 +936,10 @@ export default class Sigma<
930936
this.camera.setState(this.camera.validateState(this.camera.getState()));
931937

932938
if (oldSettings) {
939+
const zIndexingUpdated = !!oldSettings.zIndex !== !!settings.zIndex;
940+
933941
// Check edge programs:
934-
if (oldSettings.edgeProgramClasses !== settings.edgeProgramClasses) {
942+
if (zIndexingUpdated || oldSettings.edgeProgramClasses !== settings.edgeProgramClasses) {
935943
for (const type in settings.edgeProgramClasses) {
936944
if (settings.edgeProgramClasses[type] !== oldSettings.edgeProgramClasses[type]) {
937945
this.registerEdgeProgram(type, settings.edgeProgramClasses[type]);
@@ -944,6 +952,7 @@ export default class Sigma<
944952

945953
// Check node programs:
946954
if (
955+
zIndexingUpdated ||
947956
oldSettings.nodeProgramClasses !== settings.nodeProgramClasses ||
948957
oldSettings.nodeHoverProgramClasses !== settings.nodeHoverProgramClasses
949958
) {
@@ -1194,6 +1203,8 @@ export default class Sigma<
11941203

11951204
program.render({
11961205
matrix: this.matrix,
1206+
maxEdgesDepth: this.graph.size + 1,
1207+
maxNodesDepth: this.graph.order + 1,
11971208
width: this.width,
11981209
height: this.height,
11991210
pixelRatio: this.pixelRatio,
@@ -1291,6 +1302,8 @@ export default class Sigma<
12911302

12921303
const params: RenderParams = {
12931304
matrix: this.matrix,
1305+
maxEdgesDepth: this.graph.size + 1,
1306+
maxNodesDepth: this.graph.order + 1,
12941307
width: this.width,
12951308
height: this.height,
12961309
pixelRatio: this.pixelRatio,
@@ -1356,12 +1369,6 @@ export default class Sigma<
13561369
// update
13571370
this.highlightedNodes.delete(key);
13581371
if (data.highlighted && !data.hidden) this.highlightedNodes.add(key);
1359-
1360-
// zIndex
1361-
if (this.settings.zIndex) {
1362-
if (data.zIndex < this.nodeZExtent[0]) this.nodeZExtent[0] = data.zIndex;
1363-
if (data.zIndex > this.nodeZExtent[1]) this.nodeZExtent[1] = data.zIndex;
1364-
}
13651372
}
13661373

13671374
/**
@@ -1387,7 +1394,7 @@ export default class Sigma<
13871394
delete this.nodeDataCache[key];
13881395
// Remove from node program index
13891396
delete this.nodeProgramIndex[key];
1390-
// Remove from higlighted nodes
1397+
// Remove from highlighted nodes
13911398
this.highlightedNodes.delete(key);
13921399
// Remove from hovered
13931400
if (this.hoveredNode === key) this.hoveredNode = null;
@@ -1417,12 +1424,6 @@ export default class Sigma<
14171424
// update
14181425
this.edgesWithForcedLabels.delete(key);
14191426
if (data.forceLabel && !data.hidden) this.edgesWithForcedLabels.add(key);
1420-
1421-
// Check zIndex
1422-
if (this.settings.zIndex) {
1423-
if (data.zIndex < this.edgeZExtent[0]) this.edgeZExtent[0] = data.zIndex;
1424-
if (data.zIndex > this.edgeZExtent[1]) this.edgeZExtent[1] = data.zIndex;
1425-
}
14261427
}
14271428

14281429
/**
@@ -1461,7 +1462,6 @@ export default class Sigma<
14611462
this.nodeDataCache = {};
14621463
this.edgeProgramIndex = {};
14631464
this.nodesWithForcedLabels = new Set<string>();
1464-
this.nodeZExtent = [Infinity, -Infinity];
14651465
}
14661466

14671467
/**
@@ -1472,7 +1472,6 @@ export default class Sigma<
14721472
this.edgeDataCache = {};
14731473
this.edgeProgramIndex = {};
14741474
this.edgesWithForcedLabels = new Set<string>();
1475-
this.edgeZExtent = [Infinity, -Infinity];
14761475
}
14771476

14781477
/**
@@ -1524,7 +1523,7 @@ export default class Sigma<
15241523
const data = this.nodeDataCache[node];
15251524
const nodeProgram = this.nodePrograms[data.type];
15261525
if (!nodeProgram) throw new Error(`Sigma: could not find a suitable program for node type "${data.type}"!`);
1527-
nodeProgram.process(fingerprint, position, data);
1526+
nodeProgram.process(fingerprint, position, { ...data, zIndex: this.nodeDepths[node] });
15281527
// Saving program index
15291528
this.nodeProgramIndex[node] = position;
15301529
}
@@ -1543,7 +1542,7 @@ export default class Sigma<
15431542
const extremities = this.graph.extremities(edge),
15441543
sourceData = this.nodeDataCache[extremities[0]],
15451544
targetData = this.nodeDataCache[extremities[1]];
1546-
edgeProgram.process(fingerprint, position, sourceData, targetData, data);
1545+
edgeProgram.process(fingerprint, position, sourceData, targetData, { ...data, zIndex: this.edgeDepths[edge] });
15471546
// Saving program index
15481547
this.edgeProgramIndex[edge] = position;
15491548
}

packages/sigma/src/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ export interface RenderParams {
9292
downSizingRatio: number;
9393
minEdgeThickness: number;
9494
antiAliasingFeather: number;
95+
maxNodesDepth: number;
96+
maxEdgesDepth: number;
9597
}
9698

9799
/**

packages/sigma/src/utils/misc.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Extent, PlainObject } from "../types";
1+
import { PlainObject } from "../types";
22

33
/**
44
* Function used to create DOM elements easily.
@@ -35,10 +35,9 @@ export function getPixelRatio(): number {
3535
}
3636

3737
/**
38-
* Function ordering the given elements in reverse z-order so they drawn
39-
* the correct way.
38+
* Function ordering the given elements in reverse z-order, so they are drawn the correct way.
4039
*/
41-
export function zIndexOrdering<T>(_extent: Extent, getter: (e: T) => number, elements: Array<T>): Array<T> {
40+
export function zIndexOrdering<T>(getter: (e: T) => number, elements: Array<T>): Array<T> {
4241
// If k is > n, we'll use a standard sort
4342
return elements.sort(function (a, b) {
4443
const zA = getter(a) || 0,

0 commit comments

Comments
 (0)