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 CHANGED
Binary file
@@ -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
@@ -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
- # self.rubyforge_name = 'rubyvis'
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
- .extend(tick)
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
- .extend(tick)
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
- .extend(dot)
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
+
@@ -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.2.2'
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/
@@ -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