Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(306)

Side by Side Diff: charted/lib/layout/src/treemap_layout.dart

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « charted/lib/layout/src/pie_layout.dart ('k') | charted/lib/locale/format.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2015 Google Inc. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://developers.google.com/open-source/licenses/bsd
7 */
8 part of charted.layout;
9
10 /// PaddingFunction takes a node and generates the padding for the particular
11 /// node
12 typedef List PaddingFunction(TreeMapNode node);
13
14 /**
15 * Utility layout class which recursively subdivides area into rectangles which
16 * can be used to quickly visualize the size of any node in the tree.
17 */
18 class TreeMapLayout extends HierarchyLayout {
19 /// Rectangular subdivision; squareness controlled via the target ratio.
20 static const TREEMAP_LAYOUT_SQUARIFY = 0;
21
22 /// Horizontal subdivision.
23 static const TREEMAP_LAYOUT_SLICE= 1;
24
25 /// Vertical subdivision.
26 static const TREEMAP_LAYOUT_DICE = 2;
27
28 /// Alternating between horizontal and vertical subdivision.
29 static const TREEMAP_LAYOUT_SLICE_DICE = 3;
30
31 static const _DEFAULT_PADDING = const [0, 0, 0, 0];
32
33 /// A sticky treemap layout will preserve the relative arrangement of nodes
34 /// across transitions. (not yet implemented)
35 bool _sticky = false;
36
37 /// The available layout size to the specified two-element array of numbers
38 /// representing width and height.
39 List size = [1, 1];
40
41 /// The mode to layout the Treemap.
42 int mode = TREEMAP_LAYOUT_SQUARIFY;
43
44 /// The ration to scale the Treemap.
45 num ratio = .5 * (1 + math.sqrt(5));
46
47 /// The paddingFunction for each node, defaults to return [0, 0, 0, 0].
48 PaddingFunction paddingFunction = (node) => _DEFAULT_PADDING;
49
50 /// TODO(midoringo): Implement sticky related feature.
51 get sticky => _sticky;
52 set sticky (bool sticky) {
53 _sticky = sticky;
54 }
55
56 // TODO (midoringo): handle the sticky case.
57 @override
58 List<TreeMapNode> layout(List rows, int parentColumn, int labelColumn,
59 int valueColumn) {
60 var nodes = super.layout(rows, parentColumn, labelColumn, valueColumn);
61 var root = nodes[0];
62 root.x = 0;
63 root.y = 0;
64 root.dx = size.first;
65 root.dy = size.last;
66 _scale([root], root.dx * root.dy / root.value);
67 _squarify(root);
68 return nodes;
69 }
70
71 @override
72 TreeMapNode createNode(label, value, depth) {
73 return new TreeMapNode()
74 ..label = label
75 ..value = value
76 ..depth = depth;
77 }
78
79 void _position(List<TreeMapNode> nodes, num length, MutableRect rect,
80 bool flush, num area) {
81 var x = rect.x;
82 var y = rect.y;
83 var v = length > 0 ? (area / length).round() : 0;
84 if (length == rect.width) {
85 if (flush || (v > rect.height)) v = rect.height;
86 for (var node in nodes) {
87 node.x = x;
88 node.y = y;
89 node.dy = v;
90 x += node.dx = math.min(rect.x + rect.width - x, v > 0 ?
91 (node.area / v).round() : 0);
92 }
93 nodes.last.sticky = true;
94 nodes.last.dx += rect.x + rect.width - x;
95 rect.y += v;
96 rect.height -= v;
97 } else {
98 if (flush || (v > rect.width)) v = rect.width;
99 for (var node in nodes) {
100 node.x = x;
101 node.y = y;
102 node.dx = v;
103 y += node.dy = math.min(rect.y + rect.height - y, v > 0 ?
104 (node.area / v).round() : 0);
105 }
106 nodes.last.sticky = false;
107 nodes.last.dy += rect.y + rect.height - y;
108 rect.x += v;
109 rect.width -= v;
110 }
111 }
112
113 /// Applies padding between each nodes.
114 MutableRect _treeMapPad(TreeMapNode node, padding) {
115 var x = node.x + padding[3];
116 var y = node.y + padding.first;
117 var dx = node.dx - padding[1] - padding[3];
118 var dy = node.dy - padding.first - padding[2];
119 if (dx < 0) {
120 x += dx / 2;
121 dx = 0;
122 }
123 if (dy < 0) {
124 y += dy / 2;
125 dy = 0;
126 }
127 return new MutableRect(x, y, dx, dy);
128 }
129
130 /// Scales the node base on it's value and the layout area.
131 void _scale(List<TreeMapNode> children, var factor) {
132 var area;
133 for (var child in children) {
134 area = child.value * (factor < 0 ? 0 : factor);
135 child.area = area <= 0 ? 0 : area;
136 }
137 }
138
139 /// Computes the most amount of area needed to layout the list of nodes.
140 num _worst(List<TreeMapNode> nodes, num length, num pArea) {
141 var area;
142 var rmax = 0;
143 var rmin = double.INFINITY;
144 for (var node in nodes) {
145 area = node.area;
146 if (area <= 0) continue;
147 if (area < rmin) rmin = area;
148 if (area > rmax) rmax = area;
149 }
150 pArea *= pArea;
151 length *= length;
152 return (pArea > 0) ? math.max(length * rmax * ratio / pArea,
153 pArea / (length * rmin * ratio)) : double.INFINITY;
154 }
155
156 /// Recursively compute each nodes (and its children nodes) position and size
157 /// base on the node's property and layout mode.
158 void _squarify(TreeMapNode node) {
159 var children = node.children;
160 if (children.isNotEmpty) {
161 var rect = _treeMapPad(node, paddingFunction(node));
162 List<TreeMapNode> nodes = [];
163 var area = 0;
164 var remaining = new List.from(children);
165 var score, n,
166 best = double.INFINITY,
167 length = (mode == TREEMAP_LAYOUT_SLICE) ? rect.width :
168 (mode == TREEMAP_LAYOUT_DICE) ? rect.height :
169 (mode == TREEMAP_LAYOUT_SLICE_DICE) ? (node.depth & 1 == 1) ?
170 rect.height : rect.width : math.min(rect.width, rect.height);
171 _scale(remaining, rect.width * rect.height / node.value);
172 while ((n = remaining.length) > 0) {
173 var child = remaining[n - 1];
174 nodes.add(child);
175 area += child.area;
176 score = _worst(nodes, length, area);
177 if (mode != TREEMAP_LAYOUT_SQUARIFY || score <= best) {
178 remaining.removeLast();
179 best = score;
180 } else {
181 area -= nodes.removeLast().area;
182 _position(nodes, length, rect, false, area);
183 length = math.min(rect.width, rect.height);
184 nodes.clear();
185 area = 0;
186 best = double.INFINITY;
187 }
188 }
189 if (nodes.isNotEmpty) {
190 _position(nodes, length, rect, true, area);
191 nodes.clear();
192 area = 0;
193 }
194 children.forEach(_squarify);
195 }
196 }
197 }
198
199 class TreeMapNode extends HierarchyNode {
200 /// The minimum x-coordinate of the node position.
201 num x = 0;
202
203 /// The minimum y-coordinate of the node position.
204 num y = 0;
205
206 /// The x-extent of the node position.
207 num dx = 0;
208
209 /// The y-extent of the node position.
210 num dy = 0;
211
212 /// The area the node should take up.
213 num area = 0;
214
215 /// Attribute for the last node in the row, only used for sticky layout.
216 bool sticky = false;
217 }
OLDNEW
« no previous file with comments | « charted/lib/layout/src/pie_layout.dart ('k') | charted/lib/locale/format.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698