rubyvis 0.3.2 → 0.3.3
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 +7 -0
- data/Manifest.txt +6 -0
- data/examples/bubble_charts.rb +60 -0
- data/examples/circle_packing.rb +54 -0
- data/examples/indent.rb +71 -0
- data/lib/rubyvis.rb +2 -1
- data/lib/rubyvis/dom.rb +4 -2
- data/lib/rubyvis/flatten.rb +128 -0
- data/lib/rubyvis/layout.rb +2 -0
- data/lib/rubyvis/layout/indent.rb +81 -0
- data/lib/rubyvis/layout/network.rb +61 -42
- data/lib/rubyvis/layout/pack.rb +333 -0
- data/lib/rubyvis/mark.rb +8 -2
- data/lib/rubyvis/mark/shorcut_methods.rb +28 -0
- data/lib/rubyvis/scene/svg_scene.rb +28 -2
- data/lib/rubyvis/sceneelement.rb +1 -1
- metadata +9 -3
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
=== 0.3.3 / 2010-11-23
|
2
|
+
|
3
|
+
* Implemented Rubyvis::Layout::Pack, Rubyvis::Layout::Indent and Rubyvis::Flatten
|
4
|
+
* Implemeted Rubyvis::Mark.title()
|
5
|
+
* New examples: bubble charts and circle packing
|
6
|
+
* Better documentation for Network
|
7
|
+
|
1
8
|
=== 0.3.2 / 2010-11-23
|
2
9
|
|
3
10
|
* Updated examples
|
data/Manifest.txt
CHANGED
@@ -10,8 +10,10 @@ examples/area_interpolation.rb
|
|
10
10
|
examples/bar_column_chart.rb
|
11
11
|
examples/barley/barley.rb
|
12
12
|
examples/barley/barley_data.rb
|
13
|
+
examples/bubble_charts.rb
|
13
14
|
examples/cars/cars.rb
|
14
15
|
examples/cars/cars_data.rb
|
16
|
+
examples/circle_packing.rb
|
15
17
|
examples/crimea/crimea_data.rb
|
16
18
|
examples/crimea/crimea_grouped_bar.rb
|
17
19
|
examples/crimea/crimea_line.rb
|
@@ -23,6 +25,7 @@ examples/fixtures/tipsy.gif
|
|
23
25
|
examples/grouped_charts.rb
|
24
26
|
examples/icicle.rb
|
25
27
|
examples/image.rb
|
28
|
+
examples/indent.rb
|
26
29
|
examples/line.rb
|
27
30
|
examples/line_and_step.rb
|
28
31
|
examples/line_interpolation.rb
|
@@ -39,6 +42,7 @@ lib/rubyvis.rb
|
|
39
42
|
lib/rubyvis/color/color.rb
|
40
43
|
lib/rubyvis/color/colors.rb
|
41
44
|
lib/rubyvis/dom.rb
|
45
|
+
lib/rubyvis/flatten.rb
|
42
46
|
lib/rubyvis/format.rb
|
43
47
|
lib/rubyvis/format/date.rb
|
44
48
|
lib/rubyvis/format/number.rb
|
@@ -48,7 +52,9 @@ lib/rubyvis/javascript_behaviour.rb
|
|
48
52
|
lib/rubyvis/layout.rb
|
49
53
|
lib/rubyvis/layout/cluster.rb
|
50
54
|
lib/rubyvis/layout/hierarchy.rb
|
55
|
+
lib/rubyvis/layout/indent.rb
|
51
56
|
lib/rubyvis/layout/network.rb
|
57
|
+
lib/rubyvis/layout/pack.rb
|
52
58
|
lib/rubyvis/layout/partition.rb
|
53
59
|
lib/rubyvis/layout/stack.rb
|
54
60
|
lib/rubyvis/layout/treemap.rb
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# Bubble charts, such as those provided by "Many Eyes":http://manyeyes.alphaworks.ibm.com/manyeyes/page/Bubble_Chart.html, encode data in the area of circles. Although less perceptually accurate than bar charts, they can pack hundreds of values into a small space. A similar technique is the Dorling cartogram, where circles are positioned according to geography rather than arbitrarily. Here we compare the file sizes of the Rubyvis library files
|
2
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
3
|
+
require 'rubyvis'
|
4
|
+
|
5
|
+
|
6
|
+
def get_files(path)
|
7
|
+
h={}
|
8
|
+
Dir.glob("#{path}/*").each {|e|
|
9
|
+
next if File.expand_path(e)=~/pkg|web|vendor|doc|~/
|
10
|
+
pa=File.expand_path(e)
|
11
|
+
if File.stat(pa).directory?
|
12
|
+
h[File.basename(pa)]=get_files(pa)
|
13
|
+
else
|
14
|
+
h[File.basename(pa)]=File.stat(pa).size
|
15
|
+
end
|
16
|
+
}
|
17
|
+
h
|
18
|
+
end
|
19
|
+
|
20
|
+
files=get_files(File.dirname(__FILE__)+"/../lib")
|
21
|
+
|
22
|
+
classes = Rubyvis.nodes(Rubyvis.flatten(files).leaf(lambda {|v| v.is_a? Numeric}).array)
|
23
|
+
|
24
|
+
|
25
|
+
classes[1,classes.size-1].each {|d|
|
26
|
+
#p d.node_value.keys
|
27
|
+
d.node_name = "/" + d.node_value[:keys].join("/")
|
28
|
+
i = d.node_name.rindex("/")
|
29
|
+
class << d
|
30
|
+
attr_accessor :class_name, :package_name
|
31
|
+
end
|
32
|
+
d.class_name = d.node_name[i+1,d.node_name.size-(i+1)].gsub(".rb","")
|
33
|
+
d.package_name = d.node_name[0,i]
|
34
|
+
d.node_value = d.node_value[:value]
|
35
|
+
}
|
36
|
+
# For pretty number formatting.
|
37
|
+
format = Rubyvis.Format.number
|
38
|
+
|
39
|
+
vis = Rubyvis::Panel.new.
|
40
|
+
width(600)
|
41
|
+
.height(600)
|
42
|
+
c20=Rubyvis::Colors.category20()
|
43
|
+
vis.add(pv.Layout.Pack)
|
44
|
+
.top(-50)
|
45
|
+
.bottom(-50)
|
46
|
+
.nodes(classes)
|
47
|
+
.size(lambda {|d| d.node_value})
|
48
|
+
.spacing(0)
|
49
|
+
.order(nil)
|
50
|
+
.node.add(Rubyvis::Dot)
|
51
|
+
.fill_style(lambda {|d| c20.scale(d.package_name)})
|
52
|
+
.stroke_style(lambda {|d| c20.scale(d.package_name).darker})
|
53
|
+
.visible(lambda {|d| d.parent_node})
|
54
|
+
.title(lambda {|d| d.node_name + ": " + format.format(d.node_value)})
|
55
|
+
.anchor("center").add(pv.Label)
|
56
|
+
.text(lambda {|d| d.class_name[0, Math.sqrt(d.node_value).to_i / 8]})
|
57
|
+
|
58
|
+
vis.render();
|
59
|
+
puts vis.to_svg
|
60
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# = Circle Packing
|
2
|
+
# Enclosure diagrams are also space-filling, using containment rather than adjacency to represent the hierarchy. As with adjacency diagrams, the size of any node in the tree is quickly revealed. Although circle packing does not use space as efficiently as a treemap, the “wasted” space effectively reveals the hierarchy. At the same time, node sizes can be rapidly compared using area judgments.
|
3
|
+
# By flattening the hierarchy, the pack layout can also be used to create "bubble charts":bubble_charts.html.
|
4
|
+
# This example uses RBP API.
|
5
|
+
|
6
|
+
|
7
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
8
|
+
require 'rubyvis'
|
9
|
+
|
10
|
+
|
11
|
+
def get_files(path)
|
12
|
+
h={}
|
13
|
+
Dir.glob("#{path}/*").each {|e|
|
14
|
+
next if File.expand_path(e)=~/pkg|web|vendor|doc|~/
|
15
|
+
pa=File.expand_path(e)
|
16
|
+
if File.stat(pa).directory?
|
17
|
+
h[File.basename(pa)]=get_files(pa)
|
18
|
+
else
|
19
|
+
h[File.basename(pa)]=File.stat(pa).size
|
20
|
+
end
|
21
|
+
}
|
22
|
+
h
|
23
|
+
end
|
24
|
+
|
25
|
+
files=get_files(File.dirname(__FILE__)+"/../lib/")
|
26
|
+
|
27
|
+
format = Rubyvis::Format.number();
|
28
|
+
|
29
|
+
vis = Rubyvis::Panel.new do
|
30
|
+
width 600
|
31
|
+
height 796
|
32
|
+
margin 2
|
33
|
+
layout_pack do
|
34
|
+
nodes Rubyvis.dom(files).root("Rubyvis").nodes
|
35
|
+
size(lambda {|d| d.node_value})
|
36
|
+
node.dot do
|
37
|
+
fill_style {|d|
|
38
|
+
d.first_child ? "rgba(31, 119, 180, 0.25)" : "#ff7f0e"
|
39
|
+
}
|
40
|
+
title {|d|
|
41
|
+
d.node_name.to_s + (d.first_child ? "" : ": " + format.format(d.node_value))}
|
42
|
+
|
43
|
+
line_width 1
|
44
|
+
end
|
45
|
+
node_label.label do
|
46
|
+
visible {|d| !d.first_child}
|
47
|
+
text {|d| d.node_name[0, Math.sqrt(d.node_value) / 10]}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
vis.render()
|
53
|
+
puts vis.to_svg
|
54
|
+
|
data/examples/indent.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# = Indented Tree
|
2
|
+
# Indented trees are widely-used to represent file systems, among other applications. Although indented trees require much vertical space and do not easily facilitate multiscale inference, they do allow efficient interactive exploration of the tree to find a specific node.
|
3
|
+
# In addition, the indent layout allows rapid scanning of node labels, and multivariate data such as file size can be displayed adjacent to the hierarchy.
|
4
|
+
#
|
5
|
+
# Uses Protovis API
|
6
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
7
|
+
require 'rubyvis'
|
8
|
+
|
9
|
+
|
10
|
+
def get_files(path)
|
11
|
+
h={}
|
12
|
+
Dir.glob("#{path}/*").each {|e|
|
13
|
+
next if File.expand_path(e)=~/pkg|web|vendor|doc|~/
|
14
|
+
pa=File.expand_path(e)
|
15
|
+
if File.stat(pa).directory?
|
16
|
+
h[File.basename(pa)]=get_files(pa)
|
17
|
+
else
|
18
|
+
h[File.basename(pa)]=File.stat(pa).size
|
19
|
+
end
|
20
|
+
}
|
21
|
+
h
|
22
|
+
end
|
23
|
+
|
24
|
+
files=get_files(File.dirname(__FILE__)+"/../")
|
25
|
+
|
26
|
+
|
27
|
+
root = Rubyvis.dom(files)
|
28
|
+
.root("rubyvis")
|
29
|
+
.sort(lambda {|a,b| a.node_name<=>b.node_name})
|
30
|
+
|
31
|
+
#/* Recursively compute the package sizes. */
|
32
|
+
root.visit_after {|n,i|
|
33
|
+
if (n.first_child)
|
34
|
+
n.node_value= Rubyvis.sum(n.child_nodes , lambda {|nn| nn.node_value})
|
35
|
+
end
|
36
|
+
}
|
37
|
+
|
38
|
+
def t(d)
|
39
|
+
d.parent_node ? (t(d.parent_node) + "." + d.node_name) : d.node_name
|
40
|
+
end
|
41
|
+
|
42
|
+
vis = Rubyvis::Panel.new()
|
43
|
+
.width(260)
|
44
|
+
.height((root.nodes.size + 1)* 12)
|
45
|
+
.margin(5)
|
46
|
+
|
47
|
+
layout = vis.add(pv.Layout.Indent)
|
48
|
+
.nodes(lambda {root.nodes})
|
49
|
+
.depth(12)
|
50
|
+
.breadth(12)
|
51
|
+
|
52
|
+
layout.link.add(pv.Line)
|
53
|
+
|
54
|
+
node = layout.node.add(pv.Panel)
|
55
|
+
.top(lambda {|n| n.y - 6})
|
56
|
+
.height(12)
|
57
|
+
.right(6)
|
58
|
+
.strokeStyle(nil)
|
59
|
+
|
60
|
+
node.anchor("left").add(pv.Dot)
|
61
|
+
.strokeStyle("#1f77b4")
|
62
|
+
.fillStyle(lambda {|n| n.first_child ? "#aec7e8" : "#ff7f0e"})
|
63
|
+
.title(lambda {|d| t(d)})
|
64
|
+
.anchor("right").add(pv.Label)
|
65
|
+
.text(lambda {|n| n.node_name})
|
66
|
+
|
67
|
+
node.anchor("right").add(pv.Label)
|
68
|
+
.text(lambda {|n| (n.node_value >> 10).to_s + "KB"})
|
69
|
+
|
70
|
+
vis.render()
|
71
|
+
puts vis.to_svg
|
data/lib/rubyvis.rb
CHANGED
@@ -8,6 +8,7 @@ require 'rubyvis/internals'
|
|
8
8
|
require 'rubyvis/sceneelement'
|
9
9
|
require 'rubyvis/property'
|
10
10
|
require 'rubyvis/nest'
|
11
|
+
require 'rubyvis/flatten'
|
11
12
|
|
12
13
|
require 'rubyvis/javascript_behaviour'
|
13
14
|
require 'rubyvis/format'
|
@@ -29,7 +30,7 @@ require 'rubyvis/mark/shorcut_methods'
|
|
29
30
|
module Rubyvis
|
30
31
|
@document=nil
|
31
32
|
# Rubyvis version
|
32
|
-
VERSION = '0.3.
|
33
|
+
VERSION = '0.3.3'
|
33
34
|
# Protovis API on which current Rubyvis is based
|
34
35
|
PROTOVIS_API_VERSION='3.3'
|
35
36
|
# You actually can do it! http://snipplr.com/view/2137/uses-for-infinity-in-ruby/
|
data/lib/rubyvis/dom.rb
CHANGED
@@ -110,8 +110,10 @@ module Rubyvis
|
|
110
110
|
attr_accessor :angle
|
111
111
|
attr_accessor :start_angle
|
112
112
|
attr_accessor :outer_radius
|
113
|
-
attr_accessor :inner_radius
|
114
|
-
|
113
|
+
attr_accessor :inner_radius
|
114
|
+
attr_accessor :radius
|
115
|
+
attr_accessor :_p
|
116
|
+
attr_accessor :n
|
115
117
|
|
116
118
|
# Constructs a DOM node for the specified value. Instances of this class are
|
117
119
|
# not typically created directly; instead they are generated from a JavaScript
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
# Returns a {@link pv.Flatten} operator for the specified map. This is a
|
3
|
+
# convenience factory method, equivalent to <tt>new pv.Flatten(map)</tt>.
|
4
|
+
def self.flatten(map)
|
5
|
+
Flatten.new(map)
|
6
|
+
end
|
7
|
+
# Represents a flatten operator for the specified array. Flattening
|
8
|
+
# allows hierarchical maps to be flattened into an array. The levels in the
|
9
|
+
# input tree are specified by <i>key</i> functions.
|
10
|
+
#
|
11
|
+
# <p>For example, consider the following hierarchical data structure of Barley
|
12
|
+
# yields, from various sites in Minnesota during 1931-2:
|
13
|
+
#
|
14
|
+
# <pre>{ 1931: {
|
15
|
+
# Manchuria: {
|
16
|
+
# "University Farm": 27.00,
|
17
|
+
# "Waseca": 48.87,
|
18
|
+
# "Morris": 27.43,
|
19
|
+
# ... },
|
20
|
+
# Glabron: {
|
21
|
+
# "University Farm": 43.07,
|
22
|
+
# "Waseca": 55.20,
|
23
|
+
# ... } },
|
24
|
+
# 1932: {
|
25
|
+
# ... } }</pre>
|
26
|
+
#
|
27
|
+
# To facilitate visualization, it may be useful to flatten the tree into a
|
28
|
+
# tabular array:
|
29
|
+
#
|
30
|
+
# <pre>var array = pv.flatten(yields)
|
31
|
+
# .key("year")
|
32
|
+
# .key("variety")
|
33
|
+
# .key("site")
|
34
|
+
# .key("yield")
|
35
|
+
# .array();</pre>
|
36
|
+
#
|
37
|
+
# This returns an array of object elements. Each element in the array has
|
38
|
+
# attributes corresponding to this flatten operator's keys:
|
39
|
+
#
|
40
|
+
# <pre>{ site: "University Farm", variety: "Manchuria", year: 1931, yield: 27 },
|
41
|
+
# { site: "Waseca", variety: "Manchuria", year: 1931, yield: 48.87 },
|
42
|
+
# { site: "Morris", variety: "Manchuria", year: 1931, yield: 27.43 },
|
43
|
+
# { site: "University Farm", variety: "Glabron", year: 1931, yield: 43.07 },
|
44
|
+
# { site: "Waseca", variety: "Glabron", year: 1931, yield: 55.2 }, ...</pre>
|
45
|
+
#
|
46
|
+
# <p>The flatten operator is roughly the inverse of the {@link pv.Nest} and
|
47
|
+
# {@link pv.Tree} operators.
|
48
|
+
#
|
49
|
+
class Flatten
|
50
|
+
def initialize(map)
|
51
|
+
@map=map
|
52
|
+
@keys=[]
|
53
|
+
@leaf=nil
|
54
|
+
end
|
55
|
+
# Flattens using the specified key function. Multiple keys may be added to the
|
56
|
+
# flatten; the tiers of the underlying tree must correspond to the specified
|
57
|
+
# keys, in order. The order of the returned array is undefined; however, you
|
58
|
+
# can easily sort it.
|
59
|
+
#
|
60
|
+
# @param {string} key the key name.
|
61
|
+
# @param {function} [f] an optional value map function.
|
62
|
+
# @returns {pv.Nest} this.
|
63
|
+
|
64
|
+
def key(k, f=nil)
|
65
|
+
@keys.push(OpenStruct.new({:name=>key,:value=>f}))
|
66
|
+
@leaf=nil
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
# Flattens using the specified leaf function. This is an alternative to
|
71
|
+
# specifying an explicit set of keys; the tiers of the underlying tree will be
|
72
|
+
# determined dynamically by recursing on the values, and the resulting keys
|
73
|
+
# will be stored in the entries <tt>keys</tt> attribute. The leaf function must
|
74
|
+
# return true for leaves, and false for internal nodes.
|
75
|
+
#
|
76
|
+
# @param {function} f a leaf function.
|
77
|
+
# @returns {pv.Nest} this.
|
78
|
+
def leaf(f)
|
79
|
+
@keys.clear
|
80
|
+
@leaf=f
|
81
|
+
self
|
82
|
+
end
|
83
|
+
def recurse(value,i)
|
84
|
+
if @leaf.call(value)
|
85
|
+
@entries.push({:keys=>@stack.dup, :value=>value})
|
86
|
+
else
|
87
|
+
value.each {|key,v|
|
88
|
+
@stack.push(key)
|
89
|
+
recurse(v, i+1)
|
90
|
+
@stack.pop
|
91
|
+
}
|
92
|
+
end
|
93
|
+
end
|
94
|
+
def visit(value,i)
|
95
|
+
if (i < @keys.size - 1)
|
96
|
+
value.each {|key,v|
|
97
|
+
@stack.push(key)
|
98
|
+
visit(v,i+1)
|
99
|
+
@stack.pop
|
100
|
+
}
|
101
|
+
else
|
102
|
+
@entries.push(@stack+value)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
# Returns the flattened array. Each entry in the array is an object; each
|
106
|
+
# object has attributes corresponding to this flatten operator's keys.
|
107
|
+
#
|
108
|
+
# @returns an array of elements from the flattened map.
|
109
|
+
def array
|
110
|
+
@entries=[]
|
111
|
+
@stack=[]
|
112
|
+
if @leaf
|
113
|
+
recurse(@map,0)
|
114
|
+
return @entries
|
115
|
+
end
|
116
|
+
visit(@map,0)
|
117
|
+
@entries.map {|stack|
|
118
|
+
m={}
|
119
|
+
@keys.each_with_index {|k,i|
|
120
|
+
v=@stack[i]
|
121
|
+
m[k.name]=k.value ? k.value.js_call(self,v) : v
|
122
|
+
}
|
123
|
+
m
|
124
|
+
}
|
125
|
+
end
|
126
|
+
alias :to_a :array
|
127
|
+
end
|
128
|
+
end
|
data/lib/rubyvis/layout.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
class Layout
|
3
|
+
# Alias for Rubyvis::Layout::Indent
|
4
|
+
def self.Indent
|
5
|
+
Rubyvis::Layout::Indent
|
6
|
+
end
|
7
|
+
# Implements a hierarchical layout using the indent algorithm. This
|
8
|
+
# layout implements a node-link diagram where the nodes are presented in
|
9
|
+
# preorder traversal, and nodes are indented based on their depth from the
|
10
|
+
# root. This technique is used ubiquitously by operating systems to represent
|
11
|
+
# file directories; although it requires much vertical space, indented trees
|
12
|
+
# allow efficient <i>interactive</i> exploration of trees to find a specific
|
13
|
+
# node. In addition they allow rapid scanning of node labels, and multivariate
|
14
|
+
# data such as file sizes can be displayed adjacent to the hierarchy.
|
15
|
+
#
|
16
|
+
# <p>The indent layout can be configured using the <tt>depth</tt> and
|
17
|
+
# <tt>breadth</tt> properties, which control the increments in pixel space for
|
18
|
+
# each indent and row in the layout. This layout does not support multiple
|
19
|
+
# orientations; the root node is rendered in the top-left, while
|
20
|
+
# <tt>breadth</tt> is a vertical offset from the top, and <tt>depth</tt> is a
|
21
|
+
# horizontal offset from the left.
|
22
|
+
#
|
23
|
+
# <p>For more details on how to use this layout, see
|
24
|
+
# Rubyvis::Layout::Hierarchy
|
25
|
+
class Indent < Hierarchy
|
26
|
+
@properties=Hierarchy.properties.dup
|
27
|
+
# Constructs a new, empty indent layout. Layouts are not typically constructed
|
28
|
+
# directly; instead, they are added to an existing panel via
|
29
|
+
# Rubyvis::Mark.add
|
30
|
+
def initialize
|
31
|
+
super
|
32
|
+
@link.interpolate("step-after")
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# :attr: depth
|
37
|
+
# The horizontal offset between different levels of the tree; defaults to 15.
|
38
|
+
#
|
39
|
+
|
40
|
+
##
|
41
|
+
# :attr: breadth
|
42
|
+
# The vertical offset between nodes; defaults to 15.
|
43
|
+
#
|
44
|
+
|
45
|
+
attr_accessor_dsl :depth, :breadth
|
46
|
+
|
47
|
+
# Default properties for indent layouts. By default the depth and breadth
|
48
|
+
# offsets are 15 pixels.
|
49
|
+
def self.defaults
|
50
|
+
Rubyvis::Layout::Indent.new.mark_extend(Rubyvis::Layout::Hierarchy.defaults).
|
51
|
+
depth(15).
|
52
|
+
breadth(15)
|
53
|
+
end
|
54
|
+
|
55
|
+
def position(n, breadth, depth)
|
56
|
+
n.x = @ax + depth * @dspace
|
57
|
+
depth+=1
|
58
|
+
n.y = @ay + breadth * @bspace
|
59
|
+
breadth+=1
|
60
|
+
n.mid_angle = 0
|
61
|
+
c=n.first_child
|
62
|
+
while c
|
63
|
+
breadth=position(c,breadth,depth)
|
64
|
+
c=c.next_sibling
|
65
|
+
end
|
66
|
+
breadth;
|
67
|
+
end
|
68
|
+
private :position
|
69
|
+
def build_implied(s)
|
70
|
+
return nil if hierarchy_build_implied(s)
|
71
|
+
nodes = s.nodes
|
72
|
+
@bspace = s.breadth
|
73
|
+
@dspace = s.depth
|
74
|
+
@ax = 0
|
75
|
+
@ay = 0
|
76
|
+
position(nodes[0], 1, 1)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -75,7 +75,22 @@ module Rubyvis
|
|
75
75
|
# @see Rubyvis::Layout::Rollup
|
76
76
|
class Network < Rubyvis::Layout
|
77
77
|
@properties=Layout.properties.dup
|
78
|
-
|
78
|
+
# The node prototype. This prototype is intended to be used with a
|
79
|
+
# Dot mark in conjunction with the link prototype.
|
80
|
+
attr_accessor :node
|
81
|
+
# The link prototype, which renders edges between source nodes and target
|
82
|
+
# nodes. This prototype is intended to be used with a Line mark in
|
83
|
+
# conjunction with the node prototype.
|
84
|
+
attr_accessor :link
|
85
|
+
# The node label prototype, which renders the node name adjacent to the node.
|
86
|
+
# This prototype is provided as an alternative to using the anchor on the
|
87
|
+
# node mark; it is primarily intended to be used with radial node-link
|
88
|
+
# layouts, since it provides a convenient mechanism to set the text angle.
|
89
|
+
#
|
90
|
+
# NOTE FOR PROTOVIS USERS: The original name of method was +label+
|
91
|
+
# but it was replaced to not conflict with rubyvis shortcut
|
92
|
+
# method Mark.label()
|
93
|
+
attr_accessor :node_label
|
79
94
|
attr_accessor :_id
|
80
95
|
def initialize
|
81
96
|
super
|
@@ -84,9 +99,8 @@ module Rubyvis
|
|
84
99
|
@link=_link
|
85
100
|
@node_label=_node_label
|
86
101
|
end
|
87
|
-
|
88
|
-
|
89
|
-
def _node
|
102
|
+
|
103
|
+
def _node #:nodoc:
|
90
104
|
that=self
|
91
105
|
m=Mark.new().
|
92
106
|
data(lambda {that.nodes}).
|
@@ -97,7 +111,7 @@ module Rubyvis
|
|
97
111
|
m.parent = self
|
98
112
|
m
|
99
113
|
end
|
100
|
-
module LinkAdd
|
114
|
+
module LinkAdd # :nodoc:
|
101
115
|
attr_accessor :that
|
102
116
|
def add(type)
|
103
117
|
that=@that
|
@@ -108,11 +122,9 @@ module Rubyvis
|
|
108
122
|
end
|
109
123
|
end
|
110
124
|
|
111
|
-
|
112
|
-
# nodes. This prototype is intended to be used with a Line mark in
|
113
|
-
# conjunction with the node prototype.
|
125
|
+
|
114
126
|
|
115
|
-
def _link
|
127
|
+
def _link # :nodoc:
|
116
128
|
that=self
|
117
129
|
l=Mark.new().
|
118
130
|
mark_extend(@node).
|
@@ -125,14 +137,8 @@ module Rubyvis
|
|
125
137
|
l
|
126
138
|
end
|
127
139
|
|
128
|
-
|
129
|
-
|
130
|
-
# node mark; it is primarily intended to be used with radial node-link
|
131
|
-
# layouts, since it provides a convenient mechanism to set the text angle.
|
132
|
-
#
|
133
|
-
# NOTE FOR PROTOVIS USERS: The original name of method was +label+
|
134
|
-
# but it was replaced to not conflict with Mark.label()
|
135
|
-
def _node_label
|
140
|
+
|
141
|
+
def _node_label #:nodoc:
|
136
142
|
that=self
|
137
143
|
nl=Mark.new().
|
138
144
|
mark_extend(@node).
|
@@ -149,12 +155,17 @@ module Rubyvis
|
|
149
155
|
nl.parent = self
|
150
156
|
nl
|
151
157
|
end
|
158
|
+
|
152
159
|
##
|
153
|
-
# :
|
154
|
-
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
160
|
+
# :attr: nodes
|
161
|
+
#
|
162
|
+
# an array of objects representing nodes. Objects in this array must conform to the Rubyvis::Layout::Network::Node interface; which is
|
163
|
+
# to say, be careful to avoid naming collisions with automatic attributes such
|
164
|
+
# as <tt>index</tt> and <tt>link_degree</tt>. If the nodes property is defined
|
165
|
+
# as an array of 'primitives' (objects which doesn't respond to node_value)
|
166
|
+
# these primitives are automatically wrapped in an OpenStruct object;
|
167
|
+
# the resulting object's <tt>node_value</tt>
|
168
|
+
# attribute points to the original primitive value.
|
158
169
|
|
159
170
|
attr_accessor_dsl [:nodes, lambda {|v|
|
160
171
|
out=[]
|
@@ -165,6 +176,18 @@ module Rubyvis
|
|
165
176
|
}
|
166
177
|
out
|
167
178
|
}]
|
179
|
+
|
180
|
+
##
|
181
|
+
# :attr: links
|
182
|
+
#
|
183
|
+
# an array of objects representing links. Objects in
|
184
|
+
# this array must conform to the Rubyvis::Layout::Network::Link interface; at a
|
185
|
+
# minimum, either <tt>source</tt> and <tt>target</tt> indexes or
|
186
|
+
# <tt>source_node</tt> and <tt>target_node</tt> references must be set.
|
187
|
+
# Note that if the links property is defined after the nodes property,
|
188
|
+
# the links can be defined in terms of <tt>self.nodes()</tt>.
|
189
|
+
|
190
|
+
|
168
191
|
attr_accessor_dsl [:links, lambda {|v|
|
169
192
|
out=[]
|
170
193
|
v.map {|d|
|
@@ -189,7 +212,7 @@ module Rubyvis
|
|
189
212
|
|
190
213
|
# @private Skip evaluating properties if cached. */
|
191
214
|
|
192
|
-
def build_properties(s, properties)
|
215
|
+
def build_properties(s, properties) # :nodoc:
|
193
216
|
s_id=s._id
|
194
217
|
s_id||=0
|
195
218
|
if (s_id < self._id)
|
@@ -197,10 +220,10 @@ module Rubyvis
|
|
197
220
|
end
|
198
221
|
end
|
199
222
|
|
200
|
-
def build_implied(s)
|
223
|
+
def build_implied(s) # :nodoc:
|
201
224
|
network_build_implied(s)
|
202
225
|
end
|
203
|
-
def network_build_implied(s)
|
226
|
+
def network_build_implied(s) # :nodoc:
|
204
227
|
layout_build_implied(s)
|
205
228
|
return true if (!s._id.nil? and s._id >= self._id)
|
206
229
|
s._id= self._id
|
@@ -224,8 +247,8 @@ module Rubyvis
|
|
224
247
|
false
|
225
248
|
end
|
226
249
|
|
227
|
-
# Represents a node in a network layout.
|
228
|
-
#
|
250
|
+
# Represents a node in a network layout.
|
251
|
+
# This class mostly serves to document the attributes that are
|
229
252
|
# used on nodes in network layouts. (Note that hierarchical nodes place
|
230
253
|
# additional requirements on node representation, vis Rubyvis::Dom::Node.)
|
231
254
|
#
|
@@ -245,23 +268,19 @@ module Rubyvis
|
|
245
268
|
|
246
269
|
# The node name; optional. If present, this attribute will be used to provide
|
247
270
|
# the text for node labels. If not present, the label text will fallback to the
|
248
|
-
# <tt>
|
271
|
+
# <tt>node_value</tt> attribute.
|
249
272
|
#
|
250
273
|
# @type string
|
251
274
|
attr_accessor :node_name
|
252
275
|
|
253
|
-
# The node value; optional. If present, and no <tt>
|
254
|
-
#
|
255
|
-
# also automatically populated if the nodes are specified as an array of
|
256
|
-
# primitives, such as strings or numbers.
|
257
|
-
#
|
258
|
-
# @type object
|
276
|
+
# The node value; optional. If present, and no <tt>node_name</tt> attribute is present, the node value will be used as the label text.
|
277
|
+
# This attribute is also automatically populated if the nodes are specified as an array of 'primitives', such as strings or numbers.
|
259
278
|
attr_accessor :node_value
|
260
279
|
end
|
261
280
|
|
262
281
|
|
263
|
-
# Represents a link in a network layout.
|
264
|
-
#
|
282
|
+
# Represents a link in a network layout.
|
283
|
+
# This class mostly serves to document the attributes that are
|
265
284
|
# used on links in network layouts. For hierarchical layouts, this class is
|
266
285
|
# used to represent the parent-child links.
|
267
286
|
#
|
@@ -277,21 +296,21 @@ module Rubyvis
|
|
277
296
|
# default value of 1 is used.
|
278
297
|
#
|
279
298
|
# @type number
|
280
|
-
|
281
|
-
|
299
|
+
|
300
|
+
|
282
301
|
attr_accessor :link_value
|
283
302
|
|
284
303
|
# The link's source node. If not set, this value will be derived from the
|
285
304
|
# <tt>source</tt> attribute index.
|
286
305
|
#
|
287
306
|
# @type pv.Layout.Network.Node
|
288
|
-
|
307
|
+
|
289
308
|
attr_accessor :source_node
|
290
309
|
# The link's target node. If not set, this value will be derived from the
|
291
310
|
# <tt>target</tt> attribute index.
|
292
311
|
#
|
293
312
|
# @type pv.Layout.Network.Node
|
294
|
-
|
313
|
+
|
295
314
|
attr_accessor :target_node
|
296
315
|
# Alias for <tt>sourceNode</tt>, as expressed by the index of the source node.
|
297
316
|
# This attribute is not populated automatically, but may be used as a more
|
@@ -299,7 +318,7 @@ module Rubyvis
|
|
299
318
|
# representation.
|
300
319
|
#
|
301
320
|
# @type number
|
302
|
-
|
321
|
+
|
303
322
|
attr_accessor :source
|
304
323
|
# Alias for <tt>targetNode</tt>, as expressed by the index of the target node.
|
305
324
|
# This attribute is not populated automatically, but may be used as a more
|
@@ -307,7 +326,7 @@ module Rubyvis
|
|
307
326
|
# representation.
|
308
327
|
#
|
309
328
|
# @type number
|
310
|
-
|
329
|
+
|
311
330
|
attr_accessor :target
|
312
331
|
# Alias for <tt>linkValue</tt>. This attribute is not populated automatically,
|
313
332
|
# but may be used instead of the <tt>linkValue</tt> attribute when specifying
|
@@ -0,0 +1,333 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
class Layout
|
3
|
+
# Alias for Rubyvis::Layout::Indent
|
4
|
+
def self.Pack
|
5
|
+
Rubyvis::Layout::Pack
|
6
|
+
end
|
7
|
+
|
8
|
+
# Implements a hierarchical layout using circle-packing. The meaning of
|
9
|
+
# the exported mark prototypes changes slightly in the space-filling
|
10
|
+
# implementation:<ul>
|
11
|
+
#
|
12
|
+
# <li><tt>node</tt> - for rendering nodes; typically a {@link pv.Dot}.
|
13
|
+
#
|
14
|
+
# <p><li><tt>link</tt> - unsupported; undefined. Links are encoded implicitly
|
15
|
+
# in the arrangement of the space-filling nodes.
|
16
|
+
#
|
17
|
+
# <p><li><tt>label</tt> - for rendering node labels; typically a
|
18
|
+
# {@link pv.Label}.
|
19
|
+
#
|
20
|
+
# </ul>The pack layout support dynamic sizing for leaf nodes, if a
|
21
|
+
# {@link #size} psuedo-property is specified. The default size function returns
|
22
|
+
# 1, causing all leaf nodes to be sized equally, and all internal nodes to be
|
23
|
+
# sized by the number of leaf nodes they have as descendants.
|
24
|
+
#
|
25
|
+
# <p>The size function can be used in conjunction with the order property,
|
26
|
+
# which allows the nodes to the sorted by the computed size. Note: for sorting
|
27
|
+
# based on other data attributes, simply use the default <tt>null</tt> for the
|
28
|
+
# order property, and sort the nodes beforehand using the {@link pv.Dom}
|
29
|
+
# operator.
|
30
|
+
#
|
31
|
+
# <p>For more details on how to use this layout, see
|
32
|
+
# {@link pv.Layout.Hierarchy}.
|
33
|
+
#
|
34
|
+
# @extends pv.Layout.Hierarchy
|
35
|
+
# @see <a href="http://portal.acm.org/citation.cfm?id=1124772.1124851"
|
36
|
+
# >"Visualization of large hierarchical data by circle packing"</a> by W. Wang,
|
37
|
+
# H. Wang, G. Dai, and H. Wang, ACM CHI 2006.
|
38
|
+
#/
|
39
|
+
class Pack < Hierarchy
|
40
|
+
@properties=Hierarchy.properties.dup
|
41
|
+
def initialize
|
42
|
+
super
|
43
|
+
@node.
|
44
|
+
shape_radius(lambda {|n| n.radius }).
|
45
|
+
stroke_style("rgb(31, 119, 180)").
|
46
|
+
fill_style("rgba(31, 119, 180, 0.25)")
|
47
|
+
|
48
|
+
|
49
|
+
@node_label.text_align("center")
|
50
|
+
|
51
|
+
@link=nil
|
52
|
+
|
53
|
+
@radius = lambda { 1 }
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
##
|
58
|
+
# :attr: spacing
|
59
|
+
# The spacing parameter; defaults to 1, which provides a little bit of padding
|
60
|
+
# between sibling nodes and the enclosing circle. Larger values increase the
|
61
|
+
# spacing, by making the sibling nodes smaller; a value of zero makes the leaf
|
62
|
+
# nodes as large as possible, with no padding on enclosing circles.
|
63
|
+
#
|
64
|
+
# @type number
|
65
|
+
|
66
|
+
##
|
67
|
+
# :attr: order
|
68
|
+
# The sibling node order. The default order is <tt>null</tt>, which means to
|
69
|
+
# use the sibling order specified by the nodes property as-is. A value of
|
70
|
+
# "ascending" will sort siblings in ascending order of size, while "descending"
|
71
|
+
# will do the reverse. For sorting based on data attributes other than size,
|
72
|
+
# use the default <tt>null</tt> for the order property, and sort the nodes
|
73
|
+
# beforehand using the {@link pv.Dom} operator.
|
74
|
+
#
|
75
|
+
# @see pv.Dom.Node#sort
|
76
|
+
|
77
|
+
|
78
|
+
attr_accessor_dsl :spacing, :order
|
79
|
+
|
80
|
+
##
|
81
|
+
# Default properties for circle-packing layouts. The default spacing parameter
|
82
|
+
# is 1 and the default order is "ascending".
|
83
|
+
#
|
84
|
+
def self.defaults
|
85
|
+
Rubyvis::Layout::Pack.new.mark_extend(Rubyvis::Layout::Hierarchy.defaults).
|
86
|
+
spacing(1).
|
87
|
+
order("ascending")
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
# TODO is it possible for spacing to operate in pixel space?
|
92
|
+
# Right now it appears to be multiples of the smallest radius.
|
93
|
+
|
94
|
+
##
|
95
|
+
# Specifies the sizing function. By default, a sizing function is disabled and
|
96
|
+
# all nodes are given constant size. The sizing function is invoked for each
|
97
|
+
# leaf node in the tree (passed to the constructor).
|
98
|
+
#
|
99
|
+
# <p>For example, if the tree data structure represents a file system, with
|
100
|
+
# files as leaf nodes, and each file has a <tt>bytes</tt> attribute, you can
|
101
|
+
# specify a size function as:
|
102
|
+
#
|
103
|
+
# <pre> .size(function(d) d.bytes)</pre>
|
104
|
+
#
|
105
|
+
# As with other properties, a size function may specify additional arguments to
|
106
|
+
# access the data associated with the layout and any enclosing panels.
|
107
|
+
#
|
108
|
+
# @param {function} f the new sizing function.
|
109
|
+
# @returns {pv.Layout.Pack} this.
|
110
|
+
def size(f)
|
111
|
+
if f.is_a? Proc
|
112
|
+
@radius=lambda {|*args| Math.sqrt(f.js_apply(self,args))}
|
113
|
+
else
|
114
|
+
f=Math.sqrt(f)
|
115
|
+
@radius=lambda {f}
|
116
|
+
end
|
117
|
+
self
|
118
|
+
end
|
119
|
+
## @private Compute the radii of the leaf nodes. #/
|
120
|
+
|
121
|
+
def radii(nodes)
|
122
|
+
stack=Mark.stack
|
123
|
+
stack.unshift(nil)
|
124
|
+
nodes.each {|c|
|
125
|
+
if !c.first_child
|
126
|
+
stack[0]=c
|
127
|
+
c.radius = @radius.js_apply(self, stack)
|
128
|
+
end
|
129
|
+
}
|
130
|
+
stack.shift
|
131
|
+
end
|
132
|
+
def pack_tree(n)
|
133
|
+
nodes = []
|
134
|
+
c=n.first_child
|
135
|
+
while(c)
|
136
|
+
c.radius=pack_tree(c) if c.first_child
|
137
|
+
c.n=c._p=c
|
138
|
+
nodes.push(c)
|
139
|
+
c=c.next_sibling
|
140
|
+
end
|
141
|
+
|
142
|
+
# Sort.
|
143
|
+
case @s.order
|
144
|
+
when "ascending"
|
145
|
+
nodes.sort {|a,b| a.radius<=>b.radius}
|
146
|
+
when 'descending'
|
147
|
+
nodes.sort {|a,b| b.radius<=>a.radius}
|
148
|
+
when 'reverse'
|
149
|
+
nodes.reverse
|
150
|
+
end
|
151
|
+
|
152
|
+
return pack_circle(nodes)
|
153
|
+
end
|
154
|
+
def bound(n)
|
155
|
+
@x_min = [n.x - n.radius, @x_min].min
|
156
|
+
@x_max = [n.x + n.radius, @x_max].max
|
157
|
+
@y_min = [n.y - n.radius, @y_min].min
|
158
|
+
@y_max = [n.y + n.radius, @y_max].max
|
159
|
+
end
|
160
|
+
def insert(a,b)
|
161
|
+
c = a.n
|
162
|
+
a.n = b
|
163
|
+
b._p = a
|
164
|
+
b.n = c
|
165
|
+
c._p = b
|
166
|
+
end
|
167
|
+
def splice(a, b)
|
168
|
+
a.n = b
|
169
|
+
b._p = a
|
170
|
+
end
|
171
|
+
def intersects(a, b)
|
172
|
+
dx = b.x - a.x
|
173
|
+
dy = b.y - a.y
|
174
|
+
dr = a.radius + b.radius
|
175
|
+
(dr * dr - dx * dx - dy * dy) > 0.001 # within epsilon
|
176
|
+
end
|
177
|
+
|
178
|
+
## @private #/
|
179
|
+
def place(a, b, c)
|
180
|
+
da = b.radius + c.radius
|
181
|
+
db = a.radius + c.radius
|
182
|
+
dx = b.x - a.x
|
183
|
+
dy = b.y - a.y
|
184
|
+
dc = Math.sqrt(dx * dx + dy * dy)
|
185
|
+
cos = (db * db + dc * dc - da * da) / (2.0 * db * dc)
|
186
|
+
|
187
|
+
theta = Math.acos(cos)
|
188
|
+
x = cos * db
|
189
|
+
h = Math.sin(theta) * db
|
190
|
+
dx /= dc
|
191
|
+
dy /= dc
|
192
|
+
c.x = a.x + x * dx + h * dy
|
193
|
+
c.y = a.y + x * dy - h * dx
|
194
|
+
end
|
195
|
+
|
196
|
+
# @private #/
|
197
|
+
def transform(n, x, y, k)
|
198
|
+
c=n.first_child
|
199
|
+
while(c) do
|
200
|
+
c.x += n.x
|
201
|
+
c.y += n.y
|
202
|
+
transform(c, x, y, k)
|
203
|
+
c=c.next_sibling
|
204
|
+
end
|
205
|
+
n.x = x + k * n.x
|
206
|
+
n.y = y + k * n.y
|
207
|
+
n.radius *= k
|
208
|
+
n.mid_angle=0 # Undefined on protovis
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
def pack_circle(nodes)
|
213
|
+
@x_min = Infinity
|
214
|
+
@x_max = -Infinity
|
215
|
+
@y_min = Infinity
|
216
|
+
@y_max = -Infinity
|
217
|
+
a=b=c=j=k=nil
|
218
|
+
|
219
|
+
|
220
|
+
# Create first node.
|
221
|
+
a = nodes[0];
|
222
|
+
a.x = -a.radius
|
223
|
+
a.y = 0
|
224
|
+
bound(a)
|
225
|
+
|
226
|
+
# Create second node. #/
|
227
|
+
if (nodes.size > 1)
|
228
|
+
b = nodes[1]
|
229
|
+
b.x = b.radius
|
230
|
+
b.y = 0
|
231
|
+
bound(b)
|
232
|
+
|
233
|
+
# Create third node and build chain.
|
234
|
+
if (nodes.size > 2)
|
235
|
+
c = nodes[2]
|
236
|
+
place(a, b, c)
|
237
|
+
bound(c)
|
238
|
+
insert(a, c)
|
239
|
+
a._p = c
|
240
|
+
insert(c, b)
|
241
|
+
b = a.n
|
242
|
+
|
243
|
+
# Now iterate through the rest.
|
244
|
+
i=3
|
245
|
+
while(i<nodes.size) do
|
246
|
+
c=nodes[i]
|
247
|
+
place(a, b, c)
|
248
|
+
|
249
|
+
# Search for the closest intersection. #/
|
250
|
+
isect = 0
|
251
|
+
s1 = 1
|
252
|
+
s2 = 1
|
253
|
+
|
254
|
+
j=b.n
|
255
|
+
while(j!=b) do
|
256
|
+
if (intersects(j,c))
|
257
|
+
isect=1;
|
258
|
+
break;
|
259
|
+
end
|
260
|
+
j=j.n
|
261
|
+
s1+=1
|
262
|
+
end
|
263
|
+
|
264
|
+
if isect==1
|
265
|
+
k=a._p
|
266
|
+
while(k!=k._p) do
|
267
|
+
if(intersects(k,c))
|
268
|
+
if(s2<s1)
|
269
|
+
isect=-1
|
270
|
+
k=j
|
271
|
+
end
|
272
|
+
break
|
273
|
+
end
|
274
|
+
k=k._p
|
275
|
+
s2+=1
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
|
280
|
+
# Update node chain. #/
|
281
|
+
if (isect == 0)
|
282
|
+
insert(a, c)
|
283
|
+
b = c
|
284
|
+
bound(c)
|
285
|
+
elsif (isect > 0)
|
286
|
+
splice(a, j)
|
287
|
+
b = j
|
288
|
+
i-=1
|
289
|
+
elsif (isect < 0)
|
290
|
+
splice(j, b)
|
291
|
+
a = j
|
292
|
+
i-=1
|
293
|
+
end
|
294
|
+
i+=1
|
295
|
+
end
|
296
|
+
|
297
|
+
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
# Re-center the circles and return the encompassing radius. #/
|
302
|
+
cx = (@x_min + @x_max) / 2.0
|
303
|
+
cy = (@y_min + @y_max) / 2.0
|
304
|
+
cr = 0
|
305
|
+
nodes.each do |n|
|
306
|
+
n.x -= cx
|
307
|
+
n.y -= cy
|
308
|
+
cr = [cr, n.radius + Math.sqrt(n.x * n.x + n.y * n.y)].max
|
309
|
+
end
|
310
|
+
cr + @s.spacing
|
311
|
+
end
|
312
|
+
|
313
|
+
|
314
|
+
def build_implied(s)
|
315
|
+
return nil if hierarchy_build_implied(s)
|
316
|
+
@s=s
|
317
|
+
nodes = s.nodes
|
318
|
+
root = nodes[0]
|
319
|
+
radii(nodes)
|
320
|
+
|
321
|
+
# Recursively compute the layout. #/
|
322
|
+
root.x = 0
|
323
|
+
root.y = 0
|
324
|
+
root.radius = pack_tree(root)
|
325
|
+
|
326
|
+
w = self.width
|
327
|
+
h = self.height
|
328
|
+
k = 1.0 / [2.0 * root.radius / w, 2.0 * root.radius / h].max
|
329
|
+
transform(root, w / 2.0, h / 2.0, k)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
data/lib/rubyvis/mark.rb
CHANGED
@@ -460,8 +460,12 @@ module Rubyvis
|
|
460
460
|
end
|
461
461
|
end
|
462
462
|
# Execute a block using this mark as a reference
|
463
|
+
# <b>Example</b>
|
464
|
+
# bar.execute |b|
|
465
|
+
# b.width 10
|
466
|
+
# b.add(Rubyvis::Label)
|
467
|
+
# end
|
463
468
|
def execute(&block)
|
464
|
-
|
465
469
|
block.arity<1 ? self.instance_eval(&block) : block.call(self)
|
466
470
|
end
|
467
471
|
# The mark type; a lower name. The type name controls rendering
|
@@ -486,7 +490,9 @@ module Rubyvis
|
|
486
490
|
# or its prototype, and so on. The prototype mark need not be the same
|
487
491
|
# type of mark as this mark. (Note that for inheritance to be useful,
|
488
492
|
# properties with the same name on different mark types should
|
489
|
-
# have equivalent meaning.
|
493
|
+
# have equivalent meaning).
|
494
|
+
# On protovis, this method is called +extend+, but it should be changed
|
495
|
+
# because clashed with native +extend+ method
|
490
496
|
def mark_extend(proto)
|
491
497
|
@proto=proto
|
492
498
|
@target=proto.target
|
@@ -212,5 +212,33 @@ class Rubyvis::Mark
|
|
212
212
|
# See Mark for examples of use
|
213
213
|
mark_method :layout_cluster, Rubyvis::Layout::Cluster
|
214
214
|
|
215
|
+
##
|
216
|
+
# :method: layout_indent(opts,&block)
|
217
|
+
#
|
218
|
+
# Adds a Layout::Indent to current mark.
|
219
|
+
#
|
220
|
+
# If a block is provided, the context will be defined differently if
|
221
|
+
# parameter is provided
|
222
|
+
# * Without parameter: block executed inside context of new mark
|
223
|
+
# * With paramenter: block executed inside context of current mark.
|
224
|
+
# Paramenter references new mark
|
225
|
+
#
|
226
|
+
# See Mark for examples of use
|
227
|
+
mark_method :layout_indent, Rubyvis::Layout::Indent
|
228
|
+
|
229
|
+
##
|
230
|
+
# :method: layout_pack(opts,&block)
|
231
|
+
#
|
232
|
+
# Adds a Layout::Pack to current mark.
|
233
|
+
#
|
234
|
+
# If a block is provided, the context will be defined differently if
|
235
|
+
# parameter is provided
|
236
|
+
# * Without parameter: block executed inside context of new mark
|
237
|
+
# * With paramenter: block executed inside context of current mark.
|
238
|
+
# Paramenter references new mark
|
239
|
+
#
|
240
|
+
# See Mark for examples of use
|
241
|
+
mark_method :layout_pack, Rubyvis::Layout::Pack
|
242
|
+
|
215
243
|
|
216
244
|
end
|
@@ -86,14 +86,40 @@ module Rubyvis
|
|
86
86
|
|
87
87
|
def self.append(e,scenes,index)
|
88
88
|
e._scene=OpenStruct.new({:scenes=>scenes, :index=>index})
|
89
|
-
|
89
|
+
e=self.title(e,scenes[index])
|
90
90
|
|
91
91
|
if(!e.parent)
|
92
92
|
scenes._g.add_element(e)
|
93
93
|
end
|
94
94
|
return e.next_sibling_node
|
95
95
|
end
|
96
|
-
|
96
|
+
|
97
|
+
# Applies a title tooltip to the specified element <tt>e</tt>, using the
|
98
|
+
# <tt>title</tt> property of the specified scene node <tt>s</tt>. Note that
|
99
|
+
# this implementation does not create an SVG <tt>title</tt> element as a child
|
100
|
+
# of <tt>e</tt>; although this is the recommended standard, it is only
|
101
|
+
# supported in Opera. Instead, an anchor element is created around the element
|
102
|
+
# <tt>e</tt>, and the <tt>xlink:title</tt> attribute is set accordingly.
|
103
|
+
#
|
104
|
+
# @param e an SVG element.
|
105
|
+
# @param s a scene node.
|
106
|
+
|
107
|
+
def self.title(e,s)
|
108
|
+
a = e.parent
|
109
|
+
a=nil if (a and (a.tag_name != "a"))
|
110
|
+
if (s.title)
|
111
|
+
if (!a)
|
112
|
+
a = self.create("a")
|
113
|
+
e.parent.replace_child(a, e) if (e.parent)
|
114
|
+
a.add_element(e)
|
115
|
+
end
|
116
|
+
a.add_attribute('xlink:title',s.title)
|
117
|
+
return a;
|
118
|
+
end
|
119
|
+
a.parent_node.replace_child(e, a) if (a)
|
120
|
+
e
|
121
|
+
end
|
122
|
+
|
97
123
|
def self.expect(e, type, attributes, style=nil)
|
98
124
|
|
99
125
|
if (e)
|
data/lib/rubyvis/sceneelement.rb
CHANGED
@@ -8,7 +8,7 @@ module Rubyvis
|
|
8
8
|
end
|
9
9
|
include Enumerable
|
10
10
|
attr_accessor :visible
|
11
|
-
attr_accessor :mark, :type, :child_index, :parent, :parent_index, :target, :defs, :data, :antialias, :line_width, :fill_style, :overflow, :width, :height, :top, :bottom, :left, :right, :title, :reverse, :stroke_style, :transform, :canvas, :_g, :events, :cursor, :children, :id, :segmented, :interpolate, :tension, :name, :text_baseline, :text_align, :text, :font, :text_angle, :text_style, :text_margin, :text_decoration, :text_shadow, :line_join, :eccentricity, :shape_size, :shape, :shape_angle, :shape_radius, :start_angle, :end_angle, :angle, :inner_radius, :outer_radius, :layers, :orient, :offset, :order,:url, :image_width, :image_height, :image, :_id, :nodes, :round, :links, :padding_left, :padding_right, :padding_top, :padding_bottom, :mode, :group
|
11
|
+
attr_accessor :mark, :type, :child_index, :parent, :parent_index, :target, :defs, :data, :antialias, :line_width, :fill_style, :overflow, :width, :height, :top, :bottom, :left, :right, :title, :reverse, :stroke_style, :transform, :canvas, :_g, :events, :cursor, :children, :id, :segmented, :interpolate, :tension, :name, :text_baseline, :text_align, :text, :font, :text_angle, :text_style, :text_margin, :text_decoration, :text_shadow, :line_join, :eccentricity, :shape_size, :shape, :shape_angle, :shape_radius, :start_angle, :end_angle, :angle, :inner_radius, :outer_radius, :layers, :orient, :offset, :order,:url, :image_width, :image_height, :image, :_id, :nodes, :round, :links, :padding_left, :padding_right, :padding_top, :padding_bottom, :mode, :group, :depth, :breadth, :spacing
|
12
12
|
|
13
13
|
def []=(v,i)
|
14
14
|
if v.is_a? Numeric
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyvis
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 3
|
10
|
+
version: 0.3.3
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Claudio Bustos
|
@@ -152,8 +152,10 @@ files:
|
|
152
152
|
- examples/bar_column_chart.rb
|
153
153
|
- examples/barley/barley.rb
|
154
154
|
- examples/barley/barley_data.rb
|
155
|
+
- examples/bubble_charts.rb
|
155
156
|
- examples/cars/cars.rb
|
156
157
|
- examples/cars/cars_data.rb
|
158
|
+
- examples/circle_packing.rb
|
157
159
|
- examples/crimea/crimea_data.rb
|
158
160
|
- examples/crimea/crimea_grouped_bar.rb
|
159
161
|
- examples/crimea/crimea_line.rb
|
@@ -165,6 +167,7 @@ files:
|
|
165
167
|
- examples/grouped_charts.rb
|
166
168
|
- examples/icicle.rb
|
167
169
|
- examples/image.rb
|
170
|
+
- examples/indent.rb
|
168
171
|
- examples/line.rb
|
169
172
|
- examples/line_and_step.rb
|
170
173
|
- examples/line_interpolation.rb
|
@@ -181,6 +184,7 @@ files:
|
|
181
184
|
- lib/rubyvis/color/color.rb
|
182
185
|
- lib/rubyvis/color/colors.rb
|
183
186
|
- lib/rubyvis/dom.rb
|
187
|
+
- lib/rubyvis/flatten.rb
|
184
188
|
- lib/rubyvis/format.rb
|
185
189
|
- lib/rubyvis/format/date.rb
|
186
190
|
- lib/rubyvis/format/number.rb
|
@@ -190,7 +194,9 @@ files:
|
|
190
194
|
- lib/rubyvis/layout.rb
|
191
195
|
- lib/rubyvis/layout/cluster.rb
|
192
196
|
- lib/rubyvis/layout/hierarchy.rb
|
197
|
+
- lib/rubyvis/layout/indent.rb
|
193
198
|
- lib/rubyvis/layout/network.rb
|
199
|
+
- lib/rubyvis/layout/pack.rb
|
194
200
|
- lib/rubyvis/layout/partition.rb
|
195
201
|
- lib/rubyvis/layout/stack.rb
|
196
202
|
- lib/rubyvis/layout/treemap.rb
|
metadata.gz.sig
CHANGED
Binary file
|