;(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);