rubyvis 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +13 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +37 -0
- data/History.txt +6 -0
- data/LICENSE.txt +23 -0
- data/{README.txt → README.md} +15 -12
- data/Rakefile +4 -11
- data/lib/rubyvis.rb +1 -1
- data/lib/rubyvis/scale/quantitative.rb +14 -18
- data/lib/rubyvis/scene/svg_label.rb +1 -1
- data/rubyvis.gemspec +21 -0
- data/spec/anchor_spec.rb +2 -1
- data/spec/line_spec.rb +2 -2
- data/spec/scale_linear_datetime_spec.rb +23 -8
- data/spec/spec_helper.rb +2 -1
- metadata +31 -214
- data/.gemtest +0 -0
- data/vendor/protovis/protovis-r3.3.js +0 -287
- data/vendor/protovis/src/behavior/Behavior.js +0 -32
- data/vendor/protovis/src/behavior/Drag.js +0 -112
- data/vendor/protovis/src/behavior/Pan.js +0 -110
- data/vendor/protovis/src/behavior/Point.js +0 -157
- data/vendor/protovis/src/behavior/Resize.js +0 -104
- data/vendor/protovis/src/behavior/Select.js +0 -100
- data/vendor/protovis/src/behavior/Zoom.js +0 -85
- data/vendor/protovis/src/color/Color.js +0 -598
- data/vendor/protovis/src/color/Colors.js +0 -135
- data/vendor/protovis/src/color/Ramp.js +0 -17
- data/vendor/protovis/src/data/Arrays.js +0 -277
- data/vendor/protovis/src/data/Dom.js +0 -380
- data/vendor/protovis/src/data/Flatten.js +0 -146
- data/vendor/protovis/src/data/Histogram.js +0 -120
- data/vendor/protovis/src/data/LinearScale.js +0 -54
- data/vendor/protovis/src/data/LogScale.js +0 -142
- data/vendor/protovis/src/data/Nest.js +0 -257
- data/vendor/protovis/src/data/Numbers.js +0 -313
- data/vendor/protovis/src/data/Objects.js +0 -78
- data/vendor/protovis/src/data/OrdinalScale.js +0 -267
- data/vendor/protovis/src/data/QuantileScale.js +0 -180
- data/vendor/protovis/src/data/QuantitativeScale.js +0 -440
- data/vendor/protovis/src/data/RootScale.js +0 -55
- data/vendor/protovis/src/data/Scale.js +0 -86
- data/vendor/protovis/src/data/Transform.js +0 -109
- data/vendor/protovis/src/data/Tree.js +0 -124
- data/vendor/protovis/src/data/Vector.js +0 -118
- data/vendor/protovis/src/geo/Geo.js +0 -5
- data/vendor/protovis/src/geo/GeoScale.js +0 -307
- data/vendor/protovis/src/geo/LatLng.js +0 -23
- data/vendor/protovis/src/geo/Projection.js +0 -43
- data/vendor/protovis/src/geo/Projections.js +0 -117
- data/vendor/protovis/src/lang/Array.js +0 -112
- data/vendor/protovis/src/lang/init.js +0 -26
- data/vendor/protovis/src/layout/Arc.js +0 -178
- data/vendor/protovis/src/layout/Bullet.js +0 -164
- data/vendor/protovis/src/layout/Cluster.js +0 -205
- data/vendor/protovis/src/layout/Force.js +0 -309
- data/vendor/protovis/src/layout/Grid.js +0 -119
- data/vendor/protovis/src/layout/Hierarchy.js +0 -249
- data/vendor/protovis/src/layout/Horizon.js +0 -159
- data/vendor/protovis/src/layout/Indent.js +0 -83
- data/vendor/protovis/src/layout/Layout.js +0 -56
- data/vendor/protovis/src/layout/Matrix.js +0 -177
- data/vendor/protovis/src/layout/Network.js +0 -302
- data/vendor/protovis/src/layout/Pack.js +0 -323
- data/vendor/protovis/src/layout/Partition.js +0 -203
- data/vendor/protovis/src/layout/Rollup.js +0 -203
- data/vendor/protovis/src/layout/Stack.js +0 -391
- data/vendor/protovis/src/layout/Tree.js +0 -282
- data/vendor/protovis/src/layout/Treemap.js +0 -347
- data/vendor/protovis/src/mark/Anchor.js +0 -81
- data/vendor/protovis/src/mark/Area.js +0 -268
- data/vendor/protovis/src/mark/Bar.js +0 -93
- data/vendor/protovis/src/mark/Dot.js +0 -212
- data/vendor/protovis/src/mark/Ease.js +0 -150
- data/vendor/protovis/src/mark/Image.js +0 -154
- data/vendor/protovis/src/mark/Label.js +0 -155
- data/vendor/protovis/src/mark/Line.js +0 -195
- data/vendor/protovis/src/mark/Mark.js +0 -1237
- data/vendor/protovis/src/mark/Panel.js +0 -273
- data/vendor/protovis/src/mark/Rule.js +0 -143
- data/vendor/protovis/src/mark/Transient.js +0 -7
- data/vendor/protovis/src/mark/Transition.js +0 -195
- data/vendor/protovis/src/mark/Wedge.js +0 -244
- data/vendor/protovis/src/physics/BoundConstraint.js +0 -75
- data/vendor/protovis/src/physics/ChargeForce.js +0 -184
- data/vendor/protovis/src/physics/CollisionConstraint.js +0 -113
- data/vendor/protovis/src/physics/Constraint.js +0 -26
- data/vendor/protovis/src/physics/DragForce.js +0 -49
- data/vendor/protovis/src/physics/Force.js +0 -25
- data/vendor/protovis/src/physics/Particle.js +0 -81
- data/vendor/protovis/src/physics/PositionConstraint.js +0 -72
- data/vendor/protovis/src/physics/Quadtree.js +0 -195
- data/vendor/protovis/src/physics/Simulation.js +0 -159
- data/vendor/protovis/src/physics/SpringForce.js +0 -141
- data/vendor/protovis/src/pv-internals.js +0 -154
- data/vendor/protovis/src/pv.js +0 -95
- data/vendor/protovis/src/scene/SvgArea.js +0 -172
- data/vendor/protovis/src/scene/SvgBar.js +0 -28
- data/vendor/protovis/src/scene/SvgCurve.js +0 -354
- data/vendor/protovis/src/scene/SvgDot.js +0 -81
- data/vendor/protovis/src/scene/SvgImage.js +0 -45
- data/vendor/protovis/src/scene/SvgLabel.js +0 -46
- data/vendor/protovis/src/scene/SvgLine.js +0 -159
- data/vendor/protovis/src/scene/SvgPanel.js +0 -126
- data/vendor/protovis/src/scene/SvgRule.js +0 -26
- data/vendor/protovis/src/scene/SvgScene.js +0 -185
- data/vendor/protovis/src/scene/SvgWedge.js +0 -66
- data/vendor/protovis/src/text/DateFormat.js +0 -262
- data/vendor/protovis/src/text/Format.js +0 -78
- data/vendor/protovis/src/text/NumberFormat.js +0 -227
- data/vendor/protovis/src/text/TimeFormat.js +0 -115
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
// ranges (bad, satisfactory, good)
|
|
2
|
-
// measures (actual, forecast)
|
|
3
|
-
// markers (previous, goal)
|
|
4
|
-
|
|
5
|
-
/*
|
|
6
|
-
* Chart design based on the recommendations of Stephen Few. Implementation
|
|
7
|
-
* based on the work of Clint Ivy, Jamie Love, and Jason Davies.
|
|
8
|
-
* http://projects.instantcognition.com/protovis/bulletchart/
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Constructs a new, empty bullet layout. Layouts are not typically constructed
|
|
13
|
-
* directly; instead, they are added to an existing panel via
|
|
14
|
-
* {@link pv.Mark#add}.
|
|
15
|
-
*
|
|
16
|
-
* @class
|
|
17
|
-
* @extends pv.Layout
|
|
18
|
-
*/
|
|
19
|
-
pv.Layout.Bullet = function() {
|
|
20
|
-
pv.Layout.call(this);
|
|
21
|
-
var that = this,
|
|
22
|
-
buildImplied = that.buildImplied,
|
|
23
|
-
scale = that.x = pv.Scale.linear(),
|
|
24
|
-
orient,
|
|
25
|
-
horizontal,
|
|
26
|
-
rangeColor,
|
|
27
|
-
measureColor,
|
|
28
|
-
x;
|
|
29
|
-
|
|
30
|
-
/** @private Cache layout state to optimize properties. */
|
|
31
|
-
this.buildImplied = function(s) {
|
|
32
|
-
buildImplied.call(this, x = s);
|
|
33
|
-
orient = s.orient;
|
|
34
|
-
horizontal = /^left|right$/.test(orient);
|
|
35
|
-
rangeColor = pv.ramp("#bbb", "#eee")
|
|
36
|
-
.domain(0, Math.max(1, x.ranges.length - 1));
|
|
37
|
-
measureColor = pv.ramp("steelblue", "lightsteelblue")
|
|
38
|
-
.domain(0, Math.max(1, x.measures.length - 1));
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* The range prototype.
|
|
43
|
-
*
|
|
44
|
-
* @type pv.Mark
|
|
45
|
-
* @name pv.Layout.Bullet.prototype.range
|
|
46
|
-
*/
|
|
47
|
-
(this.range = new pv.Mark())
|
|
48
|
-
.data(function() { return x.ranges; })
|
|
49
|
-
.reverse(true)
|
|
50
|
-
.left(function() { return orient == "left" ? 0 : null; })
|
|
51
|
-
.top(function() { return orient == "top" ? 0 : null; })
|
|
52
|
-
.right(function() { return orient == "right" ? 0 : null; })
|
|
53
|
-
.bottom(function() { return orient == "bottom" ? 0 : null; })
|
|
54
|
-
.width(function(d) { return horizontal ? scale(d) : null; })
|
|
55
|
-
.height(function(d) { return horizontal ? null : scale(d); })
|
|
56
|
-
.fillStyle(function() { return rangeColor(this.index); })
|
|
57
|
-
.antialias(false)
|
|
58
|
-
.parent = that;
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* The measure prototype.
|
|
62
|
-
*
|
|
63
|
-
* @type pv.Mark
|
|
64
|
-
* @name pv.Layout.Bullet.prototype.measure
|
|
65
|
-
*/
|
|
66
|
-
(this.measure = new pv.Mark())
|
|
67
|
-
.extend(this.range)
|
|
68
|
-
.data(function() { return x.measures; })
|
|
69
|
-
.left(function() { return orient == "left" ? 0 : horizontal ? null : this.parent.width() / 3.25; })
|
|
70
|
-
.top(function() { return orient == "top" ? 0 : horizontal ? this.parent.height() / 3.25 : null; })
|
|
71
|
-
.right(function() { return orient == "right" ? 0 : horizontal ? null : this.parent.width() / 3.25; })
|
|
72
|
-
.bottom(function() { return orient == "bottom" ? 0 : horizontal ? this.parent.height() / 3.25 : null; })
|
|
73
|
-
.fillStyle(function() { return measureColor(this.index); })
|
|
74
|
-
.parent = that;
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* The marker prototype.
|
|
78
|
-
*
|
|
79
|
-
* @type pv.Mark
|
|
80
|
-
* @name pv.Layout.Bullet.prototype.marker
|
|
81
|
-
*/
|
|
82
|
-
(this.marker = new pv.Mark())
|
|
83
|
-
.data(function() { return x.markers; })
|
|
84
|
-
.left(function(d) { return orient == "left" ? scale(d) : horizontal ? null : this.parent.width() / 2; })
|
|
85
|
-
.top(function(d) { return orient == "top" ? scale(d) : horizontal ? this.parent.height() / 2 : null; })
|
|
86
|
-
.right(function(d) { return orient == "right" ? scale(d) : null; })
|
|
87
|
-
.bottom(function(d) { return orient == "bottom" ? scale(d) : null; })
|
|
88
|
-
.strokeStyle("black")
|
|
89
|
-
.shape("bar")
|
|
90
|
-
.shapeAngle(function() { return horizontal ? 0 : Math.PI / 2; })
|
|
91
|
-
.parent = that;
|
|
92
|
-
|
|
93
|
-
(this.tick = new pv.Mark())
|
|
94
|
-
.data(function() { return scale.ticks(7); })
|
|
95
|
-
.left(function(d) { return orient == "left" ? scale(d) : null; })
|
|
96
|
-
.top(function(d) { return orient == "top" ? scale(d) : null; })
|
|
97
|
-
.right(function(d) { return orient == "right" ? scale(d) : horizontal ? null : -6; })
|
|
98
|
-
.bottom(function(d) { return orient == "bottom" ? scale(d) : horizontal ? -8 : null; })
|
|
99
|
-
.height(function() { return horizontal ? 6 : null; })
|
|
100
|
-
.width(function() { return horizontal ? null : 6; })
|
|
101
|
-
.parent = that;
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
pv.Layout.Bullet.prototype = pv.extend(pv.Layout)
|
|
105
|
-
.property("orient", String) // left, right, top, bottom
|
|
106
|
-
.property("ranges")
|
|
107
|
-
.property("markers")
|
|
108
|
-
.property("measures")
|
|
109
|
-
.property("maximum", Number);
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Default properties for bullet layouts.
|
|
113
|
-
*
|
|
114
|
-
* @type pv.Layout.Bullet
|
|
115
|
-
*/
|
|
116
|
-
pv.Layout.Bullet.prototype.defaults = new pv.Layout.Bullet()
|
|
117
|
-
.extend(pv.Layout.prototype.defaults)
|
|
118
|
-
.orient("left")
|
|
119
|
-
.ranges([])
|
|
120
|
-
.markers([])
|
|
121
|
-
.measures([]);
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* The orientation.
|
|
125
|
-
*
|
|
126
|
-
* @type string
|
|
127
|
-
* @name pv.Layout.Bullet.prototype.orient
|
|
128
|
-
*/
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* The array of range values.
|
|
132
|
-
*
|
|
133
|
-
* @type array
|
|
134
|
-
* @name pv.Layout.Bullet.prototype.ranges
|
|
135
|
-
*/
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* The array of marker values.
|
|
139
|
-
*
|
|
140
|
-
* @type array
|
|
141
|
-
* @name pv.Layout.Bullet.prototype.markers
|
|
142
|
-
*/
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* The array of measure values.
|
|
146
|
-
*
|
|
147
|
-
* @type array
|
|
148
|
-
* @name pv.Layout.Bullet.prototype.measures
|
|
149
|
-
*/
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Optional; the maximum range value.
|
|
153
|
-
*
|
|
154
|
-
* @type number
|
|
155
|
-
* @name pv.Layout.Bullet.prototype.maximum
|
|
156
|
-
*/
|
|
157
|
-
|
|
158
|
-
/** @private */
|
|
159
|
-
pv.Layout.Bullet.prototype.buildImplied = function(s) {
|
|
160
|
-
pv.Layout.prototype.buildImplied.call(this, s);
|
|
161
|
-
var size = this.parent[/^left|right$/.test(s.orient) ? "width" : "height"]();
|
|
162
|
-
s.maximum = s.maximum || pv.max([].concat(s.ranges, s.markers, s.measures));
|
|
163
|
-
this.x.domain(0, s.maximum).range(0, size);
|
|
164
|
-
};
|
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Constructs a new, empty cluster layout. Layouts are not typically
|
|
3
|
-
* constructed directly; instead, they are added to an existing panel via
|
|
4
|
-
* {@link pv.Mark#add}.
|
|
5
|
-
*
|
|
6
|
-
* @class Implements a hierarchical layout using the cluster (or dendrogram)
|
|
7
|
-
* algorithm. This layout provides both node-link and space-filling
|
|
8
|
-
* implementations of cluster diagrams. In many ways it is similar to
|
|
9
|
-
* {@link pv.Layout.Partition}, except that leaf nodes are positioned at maximum
|
|
10
|
-
* depth, and the depth of internal nodes is based on their distance from their
|
|
11
|
-
* deepest descendant, rather than their distance from the root.
|
|
12
|
-
*
|
|
13
|
-
* <p>The cluster layout supports a "group" property, which if true causes
|
|
14
|
-
* siblings to be positioned closer together than unrelated nodes at the same
|
|
15
|
-
* depth. Unlike the partition layout, this layout does not support dynamic
|
|
16
|
-
* sizing for leaf nodes; all leaf nodes are the same size.
|
|
17
|
-
*
|
|
18
|
-
* <p>For more details on how to use this layout, see
|
|
19
|
-
* {@link pv.Layout.Hierarchy}.
|
|
20
|
-
*
|
|
21
|
-
* @see pv.Layout.Cluster.Fill
|
|
22
|
-
* @extends pv.Layout.Hierarchy
|
|
23
|
-
*/
|
|
24
|
-
pv.Layout.Cluster = function() {
|
|
25
|
-
pv.Layout.Hierarchy.call(this);
|
|
26
|
-
var interpolate, // cached interpolate
|
|
27
|
-
buildImplied = this.buildImplied;
|
|
28
|
-
|
|
29
|
-
/** @private Cache layout state to optimize properties. */
|
|
30
|
-
this.buildImplied = function(s) {
|
|
31
|
-
buildImplied.call(this, s);
|
|
32
|
-
interpolate
|
|
33
|
-
= /^(top|bottom)$/.test(s.orient) ? "step-before"
|
|
34
|
-
: /^(left|right)$/.test(s.orient) ? "step-after"
|
|
35
|
-
: "linear";
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
this.link.interpolate(function() { return interpolate; });
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
pv.Layout.Cluster.prototype = pv.extend(pv.Layout.Hierarchy)
|
|
42
|
-
.property("group", Number)
|
|
43
|
-
.property("orient", String)
|
|
44
|
-
.property("innerRadius", Number)
|
|
45
|
-
.property("outerRadius", Number);
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* The group parameter; defaults to 0, disabling grouping of siblings. If this
|
|
49
|
-
* parameter is set to a positive number (or true, which is equivalent to 1),
|
|
50
|
-
* then additional space will be allotted between sibling groups. In other
|
|
51
|
-
* words, siblings (nodes that share the same parent) will be positioned more
|
|
52
|
-
* closely than nodes at the same depth that do not share a parent.
|
|
53
|
-
*
|
|
54
|
-
* @type number
|
|
55
|
-
* @name pv.Layout.Cluster.prototype.group
|
|
56
|
-
*/
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* The orientation. The default orientation is "top", which means that the root
|
|
60
|
-
* node is placed on the top edge, leaf nodes appear on the bottom edge, and
|
|
61
|
-
* internal nodes are in-between. The following orientations are supported:<ul>
|
|
62
|
-
*
|
|
63
|
-
* <li>left - left-to-right.
|
|
64
|
-
* <li>right - right-to-left.
|
|
65
|
-
* <li>top - top-to-bottom.
|
|
66
|
-
* <li>bottom - bottom-to-top.
|
|
67
|
-
* <li>radial - radially, with the root at the center.</ul>
|
|
68
|
-
*
|
|
69
|
-
* @type string
|
|
70
|
-
* @name pv.Layout.Cluster.prototype.orient
|
|
71
|
-
*/
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* The inner radius; defaults to 0. This property applies only to radial
|
|
75
|
-
* orientations, and can be used to compress the layout radially. Note that for
|
|
76
|
-
* the node-link implementation, the root node is always at the center,
|
|
77
|
-
* regardless of the value of this property; this property only affects internal
|
|
78
|
-
* and leaf nodes. For the space-filling implementation, a non-zero value of
|
|
79
|
-
* this property will result in the root node represented as a ring rather than
|
|
80
|
-
* a circle.
|
|
81
|
-
*
|
|
82
|
-
* @type number
|
|
83
|
-
* @name pv.Layout.Cluster.prototype.innerRadius
|
|
84
|
-
*/
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* The outer radius; defaults to fill the containing panel, based on the height
|
|
88
|
-
* and width of the layout. If the layout has no height and width specified, it
|
|
89
|
-
* will extend to fill the enclosing panel.
|
|
90
|
-
*
|
|
91
|
-
* @type number
|
|
92
|
-
* @name pv.Layout.Cluster.prototype.outerRadius
|
|
93
|
-
*/
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Defaults for cluster layouts. The default group parameter is 0 and the
|
|
97
|
-
* default orientation is "top".
|
|
98
|
-
*
|
|
99
|
-
* @type pv.Layout.Cluster
|
|
100
|
-
*/
|
|
101
|
-
pv.Layout.Cluster.prototype.defaults = new pv.Layout.Cluster()
|
|
102
|
-
.extend(pv.Layout.Hierarchy.prototype.defaults)
|
|
103
|
-
.group(0)
|
|
104
|
-
.orient("top");
|
|
105
|
-
|
|
106
|
-
/** @private */
|
|
107
|
-
pv.Layout.Cluster.prototype.buildImplied = function(s) {
|
|
108
|
-
if (pv.Layout.Hierarchy.prototype.buildImplied.call(this, s)) return;
|
|
109
|
-
|
|
110
|
-
var root = s.nodes[0],
|
|
111
|
-
group = s.group,
|
|
112
|
-
breadth,
|
|
113
|
-
depth,
|
|
114
|
-
leafCount = 0,
|
|
115
|
-
leafIndex = .5 - group / 2;
|
|
116
|
-
|
|
117
|
-
/* Count the leaf nodes and compute the depth of descendants. */
|
|
118
|
-
var p = undefined;
|
|
119
|
-
root.visitAfter(function(n) {
|
|
120
|
-
if (n.firstChild) {
|
|
121
|
-
n.depth = 1 + pv.max(n.childNodes, function(n) { return n.depth; });
|
|
122
|
-
} else {
|
|
123
|
-
if (group && (p != n.parentNode)) {
|
|
124
|
-
p = n.parentNode;
|
|
125
|
-
leafCount += group;
|
|
126
|
-
}
|
|
127
|
-
leafCount++;
|
|
128
|
-
n.depth = 0;
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
breadth = 1 / leafCount;
|
|
132
|
-
depth = 1 / root.depth;
|
|
133
|
-
|
|
134
|
-
/* Compute the unit breadth and depth of each node. */
|
|
135
|
-
var p = undefined;
|
|
136
|
-
root.visitAfter(function(n) {
|
|
137
|
-
if (n.firstChild) {
|
|
138
|
-
n.breadth = pv.mean(n.childNodes, function(n) { return n.breadth; });
|
|
139
|
-
} else {
|
|
140
|
-
if (group && (p != n.parentNode)) {
|
|
141
|
-
p = n.parentNode;
|
|
142
|
-
leafIndex += group;
|
|
143
|
-
}
|
|
144
|
-
n.breadth = breadth * leafIndex++;
|
|
145
|
-
}
|
|
146
|
-
n.depth = 1 - n.depth * depth;
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
/* Compute breadth and depth ranges for space-filling layouts. */
|
|
150
|
-
root.visitAfter(function(n) {
|
|
151
|
-
n.minBreadth = n.firstChild
|
|
152
|
-
? n.firstChild.minBreadth
|
|
153
|
-
: (n.breadth - breadth / 2);
|
|
154
|
-
n.maxBreadth = n.firstChild
|
|
155
|
-
? n.lastChild.maxBreadth
|
|
156
|
-
: (n.breadth + breadth / 2);
|
|
157
|
-
});
|
|
158
|
-
root.visitBefore(function(n) {
|
|
159
|
-
n.minDepth = n.parentNode
|
|
160
|
-
? n.parentNode.maxDepth
|
|
161
|
-
: 0;
|
|
162
|
-
n.maxDepth = n.parentNode
|
|
163
|
-
? (n.depth + root.depth)
|
|
164
|
-
: (n.minDepth + 2 * root.depth);
|
|
165
|
-
});
|
|
166
|
-
root.minDepth = -depth;
|
|
167
|
-
|
|
168
|
-
pv.Layout.Hierarchy.NodeLink.buildImplied.call(this, s);
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Constructs a new, empty space-filling cluster layout. Layouts are not
|
|
173
|
-
* typically constructed directly; instead, they are added to an existing panel
|
|
174
|
-
* via {@link pv.Mark#add}.
|
|
175
|
-
*
|
|
176
|
-
* @class A variant of cluster layout that is space-filling. The meaning of the
|
|
177
|
-
* exported mark prototypes changes slightly in the space-filling
|
|
178
|
-
* implementation:<ul>
|
|
179
|
-
*
|
|
180
|
-
* <li><tt>node</tt> - for rendering nodes; typically a {@link pv.Bar} for
|
|
181
|
-
* non-radial orientations, and a {@link pv.Wedge} for radial orientations.
|
|
182
|
-
*
|
|
183
|
-
* <p><li><tt>link</tt> - unsupported; undefined. Links are encoded implicitly
|
|
184
|
-
* in the arrangement of the space-filling nodes.
|
|
185
|
-
*
|
|
186
|
-
* <p><li><tt>label</tt> - for rendering node labels; typically a
|
|
187
|
-
* {@link pv.Label}.
|
|
188
|
-
*
|
|
189
|
-
* </ul>For more details on how to use this layout, see
|
|
190
|
-
* {@link pv.Layout.Cluster}.
|
|
191
|
-
*
|
|
192
|
-
* @extends pv.Layout.Cluster
|
|
193
|
-
*/
|
|
194
|
-
pv.Layout.Cluster.Fill = function() {
|
|
195
|
-
pv.Layout.Cluster.call(this);
|
|
196
|
-
pv.Layout.Hierarchy.Fill.constructor.call(this);
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
pv.Layout.Cluster.Fill.prototype = pv.extend(pv.Layout.Cluster);
|
|
200
|
-
|
|
201
|
-
/** @private */
|
|
202
|
-
pv.Layout.Cluster.Fill.prototype.buildImplied = function(s) {
|
|
203
|
-
if (pv.Layout.Cluster.prototype.buildImplied.call(this, s)) return;
|
|
204
|
-
pv.Layout.Hierarchy.Fill.buildImplied.call(this, s);
|
|
205
|
-
};
|
|
@@ -1,309 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Constructs a new, empty force-directed layout. Layouts are not typically
|
|
3
|
-
* constructed directly; instead, they are added to an existing panel via
|
|
4
|
-
* {@link pv.Mark#add}.
|
|
5
|
-
*
|
|
6
|
-
* @class Implements force-directed network layout as a node-link diagram. This
|
|
7
|
-
* layout uses the Fruchterman-Reingold algorithm, which applies an attractive
|
|
8
|
-
* spring force between neighboring nodes, and a repulsive electrical charge
|
|
9
|
-
* force between all nodes. An additional drag force improves stability of the
|
|
10
|
-
* simulation. See {@link pv.Force.spring}, {@link pv.Force.drag} and {@link
|
|
11
|
-
* pv.Force.charge} for more details; note that the n-body charge force is
|
|
12
|
-
* approximated using the Barnes-Hut algorithm.
|
|
13
|
-
*
|
|
14
|
-
* <p>This layout is implemented on top of {@link pv.Simulation}, which can be
|
|
15
|
-
* used directly for more control over simulation parameters. The simulation
|
|
16
|
-
* uses Position Verlet integration, which does not compute velocities
|
|
17
|
-
* explicitly, but allows for easy geometric constraints, such as bounding the
|
|
18
|
-
* nodes within the layout panel. Many of the configuration properties supported
|
|
19
|
-
* by this layout are simply passed through to the underlying forces and
|
|
20
|
-
* constraints of the simulation.
|
|
21
|
-
*
|
|
22
|
-
* <p>Force layouts are typically interactive. The gradual movement of the nodes
|
|
23
|
-
* as they stabilize to a local stress minimum can help reveal the structure of
|
|
24
|
-
* the network, as can {@link pv.Behavior.drag}, which allows the user to pick
|
|
25
|
-
* up nodes and reposition them while the physics simulation continues. This
|
|
26
|
-
* layout can also be used with pan & zoom behaviors for interaction.
|
|
27
|
-
*
|
|
28
|
-
* <p>To facilitate interaction, this layout by default automatically re-renders
|
|
29
|
-
* using a <tt>setInterval</tt> every 42 milliseconds. This can be disabled via
|
|
30
|
-
* the <tt>iterations</tt> property, which if non-null specifies the number of
|
|
31
|
-
* simulation iterations to run before the force-directed layout is finalized.
|
|
32
|
-
* Be careful not to use too high an iteration count, as this can lead to an
|
|
33
|
-
* annoying delay on page load.
|
|
34
|
-
*
|
|
35
|
-
* <p>As with other network layouts, the network data can be updated
|
|
36
|
-
* dynamically, provided the property cache is reset. See
|
|
37
|
-
* {@link pv.Layout.Network} for details. New nodes are initialized with random
|
|
38
|
-
* positions near the center. Alternatively, positions can be specified manually
|
|
39
|
-
* by setting the <tt>x</tt> and <tt>y</tt> attributes on nodes.
|
|
40
|
-
*
|
|
41
|
-
* @extends pv.Layout.Network
|
|
42
|
-
* @see <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.8444&rep=rep1&type=pdf"
|
|
43
|
-
* >"Graph Drawing by Force-directed Placement"</a> by T. Fruchterman &
|
|
44
|
-
* E. Reingold, Software--Practice & Experience, November 1991.
|
|
45
|
-
*/
|
|
46
|
-
pv.Layout.Force = function() {
|
|
47
|
-
pv.Layout.Network.call(this);
|
|
48
|
-
|
|
49
|
-
/* Force-directed graphs can be messy, so reduce the link width. */
|
|
50
|
-
this.link.lineWidth(function(d, p) { return Math.sqrt(p.linkValue) * 1.5; });
|
|
51
|
-
this.label.textAlign("center");
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
pv.Layout.Force.prototype = pv.extend(pv.Layout.Network)
|
|
55
|
-
.property("bound", Boolean)
|
|
56
|
-
.property("iterations", Number)
|
|
57
|
-
.property("dragConstant", Number)
|
|
58
|
-
.property("chargeConstant", Number)
|
|
59
|
-
.property("chargeMinDistance", Number)
|
|
60
|
-
.property("chargeMaxDistance", Number)
|
|
61
|
-
.property("chargeTheta", Number)
|
|
62
|
-
.property("springConstant", Number)
|
|
63
|
-
.property("springDamping", Number)
|
|
64
|
-
.property("springLength", Number);
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* The bound parameter; true if nodes should be constrained within the layout
|
|
68
|
-
* panel. Bounding is disabled by default. Currently the layout does not observe
|
|
69
|
-
* the radius of the nodes; strictly speaking, only the center of the node is
|
|
70
|
-
* constrained to be within the panel, with an additional 6-pixel offset for
|
|
71
|
-
* padding. A future enhancement could extend the bound constraint to observe
|
|
72
|
-
* the node's radius, which would also support bounding for variable-size nodes.
|
|
73
|
-
*
|
|
74
|
-
* <p>Note that if this layout is used in conjunction with pan & zoom
|
|
75
|
-
* behaviors, those behaviors should have their bound parameter set to the same
|
|
76
|
-
* value.
|
|
77
|
-
*
|
|
78
|
-
* @type boolean
|
|
79
|
-
* @name pv.Layout.Force.prototype.bound
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* The number of simulation iterations to run, or null if this layout is
|
|
84
|
-
* interactive. Force-directed layouts are interactive by default, using a
|
|
85
|
-
* <tt>setInterval</tt> to advance the physics simulation and re-render
|
|
86
|
-
* automatically.
|
|
87
|
-
*
|
|
88
|
-
* @type number
|
|
89
|
-
* @name pv.Layout.Force.prototype.iterations
|
|
90
|
-
*/
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* The drag constant, in the range [0,1]. A value of 0 means no drag (a
|
|
94
|
-
* perfectly frictionless environment), while a value of 1 means friction
|
|
95
|
-
* immediately cancels all momentum. The default value is 0.1, which provides a
|
|
96
|
-
* minimum amount of drag that helps stabilize bouncy springs; lower values may
|
|
97
|
-
* result in excessive bounciness, while higher values cause the simulation to
|
|
98
|
-
* take longer to converge.
|
|
99
|
-
*
|
|
100
|
-
* @type number
|
|
101
|
-
* @name pv.Layout.Force.prototype.dragConstant
|
|
102
|
-
* @see pv.Force.drag#constant
|
|
103
|
-
*/
|
|
104
|
-
|
|
105
|
-
/**
|
|
106
|
-
* The charge constant, which should be a negative number. The default value is
|
|
107
|
-
* -40; more negative values will result in a stronger repulsive force, which
|
|
108
|
-
* may lead to faster convergence at the risk of instability. Too strong
|
|
109
|
-
* repulsive charge forces can cause comparatively weak springs to be stretched
|
|
110
|
-
* well beyond their rest length, emphasizing global structure over local
|
|
111
|
-
* structure. A nonnegative value will break the Fruchterman-Reingold algorithm,
|
|
112
|
-
* and is for entertainment purposes only.
|
|
113
|
-
*
|
|
114
|
-
* @type number
|
|
115
|
-
* @name pv.Layout.Force.prototype.chargeConstant
|
|
116
|
-
* @see pv.Force.charge#constant
|
|
117
|
-
*/
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* The minimum distance at which charge forces are applied. The default minimum
|
|
121
|
-
* distance of 2 avoids applying forces that are two strong; because the physics
|
|
122
|
-
* simulation is run at discrete time intervals, it is possible for two same-
|
|
123
|
-
* charged particles to become very close or even a singularity! Since the
|
|
124
|
-
* charge force is inversely proportional to the square of the distance, very
|
|
125
|
-
* small distances can break the simulation.
|
|
126
|
-
*
|
|
127
|
-
* <p>In rare cases, two particles can become stuck on top of each other, as a
|
|
128
|
-
* minimum distance threshold will prevent the charge force from repelling them.
|
|
129
|
-
* However, this occurs very rarely because other forces and momentum typically
|
|
130
|
-
* cause the particles to become separated again, at which point the repulsive
|
|
131
|
-
* charge force kicks in.
|
|
132
|
-
*
|
|
133
|
-
* @type number
|
|
134
|
-
* @name pv.Layout.Force.prototype.chargeMinDistance
|
|
135
|
-
* @see pv.Force.charge#domain
|
|
136
|
-
*/
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* The maximum distance at which charge forces are applied. This improves
|
|
140
|
-
* performance by ignoring weak charge forces at great distances. Note that this
|
|
141
|
-
* parameter is partly redundant, as the Barnes-Hut algorithm for n-body forces
|
|
142
|
-
* already improves performance for far-away particles through approximation.
|
|
143
|
-
*
|
|
144
|
-
* @type number
|
|
145
|
-
* @name pv.Layout.Force.prototype.chargeMaxDistance
|
|
146
|
-
* @see pv.Force.charge#domain
|
|
147
|
-
*/
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* The Barnes-Hut approximation factor. The Barnes-Hut approximation criterion
|
|
151
|
-
* is the ratio of the size of the quadtree node to the distance from the point
|
|
152
|
-
* to the node's center of mass is beneath some threshold. The default value is
|
|
153
|
-
* 0.9.
|
|
154
|
-
*
|
|
155
|
-
* @type number
|
|
156
|
-
* @name pv.Layout.Force.prototype.chargeTheta
|
|
157
|
-
* @see pv.Force.charge#theta
|
|
158
|
-
*/
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* The spring constant, which should be a positive number. The default value is
|
|
162
|
-
* 0.1; greater values will result in a stronger attractive force, which may
|
|
163
|
-
* lead to faster convergence at the risk of instability. Too strong spring
|
|
164
|
-
* forces can cause comparatively weak charge forces to be ignored, emphasizing
|
|
165
|
-
* local structure over global structure. A nonpositive value will break the
|
|
166
|
-
* Fruchterman-Reingold algorithm, and is for entertainment purposes only.
|
|
167
|
-
*
|
|
168
|
-
* <p>The spring tension is automatically normalized using the inverse square
|
|
169
|
-
* root of the maximum link degree of attached nodes.
|
|
170
|
-
*
|
|
171
|
-
* @type number
|
|
172
|
-
* @name pv.Layout.Force.prototype.springConstant
|
|
173
|
-
* @see pv.Force.spring#constant
|
|
174
|
-
*/
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* The spring damping factor, in the range [0,1]. Damping functions identically
|
|
178
|
-
* to drag forces, damping spring bounciness by applying a force in the opposite
|
|
179
|
-
* direction of attached nodes' velocities. The default value is 0.3.
|
|
180
|
-
*
|
|
181
|
-
* <p>The spring damping is automatically normalized using the inverse square
|
|
182
|
-
* root of the maximum link degree of attached nodes.
|
|
183
|
-
*
|
|
184
|
-
* @type number
|
|
185
|
-
* @name pv.Layout.Force.prototype.springDamping
|
|
186
|
-
* @see pv.Force.spring#damping
|
|
187
|
-
*/
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* The spring rest length. The default value is 20 pixels. Larger values may be
|
|
191
|
-
* appropriate if the layout panel is larger, or if the nodes are rendered
|
|
192
|
-
* larger than the default dot size of 20.
|
|
193
|
-
*
|
|
194
|
-
* @type number
|
|
195
|
-
* @name pv.Layout.Force.prototype.springLength
|
|
196
|
-
* @see pv.Force.spring#length
|
|
197
|
-
*/
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Default properties for force-directed layouts. The default drag constant is
|
|
201
|
-
* 0.1, the default charge constant is -40 (with a domain of [2, 500] and theta
|
|
202
|
-
* of 0.9), and the default spring constant is 0.1 (with a damping of 0.3 and a
|
|
203
|
-
* rest length of 20).
|
|
204
|
-
*
|
|
205
|
-
* @type pv.Layout.Force
|
|
206
|
-
*/
|
|
207
|
-
pv.Layout.Force.prototype.defaults = new pv.Layout.Force()
|
|
208
|
-
.extend(pv.Layout.Network.prototype.defaults)
|
|
209
|
-
.dragConstant(.1)
|
|
210
|
-
.chargeConstant(-40)
|
|
211
|
-
.chargeMinDistance(2)
|
|
212
|
-
.chargeMaxDistance(500)
|
|
213
|
-
.chargeTheta(.9)
|
|
214
|
-
.springConstant(.1)
|
|
215
|
-
.springDamping(.3)
|
|
216
|
-
.springLength(20);
|
|
217
|
-
|
|
218
|
-
/** @private Initialize the physics simulation. */
|
|
219
|
-
pv.Layout.Force.prototype.buildImplied = function(s) {
|
|
220
|
-
|
|
221
|
-
/* Any cached interactive layouts need to be rebound for the timer. */
|
|
222
|
-
if (pv.Layout.Network.prototype.buildImplied.call(this, s)) {
|
|
223
|
-
var f = s.$force;
|
|
224
|
-
if (f) {
|
|
225
|
-
f.next = this.binds.$force;
|
|
226
|
-
this.binds.$force = f;
|
|
227
|
-
}
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
var that = this,
|
|
232
|
-
nodes = s.nodes,
|
|
233
|
-
links = s.links,
|
|
234
|
-
k = s.iterations,
|
|
235
|
-
w = s.width,
|
|
236
|
-
h = s.height;
|
|
237
|
-
|
|
238
|
-
/* Initialize positions randomly near the center. */
|
|
239
|
-
for (var i = 0, n; i < nodes.length; i++) {
|
|
240
|
-
n = nodes[i];
|
|
241
|
-
if (isNaN(n.x)) n.x = w / 2 + 40 * Math.random() - 20;
|
|
242
|
-
if (isNaN(n.y)) n.y = h / 2 + 40 * Math.random() - 20;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/* Initialize the simulation. */
|
|
246
|
-
var sim = pv.simulation(nodes);
|
|
247
|
-
|
|
248
|
-
/* Drag force. */
|
|
249
|
-
sim.force(pv.Force.drag(s.dragConstant));
|
|
250
|
-
|
|
251
|
-
/* Charge (repelling) force. */
|
|
252
|
-
sim.force(pv.Force.charge(s.chargeConstant)
|
|
253
|
-
.domain(s.chargeMinDistance, s.chargeMaxDistance)
|
|
254
|
-
.theta(s.chargeTheta));
|
|
255
|
-
|
|
256
|
-
/* Spring (attracting) force. */
|
|
257
|
-
sim.force(pv.Force.spring(s.springConstant)
|
|
258
|
-
.damping(s.springDamping)
|
|
259
|
-
.length(s.springLength)
|
|
260
|
-
.links(links));
|
|
261
|
-
|
|
262
|
-
/* Position constraint (for interactive dragging). */
|
|
263
|
-
sim.constraint(pv.Constraint.position());
|
|
264
|
-
|
|
265
|
-
/* Optionally add bound constraint. TODO: better padding. */
|
|
266
|
-
if (s.bound) {
|
|
267
|
-
sim.constraint(pv.Constraint.bound().x(6, w - 6).y(6, h - 6));
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
/** @private Returns the speed of the given node, to determine cooling. */
|
|
271
|
-
function speed(n) {
|
|
272
|
-
return n.fix ? 1 : n.vx * n.vx + n.vy * n.vy;
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/*
|
|
276
|
-
* If the iterations property is null (the default), the layout is
|
|
277
|
-
* interactive. The simulation is run until the fastest particle drops below
|
|
278
|
-
* an arbitrary minimum speed. Although the timer keeps firing, this speed
|
|
279
|
-
* calculation is fast so there is minimal CPU overhead. Note: if a particle
|
|
280
|
-
* is fixed for interactivity, treat this as a high speed and resume
|
|
281
|
-
* simulation.
|
|
282
|
-
*/
|
|
283
|
-
if (k == null) {
|
|
284
|
-
sim.step(); // compute initial previous velocities
|
|
285
|
-
sim.step(); // compute initial velocities
|
|
286
|
-
|
|
287
|
-
/* Add the simulation state to the bound list. */
|
|
288
|
-
var force = s.$force = this.binds.$force = {
|
|
289
|
-
next: this.binds.$force,
|
|
290
|
-
nodes: nodes,
|
|
291
|
-
min: 1e-4 * (links.length + 1),
|
|
292
|
-
sim: sim
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
/* Start the timer, if not already started. */
|
|
296
|
-
if (!this.$timer) this.$timer = setInterval(function() {
|
|
297
|
-
var render = false;
|
|
298
|
-
for (var f = that.binds.$force; f; f = f.next) {
|
|
299
|
-
if (pv.max(f.nodes, speed) > f.min) {
|
|
300
|
-
f.sim.step();
|
|
301
|
-
render = true;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
if (render) that.render();
|
|
305
|
-
}, 42);
|
|
306
|
-
} else for (var i = 0; i < k; i++) {
|
|
307
|
-
sim.step();
|
|
308
|
-
}
|
|
309
|
-
};
|