gerbilcharts 0.0.3
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/History.txt +11 -0
- data/License.txt +21 -0
- data/Manifest.txt +75 -0
- data/PostInstall.txt +7 -0
- data/README.txt +174 -0
- data/Rakefile +4 -0
- data/lib/gerbilcharts.rb +18 -0
- data/lib/gerbilcharts/charts.rb +16 -0
- data/lib/gerbilcharts/charts/area_chart.rb +36 -0
- data/lib/gerbilcharts/charts/bar_chart.rb +33 -0
- data/lib/gerbilcharts/charts/bar_chart_compact.rb +26 -0
- data/lib/gerbilcharts/charts/chart_base.rb +123 -0
- data/lib/gerbilcharts/charts/impulse_chart.rb +30 -0
- data/lib/gerbilcharts/charts/line_chart.rb +35 -0
- data/lib/gerbilcharts/charts/stacked_area_chart.rb +31 -0
- data/lib/gerbilcharts/models.rb +19 -0
- data/lib/gerbilcharts/models/bucketized_timeseries_graph_model.rb +138 -0
- data/lib/gerbilcharts/models/discrete_time_range.rb +63 -0
- data/lib/gerbilcharts/models/graph_model.rb +89 -0
- data/lib/gerbilcharts/models/graph_model_group.rb +240 -0
- data/lib/gerbilcharts/models/monotonous_graph_model.rb +192 -0
- data/lib/gerbilcharts/models/presets.rb +94 -0
- data/lib/gerbilcharts/models/raw_range.rb +68 -0
- data/lib/gerbilcharts/models/round_range.rb +104 -0
- data/lib/gerbilcharts/models/round_time_range.rb +105 -0
- data/lib/gerbilcharts/models/sampled_timeseries_graph_model.rb +80 -0
- data/lib/gerbilcharts/models/simple_timeseries_model_group.rb +68 -0
- data/lib/gerbilcharts/models/time_series_graph_model.rb +34 -0
- data/lib/gerbilcharts/public/brushmetal.css +197 -0
- data/lib/gerbilcharts/public/gerbil.js +327 -0
- data/lib/gerbilcharts/surfaces.rb +32 -0
- data/lib/gerbilcharts/surfaces/area_surface.rb +46 -0
- data/lib/gerbilcharts/surfaces/axis.rb +31 -0
- data/lib/gerbilcharts/surfaces/bar_surface.rb +62 -0
- data/lib/gerbilcharts/surfaces/basic_grid.rb +17 -0
- data/lib/gerbilcharts/surfaces/chart.rb +132 -0
- data/lib/gerbilcharts/surfaces/graph_element.rb +170 -0
- data/lib/gerbilcharts/surfaces/grid.rb +38 -0
- data/lib/gerbilcharts/surfaces/horizontal_axis.rb +32 -0
- data/lib/gerbilcharts/surfaces/horizontal_name_axis.rb +28 -0
- data/lib/gerbilcharts/surfaces/horizontal_time_axis.rb +25 -0
- data/lib/gerbilcharts/surfaces/impulse_surface.rb +47 -0
- data/lib/gerbilcharts/surfaces/legend.rb +59 -0
- data/lib/gerbilcharts/surfaces/line_surface.rb +53 -0
- data/lib/gerbilcharts/surfaces/mark_band.rb +17 -0
- data/lib/gerbilcharts/surfaces/panel.rb +17 -0
- data/lib/gerbilcharts/surfaces/pie_surface.rb +16 -0
- data/lib/gerbilcharts/surfaces/rect.rb +86 -0
- data/lib/gerbilcharts/surfaces/stacked_area_surface.rb +66 -0
- data/lib/gerbilcharts/surfaces/stacked_grid.rb +15 -0
- data/lib/gerbilcharts/surfaces/surface.rb +20 -0
- data/lib/gerbilcharts/surfaces/surface_background.rb +13 -0
- data/lib/gerbilcharts/surfaces/title_panel.rb +44 -0
- data/lib/gerbilcharts/surfaces/tracker.rb +62 -0
- data/lib/gerbilcharts/surfaces/vertical_axis.rb +46 -0
- data/lib/gerbilcharts/svgdc.rb +22 -0
- data/lib/gerbilcharts/svgdc/filters.rb +40 -0
- data/lib/gerbilcharts/svgdc/presentation_attributes.rb +50 -0
- data/lib/gerbilcharts/svgdc/svg_circle.rb +22 -0
- data/lib/gerbilcharts/svgdc/svg_custom_win.rb +36 -0
- data/lib/gerbilcharts/svgdc/svg_element.rb +87 -0
- data/lib/gerbilcharts/svgdc/svg_line.rb +26 -0
- data/lib/gerbilcharts/svgdc/svg_polygon.rb +34 -0
- data/lib/gerbilcharts/svgdc/svg_polyline.rb +27 -0
- data/lib/gerbilcharts/svgdc/svg_rect.rb +29 -0
- data/lib/gerbilcharts/svgdc/svg_shape.rb +10 -0
- data/lib/gerbilcharts/svgdc/svg_text.rb +21 -0
- data/lib/gerbilcharts/svgdc/svg_win.rb +52 -0
- data/lib/gerbilcharts/svgdc/svgdc.rb +335 -0
- data/lib/gerbilcharts/svgdc/transformations.rb +66 -0
- data/lib/gerbilcharts/version.rb +9 -0
- data/setup.rb +1585 -0
- data/test/test_Scratch.rb +21 -0
- data/test/test_charts.rb +119 -0
- data/test/test_gerbilcharts.rb +11 -0
- data/test/test_helper.rb +2 -0
- data/test/test_models.rb +118 -0
- data/test/test_noob.rb +81 -0
- data/test/test_ranges.rb +135 -0
- data/test/test_svgdc.rb +221 -0
- data/test/trafgen.rb +25 -0
- metadata +156 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
module GerbilCharts::Surfaces
|
2
|
+
|
3
|
+
# == Chart - container class
|
4
|
+
# Base from which all chart are derived
|
5
|
+
class Chart < GraphElement
|
6
|
+
|
7
|
+
attr_reader :anchor
|
8
|
+
attr_reader :elements
|
9
|
+
attr_reader :needslayout
|
10
|
+
attr_reader :modelgroup
|
11
|
+
attr_reader :stylesheet
|
12
|
+
attr_reader :filters
|
13
|
+
attr_reader :href
|
14
|
+
attr_reader :javascripts
|
15
|
+
attr_reader :ajaxOptions
|
16
|
+
attr_reader :ajaxContext
|
17
|
+
|
18
|
+
def initialize( opt={})
|
19
|
+
super(opt)
|
20
|
+
set_defaults
|
21
|
+
@children = []
|
22
|
+
@filters = []
|
23
|
+
@stylesheet = opt[:style] if defined? opt[:style]
|
24
|
+
@javascripts = opt[:javascripts] if opt[:javascripts]
|
25
|
+
@needslayout=false
|
26
|
+
end
|
27
|
+
|
28
|
+
def set_defaults
|
29
|
+
@javascripts = { "/javascripts/gerbil.js" => false, "/javascripts/prototype.js" => false }
|
30
|
+
end
|
31
|
+
|
32
|
+
def set_modelgroup(g)
|
33
|
+
@modelgroup=g
|
34
|
+
end
|
35
|
+
|
36
|
+
def usesAjax?
|
37
|
+
if @ajaxOptions
|
38
|
+
return true
|
39
|
+
else
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_ajaxOptions(h)
|
45
|
+
@ajaxOptions={} if @ajaxOptions == nil
|
46
|
+
@ajaxOptions.merge!(h)
|
47
|
+
end
|
48
|
+
|
49
|
+
def set_ajaxContext(h)
|
50
|
+
@ajaxContext={} if @ajaxContext == nil
|
51
|
+
@ajaxContext.merge!(h)
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
def add_child(e,opts={})
|
56
|
+
@children << e
|
57
|
+
@needslayout=true
|
58
|
+
e.setparent(self)
|
59
|
+
set_anchor(e) if opts[:anchor]
|
60
|
+
end
|
61
|
+
|
62
|
+
def render(ropts={})
|
63
|
+
svgdc = GerbilCharts::SVGDC::SVGDC.new(@bounds.width, @bounds.height)
|
64
|
+
|
65
|
+
dolayout if @needslayout
|
66
|
+
|
67
|
+
@children.each do |ch|
|
68
|
+
ch.render(svgdc)
|
69
|
+
end
|
70
|
+
|
71
|
+
@filters.each do |f|
|
72
|
+
svgdc.add_filter(f)
|
73
|
+
end
|
74
|
+
|
75
|
+
@javascripts.each_pair do |scr,inline|
|
76
|
+
svgdc.add_javascriptfile(scr, inline)
|
77
|
+
end
|
78
|
+
|
79
|
+
# set model hash, and other template contexts
|
80
|
+
if @ajaxOptions
|
81
|
+
@ajaxContext.store(:axdigest,@modelgroup.models_digest)
|
82
|
+
end
|
83
|
+
|
84
|
+
svgdc.set_ajaxOptions(@ajaxOptions) if @ajaxOptions
|
85
|
+
|
86
|
+
svgdc.set_ajaxContext(@ajaxContext) if @ajaxContext
|
87
|
+
|
88
|
+
svgdc.set_stylesheet(@stylesheet) if @stylesheet
|
89
|
+
|
90
|
+
svgdc.render(ropts)
|
91
|
+
end
|
92
|
+
|
93
|
+
def getmodelgroup
|
94
|
+
return @modelgroup
|
95
|
+
end
|
96
|
+
|
97
|
+
def create_filter(f)
|
98
|
+
@filters << f
|
99
|
+
end
|
100
|
+
|
101
|
+
def sethref(h)
|
102
|
+
@href=h
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
def dolayout
|
107
|
+
spare = Rect.new
|
108
|
+
spare.from_wh @bounds.width,@bounds.height
|
109
|
+
|
110
|
+
@children.each do |ch|
|
111
|
+
spare=ch.munch spare
|
112
|
+
end
|
113
|
+
|
114
|
+
@anchor.setbounds spare
|
115
|
+
|
116
|
+
@children.each do |ch|
|
117
|
+
ch.align_to_anchor @anchor
|
118
|
+
end
|
119
|
+
|
120
|
+
@needslayout=false
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
def set_anchor(a)
|
125
|
+
raise "Only one anchor element supported" if @anchor
|
126
|
+
@anchor =a
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module GerbilCharts::Surfaces
|
2
|
+
|
3
|
+
# Graph - base for everything you place on the graph (all rectangular)
|
4
|
+
#
|
5
|
+
class GraphElement
|
6
|
+
|
7
|
+
# constants
|
8
|
+
EXP_FIXED=1
|
9
|
+
EXP_FILL=2
|
10
|
+
|
11
|
+
# orientations
|
12
|
+
ORIENT_NORTH=1
|
13
|
+
ORIENT_SOUTH=2
|
14
|
+
ORIENT_EAST=3
|
15
|
+
ORIENT_WEST=4
|
16
|
+
ORIENT_NORTHEAST=5
|
17
|
+
ORIENT_NORTHWEST=6
|
18
|
+
ORIENT_SOUTHEAST=7
|
19
|
+
ORIENT_SOUTHWEST=8
|
20
|
+
ORIENT_OVERLAY=9
|
21
|
+
|
22
|
+
|
23
|
+
# public ro attributes
|
24
|
+
attr_reader :class
|
25
|
+
attr_reader :group
|
26
|
+
attr_reader :bounds
|
27
|
+
attr_reader :lay_orient
|
28
|
+
attr_reader :lay_expand
|
29
|
+
attr_reader :lay_dimension
|
30
|
+
attr_reader :parent
|
31
|
+
|
32
|
+
def initialize( opt={} )
|
33
|
+
@lay_orient= opt[:orient] if defined? opt[:orient]
|
34
|
+
@lay_expand= opt[:expand] if defined? opt[:expand]
|
35
|
+
@lay_dimension= opt[:dim] if defined? opt[:dim]
|
36
|
+
@bounds = Rect.new
|
37
|
+
if opt[:width] and opt[:height]
|
38
|
+
@bounds.from_wh(opt[:width],opt[:height])
|
39
|
+
end
|
40
|
+
if opt[:class]
|
41
|
+
@class=opt[:class]
|
42
|
+
end
|
43
|
+
@group="default"
|
44
|
+
@global_chart_options=opt
|
45
|
+
end
|
46
|
+
|
47
|
+
def needslayout?
|
48
|
+
if @lay_orient
|
49
|
+
return true
|
50
|
+
else
|
51
|
+
return false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def setparent(par)
|
56
|
+
@parent=par
|
57
|
+
end
|
58
|
+
|
59
|
+
def isoverlay?
|
60
|
+
if defined? @lay_orient and @lay_orient == ORIENT_OVERLAY
|
61
|
+
return true
|
62
|
+
else
|
63
|
+
return false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def scale_x val,range
|
68
|
+
return @bounds.left + @bounds.width * range.scale_factor(val)
|
69
|
+
end
|
70
|
+
|
71
|
+
def scale_y val,range
|
72
|
+
return @bounds.bottom - @bounds.height * range.scale_factor(val)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def setbounds rcbounds
|
77
|
+
@bounds.initfrom rcbounds
|
78
|
+
end
|
79
|
+
|
80
|
+
# setup SVG group element and call int_render
|
81
|
+
def render(sdc)
|
82
|
+
w=sdc.newwin(@group)
|
83
|
+
# w.add_transformation(TTranslate.new(@bounds.left, @bounds.top))
|
84
|
+
sdc.setactivewindow(w)
|
85
|
+
int_render(sdc)
|
86
|
+
sdc.setactivewindow
|
87
|
+
end
|
88
|
+
|
89
|
+
# render direct - directly render SVG using builder for complex elements
|
90
|
+
def render_direct(sdc)
|
91
|
+
raise "This Graph Element cannot render directly, incorrect usage"
|
92
|
+
end
|
93
|
+
|
94
|
+
def munch(layrect)
|
95
|
+
raise "Element does not need to be laid out" if not needslayout?
|
96
|
+
|
97
|
+
@bounds.initfrom(layrect)
|
98
|
+
case @lay_orient
|
99
|
+
when ORIENT_SOUTH
|
100
|
+
@bounds.clip_b @lay_dimension
|
101
|
+
layrect.crop_b @lay_dimension
|
102
|
+
when ORIENT_NORTH
|
103
|
+
@bounds.clip_t @lay_dimension
|
104
|
+
layrect.crop_t @lay_dimension
|
105
|
+
when ORIENT_EAST
|
106
|
+
@bounds.clip_r @lay_dimension
|
107
|
+
layrect.crop_r @lay_dimension
|
108
|
+
when ORIENT_WEST
|
109
|
+
@bounds.clip_l @lay_dimension
|
110
|
+
layrect.crop_l @lay_dimension
|
111
|
+
when ORIENT_SOUTHEAST
|
112
|
+
@bounds.clip_b @lay_dimension
|
113
|
+
@bounds.clip_r @lay_dimension
|
114
|
+
when ORIENT_NORTHEAST
|
115
|
+
@bounds.clip_t @lay_dimension
|
116
|
+
@bounds.clip_r @lay_dimension
|
117
|
+
when ORIENT_SOUTHWEST
|
118
|
+
@bounds.clip_b @lay_dimension
|
119
|
+
@bounds.clip_l @lay_dimension
|
120
|
+
when ORIENT_NORTHWEST
|
121
|
+
@bounds.clip_t @lay_dimension
|
122
|
+
@bounds.clip_l @lay_dimension
|
123
|
+
end
|
124
|
+
return layrect
|
125
|
+
end
|
126
|
+
|
127
|
+
def align_to_anchor(anc)
|
128
|
+
case @lay_orient
|
129
|
+
when ORIENT_SOUTH
|
130
|
+
@bounds.left= anc.bounds.left
|
131
|
+
@bounds.right=anc.bounds.right
|
132
|
+
when ORIENT_NORTH
|
133
|
+
@bounds.left= anc.bounds.left
|
134
|
+
@bounds.right=anc.bounds.right
|
135
|
+
when ORIENT_EAST
|
136
|
+
@bounds.top= anc.bounds.top
|
137
|
+
@bounds.bottom=anc.bounds.bottom
|
138
|
+
when ORIENT_WEST
|
139
|
+
@bounds.top= anc.bounds.top
|
140
|
+
@bounds.bottom=anc.bounds.bottom
|
141
|
+
when ORIENT_OVERLAY
|
142
|
+
@bounds.initfrom anc.bounds
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# query a global option, return the defval if option is not set
|
147
|
+
def get_global_option(optsym, defval)
|
148
|
+
if @global_chart_options[optsym]
|
149
|
+
return @global_chart_options[optsym]
|
150
|
+
else
|
151
|
+
return defval
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# utility methods to derived classes
|
156
|
+
protected
|
157
|
+
|
158
|
+
def max(a,b)
|
159
|
+
return (a>b)?a:b
|
160
|
+
end
|
161
|
+
|
162
|
+
def min(a,b)
|
163
|
+
return (a<b)?a:b
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module GerbilCharts::Surfaces
|
2
|
+
|
3
|
+
# = Grid - grid overlay
|
4
|
+
# Draws both x and y grids
|
5
|
+
class Grid < GraphElement
|
6
|
+
|
7
|
+
def initialize(opts={})
|
8
|
+
super(opts)
|
9
|
+
end
|
10
|
+
|
11
|
+
def int_render(g)
|
12
|
+
ry = grid_range_y
|
13
|
+
ry.each_label do |val,label|
|
14
|
+
yp = scale_y val,ry
|
15
|
+
g.line(@bounds.left,yp,@bounds.right,yp, {:class => "gridlineh"})
|
16
|
+
end
|
17
|
+
|
18
|
+
rx = grid_range_x
|
19
|
+
rx.each_label do |val,label|
|
20
|
+
xp = scale_x val,rx
|
21
|
+
g.line(xp,@bounds.top,xp,@bounds.bottom, {:class => "gridlinev"})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
def grid_range_x
|
28
|
+
return parent.modelgroup.effective_round_range_x
|
29
|
+
end
|
30
|
+
|
31
|
+
def grid_range_y
|
32
|
+
return parent.modelgroup.effective_round_range_y0
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module GerbilCharts::Surfaces
|
2
|
+
|
3
|
+
class HorizontalAxis < Axis
|
4
|
+
|
5
|
+
def initialize(opts={})
|
6
|
+
@class = "haxis"
|
7
|
+
super(opts)
|
8
|
+
end
|
9
|
+
|
10
|
+
def int_render(g)
|
11
|
+
super
|
12
|
+
|
13
|
+
return if parent.modelgroup.empty?
|
14
|
+
|
15
|
+
rx = parent.modelgroup.effective_round_range_x
|
16
|
+
rx.each_label do |val,label|
|
17
|
+
xp = scale_x val,rx
|
18
|
+
|
19
|
+
# make sure edge ones are visible
|
20
|
+
if (xp>=@bounds.right-10)
|
21
|
+
xp = @bounds.right-10
|
22
|
+
end
|
23
|
+
|
24
|
+
g.textout(xp, @bounds.top+10, label, {:class => "axislabel"})
|
25
|
+
g.line(xp,@bounds.top-2,xp,@bounds.top+3, {:class => "axistickmajor"})
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module GerbilCharts::Surfaces
|
2
|
+
|
3
|
+
# = Horizontal name axis
|
4
|
+
#
|
5
|
+
# Draws names of models instead of values, used for bar charts
|
6
|
+
class HorizontalNameAxis < Axis
|
7
|
+
|
8
|
+
def initialize(opts={})
|
9
|
+
@class = "haxis"
|
10
|
+
super(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def int_render(g)
|
14
|
+
super
|
15
|
+
|
16
|
+
# p "Horiz name axis #{parent.anchor.element_spacing} spacing"
|
17
|
+
xp = @bounds.left + parent.anchor.element_spacing + parent.anchor.element_width/2
|
18
|
+
parent.modelgroup.each_model_with_index do |m,i|
|
19
|
+
yoff=get_stagger_off(i,10)
|
20
|
+
g.textout(xp, @bounds.top+15+yoff, m.name, {:class => "axislabel","text-anchor" => "middle"})
|
21
|
+
xp += parent.anchor.element_width + parent.anchor.element_spacing
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GerbilCharts::Surfaces
|
2
|
+
|
3
|
+
# = HorizontalTimeAxis
|
4
|
+
# Draws time labels along x-axis
|
5
|
+
# Most charts use this type of x-axis in time series charts
|
6
|
+
class HorizontalTimeAxis < HorizontalAxis
|
7
|
+
|
8
|
+
def initialize(opts={})
|
9
|
+
@class = "haxis"
|
10
|
+
super(opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def int_render(g)
|
14
|
+
super
|
15
|
+
|
16
|
+
rx = parent.modelgroup.effective_round_range_x
|
17
|
+
sfmt = rx.format_min_value
|
18
|
+
g.textout(@bounds.left-20, @bounds.top+20, sfmt, {:class => "axislabelt0"})
|
19
|
+
g.line(@bounds.left,@bounds.top,@bounds.left,@bounds.top+10,{:class => "axistickmajor"})
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|