;(function(undefined) {
|
|
'use strict';
|
|
|
|
if (typeof sigma === 'undefined')
|
|
throw 'sigma is not declared';
|
|
|
|
// Initialize packages:
|
|
sigma.utils.pkg('sigma.middlewares');
|
|
sigma.utils.pkg('sigma.utils');
|
|
|
|
/**
|
|
* This middleware will rescale the graph such that it takes an optimal space
|
|
* on the renderer.
|
|
*
|
|
* As each middleware, this function is executed in the scope of the sigma
|
|
* instance.
|
|
*
|
|
* @param {?string} readPrefix The read prefix.
|
|
* @param {?string} writePrefix The write prefix.
|
|
* @param {object} options The parameters.
|
|
*/
|
|
sigma.middlewares.rescale = function(readPrefix, writePrefix, options) {
|
|
var i,
|
|
l,
|
|
a,
|
|
b,
|
|
c,
|
|
d,
|
|
scale,
|
|
margin,
|
|
n = this.graph.nodes(),
|
|
e = this.graph.edges(),
|
|
settings = this.settings.embedObjects(options || {}),
|
|
bounds = settings('bounds') || sigma.utils.getBoundaries(
|
|
this.graph,
|
|
readPrefix,
|
|
true
|
|
),
|
|
minX = bounds.minX,
|
|
minY = bounds.minY,
|
|
maxX = bounds.maxX,
|
|
maxY = bounds.maxY,
|
|
sizeMax = bounds.sizeMax,
|
|
weightMax = bounds.weightMax,
|
|
w = settings('width') || 1,
|
|
h = settings('height') || 1,
|
|
rescaleSettings = settings('autoRescale'),
|
|
validSettings = {
|
|
nodePosition: 1,
|
|
nodeSize: 1,
|
|
edgeSize: 1
|
|
};
|
|
|
|
/**
|
|
* What elements should we rescale?
|
|
*/
|
|
if (!(rescaleSettings instanceof Array))
|
|
rescaleSettings = ['nodePosition', 'nodeSize', 'edgeSize'];
|
|
|
|
for (i = 0, l = rescaleSettings.length; i < l; i++)
|
|
if (!validSettings[rescaleSettings[i]])
|
|
throw new Error(
|
|
'The rescale setting "' + rescaleSettings[i] + '" is not recognized.'
|
|
);
|
|
|
|
var np = ~rescaleSettings.indexOf('nodePosition'),
|
|
ns = ~rescaleSettings.indexOf('nodeSize'),
|
|
es = ~rescaleSettings.indexOf('edgeSize');
|
|
|
|
/**
|
|
* First, we compute the scaling ratio, without considering the sizes
|
|
* of the nodes : Each node will have its center in the canvas, but might
|
|
* be partially out of it.
|
|
*/
|
|
scale = settings('scalingMode') === 'outside' ?
|
|
Math.max(
|
|
w / Math.max(maxX - minX, 1),
|
|
h / Math.max(maxY - minY, 1)
|
|
) :
|
|
Math.min(
|
|
w / Math.max(maxX - minX, 1),
|
|
h / Math.max(maxY - minY, 1)
|
|
);
|
|
|
|
/**
|
|
* Then, we correct that scaling ratio considering a margin, which is
|
|
* basically the size of the biggest node.
|
|
* This has to be done as a correction since to compare the size of the
|
|
* biggest node to the X and Y values, we have to first get an
|
|
* approximation of the scaling ratio.
|
|
**/
|
|
margin =
|
|
(
|
|
settings('rescaleIgnoreSize') ?
|
|
0 :
|
|
(settings('maxNodeSize') || sizeMax) / scale
|
|
) +
|
|
(settings('sideMargin') || 0);
|
|
maxX += margin;
|
|
minX -= margin;
|
|
maxY += margin;
|
|
minY -= margin;
|
|
|
|
// Fix the scaling with the new extrema:
|
|
scale = settings('scalingMode') === 'outside' ?
|
|
Math.max(
|
|
w / Math.max(maxX - minX, 1),
|
|
h / Math.max(maxY - minY, 1)
|
|
) :
|
|
Math.min(
|
|
w / Math.max(maxX - minX, 1),
|
|
h / Math.max(maxY - minY, 1)
|
|
);
|
|
|
|
// Size homothetic parameters:
|
|
if (!settings('maxNodeSize') && !settings('minNodeSize')) {
|
|
a = 1;
|
|
b = 0;
|
|
} else if (settings('maxNodeSize') === settings('minNodeSize')) {
|
|
a = 0;
|
|
b = +settings('maxNodeSize');
|
|
} else {
|
|
a = (settings('maxNodeSize') - settings('minNodeSize')) / sizeMax;
|
|
b = +settings('minNodeSize');
|
|
}
|
|
|
|
if (!settings('maxEdgeSize') && !settings('minEdgeSize')) {
|
|
c = 1;
|
|
d = 0;
|
|
} else if (settings('maxEdgeSize') === settings('minEdgeSize')) {
|
|
c = 0;
|
|
d = +settings('minEdgeSize');
|
|
} else {
|
|
c = (settings('maxEdgeSize') - settings('minEdgeSize')) / weightMax;
|
|
d = +settings('minEdgeSize');
|
|
}
|
|
|
|
// Rescale the nodes and edges:
|
|
for (i = 0, l = e.length; i < l; i++)
|
|
e[i][writePrefix + 'size'] =
|
|
e[i][readPrefix + 'size'] * (es ? c : 1) + (es ? d : 0);
|
|
|
|
for (i = 0, l = n.length; i < l; i++) {
|
|
n[i][writePrefix + 'size'] =
|
|
n[i][readPrefix + 'size'] * (ns ? a : 1) + (ns ? b : 0);
|
|
n[i][writePrefix + 'x'] =
|
|
(n[i][readPrefix + 'x'] - (maxX + minX) / 2) * (np ? scale : 1);
|
|
n[i][writePrefix + 'y'] =
|
|
(n[i][readPrefix + 'y'] - (maxY + minY) / 2) * (np ? scale : 1);
|
|
}
|
|
};
|
|
|
|
sigma.utils.getBoundaries = function(graph, prefix, doEdges) {
|
|
var i,
|
|
l,
|
|
e = graph.edges(),
|
|
n = graph.nodes(),
|
|
weightMax = -Infinity,
|
|
sizeMax = -Infinity,
|
|
minX = Infinity,
|
|
minY = Infinity,
|
|
maxX = -Infinity,
|
|
maxY = -Infinity;
|
|
|
|
if (doEdges)
|
|
for (i = 0, l = e.length; i < l; i++)
|
|
weightMax = Math.max(e[i][prefix + 'size'], weightMax);
|
|
|
|
for (i = 0, l = n.length; i < l; i++) {
|
|
sizeMax = Math.max(n[i][prefix + 'size'], sizeMax);
|
|
maxX = Math.max(n[i][prefix + 'x'], maxX);
|
|
minX = Math.min(n[i][prefix + 'x'], minX);
|
|
maxY = Math.max(n[i][prefix + 'y'], maxY);
|
|
minY = Math.min(n[i][prefix + 'y'], minY);
|
|
}
|
|
|
|
weightMax = weightMax || 1;
|
|
sizeMax = sizeMax || 1;
|
|
|
|
return {
|
|
weightMax: weightMax,
|
|
sizeMax: sizeMax,
|
|
minX: minX,
|
|
minY: minY,
|
|
maxX: maxX,
|
|
maxY: maxY
|
|
};
|
|
};
|
|
}).call(this);
|