From 7b2aeb6baf0389ba9fb48ca90a2a5de7390b7058 Mon Sep 17 00:00:00 2001 From: Mike Bostock Date: Mon, 28 Mar 2016 14:38:52 -0700 Subject: [PATCH] Fix #27 - save node order for resquarify. --- src/treemap/squarify.js | 102 +++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 54 deletions(-) diff --git a/src/treemap/squarify.js b/src/treemap/squarify.js index 844ab1ef..dd67d28e 100644 --- a/src/treemap/squarify.js +++ b/src/treemap/squarify.js @@ -1,77 +1,52 @@ +import treemapDice from "./dice"; +import treemapSlice from "./slice"; + export default (function custom(ratio) { function squarify(parent, x0, y0, x1, y1) { - var nodes = parent.children, - node, + if (parent._squarify) return resquarify(parent, x0, y0, x1, y1); + + var squarified = parent._squarify = [], + nodes = parent.children, + row, nodeValue, i0 = 0, i1, n = nodes.length, - x2, y2, dx, dy, value = parent.value, sumValue, minValue, maxValue, - alpha, - beta, newRatio, - minRatio; + minRatio, + alpha, + beta; while (i0 < n) { dx = x1 - x0, dy = y1 - y0; - sumValue = (node = nodes[i0]).value; + minValue = maxValue = sumValue = nodes[i0].value; + alpha = Math.max(dy / dx, dx / dy) / (value * ratio); + beta = sumValue * sumValue * alpha; + minRatio = Math.max(maxValue / beta, beta / minValue); - // Are we updating a previous squarified layout? - if (node._squarify) { - for (i1 = i0 + 1; i1 < Math.abs(node._squarify); ++i1) { - sumValue += nodes[i1].value; - } - } - - // Otherwise, we’re computing a squarified layout from scratch. - else { - minValue = maxValue = sumValue; - alpha = Math.max(dy / dx, dx / dy) / (value * ratio); + // Keep adding nodes while the aspect ratio maintains or improves. + for (i1 = i0 + 1; i1 < n; ++i1) { + sumValue += nodeValue = nodes[i1].value; + if (nodeValue < minValue) minValue = nodeValue; + if (nodeValue > maxValue) maxValue = nodeValue; beta = sumValue * sumValue * alpha; - minRatio = Math.max(maxValue / beta, beta / minValue); - - // Keep adding nodes while the aspect ratio maintains or improves. - for (i1 = i0 + 1; i1 < n; ++i1) { - sumValue += nodeValue = nodes[i1].value; - if (nodeValue < minValue) minValue = nodeValue; - if (nodeValue > maxValue) maxValue = nodeValue; - beta = sumValue * sumValue * alpha; - newRatio = Math.max(maxValue / beta, beta / minValue); - if (newRatio > minRatio) { sumValue -= nodeValue; break; } - minRatio = newRatio; - } - - node._squarify = dx < dy ? i1 : -i1; + newRatio = Math.max(maxValue / beta, beta / minValue); + if (newRatio > minRatio) { sumValue -= nodeValue; break; } + minRatio = newRatio; } - // Position the row horizontally along the top of the rect. - if (node._squarify > 0) { - for (x2 = x0, y2 = y0 + dy * sumValue / value, dx /= sumValue; i0 < i1; ++i0) { - node = nodes[i0], node.x0 = x2, node.y0 = y0, node.y1 = y2; - node.x1 = x2 += node.value * dx; - } - node.x1 = x1, y0 = y2; - } - - // Position the row vertically along the left of the rect. - else { - for (y2 = y0, x2 = x0 + dx * sumValue / value, dy /= sumValue; i0 < i1; ++i0) { - node = nodes[i0], node.y0 = y2, node.x0 = x0, node.x1 = x2; - node.y1 = y2 += node.value * dy; - } - node.y1 = y1, x0 = x2; - } - - value -= sumValue; + // Position and record the row orientation. + squarified.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)}); + if (row.dice) treemapDice(row, x0, y0, x1, y0 += dy * sumValue / value); + else treemapSlice(row, x0, y0, x0 += dx * sumValue / value, y1); + value -= sumValue, i0 = i1; } - - node.x1 = x1, node.y1 = y1; } squarify.ratio = function(x) { @@ -79,4 +54,23 @@ export default (function custom(ratio) { }; return squarify; -})((1 + Math.sqrt(5)) / 2); +})((1 + Math.sqrt(5)) / 2, false); + +function resquarify(parent, x0, y0, x1, y1) { + var squarified = parent._squarify, + row, + nodes, + i, + j = -1, + n, + m = squarified.length, + value = parent.value; + + while (++j < m) { + row = squarified[j], nodes = row.children; + for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value; + if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value); + else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1); + value -= row.value; + } +}