Add treemap example.
Still a work in progress. Need to decide on the appropriate API for representing tree structures; not sure I want to go the heavyweight pv.dom route. May also need rounding to exact pixel values.
This commit is contained in:
Родитель
1d9ed5ae72
Коммит
6b8839eab6
|
@ -0,0 +1,284 @@
|
|||
{
|
||||
"analytics": {
|
||||
"cluster": {
|
||||
"AgglomerativeCluster": 3938,
|
||||
"CommunityStructure": 3812,
|
||||
"HierarchicalCluster": 6714,
|
||||
"MergeEdge": 743
|
||||
},
|
||||
"graph": {
|
||||
"BetweennessCentrality": 3534,
|
||||
"LinkDistance": 5731,
|
||||
"MaxFlowMinCut": 7840,
|
||||
"ShortestPaths": 5914,
|
||||
"SpanningTree": 3416
|
||||
},
|
||||
"optimization": {
|
||||
"AspectRatioBanker": 7074
|
||||
}
|
||||
},
|
||||
"animate": {
|
||||
"Easing": 17010,
|
||||
"FunctionSequence": 5842,
|
||||
"interpolate": {
|
||||
"ArrayInterpolator": 1983,
|
||||
"ColorInterpolator": 2047,
|
||||
"DateInterpolator": 1375,
|
||||
"Interpolator": 8746,
|
||||
"MatrixInterpolator": 2202,
|
||||
"NumberInterpolator": 1382,
|
||||
"ObjectInterpolator": 1629,
|
||||
"PointInterpolator": 1675,
|
||||
"RectangleInterpolator": 2042
|
||||
},
|
||||
"ISchedulable": 1041,
|
||||
"Parallel": 5176,
|
||||
"Pause": 449,
|
||||
"Scheduler": 5593,
|
||||
"Sequence": 5534,
|
||||
"Transition": 9201,
|
||||
"Transitioner": 19975,
|
||||
"TransitionEvent": 1116,
|
||||
"Tween": 6006
|
||||
},
|
||||
"data": {
|
||||
"converters": {
|
||||
"Converters": 721,
|
||||
"DelimitedTextConverter": 4294,
|
||||
"GraphMLConverter": 9800,
|
||||
"IDataConverter": 1314,
|
||||
"JSONConverter": 2220
|
||||
},
|
||||
"DataField": 1759,
|
||||
"DataSchema": 2165,
|
||||
"DataSet": 586,
|
||||
"DataSource": 3331,
|
||||
"DataTable": 772,
|
||||
"DataUtil": 3322
|
||||
},
|
||||
"display": {
|
||||
"DirtySprite": 8833,
|
||||
"LineSprite": 1732,
|
||||
"RectSprite": 3623,
|
||||
"TextSprite": 10066
|
||||
},
|
||||
"flex": {
|
||||
"FlareVis": 4116
|
||||
},
|
||||
"physics": {
|
||||
"DragForce": 1082,
|
||||
"GravityForce": 1336,
|
||||
"IForce": 319,
|
||||
"NBodyForce": 10498,
|
||||
"Particle": 2822,
|
||||
"Simulation": 9983,
|
||||
"Spring": 2213,
|
||||
"SpringForce": 1681
|
||||
},
|
||||
"query": {
|
||||
"AggregateExpression": 1616,
|
||||
"And": 1027,
|
||||
"Arithmetic": 3891,
|
||||
"Average": 891,
|
||||
"BinaryExpression": 2893,
|
||||
"Comparison": 5103,
|
||||
"CompositeExpression": 3677,
|
||||
"Count": 781,
|
||||
"DateUtil": 4141,
|
||||
"Distinct": 933,
|
||||
"Expression": 5130,
|
||||
"ExpressionIterator": 3617,
|
||||
"Fn": 3240,
|
||||
"If": 2732,
|
||||
"IsA": 2039,
|
||||
"Literal": 1214,
|
||||
"Match": 3748,
|
||||
"Maximum": 843,
|
||||
"methods": {
|
||||
"add": 593,
|
||||
"and": 330,
|
||||
"average": 287,
|
||||
"count": 277,
|
||||
"distinct": 292,
|
||||
"div": 595,
|
||||
"eq": 594,
|
||||
"fn": 460,
|
||||
"gt": 603,
|
||||
"gte": 625,
|
||||
"iff": 748,
|
||||
"isa": 461,
|
||||
"lt": 597,
|
||||
"lte": 619,
|
||||
"max": 283,
|
||||
"min": 283,
|
||||
"mod": 591,
|
||||
"mul": 603,
|
||||
"neq": 599,
|
||||
"not": 386,
|
||||
"or": 323,
|
||||
"orderby": 307,
|
||||
"range": 772,
|
||||
"select": 296,
|
||||
"stddev": 363,
|
||||
"sub": 600,
|
||||
"sum": 280,
|
||||
"update": 307,
|
||||
"variance": 335,
|
||||
"where": 299,
|
||||
"xor": 354,
|
||||
"_": 264
|
||||
},
|
||||
"Minimum": 843,
|
||||
"Not": 1554,
|
||||
"Or": 970,
|
||||
"Query": 13896,
|
||||
"Range": 1594,
|
||||
"StringUtil": 4130,
|
||||
"Sum": 791,
|
||||
"Variable": 1124,
|
||||
"Variance": 1876,
|
||||
"Xor": 1101
|
||||
},
|
||||
"scale": {
|
||||
"IScaleMap": 2105,
|
||||
"LinearScale": 1316,
|
||||
"LogScale": 3151,
|
||||
"OrdinalScale": 3770,
|
||||
"QuantileScale": 2435,
|
||||
"QuantitativeScale": 4839,
|
||||
"RootScale": 1756,
|
||||
"Scale": 4268,
|
||||
"ScaleType": 1821,
|
||||
"TimeScale": 5833
|
||||
},
|
||||
"util": {
|
||||
"Arrays": 8258,
|
||||
"Colors": 10001,
|
||||
"Dates": 8217,
|
||||
"Displays": 12555,
|
||||
"Filter": 2324,
|
||||
"Geometry": 10993,
|
||||
"heap": {
|
||||
"FibonacciHeap": 9354,
|
||||
"HeapNode": 1233
|
||||
},
|
||||
"IEvaluable": 335,
|
||||
"IPredicate": 383,
|
||||
"IValueProxy": 874,
|
||||
"math": {
|
||||
"DenseMatrix": 3165,
|
||||
"IMatrix": 2815,
|
||||
"SparseMatrix": 3366
|
||||
},
|
||||
"Maths": 17705,
|
||||
"Orientation": 1486,
|
||||
"palette": {
|
||||
"ColorPalette": 6367,
|
||||
"Palette": 1229,
|
||||
"ShapePalette": 2059,
|
||||
"SizePalette": 2291
|
||||
},
|
||||
"Property": 5559,
|
||||
"Shapes": 19118,
|
||||
"Sort": 6887,
|
||||
"Stats": 6557,
|
||||
"Strings": 22026
|
||||
},
|
||||
"vis": {
|
||||
"axis": {
|
||||
"Axes": 1302,
|
||||
"Axis": 24593,
|
||||
"AxisGridLine": 652,
|
||||
"AxisLabel": 636,
|
||||
"CartesianAxes": 6703
|
||||
},
|
||||
"controls": {
|
||||
"AnchorControl": 2138,
|
||||
"ClickControl": 3824,
|
||||
"Control": 1353,
|
||||
"ControlList": 4665,
|
||||
"DragControl": 2649,
|
||||
"ExpandControl": 2832,
|
||||
"HoverControl": 4896,
|
||||
"IControl": 763,
|
||||
"PanZoomControl": 5222,
|
||||
"SelectionControl": 7862,
|
||||
"TooltipControl": 8435
|
||||
},
|
||||
"data": {
|
||||
"Data": 20544,
|
||||
"DataList": 19788,
|
||||
"DataSprite": 10349,
|
||||
"EdgeSprite": 3301,
|
||||
"NodeSprite": 19382,
|
||||
"render": {
|
||||
"ArrowType": 698,
|
||||
"EdgeRenderer": 5569,
|
||||
"IRenderer": 353,
|
||||
"ShapeRenderer": 2247
|
||||
},
|
||||
"ScaleBinding": 11275,
|
||||
"Tree": 7147,
|
||||
"TreeBuilder": 9930
|
||||
},
|
||||
"events": {
|
||||
"DataEvent": 2313,
|
||||
"SelectionEvent": 1880,
|
||||
"TooltipEvent": 1701,
|
||||
"VisualizationEvent": 1117
|
||||
},
|
||||
"legend": {
|
||||
"Legend": 20859,
|
||||
"LegendItem": 4614,
|
||||
"LegendRange": 10530
|
||||
},
|
||||
"operator": {
|
||||
"distortion": {
|
||||
"BifocalDistortion": 4461,
|
||||
"Distortion": 6314,
|
||||
"FisheyeDistortion": 3444
|
||||
},
|
||||
"encoder": {
|
||||
"ColorEncoder": 3179,
|
||||
"Encoder": 4060,
|
||||
"PropertyEncoder": 4138,
|
||||
"ShapeEncoder": 1690,
|
||||
"SizeEncoder": 1830
|
||||
},
|
||||
"filter": {
|
||||
"FisheyeTreeFilter": 5219,
|
||||
"GraphDistanceFilter": 3165,
|
||||
"VisibilityFilter": 3509
|
||||
},
|
||||
"IOperator": 1286,
|
||||
"label": {
|
||||
"Labeler": 9956,
|
||||
"RadialLabeler": 3899,
|
||||
"StackedAreaLabeler": 3202
|
||||
},
|
||||
"layout": {
|
||||
"AxisLayout": 6725,
|
||||
"BundledEdgeRouter": 3727,
|
||||
"CircleLayout": 9317,
|
||||
"CirclePackingLayout": 12003,
|
||||
"DendrogramLayout": 4853,
|
||||
"ForceDirectedLayout": 8411,
|
||||
"IcicleTreeLayout": 4864,
|
||||
"IndentedTreeLayout": 3174,
|
||||
"Layout": 7881,
|
||||
"NodeLinkTreeLayout": 12870,
|
||||
"PieLayout": 2728,
|
||||
"RadialTreeLayout": 12348,
|
||||
"RandomLayout": 870,
|
||||
"StackedAreaLayout": 9121,
|
||||
"TreeMapLayout": 9191
|
||||
},
|
||||
"Operator": 2490,
|
||||
"OperatorList": 5248,
|
||||
"OperatorSequence": 4190,
|
||||
"OperatorSwitch": 2581,
|
||||
"SortOperator": 2023
|
||||
},
|
||||
"Visualization": 16540
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
// Squarified Treemaps by Mark Bruls, Kees Huizing, and Jarke J. van Wijk
|
||||
function layout_treemap() {
|
||||
var children = layout_treemapChildren,
|
||||
value = layout_treemapValue,
|
||||
size = [1, 1]; // width, height
|
||||
|
||||
// Recursively compute the node depth and value.
|
||||
// Also converts the data representation into a standard tree structure.
|
||||
// Also sorts child nodes by descending value to optimize squarification.
|
||||
function sum(data, depth, nodes) {
|
||||
var datas = children.call(treemap, data, depth),
|
||||
node = {depth: depth, data: data};
|
||||
nodes.push(node);
|
||||
if (datas) {
|
||||
var i = -1,
|
||||
n = datas.length,
|
||||
c = node.children = [],
|
||||
v = 0,
|
||||
j = depth + 1;
|
||||
while (++i < n) {
|
||||
d = sum(datas[i], j, nodes);
|
||||
if (d.value > 0) { // ignore NaN, negative, etc.
|
||||
c.push(d);
|
||||
v += d.value;
|
||||
}
|
||||
}
|
||||
node.value = v;
|
||||
} else {
|
||||
node.value = value.call(treemap, data, depth);
|
||||
}
|
||||
if (!depth) scale(node, size[0] * size[1] / node.value); // root
|
||||
return node;
|
||||
}
|
||||
|
||||
// Recursively compute the node area based on value & scale.
|
||||
function scale(node, k) {
|
||||
var children = node.children;
|
||||
node.area = node.value * k;
|
||||
if (children) {
|
||||
var i = -1,
|
||||
n = children.length;
|
||||
while (++i < n) scale(children[i], k);
|
||||
}
|
||||
}
|
||||
|
||||
// Arranges the specified children into squarified rows.
|
||||
function squarify(children, node) {
|
||||
var rect = {x: node.x, y: node.y, dx: node.dx, dy: node.dy},
|
||||
row = [],
|
||||
child,
|
||||
best = Infinity, // the best row score so far
|
||||
score, // the current row score
|
||||
u = Math.min(rect.dx, rect.dy), // initial orientation
|
||||
n;
|
||||
children = children.slice(); // copy-on-write
|
||||
children.sort(function(a, b) { return b.area - a.area; });
|
||||
row.area = 0;
|
||||
while ((n = children.length) > 0) {
|
||||
row.push(child = children[n - 1]);
|
||||
row.area += child.area;
|
||||
if ((score = worst(row, u)) <= best) { // continue with this orientation
|
||||
children.pop();
|
||||
best = score;
|
||||
} else { // abort, and try a different orientation
|
||||
row.area -= row.pop().area;
|
||||
position(row, u, rect);
|
||||
u = Math.min(rect.dx, rect.dy);
|
||||
row.length = row.area = 0;
|
||||
best = Infinity;
|
||||
}
|
||||
}
|
||||
if (row.length) {
|
||||
position(row, u, rect);
|
||||
row.length = row.area = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the score for the specified row, as the worst aspect ratio.
|
||||
function worst(row, u) {
|
||||
var s = row.area,
|
||||
r,
|
||||
rmax = 0,
|
||||
rmin = Infinity,
|
||||
i = -1,
|
||||
n = row.length;
|
||||
while (++i < n) {
|
||||
r = row[i].area;
|
||||
if (r < rmin) rmin = r;
|
||||
if (r > rmax) rmax = r;
|
||||
}
|
||||
s *= s;
|
||||
u *= u;
|
||||
return Math.max((u * rmax) / s, s / (u * rmin));
|
||||
}
|
||||
|
||||
// Positions the specified row of nodes. Modifies `rect`.
|
||||
function position(row, u, rect) {
|
||||
var i = -1,
|
||||
n = row.length,
|
||||
x = rect.x,
|
||||
y = rect.y,
|
||||
v = u ? row.area / u : 0,
|
||||
o;
|
||||
if (u == rect.dx) { // horizontal subdivision
|
||||
while (++i < n) {
|
||||
o = row[i];
|
||||
o.x = x;
|
||||
o.y = y;
|
||||
o.dy = v;
|
||||
x += o.dx = o.area / v;
|
||||
}
|
||||
rect.y += v;
|
||||
rect.dy -= v;
|
||||
} else { // vertical subdivision
|
||||
while (++i < n) {
|
||||
o = row[i];
|
||||
o.x = x;
|
||||
o.y = y;
|
||||
o.dx = v;
|
||||
y += o.dy = o.area / v;
|
||||
}
|
||||
rect.x += v;
|
||||
rect.dx -= v;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively computes the treemap layout for the node and its children.
|
||||
function layout(node) {
|
||||
var children = node.children;
|
||||
if (children) {
|
||||
squarify(children, node);
|
||||
children.forEach(layout);
|
||||
}
|
||||
}
|
||||
|
||||
function treemap(d) {
|
||||
var nodes = [],
|
||||
root = sum(d, 0, nodes);
|
||||
root.x = 0;
|
||||
root.y = 0;
|
||||
root.dx = size[0];
|
||||
root.dy = size[1];
|
||||
layout(root);
|
||||
return nodes;
|
||||
}
|
||||
|
||||
treemap.children = function(x) {
|
||||
if (!arguments.length) return children;
|
||||
children = x;
|
||||
return treemap;
|
||||
};
|
||||
|
||||
treemap.value = function(x) {
|
||||
if (!arguments.length) return value;
|
||||
value = x;
|
||||
return treemap;
|
||||
};
|
||||
|
||||
treemap.size = function(x) {
|
||||
if (!arguments.length) return size;
|
||||
size = x;
|
||||
return treemap;
|
||||
};
|
||||
|
||||
return treemap;
|
||||
}
|
||||
|
||||
function layout_treemapChildren(d) {
|
||||
return d.children;
|
||||
}
|
||||
|
||||
function layout_treemapValue(d) {
|
||||
return d.value;
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<title>Treemap</title>
|
||||
<script type="text/javascript" src="../../d3.js"></script>
|
||||
<script type="text/javascript" src="layout.js"></script>
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
font: 10px sans-serif;
|
||||
}
|
||||
|
||||
.cell {
|
||||
position: absolute;
|
||||
background: lightsteelblue;
|
||||
border: solid 1px white;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<script type="text/javascript">
|
||||
|
||||
var w = 960,
|
||||
h = 500;
|
||||
|
||||
var div = d3.select("body").append("div")
|
||||
.style("position", "relative");
|
||||
|
||||
var treemap = layout_treemap()
|
||||
.size([w, h])
|
||||
.children(function(d, i) { return typeof d.value == "object" && d3.entries(d.value); })
|
||||
.value(function(d) { return d.value; });
|
||||
|
||||
d3.json("flare.json", function(json) {
|
||||
div.data([{key: "flare", value: json}]).selectAll("div")
|
||||
.data(treemap)
|
||||
.enter().append("div")
|
||||
.attr("class", "cell")
|
||||
.style("left", function(d) { return d.x + "px"; })
|
||||
.style("top", function(d) { return d.y + "px"; })
|
||||
.style("width", function(d) { return d.dx + "px"; })
|
||||
.style("height", function(d) { return d.dy + "px"; })
|
||||
.text(function(d) { return d.data.key; });
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче