sigma
Version:
A JavaScript library aimed at visualizing graphs of thousands of nodes and edges.
122 lines (121 loc) • 4.73 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.edgeLabelsToDisplayFromNodes = exports.LabelGrid = void 0;
/**
* Class representing a single candidate for the label grid selection.
*
* It also describes a deterministic way to compare two candidates to assess
* which one is better.
*/
var LabelCandidate = /** @class */ (function () {
function LabelCandidate(key, size) {
this.key = key;
this.size = size;
}
LabelCandidate.compare = function (first, second) {
// First we compare by size
if (first.size > second.size)
return -1;
if (first.size < second.size)
return 1;
// Then since no two nodes can have the same key, we use it to
// deterministically tie-break by key
if (first.key > second.key)
return 1;
// NOTE: this comparator cannot return 0
return -1;
};
return LabelCandidate;
}());
/**
* Class representing a 2D spatial grid divided into constant-size cells.
*/
var LabelGrid = /** @class */ (function () {
function LabelGrid() {
this.width = 0;
this.height = 0;
this.cellSize = 0;
this.columns = 0;
this.rows = 0;
this.cells = {};
}
LabelGrid.prototype.resizeAndClear = function (dimensions, cellSize) {
this.width = dimensions.width;
this.height = dimensions.height;
this.cellSize = cellSize;
this.columns = Math.ceil(dimensions.width / cellSize);
this.rows = Math.ceil(dimensions.height / cellSize);
this.cells = {};
};
LabelGrid.prototype.getIndex = function (pos) {
var xIndex = Math.floor(pos.x / this.cellSize);
var yIndex = Math.floor(pos.y / this.cellSize);
return yIndex * this.columns + xIndex;
};
LabelGrid.prototype.add = function (key, size, pos) {
var candidate = new LabelCandidate(key, size);
var index = this.getIndex(pos);
var cell = this.cells[index];
if (!cell) {
cell = [];
this.cells[index] = cell;
}
cell.push(candidate);
};
LabelGrid.prototype.organize = function () {
for (var k in this.cells) {
var cell = this.cells[k];
cell.sort(LabelCandidate.compare);
}
};
LabelGrid.prototype.getLabelsToDisplay = function (ratio, density) {
// TODO: work on visible nodes to optimize? ^ -> threshold outside so that memoization works?
// TODO: adjust threshold lower, but increase cells a bit?
// TODO: hunt for geom issue in disguise
// TODO: memoize while ratio does not move. method to force recompute
var cellArea = this.cellSize * this.cellSize;
var scaledCellArea = cellArea / ratio / ratio;
var scaledDensity = (scaledCellArea * density) / cellArea;
var labelsToDisplayPerCell = Math.ceil(scaledDensity);
var labels = [];
for (var k in this.cells) {
var cell = this.cells[k];
for (var i = 0; i < Math.min(labelsToDisplayPerCell, cell.length); i++) {
labels.push(cell[i].key);
}
}
return labels;
};
return LabelGrid;
}());
exports.LabelGrid = LabelGrid;
/**
* Label heuristic selecting edge labels to display, based on displayed node
* labels
*
* @param {object} params - Parameters:
* @param {Set} displayedNodeLabels - Currently displayed node labels.
* @param {Set} highlightedNodes - Highlighted nodes.
* @param {Graph} graph - The rendered graph.
* @param {string} hoveredNode - Hovered node (optional)
* @return {Array} - The selected labels.
*/
function edgeLabelsToDisplayFromNodes(params) {
var graph = params.graph, hoveredNode = params.hoveredNode, highlightedNodes = params.highlightedNodes, displayedNodeLabels = params.displayedNodeLabels;
var worthyEdges = [];
// TODO: the code below can be optimized using #.forEach and batching the code per adj
// We should display an edge's label if:
// - Any of its extremities is highlighted or hovered
// - Both of its extremities has its label shown
graph.forEachEdge(function (edge, _, source, target) {
if (source === hoveredNode ||
target === hoveredNode ||
highlightedNodes.has(source) ||
highlightedNodes.has(target) ||
(displayedNodeLabels.has(source) && displayedNodeLabels.has(target))) {
worthyEdges.push(edge);
}
});
return worthyEdges;
}
exports.edgeLabelsToDisplayFromNodes = edgeLabelsToDisplayFromNodes;