Index: charted/lib/layout/src/treemap_layout.dart |
diff --git a/charted/lib/layout/src/treemap_layout.dart b/charted/lib/layout/src/treemap_layout.dart |
deleted file mode 100644 |
index 8f118ba22c81965765721ebf68bf9a4f6ce74668..0000000000000000000000000000000000000000 |
--- a/charted/lib/layout/src/treemap_layout.dart |
+++ /dev/null |
@@ -1,217 +0,0 @@ |
-/* |
- * Copyright 2015 Google Inc. All rights reserved. |
- * |
- * Use of this source code is governed by a BSD-style |
- * license that can be found in the LICENSE file or at |
- * https://developers.google.com/open-source/licenses/bsd |
- */ |
-part of charted.layout; |
- |
-/// PaddingFunction takes a node and generates the padding for the particular |
-/// node |
-typedef List PaddingFunction(TreeMapNode node); |
- |
-/** |
- * Utility layout class which recursively subdivides area into rectangles which |
- * can be used to quickly visualize the size of any node in the tree. |
- */ |
-class TreeMapLayout extends HierarchyLayout { |
- /// Rectangular subdivision; squareness controlled via the target ratio. |
- static const TREEMAP_LAYOUT_SQUARIFY = 0; |
- |
- /// Horizontal subdivision. |
- static const TREEMAP_LAYOUT_SLICE= 1; |
- |
- /// Vertical subdivision. |
- static const TREEMAP_LAYOUT_DICE = 2; |
- |
- /// Alternating between horizontal and vertical subdivision. |
- static const TREEMAP_LAYOUT_SLICE_DICE = 3; |
- |
- static const _DEFAULT_PADDING = const [0, 0, 0, 0]; |
- |
- /// A sticky treemap layout will preserve the relative arrangement of nodes |
- /// across transitions. (not yet implemented) |
- bool _sticky = false; |
- |
- /// The available layout size to the specified two-element array of numbers |
- /// representing width and height. |
- List size = [1, 1]; |
- |
- /// The mode to layout the Treemap. |
- int mode = TREEMAP_LAYOUT_SQUARIFY; |
- |
- /// The ration to scale the Treemap. |
- num ratio = .5 * (1 + math.sqrt(5)); |
- |
- /// The paddingFunction for each node, defaults to return [0, 0, 0, 0]. |
- PaddingFunction paddingFunction = (node) => _DEFAULT_PADDING; |
- |
- /// TODO(midoringo): Implement sticky related feature. |
- get sticky => _sticky; |
- set sticky (bool sticky) { |
- _sticky = sticky; |
- } |
- |
- // TODO (midoringo): handle the sticky case. |
- @override |
- List<TreeMapNode> layout(List rows, int parentColumn, int labelColumn, |
- int valueColumn) { |
- var nodes = super.layout(rows, parentColumn, labelColumn, valueColumn); |
- var root = nodes[0]; |
- root.x = 0; |
- root.y = 0; |
- root.dx = size.first; |
- root.dy = size.last; |
- _scale([root], root.dx * root.dy / root.value); |
- _squarify(root); |
- return nodes; |
- } |
- |
- @override |
- TreeMapNode createNode(label, value, depth) { |
- return new TreeMapNode() |
- ..label = label |
- ..value = value |
- ..depth = depth; |
- } |
- |
- void _position(List<TreeMapNode> nodes, num length, MutableRect rect, |
- bool flush, num area) { |
- var x = rect.x; |
- var y = rect.y; |
- var v = length > 0 ? (area / length).round() : 0; |
- if (length == rect.width) { |
- if (flush || (v > rect.height)) v = rect.height; |
- for (var node in nodes) { |
- node.x = x; |
- node.y = y; |
- node.dy = v; |
- x += node.dx = math.min(rect.x + rect.width - x, v > 0 ? |
- (node.area / v).round() : 0); |
- } |
- nodes.last.sticky = true; |
- nodes.last.dx += rect.x + rect.width - x; |
- rect.y += v; |
- rect.height -= v; |
- } else { |
- if (flush || (v > rect.width)) v = rect.width; |
- for (var node in nodes) { |
- node.x = x; |
- node.y = y; |
- node.dx = v; |
- y += node.dy = math.min(rect.y + rect.height - y, v > 0 ? |
- (node.area / v).round() : 0); |
- } |
- nodes.last.sticky = false; |
- nodes.last.dy += rect.y + rect.height - y; |
- rect.x += v; |
- rect.width -= v; |
- } |
- } |
- |
- /// Applies padding between each nodes. |
- MutableRect _treeMapPad(TreeMapNode node, padding) { |
- var x = node.x + padding[3]; |
- var y = node.y + padding.first; |
- var dx = node.dx - padding[1] - padding[3]; |
- var dy = node.dy - padding.first - padding[2]; |
- if (dx < 0) { |
- x += dx / 2; |
- dx = 0; |
- } |
- if (dy < 0) { |
- y += dy / 2; |
- dy = 0; |
- } |
- return new MutableRect(x, y, dx, dy); |
- } |
- |
- /// Scales the node base on it's value and the layout area. |
- void _scale(List<TreeMapNode> children, var factor) { |
- var area; |
- for (var child in children) { |
- area = child.value * (factor < 0 ? 0 : factor); |
- child.area = area <= 0 ? 0 : area; |
- } |
- } |
- |
- /// Computes the most amount of area needed to layout the list of nodes. |
- num _worst(List<TreeMapNode> nodes, num length, num pArea) { |
- var area; |
- var rmax = 0; |
- var rmin = double.INFINITY; |
- for (var node in nodes) { |
- area = node.area; |
- if (area <= 0) continue; |
- if (area < rmin) rmin = area; |
- if (area > rmax) rmax = area; |
- } |
- pArea *= pArea; |
- length *= length; |
- return (pArea > 0) ? math.max(length * rmax * ratio / pArea, |
- pArea / (length * rmin * ratio)) : double.INFINITY; |
- } |
- |
- /// Recursively compute each nodes (and its children nodes) position and size |
- /// base on the node's property and layout mode. |
- void _squarify(TreeMapNode node) { |
- var children = node.children; |
- if (children.isNotEmpty) { |
- var rect = _treeMapPad(node, paddingFunction(node)); |
- List<TreeMapNode> nodes = []; |
- var area = 0; |
- var remaining = new List.from(children); |
- var score, n, |
- best = double.INFINITY, |
- length = (mode == TREEMAP_LAYOUT_SLICE) ? rect.width : |
- (mode == TREEMAP_LAYOUT_DICE) ? rect.height : |
- (mode == TREEMAP_LAYOUT_SLICE_DICE) ? (node.depth & 1 == 1) ? |
- rect.height : rect.width : math.min(rect.width, rect.height); |
- _scale(remaining, rect.width * rect.height / node.value); |
- while ((n = remaining.length) > 0) { |
- var child = remaining[n - 1]; |
- nodes.add(child); |
- area += child.area; |
- score = _worst(nodes, length, area); |
- if (mode != TREEMAP_LAYOUT_SQUARIFY || score <= best) { |
- remaining.removeLast(); |
- best = score; |
- } else { |
- area -= nodes.removeLast().area; |
- _position(nodes, length, rect, false, area); |
- length = math.min(rect.width, rect.height); |
- nodes.clear(); |
- area = 0; |
- best = double.INFINITY; |
- } |
- } |
- if (nodes.isNotEmpty) { |
- _position(nodes, length, rect, true, area); |
- nodes.clear(); |
- area = 0; |
- } |
- children.forEach(_squarify); |
- } |
- } |
-} |
- |
-class TreeMapNode extends HierarchyNode { |
- /// The minimum x-coordinate of the node position. |
- num x = 0; |
- |
- /// The minimum y-coordinate of the node position. |
- num y = 0; |
- |
- /// The x-extent of the node position. |
- num dx = 0; |
- |
- /// The y-extent of the node position. |
- num dy = 0; |
- |
- /// The area the node should take up. |
- num area = 0; |
- |
- /// Attribute for the last node in the row, only used for sticky layout. |
- bool sticky = false; |
-} |