rubyvis 0.1.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 +3 -0
- data/Manifest.txt +44 -0
- data/README.txt +64 -0
- data/Rakefile +16 -0
- data/examples/crimea-line.rb +64 -0
- data/examples/first.rb +17 -0
- data/examples/second.rb +14 -0
- data/lib/rubyvis.rb +43 -0
- data/lib/rubyvis/color/color.rb +241 -0
- data/lib/rubyvis/color/colors.rb +40 -0
- data/lib/rubyvis/color/ramp.rb +0 -0
- data/lib/rubyvis/format.rb +19 -0
- data/lib/rubyvis/format/date.rb +18 -0
- data/lib/rubyvis/format/number.rb +31 -0
- data/lib/rubyvis/internals.rb +215 -0
- data/lib/rubyvis/javascript_behaviour.rb +64 -0
- data/lib/rubyvis/label.rb +0 -0
- data/lib/rubyvis/mark.rb +528 -0
- data/lib/rubyvis/mark/anchor.rb +22 -0
- data/lib/rubyvis/mark/area.rb +34 -0
- data/lib/rubyvis/mark/bar.rb +23 -0
- data/lib/rubyvis/mark/label.rb +17 -0
- data/lib/rubyvis/mark/line.rb +14 -0
- data/lib/rubyvis/mark/panel.rb +87 -0
- data/lib/rubyvis/mark/rule.rb +28 -0
- data/lib/rubyvis/scale.rb +34 -0
- data/lib/rubyvis/scale/linear.rb +5 -0
- data/lib/rubyvis/scale/ordinal.rb +52 -0
- data/lib/rubyvis/scale/quantitative.rb +263 -0
- data/lib/rubyvis/scene/svg_bar.rb +31 -0
- data/lib/rubyvis/scene/svg_label.rb +51 -0
- data/lib/rubyvis/scene/svg_panel.rb +117 -0
- data/lib/rubyvis/scene/svg_rule.rb +29 -0
- data/lib/rubyvis/scene/svg_scene.rb +118 -0
- data/lib/rubyvis/sceneelement.rb +44 -0
- data/lib/rubyvis/transform.rb +25 -0
- data/spec/internal_spec.rb +146 -0
- data/spec/javascript_behaviour_spec.rb +64 -0
- data/spec/panel_spec.rb +8 -0
- data/spec/scale_linear_spec.rb +121 -0
- data/spec/scale_spec.rb +8 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +27 -0
- metadata +160 -0
- metadata.gz.sig +2 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Anchor(target)
|
3
|
+
Rubyvis::Anchor.new(target)
|
4
|
+
end
|
5
|
+
|
6
|
+
class Anchor < Mark
|
7
|
+
@properties=Mark.properties
|
8
|
+
attr_accessor_dsl :name, :text_baseline, :text_align
|
9
|
+
def type
|
10
|
+
'area'
|
11
|
+
end
|
12
|
+
def initialize(target)
|
13
|
+
super()
|
14
|
+
self.target=target
|
15
|
+
self.parent=target.parent
|
16
|
+
end
|
17
|
+
def _extend(proto)
|
18
|
+
self.proto=proto
|
19
|
+
return self
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Area
|
3
|
+
Rubyvis::Area
|
4
|
+
end
|
5
|
+
|
6
|
+
class Area < Mark
|
7
|
+
@properties=Mark.properties
|
8
|
+
attr_accessor_dsl :width, :height, :line_width, :stroke_style, :fill_style, :segmented, :interpolate, :tension
|
9
|
+
def type
|
10
|
+
'area'
|
11
|
+
end
|
12
|
+
def defaults
|
13
|
+
sd=super
|
14
|
+
return sd.merge({:line_width=>1.5, :fill_style=>pv.Colors.category20.by(pv.parent), :interpolate=>'linear', :tension=>0.7})
|
15
|
+
end
|
16
|
+
def build_implied(s)
|
17
|
+
s.heigth=0 if s.height.nil?
|
18
|
+
s.width=0 if s.width.nil?
|
19
|
+
super(s)
|
20
|
+
end
|
21
|
+
def self.anchor(name)
|
22
|
+
Mark.anchor(name).interpolate(lambda {
|
23
|
+
self.scene.target[self.index].interpolate
|
24
|
+
}).eccentricity(lambda {
|
25
|
+
self.scene.target[self.index].eccentricity
|
26
|
+
}).tension(lambda {
|
27
|
+
self.scene.target[self.index].tension
|
28
|
+
})
|
29
|
+
end
|
30
|
+
def anchor
|
31
|
+
(self.class).anchor(name)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Bar
|
3
|
+
Rubyvis::Bar
|
4
|
+
end
|
5
|
+
class Bar < Mark
|
6
|
+
def type
|
7
|
+
"bar"
|
8
|
+
end
|
9
|
+
|
10
|
+
@properties=Mark.properties
|
11
|
+
attr_accessor_dsl :width, :height, :line_width, :stroke_style, :fill_style
|
12
|
+
def defaults
|
13
|
+
sd=super
|
14
|
+
return sd.merge({:line_width=>1.5, :fill_style=>Rubyvis.Colors.category20().by(Rubyvis.parent)})
|
15
|
+
end
|
16
|
+
def svg_render_pre
|
17
|
+
"<rect fill='#{pr_svg(:fill_style)}' height='#{pr_svg(:height)}' width='#{pr_svg(:width)}' x='#{pr_svg(:left)}' y='#{pr_svg(:top)}'>"
|
18
|
+
end
|
19
|
+
def svg_render_post
|
20
|
+
"</rect>"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Label
|
3
|
+
Rubyvis::Label
|
4
|
+
end
|
5
|
+
|
6
|
+
class Label < Mark
|
7
|
+
@properties=Mark.properties
|
8
|
+
attr_accessor_dsl :text, :font, :text_angle, :text_style, :text_align, :text_baseline, :text_margin, :text_decoration, :text_shadow
|
9
|
+
def type
|
10
|
+
'label'
|
11
|
+
end
|
12
|
+
def defaults
|
13
|
+
sd=super
|
14
|
+
return sd.merge({:events=>'none', :text=>lambda{|x| puts "->#{x}"; x}, :font=>"10px sans-serif", :text_angle=>0, :text_style=>pv.color('black'), :text_align=>'left', :text_baseline=>'bottom', :text_margin=>3})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Line
|
3
|
+
Rubyvis::Line
|
4
|
+
end
|
5
|
+
|
6
|
+
class Line < Mark
|
7
|
+
@properties=Mark.properties
|
8
|
+
attr_accessor_dsl :line_width, :line_join, :stroke_style, :fill_style, :segmented, :interporale, :eccentricity, :tension
|
9
|
+
def defaults
|
10
|
+
sd=super
|
11
|
+
return sd.merge({:line_join=>'miter', :line_width=>1.5, :stroke_style=>RubyVis::Color.category10().by(pv.parent), :interpolate=>'linear', :eccentricity=>0, :tension=>7})
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Panel
|
3
|
+
Rubyvis::Panel
|
4
|
+
end
|
5
|
+
class Panel < Bar
|
6
|
+
def type
|
7
|
+
"panel"
|
8
|
+
end
|
9
|
+
|
10
|
+
@properties=Bar.properties
|
11
|
+
attr_accessor_dsl :transform, :overflow, :canvas
|
12
|
+
attr_accessor :children, :root
|
13
|
+
def initialize
|
14
|
+
super
|
15
|
+
@children=[]
|
16
|
+
@root=self
|
17
|
+
end
|
18
|
+
def defaults
|
19
|
+
sd=super
|
20
|
+
return sd.merge({:fill_style=>nil, :overflow=>'visible', :canvas=>Rubyvis.document.add_element("canvas")})
|
21
|
+
end
|
22
|
+
def add(type)
|
23
|
+
child=type.new
|
24
|
+
child.parent=self
|
25
|
+
child.root=root
|
26
|
+
child.child_index=children.size
|
27
|
+
children.push(child)
|
28
|
+
child
|
29
|
+
end
|
30
|
+
|
31
|
+
attr_reader :_canvas
|
32
|
+
def bind
|
33
|
+
super
|
34
|
+
children.each {|c|
|
35
|
+
c.bind()
|
36
|
+
}
|
37
|
+
end
|
38
|
+
def build_instance(s)
|
39
|
+
super(s)
|
40
|
+
return if !s.visible
|
41
|
+
s.children=[] if !s.children
|
42
|
+
scale=self.scale*s.transform.k
|
43
|
+
n=self.children.size
|
44
|
+
Mark.index=-1
|
45
|
+
n.times {|i|
|
46
|
+
child=children[i]
|
47
|
+
child.scene=s.children[i]
|
48
|
+
child.scale=scale
|
49
|
+
child.build()
|
50
|
+
}
|
51
|
+
n.times {|i|
|
52
|
+
child=children[i]
|
53
|
+
s.children[i]=child.scene
|
54
|
+
child.scene=nil
|
55
|
+
child.scale=nil
|
56
|
+
}
|
57
|
+
s.children=s.children[0,n]
|
58
|
+
end
|
59
|
+
def build_implied(s)
|
60
|
+
if(!self.parent)
|
61
|
+
c=s.canvas
|
62
|
+
if(c)
|
63
|
+
if s.width.nil?
|
64
|
+
w=Rubyvis.css(c,'width')
|
65
|
+
s.width=w-s.left-s.right
|
66
|
+
end
|
67
|
+
if s.height.nil?
|
68
|
+
w=Rubyvis.css(c,'height')
|
69
|
+
s.height=h-s.top-s.bottom
|
70
|
+
end
|
71
|
+
else
|
72
|
+
@_canvas||={}
|
73
|
+
cache=@_canvas
|
74
|
+
if(!(c=cache[self.index]))
|
75
|
+
c=cache[this.index]=Rubyvis.add_element('span')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
s.canvas=c
|
79
|
+
end
|
80
|
+
|
81
|
+
s.transform=Rubyvis.Transform.identity if (s.transform.nil?)
|
82
|
+
super(s)
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Rule
|
3
|
+
Rubyvis::Rule
|
4
|
+
end
|
5
|
+
class Rule < Mark
|
6
|
+
@properties=Mark.properties
|
7
|
+
attr_accessor_dsl :width, :height, :line_width, :stroke_style
|
8
|
+
def defaults
|
9
|
+
sd=super
|
10
|
+
return sd.merge({:line_width=>1,:stroke_style=>pv.color('black'),:antialias=>false})
|
11
|
+
end
|
12
|
+
def type
|
13
|
+
'rule'
|
14
|
+
end
|
15
|
+
def build_implied(s)
|
16
|
+
l=s.left
|
17
|
+
r=s.right
|
18
|
+
t=s.top
|
19
|
+
b=s.bottom
|
20
|
+
if((!s.width.nil?) or ((l.nil?) and (r.nil?)) or ((!r.nil?) or (!l.nil?)))
|
21
|
+
s.height=0
|
22
|
+
else
|
23
|
+
s.width=0
|
24
|
+
end
|
25
|
+
super(s)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
def self.Scale
|
3
|
+
Rubyvis::Scale
|
4
|
+
end
|
5
|
+
module Scale
|
6
|
+
def self.quantitative(*args)
|
7
|
+
Quantitative.new(*args)
|
8
|
+
end
|
9
|
+
def self.linear(*args)
|
10
|
+
Linear.new(*args)
|
11
|
+
end
|
12
|
+
def self.ordinal(*args)
|
13
|
+
Ordinal.new(*args)
|
14
|
+
end
|
15
|
+
def self.interpolator(start,_end)
|
16
|
+
if start.is_a? Numeric
|
17
|
+
return lambda {|t| t*(_end-start)+start}
|
18
|
+
end
|
19
|
+
start=Rubyvis.color(start).rgb()
|
20
|
+
_end = Rubyvis.color(_end).rgb()
|
21
|
+
return lambda {|t|
|
22
|
+
a=start.a*(1-t)+_end.a*t
|
23
|
+
a=0 if a<1e-5
|
24
|
+
return (start.a == 0) ? Rubyvis.rgb(_end.r, _end.g, _end.b, a) : ((_end.a == 0) ? pv.rgb(start.r, start.g, start.b, a) : Rubyvis.rgb(
|
25
|
+
(start.r * (1 - t) + _end.r * t).round,
|
26
|
+
(start.g * (1 - t) + _end.g * t).round,
|
27
|
+
(start.b * (1 - t) + _end.b * t).round, a))
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
require 'rubyvis/scale/quantitative.rb'
|
33
|
+
require 'rubyvis/scale/linear.rb'
|
34
|
+
require 'rubyvis/scale/ordinal.rb'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
class Scale::Ordinal
|
3
|
+
include Rubyvis::Scale
|
4
|
+
|
5
|
+
def initialize(*args)
|
6
|
+
@d=[] # domain
|
7
|
+
@i={}
|
8
|
+
@r=[]
|
9
|
+
@band=0
|
10
|
+
domain(*args)
|
11
|
+
end
|
12
|
+
def scale(x)
|
13
|
+
if @i[x].nil?
|
14
|
+
@d.push(x)
|
15
|
+
@i[x]=@d.size-1
|
16
|
+
end
|
17
|
+
@r[@i[x] % @r.size]
|
18
|
+
end
|
19
|
+
def domain(*arguments)
|
20
|
+
array,f=arguments[0],arguments[1]
|
21
|
+
if(arguments.size>0)
|
22
|
+
array= (array.is_a? Array) ? ((arguments.size>1) ? array.map(&f) : array) : arguments.dup
|
23
|
+
@d=array.uniq
|
24
|
+
i=pv.numerate(d)
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
@d
|
28
|
+
end
|
29
|
+
def range(*arguments)
|
30
|
+
array, f = arguments[0],arguments[1]
|
31
|
+
if(arguments.size>0)
|
32
|
+
@r=(array.is_a? Array) ? ((arguments.size>1) ? array.map(&f) : array) : arguments.dup
|
33
|
+
if @r[0].is_a? String
|
34
|
+
@r=@r.map {|i| pv.color(i)}
|
35
|
+
end
|
36
|
+
self
|
37
|
+
end
|
38
|
+
@r
|
39
|
+
end
|
40
|
+
def split(min,max)
|
41
|
+
step=(max-min).quo(domain().size)
|
42
|
+
@r=pv.range(min+step.quo(2),max,step)
|
43
|
+
self
|
44
|
+
end
|
45
|
+
def by(*arguments)
|
46
|
+
f,dummy=arguments
|
47
|
+
t=self
|
48
|
+
by=lambda { t.scale(f.js_apply(self,arguments))}
|
49
|
+
by
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
module Rubyvis
|
2
|
+
class Scale::Quantitative
|
3
|
+
include Rubyvis::Scale
|
4
|
+
attr_reader :l
|
5
|
+
def initialize(*args)
|
6
|
+
@d=[0,1] # domain
|
7
|
+
@l=[0,1] # transformed domain
|
8
|
+
@r=[0,1] # default range
|
9
|
+
@i=[Rubyvis.identity] # default interpolator
|
10
|
+
@type=:to_f # default type
|
11
|
+
@n=false
|
12
|
+
@f=Rubyvis.identity # default forward transformation
|
13
|
+
@g=Rubyvis.identity
|
14
|
+
@tick_format=lambda {|x| x.to_f}
|
15
|
+
domain(*args)
|
16
|
+
end
|
17
|
+
def new_date(x=nil)
|
18
|
+
x.nil? ? Date.today : DateTime.civil(x)
|
19
|
+
end
|
20
|
+
|
21
|
+
def scale(x)
|
22
|
+
j=Rubyvis.search(@d,x)
|
23
|
+
j=-j-2 if (j<0)
|
24
|
+
j=[0,[@i.size-1,j].min].max
|
25
|
+
# p @l
|
26
|
+
# puts "Primero #{j}: #{@f.call(x) - @l[j]}"
|
27
|
+
# puts "Segundo #{(@l[j + 1] - @l[j])}"
|
28
|
+
@i[j].call((@f.call(x) - @l[j]) .quo(@l[j + 1] - @l[j]));
|
29
|
+
end
|
30
|
+
def [](x)
|
31
|
+
scale(x)
|
32
|
+
end
|
33
|
+
def transform(forward, inverse)
|
34
|
+
@f=lambda {|x| @n ? -forward.call(-x) : forward.call(x); }
|
35
|
+
@g=lambda {|y| @n ? -inverse.call(-y) : inverse.call(y); }
|
36
|
+
@l=@d.map{|v| @f.call(v)}
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def domain(*arguments)
|
42
|
+
array,min,max=arguments
|
43
|
+
if (arguments.size>0)
|
44
|
+
if array.is_a? Array
|
45
|
+
min = pv.identity if (arguments.size < 2)
|
46
|
+
max = min if (arguments.size < 3)
|
47
|
+
o = array.size>0 && [array[0]].min
|
48
|
+
@d = array.size ? [Rubyvis.min(array, min), Rubyvis.max(array, max)] : [];
|
49
|
+
else
|
50
|
+
o = array;
|
51
|
+
@d = arguments.map {|i| i.to_f}
|
52
|
+
end
|
53
|
+
if !@d.size
|
54
|
+
@d = [-Infinity, Infinity];
|
55
|
+
elsif (@d.size == 1)
|
56
|
+
@d = [@d.first, @d.first]
|
57
|
+
end
|
58
|
+
@n = (@d.first<0 or @d.last<0)
|
59
|
+
@l=@d.map{|v| @f.call(v)}
|
60
|
+
@type = (o.is_a? Date) ? new_date : :to_f;
|
61
|
+
return self
|
62
|
+
end
|
63
|
+
# TODO: Fix this.
|
64
|
+
@d.map{|v|
|
65
|
+
case @type
|
66
|
+
when :to_f
|
67
|
+
v.to_f
|
68
|
+
when :to_date
|
69
|
+
Date.new(v)
|
70
|
+
else
|
71
|
+
v
|
72
|
+
end
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
def range(*arguments)
|
78
|
+
if (arguments.size>0)
|
79
|
+
@r = arguments.dup
|
80
|
+
if (@r.size==0)
|
81
|
+
@r = [-Infinity, Infinity];
|
82
|
+
elsif (@r.size == 1)
|
83
|
+
@r = [@r[0], @r[0]]
|
84
|
+
end
|
85
|
+
@i=(@r.size-1).times.map do |j|
|
86
|
+
Rubyvis::Scale.interpolator(@r[j], @r[j + 1]);
|
87
|
+
end
|
88
|
+
return self
|
89
|
+
end
|
90
|
+
@r
|
91
|
+
end
|
92
|
+
|
93
|
+
def invert(y)
|
94
|
+
j=Rubyvis.search(@r, y)
|
95
|
+
j=-j-2 if j<0
|
96
|
+
j = [0, [@i.size - 1, j].min].max
|
97
|
+
|
98
|
+
@g.call(@l[j] + (y - @r[j]).quo(@r[j + 1] - @r[j]) * (@l[j + 1] - @l[j]));
|
99
|
+
end
|
100
|
+
|
101
|
+
def type(v=nil)
|
102
|
+
return @type if v.nil?
|
103
|
+
case @type
|
104
|
+
when Numeric
|
105
|
+
v.to_f
|
106
|
+
when Date
|
107
|
+
raise "Not implemented yet"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
# TODO: FIX this func
|
111
|
+
def ticks(*arguments)
|
112
|
+
m = arguments[0]
|
113
|
+
start = @d.first
|
114
|
+
_end = @d.last
|
115
|
+
reverse = _end < start
|
116
|
+
min = reverse ? _end : start
|
117
|
+
max = reverse ? start : _end
|
118
|
+
span = max - min
|
119
|
+
|
120
|
+
# Special case: empty, invalid or infinite span.
|
121
|
+
if (!span or (span.is_a? Float and span.infinite?))
|
122
|
+
@tick_format= Rubyvis.Format.date("%x") if (@type == newDate)
|
123
|
+
return [type(min)];
|
124
|
+
end
|
125
|
+
# From here, �chaos!
|
126
|
+
#/* Special case: dates. */
|
127
|
+
if (@type == new_date)
|
128
|
+
#/* Floor the date d given the precision p. */
|
129
|
+
lambda do |d,p|
|
130
|
+
case(p)
|
131
|
+
when 31536e6
|
132
|
+
d.setMonth(0);
|
133
|
+
when 2592e6
|
134
|
+
d.setDate(1);
|
135
|
+
when 6048e5
|
136
|
+
if (p == 6048e5)
|
137
|
+
d.setDate(d.getDate() - d.getDay());
|
138
|
+
end
|
139
|
+
when 864e5
|
140
|
+
d.setHours(0);
|
141
|
+
when 36e5
|
142
|
+
d.setMinutes(0);
|
143
|
+
when 6e4
|
144
|
+
d.setSeconds(0);
|
145
|
+
when 1e3
|
146
|
+
d.setMilliseconds(0);
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
precision, format, increment, step = 1,1,1,1
|
151
|
+
if (span >= 3 * 31536e6)
|
152
|
+
precision = 31536e6;
|
153
|
+
format = "%Y";
|
154
|
+
increment = lambda {|d| d.setFullYear(d.getFullYear() + step); };
|
155
|
+
elsif (span >= 3 * 2592e6)
|
156
|
+
precision = 2592e6;
|
157
|
+
format = "%m/%Y";
|
158
|
+
increment = lambda {|d| d.setMonth(d.getMonth() + step); };
|
159
|
+
elsif (span >= 3 * 6048e5)
|
160
|
+
precision = 6048e5;
|
161
|
+
format = "%m/%d";
|
162
|
+
increment = lambda {|d| d.setDate(d.getDate() + 7 * step); };
|
163
|
+
elsif (span >= 3 * 864e5)
|
164
|
+
precision = 864e5;
|
165
|
+
format = "%m/%d";
|
166
|
+
increment = lambda {|d| d.setDate(d.getDate() + step); };
|
167
|
+
elsif (span >= 3 * 36e5)
|
168
|
+
precision = 36e5;
|
169
|
+
format = "%I:%M %p";
|
170
|
+
increment = lambda {|d| d.setHours(d.getHours() + step); };
|
171
|
+
elsif (span >= 3 * 6e4)
|
172
|
+
precision = 6e4;
|
173
|
+
format = "%I:%M %p";
|
174
|
+
increment = lambda {|d| d.setMinutes(d.getMinutes() + step); };
|
175
|
+
elsif (span >= 3 * 1e3)
|
176
|
+
precision = 1e3;
|
177
|
+
format = "%I:%M:%S";
|
178
|
+
increment = lambda {|d| d.setSeconds(d.getSeconds() + step); };
|
179
|
+
else
|
180
|
+
precision = 1;
|
181
|
+
format = "%S.%Qs";
|
182
|
+
increment = lambda {|d| d.setTime(d.getTime() + step); };
|
183
|
+
end
|
184
|
+
@tick_format = pv.Format.date(format);
|
185
|
+
|
186
|
+
date = Date.new(min)
|
187
|
+
dates = []
|
188
|
+
#floor(date, precision);
|
189
|
+
|
190
|
+
# If we'd generate too many ticks, skip some!.
|
191
|
+
n = span.quo(precision)
|
192
|
+
if (n > 10)
|
193
|
+
case (precision)
|
194
|
+
when 36e5
|
195
|
+
step = (n > 20) ? 6 : 3;
|
196
|
+
date.setHours(Math.floor(date.getHours() / step) * step);
|
197
|
+
when 2592e6
|
198
|
+
step = 3; # seasons
|
199
|
+
date.setMonth(Math.floor(date.getMonth() / step) * step);
|
200
|
+
when 6e4
|
201
|
+
step = (n > 30) ? 15 : ((n > 15) ? 10 : 5);
|
202
|
+
date.setMinutes(Math.floor(date.getMinutes() / step) * step);
|
203
|
+
when 1e3
|
204
|
+
step = (n > 90) ? 15 : ((n > 60) ? 10 : 5);
|
205
|
+
date.setSeconds(Math.floor(date.getSeconds() / step) * step);
|
206
|
+
when 1
|
207
|
+
step = (n > 1000) ? 250 : ((n > 200) ? 100 : ((n > 100) ? 50 : ((n > 50) ? 25 : 5)));
|
208
|
+
date.setMilliseconds(Math.floor(date.getMilliseconds() / step) * step);
|
209
|
+
else
|
210
|
+
step = pv.logCeil(n / 15, 10);
|
211
|
+
if (n / step < 2)
|
212
|
+
step =step.quo(5)
|
213
|
+
elsif (n / step < 5)
|
214
|
+
step = step.quo(2)
|
215
|
+
end
|
216
|
+
date.setFullYear((date.getFullYear().quo(step)).floor * step);
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
while (true)
|
221
|
+
increment(date);
|
222
|
+
break if (date > max)
|
223
|
+
dates.push(Date.new(date));
|
224
|
+
end
|
225
|
+
return reverse ? dates.reverse() : dates;
|
226
|
+
end
|
227
|
+
|
228
|
+
# Normal case: numbers.
|
229
|
+
m = 10 if (arguments.size==0)
|
230
|
+
|
231
|
+
step = pv.log_floor(span.quo(m), 10)
|
232
|
+
err = m.quo(span.quo(step))
|
233
|
+
if (err <= 0.15)
|
234
|
+
step = step*10
|
235
|
+
elsif (err <= 0.35)
|
236
|
+
step = step*5
|
237
|
+
elsif (err <= 0.75)
|
238
|
+
step = step*2
|
239
|
+
end
|
240
|
+
start = (min.quo(step)).ceil * step
|
241
|
+
_end = (max.quo(step)).floor * step
|
242
|
+
@tick_format= pv.Format.number().fraction_digits([0, -(pv.log(step, 10) + 0.01).floor].max);
|
243
|
+
ticks = pv.range(start, _end + step, step);
|
244
|
+
return reverse ? ticks.reverse() : ticks;
|
245
|
+
end
|
246
|
+
def nice
|
247
|
+
if (@d.size!=2)
|
248
|
+
return self;
|
249
|
+
end
|
250
|
+
start=@d.first
|
251
|
+
_end=@d[@d.size-1]
|
252
|
+
reverse=_end<start
|
253
|
+
min=reverse ? _end : start
|
254
|
+
max = reverse ? start : _end
|
255
|
+
span=max-min
|
256
|
+
return self if(!span or span.infinite?)
|
257
|
+
step=10**((Math::log(span).quo(Math::log(10))).round-1)
|
258
|
+
@d=[(min.quo(step)).floor*step, (max.quo(step)).ceil*step]
|
259
|
+
@d.reverse if reverse
|
260
|
+
@l=@d.map {|v| @f.call(v)}
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|