rubyvis 0.3.6 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|