rubyvis 0.1.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 +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
|