rubyvis 0.3.6 → 0.4.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 +16 -0
- data/Manifest.txt +61 -0
- data/README.txt +9 -7
- data/Rakefile +1 -1
- data/lib/rubyvis.rb +3 -17
- data/lib/rubyvis/color/color.rb +11 -13
- data/lib/rubyvis/flatten.rb +5 -7
- data/lib/rubyvis/layout/stack.rb +15 -10
- data/lib/rubyvis/mark.rb +10 -2
- data/lib/rubyvis/mark/area.rb +5 -3
- data/lib/rubyvis/mark/line.rb +4 -3
- data/lib/rubyvis/mark/panel.rb +8 -3
- data/lib/rubyvis/mark/rule.rb +1 -0
- data/lib/rubyvis/scene/svg_area.rb +17 -17
- data/lib/rubyvis/scene/svg_curve.rb +8 -5
- data/lib/rubyvis/scene/svg_line.rb +32 -29
- data/lib/rubyvis/scene/svg_scene.rb +3 -5
- data/lib/rubyvis/scene/svg_wedge.rb +4 -3
- data/lib/rubyvis/vector.rb +104 -0
- data/spec/anchor_spec.rb +29 -0
- data/spec/area_spec.rb +83 -0
- data/spec/bar_spec.rb +3 -0
- data/spec/color_spec.rb +13 -1
- data/spec/dot_spec.rb +41 -0
- data/spec/fixtures/anchor.html +25 -0
- data/spec/fixtures/anchor.svg +1 -0
- data/spec/fixtures/area-segmented.html +29 -0
- data/spec/fixtures/area_interpolation.html +66 -0
- data/spec/fixtures/area_interpolation.svg +1 -0
- data/spec/fixtures/area_segmented.svg +1 -0
- data/spec/fixtures/dot-anchor.html +33 -0
- data/spec/fixtures/dot_anchor.svg +1 -0
- data/spec/fixtures/layers.js +28 -0
- data/spec/fixtures/layout_arc.svg +1 -0
- data/spec/fixtures/layout_cluster.html +39 -0
- data/spec/fixtures/layout_cluster.svg +1 -0
- data/spec/fixtures/layout_cluster_left_group_2.html +39 -0
- data/spec/fixtures/layout_cluster_left_group_2.svg +1 -0
- data/spec/fixtures/layout_grid.html +34 -0
- data/spec/fixtures/layout_grid.svg +1 -0
- data/spec/fixtures/layout_horizon.svg +24 -0
- data/spec/fixtures/layout_indent.html +39 -0
- data/spec/fixtures/layout_indent.svg +1 -0
- data/spec/fixtures/layout_matrix.svg +1 -0
- data/spec/fixtures/layout_pack.html +38 -0
- data/spec/fixtures/layout_pack.svg +1 -0
- data/spec/fixtures/layout_partition_fill.html +40 -0
- data/spec/fixtures/layout_partition_fill.svg +32 -0
- data/spec/fixtures/layout_tree_orient_left.html +36 -0
- data/spec/fixtures/layout_tree_orient_left.svg +1 -0
- data/spec/fixtures/layout_tree_orient_radial_breadth_20.html +39 -0
- data/spec/fixtures/layout_tree_orient_radial_breadth_20.svg +1 -0
- data/spec/fixtures/layout_tree_orient_top.svg +1 -0
- data/spec/fixtures/layout_treemap.svg +1 -0
- data/spec/fixtures/line_interpolation.html +63 -0
- data/spec/fixtures/line_interpolation.svg +1 -0
- data/spec/fixtures/line_interpolation_segmented.html +65 -0
- data/spec/fixtures/line_interpolation_segmented.svg +1 -0
- data/spec/fixtures/protovis-r3.3.js +287 -0
- data/spec/fixtures/rule-anchor.html +33 -0
- data/spec/fixtures/rule_anchor.svg +1 -0
- data/spec/fixtures/stack-expand.html +41 -0
- data/spec/fixtures/stack-silohouette.html +41 -0
- data/spec/fixtures/stack-wiggle.html +41 -0
- data/spec/fixtures/stack_expand.svg +1 -0
- data/spec/fixtures/stack_silohouette.svg +1 -0
- data/spec/fixtures/stack_wiggle.svg +1 -0
- data/spec/fixtures/svgscene.html +26 -0
- data/spec/fixtures/wedge-anchor.html +33 -0
- data/spec/fixtures/wedge-donut.html +35 -0
- data/spec/fixtures/wedge_anchor.svg +1 -0
- data/spec/fixtures/wedge_donut.svg +1 -0
- data/spec/flatten_spec.rb +47 -0
- data/spec/layout_arc_spec.rb +7 -26
- data/spec/layout_cluster_spec.rb +52 -0
- data/spec/layout_grid_spec.rb +40 -0
- data/spec/layout_horizon_spec.rb +6 -25
- data/spec/layout_indent_spec.rb +53 -0
- data/spec/layout_matrix_spec.rb +25 -52
- data/spec/layout_pack_spec.rb +49 -0
- data/spec/layout_partition_spec.rb +45 -0
- data/spec/layout_stack_spec.rb +60 -0
- data/spec/layout_tree_spec.rb +56 -0
- data/spec/layout_treemap_spec.rb +41 -0
- data/spec/line_spec.rb +118 -0
- data/spec/mark_spec.rb +4 -0
- data/spec/panel_spec.rb +12 -1
- data/spec/rule_spec.rb +34 -0
- data/spec/spec_helper.rb +158 -3
- data/spec/vector_spec.rb +36 -0
- data/spec/wedge_spec.rb +66 -0
- metadata +67 -14
- metadata.gz.sig +0 -0
data/lib/rubyvis/mark/area.rb
CHANGED
@@ -67,13 +67,15 @@ module Rubyvis
|
|
67
67
|
|
68
68
|
def area_bind
|
69
69
|
mark_bind
|
70
|
-
binds = self.binds
|
71
70
|
|
71
|
+
binds = self.binds
|
72
72
|
required = binds.required
|
73
73
|
optional = binds.optional
|
74
|
+
|
74
75
|
optional.size.times {|i|
|
75
76
|
prop = optional[i]
|
76
|
-
prop.fixed = fixed.include? prop.name
|
77
|
+
prop.fixed = fixed.keys.include? prop.name
|
78
|
+
|
77
79
|
if (prop.name == "segmented")
|
78
80
|
required.push(prop)
|
79
81
|
end
|
@@ -95,7 +97,7 @@ module Rubyvis
|
|
95
97
|
}).tension(lambda {
|
96
98
|
self.scene.target[self.index].tension
|
97
99
|
})
|
98
|
-
|
100
|
+
anchor
|
99
101
|
end
|
100
102
|
end
|
101
103
|
|
data/lib/rubyvis/mark/line.rb
CHANGED
@@ -7,12 +7,13 @@ module Rubyvis
|
|
7
7
|
module LinePrototype # :nodoc:
|
8
8
|
include AreaPrototype
|
9
9
|
def line_anchor(name)
|
10
|
+
|
10
11
|
anchor=area_anchor(name).text_align(lambda {|d|
|
11
|
-
{'left'=>'right','bottom'=>'center', 'top'=>'center','center'=>'center','right'=>'left'}[self.name]
|
12
|
+
{'left'=>'right', 'bottom'=>'center', 'top'=>'center', 'center'=>'center','right'=>'left'}[self.name()]
|
12
13
|
}).text_baseline(lambda{|d|
|
13
|
-
{'top'=>'bottom', 'right'=>'middle', 'left'=>'middle','center'=>'middle','bottom'=>'top'}[self.name]
|
14
|
+
{'top'=>'bottom', 'right'=>'middle', 'left'=>'middle','center'=>'middle', 'bottom'=>'top'}[self.name()]
|
14
15
|
})
|
15
|
-
|
16
|
+
anchor
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
data/lib/rubyvis/mark/panel.rb
CHANGED
@@ -96,18 +96,23 @@ module Rubyvis
|
|
96
96
|
end
|
97
97
|
if s.width.nil?
|
98
98
|
w=Rubyvis.css(c,'width')
|
99
|
-
s.width=w-s.left-s.right
|
99
|
+
s.width=w - s.left - s.right
|
100
100
|
end
|
101
101
|
if s.height.nil?
|
102
102
|
w=Rubyvis.css(c,'height')
|
103
|
-
s.height=h-s.top-s.bottom
|
103
|
+
s.height=h - s.top - s.bottom
|
104
104
|
end
|
105
105
|
|
106
106
|
else
|
107
107
|
@_canvas||={}
|
108
108
|
cache=@_canvas
|
109
109
|
if(!(c=cache[self.index]))
|
110
|
-
|
110
|
+
document=REXML::Document.new
|
111
|
+
document.add_element("document")
|
112
|
+
cache[self.index]=document.root
|
113
|
+
c=cache[self.index]
|
114
|
+
|
115
|
+
#c=cache[self.index]=Rubyvis.document.add_element('span')
|
111
116
|
end
|
112
117
|
end
|
113
118
|
s.canvas=c
|
data/lib/rubyvis/mark/rule.rb
CHANGED
@@ -4,7 +4,7 @@ module Rubyvis
|
|
4
4
|
e = scenes._g.elements[1]
|
5
5
|
return e if scenes.size==0
|
6
6
|
s=scenes[0]
|
7
|
-
# segmented
|
7
|
+
# segmented
|
8
8
|
return self.area_segment(scenes) if (s.segmented)
|
9
9
|
# visible
|
10
10
|
return e if (!s.visible)
|
@@ -63,8 +63,8 @@ module Rubyvis
|
|
63
63
|
}
|
64
64
|
|
65
65
|
if (s.interpolate == "basis")
|
66
|
-
pathT = Rubyvis::SvgScene.curve_basis(pointsT)
|
67
|
-
pathB = Rubyvis::SvgScene.curve_basis(pointsB)
|
66
|
+
pathT = Rubyvis::SvgScene.curve_basis(pointsT)
|
67
|
+
pathB = Rubyvis::SvgScene.curve_basis(pointsB)
|
68
68
|
elsif (s.interpolate == "cardinal")
|
69
69
|
pathT = Rubyvis::SvgScene.curve_cardinal(pointsT, s.tension);
|
70
70
|
pathB = Rubyvis::SvgScene.curve_cardinal(pointsB, s.tension);
|
@@ -127,12 +127,10 @@ module Rubyvis
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def self.area_segment(scenes)
|
130
|
-
|
131
130
|
e = scenes._g.elements[1]
|
132
131
|
s = scenes[0]
|
133
|
-
pathsT=
|
134
|
-
pathsB=
|
135
|
-
|
132
|
+
pathsT=nil
|
133
|
+
pathsB=nil
|
136
134
|
if (s.interpolate == "basis" or s.interpolate == "cardinal" or s.interpolate == "monotone")
|
137
135
|
pointsT = []
|
138
136
|
pointsB = []
|
@@ -144,16 +142,17 @@ module Rubyvis
|
|
144
142
|
}
|
145
143
|
|
146
144
|
if (s.interpolate == "basis")
|
147
|
-
|
148
|
-
|
149
|
-
elsif (s.interpolate == "cardinal")
|
150
|
-
|
151
|
-
|
145
|
+
pathsT = Rubyvis::SvgScene.curve_basis_segments(pointsT)
|
146
|
+
pathsB = Rubyvis::SvgScene.curve_basis_segments(pointsB)
|
147
|
+
elsif (s.interpolate == "cardinal")
|
148
|
+
pathsT = Rubyvis::SvgScene.curve_cardinal_segments(pointsT, s.tension);
|
149
|
+
pathsB = Rubyvis::SvgScene.curve_cardinal_segments(pointsB, s.tension);
|
152
150
|
elsif # monotone
|
153
|
-
|
154
|
-
|
151
|
+
pathsT = Rubyvis::SvgScene.curve_monotone_segments(pointsT)
|
152
|
+
pathsB = Rubyvis::SvgScene.curve_monotone_segments(pointsB)
|
155
153
|
end
|
156
154
|
end
|
155
|
+
|
157
156
|
n=scenes.size-1
|
158
157
|
n.times {|i|
|
159
158
|
|
@@ -163,9 +162,10 @@ module Rubyvis
|
|
163
162
|
# /* visible */
|
164
163
|
next if (!s1.visible or !s2.visible)
|
165
164
|
|
166
|
-
fill =
|
167
|
-
stroke =
|
168
|
-
next
|
165
|
+
fill = s1.fill_style
|
166
|
+
stroke = s1.stroke_style
|
167
|
+
next if (fill.opacity==0 and stroke.opacity==0)
|
168
|
+
|
169
169
|
d=nil
|
170
170
|
if (pathsT)
|
171
171
|
pathT = pathsT[i]
|
@@ -102,7 +102,7 @@ module Rubyvis::SvgScene
|
|
102
102
|
p1 = p2;
|
103
103
|
p2 = p3;
|
104
104
|
p3 = points[2];
|
105
|
-
paths.push(firstPath + self.path_basis(p0, p1, p2, p3))
|
105
|
+
paths.push(firstPath + self.path_basis(p0, p1, p2, p3).to_s) # merge first & second path
|
106
106
|
3.upto(points.size-1) {|i|
|
107
107
|
p0 = p1;
|
108
108
|
p1 = p2;
|
@@ -112,7 +112,7 @@ module Rubyvis::SvgScene
|
|
112
112
|
}
|
113
113
|
|
114
114
|
# merge last & second-to-last path
|
115
|
-
paths.push(path_basis(p1, p2, p3, p3).segment + path_basis(p2, p3, p3, p3))
|
115
|
+
paths.push(path_basis(p1, p2, p3, p3).segment + path_basis(p2, p3, p3, p3).to_s)
|
116
116
|
paths
|
117
117
|
end
|
118
118
|
|
@@ -258,11 +258,14 @@ module Rubyvis::SvgScene
|
|
258
258
|
d = []
|
259
259
|
m = []
|
260
260
|
dx = []
|
261
|
+
k=0
|
261
262
|
|
262
263
|
#/* Compute the slopes of the secant lines between successive points. */
|
263
|
-
|
264
|
+
|
265
|
+
while(k < points.size-1) do
|
264
266
|
d[k] = (points[k+1].top - points[k].top) / (points[k+1].left - points[k].left).to_f
|
265
|
-
|
267
|
+
k+=1
|
268
|
+
end
|
266
269
|
|
267
270
|
#/* Initialize the tangents at every point as the average of the secants. */
|
268
271
|
m[0] = d[0]
|
@@ -320,7 +323,7 @@ module Rubyvis::SvgScene
|
|
320
323
|
# * @param points the array of points.
|
321
324
|
#/
|
322
325
|
def self.curve_monotone_segments(points)
|
323
|
-
|
326
|
+
return "" if (points.size <= 2)
|
324
327
|
self.curve_hermite_segments(points, self.monotone_tangents(points))
|
325
328
|
end
|
326
329
|
|
@@ -15,7 +15,7 @@ module Rubyvis
|
|
15
15
|
return e if (fill.opacity==0.0 and stroke.opacity==0.0)
|
16
16
|
#/* points */
|
17
17
|
|
18
|
-
d = "M
|
18
|
+
d = "M#{s.left},#{s.top}"
|
19
19
|
|
20
20
|
if (scenes.size > 2 and (['basis', 'cardinal', 'monotone'].include? s.interpolate))
|
21
21
|
case (s.interpolate)
|
@@ -55,37 +55,40 @@ module Rubyvis
|
|
55
55
|
s = scenes[0];
|
56
56
|
paths=nil
|
57
57
|
case s.interpolate
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
when "basis"
|
59
|
+
paths = curve_basis_segments(scenes)
|
60
|
+
when "cardinal"
|
61
|
+
paths=curve_cardinal_segments(scenes, s.tension)
|
62
|
+
when "monotone"
|
63
|
+
paths = curve_monotone_segments(scenes)
|
64
64
|
end
|
65
65
|
|
66
|
-
(scenes.
|
66
|
+
(0...(scenes.size-1)).each {|i|
|
67
67
|
|
68
68
|
s1 = scenes[i]
|
69
69
|
s2 = scenes[i + 1];
|
70
|
-
|
70
|
+
#p "#{s1.top} #{s1.left} #{s1.line_width} #{s1.interpolate} #{s1.line_join}"
|
71
71
|
# visible
|
72
|
-
next if (!s1.visible
|
72
|
+
next if (!s1.visible or !s2.visible)
|
73
73
|
|
74
74
|
stroke = s1.stroke_style
|
75
|
-
fill = Rubyvis
|
75
|
+
fill = Rubyvis::Color.transparent
|
76
76
|
|
77
77
|
next if stroke.opacity==0.0
|
78
78
|
|
79
79
|
# interpolate
|
80
80
|
d=nil
|
81
|
-
if ((s1.interpolate == "linear") and (s1.
|
82
|
-
fill = stroke
|
83
|
-
stroke = Rubyvis
|
84
|
-
|
81
|
+
if ((s1.interpolate == "linear") and (s1.line_join == "miter"))
|
82
|
+
fill = stroke
|
83
|
+
stroke = Rubyvis::Color.transparent
|
84
|
+
s0=((i-1) < 0) ? nil : scenes[i-1]
|
85
|
+
s3=((i+2) >= scenes.size) ? nil : scenes[i+2]
|
86
|
+
|
87
|
+
d = path_join(s0, s1, s2, s3)
|
85
88
|
elsif(paths)
|
86
89
|
d = paths[i]
|
87
90
|
else
|
88
|
-
d = "M
|
91
|
+
d = "M#{s1.left},#{s1.top}#{path_segment(s1, s2)}"
|
89
92
|
end
|
90
93
|
|
91
94
|
e = SvgScene.expect(e, "path", {
|
@@ -102,7 +105,7 @@ module Rubyvis
|
|
102
105
|
});
|
103
106
|
e = SvgScene.append(e, scenes, i);
|
104
107
|
}
|
105
|
-
|
108
|
+
e
|
106
109
|
end
|
107
110
|
|
108
111
|
# Returns the path segment for the specified points. */
|
@@ -148,17 +151,16 @@ module Rubyvis
|
|
148
151
|
|
149
152
|
p2 = Rubyvis.vector(s2.left, s2.top)
|
150
153
|
|
151
|
-
|
152
|
-
|
153
|
-
v = p.perp().norm()
|
154
|
+
_p = p2.minus(p1)
|
154
155
|
|
155
|
-
|
156
|
+
v = _p.perp().norm()
|
157
|
+
|
158
|
+
w = v.times(s1.line_width / (2.0 * self.scale))
|
156
159
|
|
157
160
|
a = p1.plus(w)
|
158
161
|
b = p2.plus(w)
|
159
162
|
c = p2.minus(w)
|
160
163
|
d = p1.minus(w)
|
161
|
-
|
162
164
|
#/*
|
163
165
|
# * Start join. P0 is the previous line segment's start point. We define the
|
164
166
|
# * cutting plane as the average of the vector perpendicular to P0-P1, and
|
@@ -167,19 +169,20 @@ module Rubyvis
|
|
167
169
|
# * Note that we don't implement miter limits, so these can get wild.
|
168
170
|
# */
|
169
171
|
if (s0 and s0.visible)
|
170
|
-
v1 = p1.minus(s0.left, s0.top).perp().norm().plus(v)
|
171
|
-
d = line_intersect(p1, v1, d,
|
172
|
-
a = line_intersect(p1, v1, a,
|
172
|
+
v1 = p1.minus(s0.left, s0.top).perp().norm().plus(v)
|
173
|
+
d = line_intersect(p1, v1, d, _p)
|
174
|
+
a = line_intersect(p1, v1, a, _p)
|
173
175
|
end
|
174
176
|
|
175
177
|
#/* Similarly, for end join. */
|
176
|
-
if (s3
|
178
|
+
if (s3 and s3.visible)
|
177
179
|
v2 = Rubyvis.vector(s3.left, s3.top).minus(p2).perp().norm().plus(v);
|
178
|
-
c = line_intersect(p2, v2, c,
|
179
|
-
b = line_intersect(p2, v2, b,
|
180
|
+
c = line_intersect(p2, v2, c, _p);
|
181
|
+
b = line_intersect(p2, v2, b, _p);
|
180
182
|
end
|
181
183
|
|
182
|
-
|
184
|
+
d="M#{a.x},#{a.y}L#{b.x},#{b.y} #{c.x},#{c.y} #{d.x},#{d.y}"
|
185
|
+
d
|
183
186
|
end
|
184
187
|
end
|
185
188
|
end
|
@@ -9,7 +9,7 @@ require 'rubyvis/scene/svg_wedge'
|
|
9
9
|
require 'rubyvis/scene/svg_image'
|
10
10
|
require 'rubyvis/scene/svg_curve'
|
11
11
|
|
12
|
-
class REXML::Element
|
12
|
+
class REXML::Element #:nodoc:
|
13
13
|
attr_accessor :_scene
|
14
14
|
end
|
15
15
|
|
@@ -58,7 +58,6 @@ module Rubyvis
|
|
58
58
|
|
59
59
|
{:svg=>svg,:css=>css}
|
60
60
|
end
|
61
|
-
|
62
61
|
def self.update_all(scenes)
|
63
62
|
puts "update_all: #{scenes.inspect}" if $DEBUG
|
64
63
|
if (scenes.size>0 and scenes[0].reverse and scenes.type!='line' and scenes.type!='area')
|
@@ -85,12 +84,11 @@ module Rubyvis
|
|
85
84
|
|
86
85
|
def self.append(e,scenes,index)
|
87
86
|
e._scene=OpenStruct.new({:scenes=>scenes, :index=>index})
|
88
|
-
e=self.title(e,scenes[index])
|
89
|
-
|
87
|
+
e=self.title(e, scenes[index])
|
90
88
|
if(!e.parent)
|
91
89
|
scenes._g.add_element(e)
|
92
90
|
end
|
93
|
-
|
91
|
+
e.next_sibling_node
|
94
92
|
end
|
95
93
|
|
96
94
|
# Applies a title tooltip to the specified element <tt>e</tt>, using the
|
@@ -11,11 +11,12 @@ module Rubyvis
|
|
11
11
|
|
12
12
|
r1 = s.inner_radius
|
13
13
|
r2 = s.outer_radius
|
14
|
+
|
14
15
|
a = (s.angle).abs
|
15
16
|
_p=nil
|
16
17
|
|
17
18
|
if (a >= 2 * Math::PI)
|
18
|
-
if (r1)
|
19
|
+
if (r1!=0)
|
19
20
|
_p = "M0,#{r2 }A#{r2},#{r2} 0 1,1 0,#{-r2}A#{r2 },#{r2 } 0 1,1 0,#{r2}M0,#{r1}A#{r1},#{r1} 0 1,1 0,#{-r1}A#{r1},#{r1} 0 1,1 0,#{r1 }Z"
|
20
21
|
else
|
21
22
|
_p = "M0,#{r2}A#{r2},#{r2} 0 1,1 0,#{-r2}A#{r2},#{r2} 0 1,1 0,#{r2 }Z"
|
@@ -27,10 +28,10 @@ module Rubyvis
|
|
27
28
|
c2 = Math.cos(ea)
|
28
29
|
s1 = Math.sin(sa)
|
29
30
|
s2 = Math.sin(ea)
|
30
|
-
if (r1)
|
31
|
+
if (r1!=0)
|
31
32
|
_p = "M#{r2 * c1},#{r2 * s1}A#{r2},#{r2} 0 #{((a < Math::PI) ? "0" : "1")},1 #{r2 * c2},#{r2 * s2}L#{r1 * c2},#{r1 * s2}A#{r1},#{r1} 0 #{((a < Math::PI) ? "0" : "1")},0 #{r1 * c1},#{r1 * s1}Z"
|
32
33
|
else
|
33
|
-
_p = "M#{r2 * c1},#{r2 * s1}A#{r2},#{r2} 0 #{((a < Math
|
34
|
+
_p = "M#{r2 * c1},#{r2 * s1}A#{r2},#{r2} 0 #{((a < Math::PI) ? "0" : "1")},1 #{r2 * c2},#{r2 * s2}L0,0Z"
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
# Returns a {@link pv.Vector} for the specified <i>x</i> and <i>y</i>
|
3
|
+
# coordinate. This is a convenience factory method, equivalent to <tt>new
|
4
|
+
# pv.Vector(x, y)</tt>.
|
5
|
+
#
|
6
|
+
# @see pv.Vector
|
7
|
+
# @param {number} x the <i>x</i> coordinate.
|
8
|
+
# @param {number} y the <i>y</i> coordinate.
|
9
|
+
# @returns {pv.Vector} a vector for the specified coordinates.
|
10
|
+
|
11
|
+
def self.vector(x,y)
|
12
|
+
Rubyvis::Vector.new(x,y)
|
13
|
+
end
|
14
|
+
class Vector
|
15
|
+
attr_accessor :x,:y
|
16
|
+
# Constructs a {@link pv.Vector} for the specified <i>x</i> and <i>y</i>
|
17
|
+
# coordinate. This constructor should not be invoked directly; use
|
18
|
+
# {@link pv.vector} instead.
|
19
|
+
#
|
20
|
+
# @class Represents a two-dimensional vector; a 2-tuple <i>⟨x,
|
21
|
+
# y⟩</i>. The intent of this class is to simplify vector math. Note that
|
22
|
+
# in performance-sensitive cases it may be more efficient to represent 2D
|
23
|
+
# vectors as simple objects with <tt>x</tt> and <tt>y</tt> attributes, rather
|
24
|
+
# than using instances of this class.
|
25
|
+
#
|
26
|
+
# @param {number} x the <i>x</i> coordinate.
|
27
|
+
# @param {number} y the <i>y</i> coordinate.
|
28
|
+
def initialize(x,y)
|
29
|
+
@x=x
|
30
|
+
@y=y
|
31
|
+
end
|
32
|
+
def ==(v)
|
33
|
+
@x==v.x and @y==v.y
|
34
|
+
end
|
35
|
+
# Returns a vector perpendicular to this vector: <i>⟨-y, x⟩</i>.
|
36
|
+
#
|
37
|
+
# @returns {pv.Vector} a perpendicular vector.
|
38
|
+
#/
|
39
|
+
def perp
|
40
|
+
Rubyvis::Vector.new(-@y,@x)
|
41
|
+
end
|
42
|
+
# Returns a normalized copy of this vector: a vector with the same direction,
|
43
|
+
# but unit length. If this vector has zero length this method returns a copy of
|
44
|
+
# this vector.
|
45
|
+
#
|
46
|
+
# @returns {pv.Vector} a unit vector.
|
47
|
+
def norm
|
48
|
+
l=length()
|
49
|
+
times(l!=0 ? (1.0 / l) : 1.0)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns the magnitude of this vector, defined as <i>sqrt(x * x + y * y)</i>.
|
53
|
+
#
|
54
|
+
# @returns {number} a length.
|
55
|
+
def length
|
56
|
+
Math.sqrt(@x**2 + @y**2)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns a scaled copy of this vector: <i>⟨x * k, y * k⟩</i>.
|
60
|
+
# To perform the equivalent divide operation, use <i>1 / k</i>.
|
61
|
+
#
|
62
|
+
# @param {number} k the scale factor.
|
63
|
+
# @returns {pv.Vector} a scaled vector.
|
64
|
+
def times(k)
|
65
|
+
Rubyvis::Vector.new(@x * k, @y * k)
|
66
|
+
end
|
67
|
+
# Returns this vector plus the vector <i>v</i>: <i>⟨x + v.x, y +
|
68
|
+
# v.y⟩</i>. If only one argument is specified, it is interpreted as the
|
69
|
+
# vector <i>v</i>.
|
70
|
+
#
|
71
|
+
# @param {number} x the <i>x</i> coordinate to add.
|
72
|
+
# @param {number} y the <i>y</i> coordinate to add.
|
73
|
+
# @returns {pv.Vector} a new vector.
|
74
|
+
def plus(x,y=nil)
|
75
|
+
|
76
|
+
return (y.nil?) ? Rubyvis::Vector.new(@x + x.x, @y + x.y) : Rubyvis::Vector.new(@x + x, @y + y)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Returns this vector minus the vector <i>v</i>: <i>⟨x - v.x, y -
|
80
|
+
# v.y⟩</i>. If only one argument is specified, it is interpreted as the
|
81
|
+
# vector <i>v</i>.
|
82
|
+
#
|
83
|
+
# @param {number} x the <i>x</i> coordinate to subtract.
|
84
|
+
# @param {number} y the <i>y</i> coordinate to subtract.
|
85
|
+
# @returns {pv.Vector} a new vector.
|
86
|
+
|
87
|
+
def minus(x,y=nil)
|
88
|
+
|
89
|
+
return (y.nil?) ? Rubyvis::Vector.new(@x - x.x, @y - x.y) : Rubyvis::Vector.new(@x - x, @y - y)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Returns the dot product of this vector and the vector <i>v</i>: <i>x * v.x +
|
93
|
+
# y * v.y</i>. If only one argument is specified, it is interpreted as the
|
94
|
+
# vector <i>v</i>.
|
95
|
+
#
|
96
|
+
# @param {number} x the <i>x</i> coordinate to dot.
|
97
|
+
# @param {number} y the <i>y</i> coordinate to dot.
|
98
|
+
# @returns {number} a dot product.
|
99
|
+
def dot(x, y=nil)
|
100
|
+
(y.nil?) ? @x * x.x + @y * x.y : @x * x + @y * y
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|