rubyvis 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +10 -0
- data/Manifest.txt +7 -0
- data/Rakefile +2 -10
- data/examples/antibiotics/antibiotics_scatter.rb +4 -5
- data/examples/antibiotics/antibiotics_wedge.rb +0 -1
- data/examples/treemap/treemap.rb +29 -0
- data/examples/treemap/treemap_data.rb +285 -0
- data/lib/rubyvis.rb +2 -1
- data/lib/rubyvis/dom.rb +313 -0
- data/lib/rubyvis/layout.rb +8 -0
- data/lib/rubyvis/layout/hierarchy.rb +247 -0
- data/lib/rubyvis/layout/network.rb +228 -0
- data/lib/rubyvis/layout/stack.rb +2 -2
- data/lib/rubyvis/layout/treemap.rb +357 -0
- data/lib/rubyvis/mark.rb +10 -8
- data/lib/rubyvis/mark/anchor.rb +1 -1
- data/lib/rubyvis/mark/area.rb +1 -1
- data/lib/rubyvis/mark/bar.rb +1 -1
- data/lib/rubyvis/mark/dot.rb +1 -1
- data/lib/rubyvis/mark/image.rb +1 -1
- data/lib/rubyvis/mark/label.rb +1 -1
- data/lib/rubyvis/mark/line.rb +1 -1
- data/lib/rubyvis/mark/panel.rb +1 -1
- data/lib/rubyvis/mark/rule.rb +1 -1
- data/lib/rubyvis/mark/wedge.rb +1 -1
- data/lib/rubyvis/scene/svg_curve.rb +0 -1
- data/lib/rubyvis/sceneelement.rb +1 -1
- data/spec/dom_spec.rb +218 -0
- data/web/Rakefile +1 -1
- metadata +16 -25
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
=== 0.3.0 / 2010-11-17
|
2
|
+
* Network and Hierarchy classes on module Layout implemented. Require testing
|
3
|
+
* Rubyvis::Layout::Treemap fully operational
|
4
|
+
* Rubyvis::Dom almost complete, including spec
|
5
|
+
* Mark.extend changed to Mark.mark_extend, to avoid clashes with ruby extend
|
6
|
+
* Bug fix: Rubyvis::Dom::Node.sort doesn't set first_child and last_child correctly
|
7
|
+
* Updated for hoe 1.7.0
|
8
|
+
* Updated example of coordinate parallels
|
9
|
+
* New example: treemap/treemap.rb
|
10
|
+
|
1
11
|
=== 0.2.2 / 2010-11-13
|
2
12
|
|
3
13
|
* Updated to rspec 2. Bug fix: instance_eval raises an error on js_apply
|
data/Manifest.txt
CHANGED
@@ -30,16 +30,22 @@ examples/scatterplot.rb
|
|
30
30
|
examples/second.rb
|
31
31
|
examples/stacked_charts.rb
|
32
32
|
examples/third.rb
|
33
|
+
examples/treemap/treemap.rb
|
34
|
+
examples/treemap/treemap_data.rb
|
33
35
|
lib/rubyvis.rb
|
34
36
|
lib/rubyvis/color/color.rb
|
35
37
|
lib/rubyvis/color/colors.rb
|
38
|
+
lib/rubyvis/dom.rb
|
36
39
|
lib/rubyvis/format.rb
|
37
40
|
lib/rubyvis/format/date.rb
|
38
41
|
lib/rubyvis/format/number.rb
|
39
42
|
lib/rubyvis/internals.rb
|
40
43
|
lib/rubyvis/javascript_behaviour.rb
|
41
44
|
lib/rubyvis/layout.rb
|
45
|
+
lib/rubyvis/layout/hierarchy.rb
|
46
|
+
lib/rubyvis/layout/network.rb
|
42
47
|
lib/rubyvis/layout/stack.rb
|
48
|
+
lib/rubyvis/layout/treemap.rb
|
43
49
|
lib/rubyvis/mark.rb
|
44
50
|
lib/rubyvis/mark/anchor.rb
|
45
51
|
lib/rubyvis/mark/area.rb
|
@@ -75,6 +81,7 @@ lib/rubyvis/transform.rb
|
|
75
81
|
spec/anchor_spec.rb
|
76
82
|
spec/area_spec.rb
|
77
83
|
spec/bar_spec.rb
|
84
|
+
spec/dom_spec.rb
|
78
85
|
spec/internal_spec.rb
|
79
86
|
spec/javascript_behaviour_spec.rb
|
80
87
|
spec/label_spec.rb
|
data/Rakefile
CHANGED
@@ -9,20 +9,12 @@ require 'rspec'
|
|
9
9
|
require 'rspec/core/rake_task'
|
10
10
|
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
RSpec::Core::RakeTask.new do |t|
|
15
|
-
t.rspec_opts = ["-c", "-f progress", "-r ./spec/spec_helper.rb"]
|
16
|
-
t.pattern = 'spec/**/*_spec.rb'
|
17
|
-
end
|
18
|
-
|
19
|
-
|
20
12
|
Hoe.plugin :git
|
21
13
|
|
22
14
|
Hoe.spec 'rubyvis' do
|
23
15
|
self.testlib=:rspec
|
24
|
-
self.test_globs="spec/*_spec.rb"
|
25
|
-
|
16
|
+
#self.test_globs="spec/*_spec.rb"
|
17
|
+
self.rspec_options << "-c" << "-b"
|
26
18
|
self.developer('Claudio Bustos', 'clbustos_at_gmail.com')
|
27
19
|
self.version=Rubyvis::VERSION
|
28
20
|
self.extra_dev_deps << ["coderay",">=0"] << ["haml",">=0"] << ["nokogiri", ">=0"] << ["rspec",">=2.0"]
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# = Antibiotic Effectiveness : Scatterplot
|
2
|
-
#
|
3
2
|
# After World War II, antibiotics earned the moniker “wonder drugs” for quickly treating previously-incurable diseases. Data was gathered to determine which drug worked best for each bacterial infection. Comparing drug performance was an enormous aid for practitioners and scientists alike. In the fall of 1951, Will Burtin published this graph showing the effectiveness of three popular antibiotics on 16 different bacteria, measured in terms of minimum inhibitory concentration.
|
4
3
|
# Recreating this display revealed some minor errors in the original: a missing grid line at 0.01 μg/ml, and an exaggeration of some values for penicillin.
|
5
4
|
$:.unshift(File.dirname(__FILE__)+"/../../lib")
|
@@ -51,7 +50,7 @@ tick = pv.Rule.new()
|
|
51
50
|
|
52
51
|
#/* X-axis ticks. */
|
53
52
|
xtick = plot.add(pv.Rule)
|
54
|
-
.
|
53
|
+
.mark_extend(tick)
|
55
54
|
.left(z);
|
56
55
|
|
57
56
|
#/* Bottom and top labels. */
|
@@ -62,7 +61,7 @@ xtick.anchor("top").add(pv.Label)
|
|
62
61
|
|
63
62
|
#/* Y-axis ticks. */
|
64
63
|
ytick = plot.add(pv.Rule)
|
65
|
-
.
|
64
|
+
.mark_extend(tick)
|
66
65
|
.bottom(z);
|
67
66
|
|
68
67
|
#/* Bottom and top labels. */
|
@@ -96,7 +95,7 @@ dot = plot.add(pv.Dot).
|
|
96
95
|
|
97
96
|
#/* Legend. */
|
98
97
|
vis.add(pv.Dot)
|
99
|
-
.
|
98
|
+
.mark_extend(dot)
|
100
99
|
.data([{gram:"positive"}, {gram:"negative"}])
|
101
100
|
.bottom(-30)
|
102
101
|
.left(lambda { index * 100})
|
@@ -105,4 +104,4 @@ vis.add(pv.Dot)
|
|
105
104
|
.text(lambda {|d| "Gram-" + d[:gram]});
|
106
105
|
|
107
106
|
vis.render();
|
108
|
-
puts vis.to_svg
|
107
|
+
puts vis.to_svg
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# = Antibiotic Effectiveness : Pie chart
|
2
|
-
#
|
3
2
|
# After World War II, antibiotics earned the moniker “wonder drugs” for quickly treating previously-incurable diseases. Data was gathered to determine which drug worked best for each bacterial infection. Comparing drug performance was an enormous aid for practitioners and scientists alike. In the fall of 1951, Will Burtin published this graph showing the effectiveness of three popular antibiotics on 16 different bacteria, measured in terms of minimum inhibitory concentration.
|
4
3
|
# Recreating this display revealed some minor errors in the original: a missing grid line at 0.01 μg/ml, and an exaggeration of some values for penicillin.
|
5
4
|
$:.unshift(File.dirname(__FILE__)+"/../../lib")
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# = Treemap
|
2
|
+
# Introduced by Ben Shneiderman in 1991, a treemap recursively subdivides area into rectangles. As with adjacency diagrams, the size of any node in the tree is quickly revealed. This example uses color to encode different packages of the Flare visualization toolkit, and area to encode file size. “Squarified” treemaps use approximately square rectangles, which offer better readability and size estimation than naive “slice-and-dice” subdivision. Fancier algorithms such as Voronoi and jigsaw treemaps also exist but are less common.
|
3
|
+
|
4
|
+
$:.unshift(File.dirname(__FILE__)+"/../../lib")
|
5
|
+
require 'rubyvis'
|
6
|
+
load(File.dirname(__FILE__)+"/treemap_data.rb")
|
7
|
+
color = pv.Colors.category19()
|
8
|
+
nodes = pv.dom($flare).root("flare").nodes
|
9
|
+
|
10
|
+
|
11
|
+
vis = pv.Panel.new()
|
12
|
+
.width(600)
|
13
|
+
.height(1000)
|
14
|
+
|
15
|
+
treemap = vis.add(Rubyvis::Layout::Treemap).
|
16
|
+
nodes(nodes).mode("squarify").round(true)
|
17
|
+
|
18
|
+
treemap.leaf.add(Rubyvis::Panel).
|
19
|
+
fill_style(lambda{|d|
|
20
|
+
color.scale(d.parent_node.node_name)}).
|
21
|
+
stroke_style("#fff").
|
22
|
+
line_width(1).
|
23
|
+
antialias(false)
|
24
|
+
|
25
|
+
treemap.node_label.add(Rubyvis::Label).
|
26
|
+
text_style(lambda {|d| pv.rgb(0, 0, 0, 1)})
|
27
|
+
|
28
|
+
vis.render
|
29
|
+
puts vis.to_svg
|
@@ -0,0 +1,285 @@
|
|
1
|
+
$flare = {
|
2
|
+
analytics: {
|
3
|
+
cluster: {
|
4
|
+
AgglomerativeCluster: 3938,
|
5
|
+
CommunityStructure: 3812,
|
6
|
+
HierarchicalCluster: 6714,
|
7
|
+
MergeEdge: 743
|
8
|
+
},
|
9
|
+
graph: {
|
10
|
+
BetweennessCentrality: 3534,
|
11
|
+
LinkDistance: 5731,
|
12
|
+
MaxFlowMinCut: 7840,
|
13
|
+
ShortestPaths: 5914,
|
14
|
+
SpanningTree: 3416
|
15
|
+
},
|
16
|
+
optimization: {
|
17
|
+
AspectRatioBanker: 7074
|
18
|
+
}
|
19
|
+
},
|
20
|
+
animate: {
|
21
|
+
Easing: 17010,
|
22
|
+
FunctionSequence: 5842,
|
23
|
+
interpolate: {
|
24
|
+
ArrayInterpolator: 1983,
|
25
|
+
ColorInterpolator: 2047,
|
26
|
+
DateInterpolator: 1375,
|
27
|
+
Interpolator: 8746,
|
28
|
+
MatrixInterpolator: 2202,
|
29
|
+
NumberInterpolator: 1382,
|
30
|
+
ObjectInterpolator: 1629,
|
31
|
+
PointInterpolator: 1675,
|
32
|
+
RectangleInterpolator: 2042
|
33
|
+
},
|
34
|
+
ISchedulable: 1041,
|
35
|
+
Parallel: 5176,
|
36
|
+
Pause: 449,
|
37
|
+
Scheduler: 5593,
|
38
|
+
Sequence: 5534,
|
39
|
+
Transition: 9201,
|
40
|
+
Transitioner: 19975,
|
41
|
+
TransitionEvent: 1116,
|
42
|
+
Tween: 6006
|
43
|
+
},
|
44
|
+
data: {
|
45
|
+
converters: {
|
46
|
+
Converters: 721,
|
47
|
+
DelimitedTextConverter: 4294,
|
48
|
+
GraphMLConverter: 9800,
|
49
|
+
IDataConverter: 1314,
|
50
|
+
JSONConverter: 2220
|
51
|
+
},
|
52
|
+
DataField: 1759,
|
53
|
+
DataSchema: 2165,
|
54
|
+
DataSet: 586,
|
55
|
+
DataSource: 3331,
|
56
|
+
DataTable: 772,
|
57
|
+
DataUtil: 3322
|
58
|
+
},
|
59
|
+
display: {
|
60
|
+
DirtySprite: 8833,
|
61
|
+
LineSprite: 1732,
|
62
|
+
RectSprite: 3623,
|
63
|
+
TextSprite: 10066
|
64
|
+
},
|
65
|
+
flex: {
|
66
|
+
FlareVis: 4116
|
67
|
+
},
|
68
|
+
physics: {
|
69
|
+
DragForce: 1082,
|
70
|
+
GravityForce: 1336,
|
71
|
+
IForce: 319,
|
72
|
+
NBodyForce: 10498,
|
73
|
+
Particle: 2822,
|
74
|
+
Simulation: 9983,
|
75
|
+
Spring: 2213,
|
76
|
+
SpringForce: 1681
|
77
|
+
},
|
78
|
+
query: {
|
79
|
+
AggregateExpression: 1616,
|
80
|
+
And: 1027,
|
81
|
+
Arithmetic: 3891,
|
82
|
+
Average: 891,
|
83
|
+
BinaryExpression: 2893,
|
84
|
+
Comparison: 5103,
|
85
|
+
CompositeExpression: 3677,
|
86
|
+
Count: 781,
|
87
|
+
DateUtil: 4141,
|
88
|
+
Distinct: 933,
|
89
|
+
Expression: 5130,
|
90
|
+
ExpressionIterator: 3617,
|
91
|
+
Fn: 3240,
|
92
|
+
If: 2732,
|
93
|
+
IsA: 2039,
|
94
|
+
Literal: 1214,
|
95
|
+
Match: 3748,
|
96
|
+
Maximum: 843,
|
97
|
+
methods: {
|
98
|
+
add: 593,
|
99
|
+
and: 330,
|
100
|
+
average: 287,
|
101
|
+
count: 277,
|
102
|
+
distinct: 292,
|
103
|
+
div: 595,
|
104
|
+
eq: 594,
|
105
|
+
fn: 460,
|
106
|
+
gt: 603,
|
107
|
+
gte: 625,
|
108
|
+
iff: 748,
|
109
|
+
isa: 461,
|
110
|
+
lt: 597,
|
111
|
+
lte: 619,
|
112
|
+
max: 283,
|
113
|
+
min: 283,
|
114
|
+
mod: 591,
|
115
|
+
mul: 603,
|
116
|
+
neq: 599,
|
117
|
+
not: 386,
|
118
|
+
or: 323,
|
119
|
+
orderby: 307,
|
120
|
+
range: 772,
|
121
|
+
select: 296,
|
122
|
+
stddev: 363,
|
123
|
+
sub: 600,
|
124
|
+
sum: 280,
|
125
|
+
update: 307,
|
126
|
+
variance: 335,
|
127
|
+
where: 299,
|
128
|
+
xor: 354,
|
129
|
+
_: 264
|
130
|
+
},
|
131
|
+
Minimum: 843,
|
132
|
+
Not: 1554,
|
133
|
+
Or: 970,
|
134
|
+
Query: 13896,
|
135
|
+
Range: 1594,
|
136
|
+
StringUtil: 4130,
|
137
|
+
Sum: 791,
|
138
|
+
Variable: 1124,
|
139
|
+
Variance: 1876,
|
140
|
+
Xor: 1101
|
141
|
+
},
|
142
|
+
scale: {
|
143
|
+
IScaleMap: 2105,
|
144
|
+
LinearScale: 1316,
|
145
|
+
LogScale: 3151,
|
146
|
+
OrdinalScale: 3770,
|
147
|
+
QuantileScale: 2435,
|
148
|
+
QuantitativeScale: 4839,
|
149
|
+
RootScale: 1756,
|
150
|
+
Scale: 4268,
|
151
|
+
ScaleType: 1821,
|
152
|
+
TimeScale: 5833
|
153
|
+
},
|
154
|
+
util: {
|
155
|
+
Arrays: 8258,
|
156
|
+
Colors: 10001,
|
157
|
+
Dates: 8217,
|
158
|
+
Displays: 12555,
|
159
|
+
Filter: 2324,
|
160
|
+
Geometry: 10993,
|
161
|
+
heap: {
|
162
|
+
FibonacciHeap: 9354,
|
163
|
+
HeapNode: 1233
|
164
|
+
},
|
165
|
+
IEvaluable: 335,
|
166
|
+
IPredicate: 383,
|
167
|
+
IValueProxy: 874,
|
168
|
+
math: {
|
169
|
+
DenseMatrix: 3165,
|
170
|
+
IMatrix: 2815,
|
171
|
+
SparseMatrix: 3366
|
172
|
+
},
|
173
|
+
Maths: 17705,
|
174
|
+
Orientation: 1486,
|
175
|
+
palette: {
|
176
|
+
ColorPalette: 6367,
|
177
|
+
Palette: 1229,
|
178
|
+
ShapePalette: 2059,
|
179
|
+
SizePalette: 2291
|
180
|
+
},
|
181
|
+
Property: 5559,
|
182
|
+
Shapes: 19118,
|
183
|
+
Sort: 6887,
|
184
|
+
Stats: 6557,
|
185
|
+
Strings: 22026
|
186
|
+
},
|
187
|
+
vis: {
|
188
|
+
axis: {
|
189
|
+
Axes: 1302,
|
190
|
+
Axis: 24593,
|
191
|
+
AxisGridLine: 652,
|
192
|
+
AxisLabel: 636,
|
193
|
+
CartesianAxes: 6703
|
194
|
+
},
|
195
|
+
controls: {
|
196
|
+
AnchorControl: 2138,
|
197
|
+
ClickControl: 3824,
|
198
|
+
Control: 1353,
|
199
|
+
ControlList: 4665,
|
200
|
+
DragControl: 2649,
|
201
|
+
ExpandControl: 2832,
|
202
|
+
HoverControl: 4896,
|
203
|
+
IControl: 763,
|
204
|
+
PanZoomControl: 5222,
|
205
|
+
SelectionControl: 7862,
|
206
|
+
TooltipControl: 8435
|
207
|
+
},
|
208
|
+
data: {
|
209
|
+
Data: 20544,
|
210
|
+
DataList: 19788,
|
211
|
+
DataSprite: 10349,
|
212
|
+
EdgeSprite: 3301,
|
213
|
+
NodeSprite: 19382,
|
214
|
+
render: {
|
215
|
+
ArrowType: 698,
|
216
|
+
EdgeRenderer: 5569,
|
217
|
+
IRenderer: 353,
|
218
|
+
ShapeRenderer: 2247
|
219
|
+
},
|
220
|
+
ScaleBinding: 11275,
|
221
|
+
Tree: 7147,
|
222
|
+
TreeBuilder: 9930
|
223
|
+
},
|
224
|
+
events: {
|
225
|
+
DataEvent: 2313,
|
226
|
+
SelectionEvent: 1880,
|
227
|
+
TooltipEvent: 1701,
|
228
|
+
VisualizationEvent: 1117
|
229
|
+
},
|
230
|
+
legend: {
|
231
|
+
Legend: 20859,
|
232
|
+
LegendItem: 4614,
|
233
|
+
LegendRange: 10530
|
234
|
+
},
|
235
|
+
operator: {
|
236
|
+
distortion: {
|
237
|
+
BifocalDistortion: 4461,
|
238
|
+
Distortion: 6314,
|
239
|
+
FisheyeDistortion: 3444
|
240
|
+
},
|
241
|
+
encoder: {
|
242
|
+
ColorEncoder: 3179,
|
243
|
+
Encoder: 4060,
|
244
|
+
PropertyEncoder: 4138,
|
245
|
+
ShapeEncoder: 1690,
|
246
|
+
SizeEncoder: 1830
|
247
|
+
},
|
248
|
+
filter: {
|
249
|
+
FisheyeTreeFilter: 5219,
|
250
|
+
GraphDistanceFilter: 3165,
|
251
|
+
VisibilityFilter: 3509
|
252
|
+
},
|
253
|
+
IOperator: 1286,
|
254
|
+
label: {
|
255
|
+
Labeler: 9956,
|
256
|
+
RadialLabeler: 3899,
|
257
|
+
StackedAreaLabeler: 3202
|
258
|
+
},
|
259
|
+
layout: {
|
260
|
+
AxisLayout: 6725,
|
261
|
+
BundledEdgeRouter: 3727,
|
262
|
+
CircleLayout: 9317,
|
263
|
+
CirclePackingLayout: 12003,
|
264
|
+
DendrogramLayout: 4853,
|
265
|
+
ForceDirectedLayout: 8411,
|
266
|
+
IcicleTreeLayout: 4864,
|
267
|
+
IndentedTreeLayout: 3174,
|
268
|
+
Layout: 7881,
|
269
|
+
NodeLinkTreeLayout: 12870,
|
270
|
+
PieLayout: 2728,
|
271
|
+
RadialTreeLayout: 12348,
|
272
|
+
RandomLayout: 870,
|
273
|
+
StackedAreaLayout: 9121,
|
274
|
+
TreeMapLayout: 9191
|
275
|
+
},
|
276
|
+
Operator: 2490,
|
277
|
+
OperatorList: 5248,
|
278
|
+
OperatorSequence: 4190,
|
279
|
+
OperatorSwitch: 2581,
|
280
|
+
SortOperator: 2023
|
281
|
+
},
|
282
|
+
Visualization: 16540
|
283
|
+
}
|
284
|
+
};
|
285
|
+
|
data/lib/rubyvis.rb
CHANGED
@@ -17,6 +17,7 @@ require 'rubyvis/color/color'
|
|
17
17
|
require 'rubyvis/color/colors'
|
18
18
|
|
19
19
|
require 'rubyvis/layout'
|
20
|
+
require 'rubyvis/dom'
|
20
21
|
|
21
22
|
require 'rubyvis/scene/svg_scene'
|
22
23
|
require 'rubyvis/transform'
|
@@ -25,7 +26,7 @@ require 'rubyvis/transform'
|
|
25
26
|
module Rubyvis
|
26
27
|
@document=nil
|
27
28
|
# Rubyvis version
|
28
|
-
VERSION = '0.
|
29
|
+
VERSION = '0.3.0'
|
29
30
|
# Protovis API on which current Rubyvis is based
|
30
31
|
PROTOVIS_API_VERSION='3.3'
|
31
32
|
# You actually can do it! http://snipplr.com/view/2137/uses-for-infinity-in-ruby/
|
data/lib/rubyvis/dom.rb
ADDED
@@ -0,0 +1,313 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
# Returns a Rubyvis::Dom operator for the given map. This is a convenience
|
3
|
+
# factory method, equivalent to Rubyvis::Dom.new(map). To apply the operator
|
4
|
+
# and retrieve the root node, call Rubyvis::Dom.root() to retrieve all nodes
|
5
|
+
# flattened, use Rubyvis::Dom.nodes
|
6
|
+
#
|
7
|
+
# @see pv.Dom
|
8
|
+
# @param map a map from which to construct a DOM.
|
9
|
+
# @returns {pv.Dom} a DOM operator for the specified map.
|
10
|
+
def self.dom(map)
|
11
|
+
Rubyvis::Dom.new(map)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Constructs a DOM operator for the specified map. This constructor should not
|
15
|
+
# be invoked directly; use {@link pv.dom} instead.
|
16
|
+
#
|
17
|
+
# @class Represets a DOM operator for the specified map. This allows easy
|
18
|
+
# transformation of a hierarchical JavaScript object (such as a JSON map) to a
|
19
|
+
# W3C Document Object Model hierarchy. For more information on which attributes
|
20
|
+
# and methods from the specification are supported, see {@link pv.Dom.Node}.
|
21
|
+
#
|
22
|
+
# <p>Leaves in the map are determined using an associated <i>leaf</i> function;
|
23
|
+
# see {@link #leaf}. By default, leaves are any value whose type is not
|
24
|
+
# "object", such as numbers or strings.
|
25
|
+
#
|
26
|
+
# @param map a map from which to construct a DOM.
|
27
|
+
class Dom
|
28
|
+
def initialize(map)
|
29
|
+
@_map=map
|
30
|
+
@leaf=lambda {|n| !n.respond_to? :each }
|
31
|
+
end
|
32
|
+
# Sets or gets the leaf function for this DOM operator. The leaf function
|
33
|
+
# identifies which values in the map are leaves, and which are internal nodes.
|
34
|
+
# By default, objects are considered internal nodes, and primitives (such as
|
35
|
+
# numbers and strings) are considered leaves.
|
36
|
+
#
|
37
|
+
# @param {function} f the new leaf function.
|
38
|
+
# @returns the current leaf function, or <tt>this</tt>.
|
39
|
+
def leaf(f=nil)
|
40
|
+
if !f.nil?
|
41
|
+
@leaf=f
|
42
|
+
self
|
43
|
+
end
|
44
|
+
@leaf
|
45
|
+
end
|
46
|
+
|
47
|
+
def root_recurse(map)
|
48
|
+
n = Rubyvis::Dom::Node.new
|
49
|
+
map.each {|k,v|
|
50
|
+
n.append_child(@leaf.call(v) ? Rubyvis::Dom::Node.new(v) : root_recurse(v)).node_name = k
|
51
|
+
}
|
52
|
+
return n
|
53
|
+
end
|
54
|
+
|
55
|
+
# Applies the DOM operator, returning the root node.
|
56
|
+
def root(node_name=nil)
|
57
|
+
root=root_recurse(@_map)
|
58
|
+
root.node_name=node_name
|
59
|
+
root
|
60
|
+
end
|
61
|
+
|
62
|
+
# Applies the DOM operator, returning the array of all nodes in preorder
|
63
|
+
# traversal.
|
64
|
+
# @returns {array} the array of nodes in preorder traversal.
|
65
|
+
def nodes
|
66
|
+
self.root.nodes
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.Node(value)
|
70
|
+
Node.new(value)
|
71
|
+
end
|
72
|
+
# Represents a <tt>Node</tt> in the W3C Document Object Model.
|
73
|
+
class Node
|
74
|
+
# The node name. When generated from a map, the node name corresponds to the
|
75
|
+
# key at the given level in the map. Note that the root node has no associated
|
76
|
+
# key, and thus has an undefined node name (and no <tt>parentNode</tt>).
|
77
|
+
attr_accessor :node_name
|
78
|
+
|
79
|
+
# The node value. When generated from a map, node value corresponds to
|
80
|
+
# the leaf value for leaf nodes, and is undefined for internal nodes.
|
81
|
+
attr_reader :node_value
|
82
|
+
|
83
|
+
# The array of child nodes. This array is empty for leaf nodes. An easy way to
|
84
|
+
# check if child nodes exist is to query <tt>firstChild</tt>.
|
85
|
+
attr_accessor :child_nodes
|
86
|
+
attr_accessor :parent_node
|
87
|
+
# The first child, which is null for leaf nodes.
|
88
|
+
|
89
|
+
attr_accessor :first_child
|
90
|
+
attr_accessor :last_child
|
91
|
+
attr_accessor :previous_sibling
|
92
|
+
attr_accessor :next_sibling
|
93
|
+
|
94
|
+
attr_accessor :index
|
95
|
+
attr_accessor :link_degree
|
96
|
+
attr_accessor :depth
|
97
|
+
attr_accessor :dx
|
98
|
+
attr_accessor :dy
|
99
|
+
attr_accessor :x
|
100
|
+
attr_accessor :y
|
101
|
+
attr_accessor :size
|
102
|
+
|
103
|
+
|
104
|
+
# Constructs a DOM node for the specified value. Instances of this class are
|
105
|
+
# not typically created directly; instead they are generated from a JavaScript
|
106
|
+
# map using the {@link pv.Dom} operator.
|
107
|
+
def initialize(value=nil)
|
108
|
+
@node_value = value
|
109
|
+
@child_nodes=[]
|
110
|
+
@parent_node=nil
|
111
|
+
@first_child=nil
|
112
|
+
@last_child=nil
|
113
|
+
@previous_sibling=nil
|
114
|
+
@next_sibling=nil
|
115
|
+
|
116
|
+
end
|
117
|
+
# Removes the specified child node from this node.
|
118
|
+
def remove_child(n)
|
119
|
+
i=@child_nodes.index n
|
120
|
+
raise "child not found" if i.nil?
|
121
|
+
@child_nodes.delete_at i
|
122
|
+
if n.previous_sibling
|
123
|
+
n.previous_sibling.next_sibling=n.next_sibling
|
124
|
+
else
|
125
|
+
@first_child=n.next_sibling
|
126
|
+
end
|
127
|
+
if n.next_sibling
|
128
|
+
n.next_sibling.previous_sibling=n.previous_sibling
|
129
|
+
else
|
130
|
+
@last_child=n.previous_sibling
|
131
|
+
end
|
132
|
+
n.next_sibling=nil
|
133
|
+
n.previous_sibling=nil
|
134
|
+
n.parent_node=nil
|
135
|
+
n
|
136
|
+
end
|
137
|
+
|
138
|
+
# Appends the specified child node to this node. If the specified child is
|
139
|
+
# already part of the DOM, the child is first removed before being added to
|
140
|
+
# this node.
|
141
|
+
def append_child(n)
|
142
|
+
if n.parent_node
|
143
|
+
n.parent_node.remove_child(n)
|
144
|
+
end
|
145
|
+
n.parent_node=self
|
146
|
+
n.previous_sibling=last_child
|
147
|
+
if self.last_child
|
148
|
+
@last_child.next_sibling = n
|
149
|
+
else
|
150
|
+
@first_child=n
|
151
|
+
end
|
152
|
+
@last_child=n
|
153
|
+
child_nodes.push(n)
|
154
|
+
n
|
155
|
+
end
|
156
|
+
|
157
|
+
# Inserts the specified child <i>n</i> before the given reference child
|
158
|
+
# <i>r</i> of this node. If <i>r</i> is null, this method is equivalent to
|
159
|
+
# {@link #appendChild}. If <i>n</i> is already part of the DOM, it is first
|
160
|
+
# removed before being inserted.
|
161
|
+
#
|
162
|
+
# @throws Error if <i>r</i> is non-null and not a child of this node.
|
163
|
+
# @returns {pv.Dom.Node} the inserted child.
|
164
|
+
def insert_before(n, r)
|
165
|
+
return append_child(n) if !r
|
166
|
+
i=@child_nodes.index r
|
167
|
+
raise "child not found" if i.nil?
|
168
|
+
n.parent_node.remove_child(n) if n.parent_node
|
169
|
+
n.parent_node=self
|
170
|
+
n.next_sibling=r
|
171
|
+
n.previous_sibling = r.previous_sibling
|
172
|
+
if r.previous_sibling
|
173
|
+
r.previous_sibling.next_sibling=n
|
174
|
+
r.previous_sibling=n
|
175
|
+
else
|
176
|
+
@last_child=n if r==@last_child
|
177
|
+
@first_child=n
|
178
|
+
end
|
179
|
+
@child_nodes = @child_nodes[0,i] + [n] + @child_nodes[i, child_nodes.size-i]
|
180
|
+
n
|
181
|
+
end
|
182
|
+
# Replaces the specified child <i>r</i> of this node with the node <i>n</i>. If
|
183
|
+
# <i>n</i> is already part of the DOM, it is first removed before being added.
|
184
|
+
|
185
|
+
def replace_child(n,r)
|
186
|
+
i=child_nodes.index r
|
187
|
+
raise "child not found" if i.nil?
|
188
|
+
n.parent_node.remove_child(n) if n.parent_node
|
189
|
+
n.parent_node=self
|
190
|
+
n.next_sibling=r.next_sibling
|
191
|
+
n.previous_sibling=r.previous_sibling
|
192
|
+
if r.previous_sibling
|
193
|
+
r.previous_sibling.next_sibling=n
|
194
|
+
else
|
195
|
+
@first_child=n
|
196
|
+
end
|
197
|
+
if r.next_sibling
|
198
|
+
r.next_sibling.previous_sibling=n
|
199
|
+
else
|
200
|
+
@last_child=n
|
201
|
+
end
|
202
|
+
|
203
|
+
@child_nodes[i]=n
|
204
|
+
r
|
205
|
+
end
|
206
|
+
|
207
|
+
def visit_visit(n,i,block,moment)
|
208
|
+
block.call(n,i) if moment==:before
|
209
|
+
c=n.first_child
|
210
|
+
while c
|
211
|
+
visit_visit(c,i+1, block,moment)
|
212
|
+
c=c.next_sibling
|
213
|
+
end
|
214
|
+
block.call(n,i) if moment==:after
|
215
|
+
end
|
216
|
+
private :visit_visit
|
217
|
+
|
218
|
+
# Visits each node in the tree in preorder traversal, applying the specified
|
219
|
+
# proc <i>block</i>. The arguments to the function are:<ol>
|
220
|
+
#
|
221
|
+
# <li>The current node.
|
222
|
+
# <li>The current depth, starting at 0 for the root node.</ol>
|
223
|
+
|
224
|
+
def visit_before(f=nil,&block)
|
225
|
+
block=f unless f.nil?
|
226
|
+
raise "Should pass a Proc" if block.nil?
|
227
|
+
visit_visit(self,0,block, :before)
|
228
|
+
end
|
229
|
+
# Visits each node in the tree in postorder traversal, applying the specified
|
230
|
+
# function <i>f</i>. The arguments to the function are:<ol>
|
231
|
+
#
|
232
|
+
# <li>The current node.
|
233
|
+
# <li>The current depth, starting at 0 for the root node.</ol>
|
234
|
+
def visit_after(f=nil,&block)
|
235
|
+
block=f unless f.nil?
|
236
|
+
raise "Should pass a Proc" if block.nil?
|
237
|
+
visit_visit(self,0,block, :after)
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
# Sorts child nodes of this node, and all descendent nodes recursively, using
|
242
|
+
# the specified comparator function <tt>f</tt>. The comparator function is
|
243
|
+
# passed two nodes to compare.
|
244
|
+
#
|
245
|
+
# <p>Note: during the sort operation, the comparator function should not rely
|
246
|
+
# on the tree being well-formed; the values of <tt>previousSibling</tt> and
|
247
|
+
# <tt>nextSibling</tt> for the nodes being compared are not defined during the
|
248
|
+
# sort operation.
|
249
|
+
#
|
250
|
+
# @param {function} f a comparator function.
|
251
|
+
# @returns this.
|
252
|
+
def sort(f_a=nil,&f)
|
253
|
+
f=f_a unless f_a.nil?
|
254
|
+
raise "Should pass a Proc" if f.nil?
|
255
|
+
if @first_child
|
256
|
+
@child_nodes.sort!(&f)
|
257
|
+
_p=@first_child = child_nodes[0]
|
258
|
+
_p.previous_sibling=nil
|
259
|
+
(1...@child_nodes.size).each {|i|
|
260
|
+
_p.sort(&f)
|
261
|
+
c=@child_nodes[i]
|
262
|
+
c.previous_sibling=_p
|
263
|
+
_p=_p.next_sibling=c
|
264
|
+
}
|
265
|
+
@last_child=_p
|
266
|
+
_p.next_sibling=nil
|
267
|
+
_p.sort(f)
|
268
|
+
end
|
269
|
+
self
|
270
|
+
end
|
271
|
+
# Reverses all sibling nodes.
|
272
|
+
def reverse
|
273
|
+
child_nodes=[]
|
274
|
+
visit_after {|n,dummy|
|
275
|
+
while(n.last_child) do
|
276
|
+
child_nodes.push(n.remove_child(n.last_child))
|
277
|
+
end
|
278
|
+
c=nil
|
279
|
+
while(c=child_nodes.pop)
|
280
|
+
n.insert_before(c,n.first_child)
|
281
|
+
end
|
282
|
+
}
|
283
|
+
self
|
284
|
+
end
|
285
|
+
def nodes_flatten(node,array)
|
286
|
+
array.push(node)
|
287
|
+
node.child_nodes.each {|n|
|
288
|
+
nodes_flatten(n,array)
|
289
|
+
}
|
290
|
+
end
|
291
|
+
private :nodes_flatten
|
292
|
+
def nodes
|
293
|
+
array=[]
|
294
|
+
nodes_flatten(self,array)
|
295
|
+
array
|
296
|
+
end
|
297
|
+
# toggle missing
|
298
|
+
def inspect
|
299
|
+
childs=@child_nodes.map{|e| e.inspect}.join(",")
|
300
|
+
"#<#{self.class} #{object_id.to_s(16)} (#{}), name: #{@node_name}, value: #{@node_value} child_nodes: [#{childs}]>"
|
301
|
+
end
|
302
|
+
end # End Node
|
303
|
+
end # End Dom
|
304
|
+
# Given a flat array of values, returns a simple DOM with each value wrapped by
|
305
|
+
# a node that is a child of the root node.
|
306
|
+
def self.nodes(values)
|
307
|
+
root=Rubyvis::Dom::Node.new
|
308
|
+
values.each do |v,i|
|
309
|
+
root.append_child(Rubyvis::Dom::Node.new(v))
|
310
|
+
end
|
311
|
+
root.nodes()
|
312
|
+
end
|
313
|
+
end
|