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,29 @@
|
|
1
|
+
module GerbilCharts::SVGDC
|
2
|
+
|
3
|
+
# = SVGRect - a simple rectangle
|
4
|
+
#
|
5
|
+
class SVGRect < SVGShape
|
6
|
+
|
7
|
+
attr_accessor :x,:y,:w, :h
|
8
|
+
|
9
|
+
|
10
|
+
# x = x position
|
11
|
+
# y = y position
|
12
|
+
# w = width
|
13
|
+
# h = height
|
14
|
+
#
|
15
|
+
# To create rectangle top left corner at (10,10) and width 200,height 100 do :
|
16
|
+
# SVGRect.new (10,10,200,150)
|
17
|
+
def initialize(x,y,w,h)
|
18
|
+
@x,@y,@w,@h=x,y,w,h
|
19
|
+
super()
|
20
|
+
end
|
21
|
+
|
22
|
+
def render(xfrag)
|
23
|
+
h= { :x => @x, :y => @y, :width => @w, :height => @h }
|
24
|
+
render_base(xfrag) { xfrag.rect( h.merge(render_attributes)) }
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GerbilCharts::SVGDC
|
2
|
+
|
3
|
+
# = SVGText
|
4
|
+
# A line of text
|
5
|
+
class SVGText < SVGElement
|
6
|
+
|
7
|
+
attr_reader :x, :y, :str
|
8
|
+
|
9
|
+
def initialize(x,y,str)
|
10
|
+
super()
|
11
|
+
@x,@y,@str=x,y,str
|
12
|
+
end
|
13
|
+
|
14
|
+
def render(xfrag)
|
15
|
+
h= { :x => @x, :y => @y}
|
16
|
+
render_base(xfrag) { xfrag.text(@str, h.merge(render_attributes)) }
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module GerbilCharts::SVGDC
|
2
|
+
|
3
|
+
# = SVGWin
|
4
|
+
# a conceptual window, maps to a 'g' element in the SVG spec
|
5
|
+
# allows you to layer or nest easily
|
6
|
+
#
|
7
|
+
class SVGWin < SVGElement
|
8
|
+
attr_reader :ops
|
9
|
+
attr_reader :transforms
|
10
|
+
|
11
|
+
def initialize(name, opts={})
|
12
|
+
|
13
|
+
# add default options first
|
14
|
+
# by default windows will define fill = none and stroke = black
|
15
|
+
|
16
|
+
add_options("id"=> name, "fill" => "none", "stroke" => "black" )
|
17
|
+
|
18
|
+
add_options opts
|
19
|
+
|
20
|
+
@ops=[]
|
21
|
+
super()
|
22
|
+
end
|
23
|
+
|
24
|
+
def <<(p)
|
25
|
+
@ops<<p
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_transformation(t)
|
29
|
+
@transforms=Array.new unless @transforms
|
30
|
+
@transforms << t
|
31
|
+
end
|
32
|
+
|
33
|
+
def render(xfrag)
|
34
|
+
h= {}
|
35
|
+
|
36
|
+
if @transforms
|
37
|
+
strt=""
|
38
|
+
@transforms.each do |t|
|
39
|
+
strt << t.render
|
40
|
+
end
|
41
|
+
h.store(:transform, strt)
|
42
|
+
end
|
43
|
+
|
44
|
+
xfrag.g(h.merge(render_attributes)) {
|
45
|
+
@ops.each do |op|
|
46
|
+
op.render(xfrag)
|
47
|
+
end
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,335 @@
|
|
1
|
+
module GerbilCharts::SVGDC
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
gem 'builder'
|
5
|
+
require 'builder'
|
6
|
+
|
7
|
+
# =SVGDC
|
8
|
+
#
|
9
|
+
# Simulates a simple Device Context like CDC in MFC/Windows
|
10
|
+
#
|
11
|
+
# == A simple example
|
12
|
+
# Create a 500x400 window, draw a circle, draw 10 rectangles and save it !
|
13
|
+
#
|
14
|
+
# g=SVGDC.new(500,400)
|
15
|
+
# g.circle(40,50,20)
|
16
|
+
# 1.upto(10) do |w|
|
17
|
+
# g.rectangle(80+w*4,10,10*w,45)
|
18
|
+
# end
|
19
|
+
# g.render("/tmp/tbasic1.svg")
|
20
|
+
#
|
21
|
+
class SVGDC
|
22
|
+
|
23
|
+
attr_accessor :width
|
24
|
+
attr_accessor :height
|
25
|
+
attr_reader :curr_win, :base_win
|
26
|
+
attr_reader :curr_presentation_context
|
27
|
+
attr_reader :svg_styles
|
28
|
+
attr_reader :svg_predefs
|
29
|
+
attr_reader :svg_javascript
|
30
|
+
attr_reader :ref_javascripts
|
31
|
+
attr_reader :ajaxOptions
|
32
|
+
attr_reader :ajaxContext
|
33
|
+
attr_reader :use_tooltips
|
34
|
+
|
35
|
+
def initialize(w,h)
|
36
|
+
@width,@height=w,h
|
37
|
+
@ops = Array.new
|
38
|
+
@curr_presentation_context={}
|
39
|
+
@base_win=SVGWin.new("Gerbil_Root_Window")
|
40
|
+
setactivewindow(@base_win)
|
41
|
+
@svg_predefs = []
|
42
|
+
@use_tooltips=true
|
43
|
+
end
|
44
|
+
|
45
|
+
# ==Note on Stylesheet
|
46
|
+
# Searches for the stylesheet in the current directory or in the gerbilcharts/public directory
|
47
|
+
# If you want to use your own stylesheets put them in the working directory, or in the
|
48
|
+
# public directory of gerbilcharts.
|
49
|
+
def set_stylesheet(cssfile)
|
50
|
+
if File.exists? cssfile
|
51
|
+
@svg_styles=File.read(cssfile)
|
52
|
+
else
|
53
|
+
try_from_gem = File.dirname(__FILE__) + "/../public/" + cssfile
|
54
|
+
if not File.exists? try_from_gem
|
55
|
+
p "The stylesheet #{cssfile} was not found. Make sure it exists in the current directory, or in the gem public area"
|
56
|
+
raise "Stylesheet #{cssfile} not found in current directory or in the gerbilcharts/public folder"
|
57
|
+
else
|
58
|
+
@svg_styles=File.read(try_from_gem)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_javascriptfile(jsfile,inlined)
|
64
|
+
if inlined
|
65
|
+
@svg_javascript = "" if @svg_javascript == nil
|
66
|
+
@svg_javascript << File.read(jsfile)
|
67
|
+
else
|
68
|
+
@ref_javascripts = [] if @ref_javascripts == nil
|
69
|
+
@ref_javascripts << jsfile
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def enable_tooltips(bval)
|
74
|
+
@use_tooltips=bval
|
75
|
+
end
|
76
|
+
|
77
|
+
def requires_ajax_block?
|
78
|
+
if @ajaxOptions.nil? and @ajaxContext.nil?
|
79
|
+
return false
|
80
|
+
else
|
81
|
+
return true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def requires_tooltips?
|
86
|
+
return @use_tooltips
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_ajaxContext(h)
|
90
|
+
@ajaxContext=h
|
91
|
+
end
|
92
|
+
|
93
|
+
def set_ajaxOptions(h)
|
94
|
+
@ajaxOptions=h
|
95
|
+
end
|
96
|
+
|
97
|
+
def add_filter(filter)
|
98
|
+
@svg_predefs << filter
|
99
|
+
end
|
100
|
+
|
101
|
+
# create a new window ,
|
102
|
+
# all subsequent operations work on this new window
|
103
|
+
def newwin(name, opts={})
|
104
|
+
w=SVGWin.new(name, opts)
|
105
|
+
@curr_win << w
|
106
|
+
w
|
107
|
+
end
|
108
|
+
|
109
|
+
def setactivewindow(w=nil)
|
110
|
+
@curr_win = w ? w : @base_win
|
111
|
+
end
|
112
|
+
|
113
|
+
# render to XML Builder fragment
|
114
|
+
def render_to_frag(doc,opts)
|
115
|
+
|
116
|
+
# if options has windowonly option, then just render the top most window
|
117
|
+
if opts[:windowonly]
|
118
|
+
# render contents of top window
|
119
|
+
doc.g(:id => "GerbilSVGGraph") {
|
120
|
+
@curr_win.render(doc)
|
121
|
+
}
|
122
|
+
return
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
# svg base attributes
|
127
|
+
svg_attributes = {:xmlns => "http://www.w3.org/2000/svg", "xmlns:xlink" => "http://www.w3.org/1999/xlink", :version => "1.1", :width => @width, :height => @height}
|
128
|
+
if @use_tooltips
|
129
|
+
svg_attributes.store(:onload,"Init(evt)")
|
130
|
+
end
|
131
|
+
|
132
|
+
doc.svg(svg_attributes) {
|
133
|
+
|
134
|
+
# stylesheet (inlined into SVG)
|
135
|
+
if @svg_styles
|
136
|
+
doc.style(@svg_styles, :type => "text/css")
|
137
|
+
end
|
138
|
+
|
139
|
+
# javascripts (ajax, etc) hrefed
|
140
|
+
if @ref_javascripts
|
141
|
+
@ref_javascripts.each do |scr|
|
142
|
+
doc.script(:type => "text/javascript", "xlink:href" => scr)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# javascript inlined again
|
147
|
+
if @svg_javascript
|
148
|
+
doc.script(:type => "text/javascript") {
|
149
|
+
doc.cdata!(@svg_javascript)
|
150
|
+
}
|
151
|
+
end
|
152
|
+
|
153
|
+
# defs (all image filters go here)
|
154
|
+
doc.defs() {
|
155
|
+
@svg_predefs.each do |filter|
|
156
|
+
filter.render(doc)
|
157
|
+
end
|
158
|
+
}
|
159
|
+
|
160
|
+
# Ajax block (for gerbilAjax.js library)
|
161
|
+
if requires_ajax_block?
|
162
|
+
doc.g(:id => "GerbilAjaxBlock") {
|
163
|
+
|
164
|
+
ao = {:id => "GerbilAjaxOptions"}
|
165
|
+
@ajaxOptions.each_pair do |k,v|
|
166
|
+
ao.store(k,v)
|
167
|
+
end
|
168
|
+
doc.g(ao)
|
169
|
+
|
170
|
+
if @ajaxContext
|
171
|
+
ac = {:id => "GerbilAjaxContext"}
|
172
|
+
@ajaxContext.each_pair do |k,v|
|
173
|
+
ac.store(k,v)
|
174
|
+
end
|
175
|
+
doc.g(ac)
|
176
|
+
end
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
180
|
+
# render contents of top window
|
181
|
+
doc.g(:id => "GerbilSVGGraph") {
|
182
|
+
@curr_win.render(doc)
|
183
|
+
}
|
184
|
+
|
185
|
+
# render tooltips optional
|
186
|
+
if @use_tooltips
|
187
|
+
doc.g(:id=>'ToolTip', :opacity=>'0.8', :visibility=>'hidden', "pointer-events"=>'none') {
|
188
|
+
doc.rect(:id=>'tipbox', :x=>'0', :y=>'5', :width=>'88', :height=> '20', :rx=> '2', :ry=> '2', :fill=>'white', :stroke=>'black')
|
189
|
+
doc.text(:id=>'tipText', :x=>'5', :y=>'20', "font-family"=> 'Arial', "font-size"=>'12') {
|
190
|
+
doc.tspan(:id=>'tipTitle', :x=>'5', "font-weight"=>'bold') {
|
191
|
+
doc.cdata!("")
|
192
|
+
}
|
193
|
+
doc.tspan(:id=>'tipDesc', :x=>'5', :dy=> 15, "fill"=>'blue') {
|
194
|
+
doc.cdata!("")
|
195
|
+
}
|
196
|
+
}
|
197
|
+
}
|
198
|
+
end
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
# render the SVG fragments to a string
|
203
|
+
# options
|
204
|
+
def render_to_string(opts={})
|
205
|
+
|
206
|
+
# render all the elements accumulated so far
|
207
|
+
svg_string=""
|
208
|
+
doc = Builder::XmlMarkup.new(:target => svg_string, :indent => 2, :standalone => "no")
|
209
|
+
doc.instruct!
|
210
|
+
doc.declare! :DOCTYPE, :svg, :PUBLIC,"-//W3C//DTD SVG 1.1//EN","http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"
|
211
|
+
|
212
|
+
render_to_frag(doc,opts)
|
213
|
+
|
214
|
+
# return the svg_string
|
215
|
+
return svg_string
|
216
|
+
end
|
217
|
+
|
218
|
+
# render the SVG to a file
|
219
|
+
def render_to_file(outpath,opts={})
|
220
|
+
svg_string = render_to_string(opts)
|
221
|
+
File.open(outpath, 'w') { |file|
|
222
|
+
file.write(svg_string)
|
223
|
+
}
|
224
|
+
end
|
225
|
+
|
226
|
+
# synonym for render_to_file with no options
|
227
|
+
def render(opts={})
|
228
|
+
render_to_string(opts[:string],opts) if opts[:string]
|
229
|
+
render_to_file(opts[:file],opts) if opts[:file]
|
230
|
+
render_to_frag(opts[:xfrag],opts) if opts[:xfrag]
|
231
|
+
end
|
232
|
+
|
233
|
+
# prime the graphics object
|
234
|
+
def prime_object(gobj, opt)
|
235
|
+
add_selected_presentations(gobj)
|
236
|
+
add_options(gobj,opt)
|
237
|
+
gobj
|
238
|
+
end
|
239
|
+
|
240
|
+
# add presentation attributes
|
241
|
+
def add_selected_presentations(gobj)
|
242
|
+
@curr_presentation_context.each do |k,v|
|
243
|
+
gobj.add_presentation v
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# add other options (eg, CSS class)
|
248
|
+
def add_options(gobj, opt)
|
249
|
+
gobj.add_options(opt)
|
250
|
+
gobj
|
251
|
+
end
|
252
|
+
|
253
|
+
# add a shape directly with options
|
254
|
+
def addshape(shape,opt={})
|
255
|
+
@curr_win << prime_object(shape,opt)
|
256
|
+
end
|
257
|
+
|
258
|
+
def circle(x,y,r,opt={})
|
259
|
+
@curr_win << prime_object(SVGCircle.new(x,y,r),opt)
|
260
|
+
end
|
261
|
+
|
262
|
+
def moveto(x,y)
|
263
|
+
@curr_polyline=SVGPolyline.new
|
264
|
+
@curr_polyline.lineto(x,y)
|
265
|
+
end
|
266
|
+
|
267
|
+
def lineto(x,y)
|
268
|
+
@curr_polyline=SVGPolyline.new if not @curr_polyline
|
269
|
+
@curr_polyline.lineto(x,y)
|
270
|
+
end
|
271
|
+
|
272
|
+
def endline(opt={})
|
273
|
+
if @curr_polyline
|
274
|
+
@curr_win << prime_object(@curr_polyline,opt)
|
275
|
+
end
|
276
|
+
@curr_polyline=nil
|
277
|
+
end
|
278
|
+
|
279
|
+
def begin_polygon
|
280
|
+
@curr_polygon=SVGPolygon.new
|
281
|
+
end
|
282
|
+
|
283
|
+
def polygon_point(x,y)
|
284
|
+
@curr_polygon ||= SVGPolygon.new
|
285
|
+
@curr_polygon.addpoint(x,y)
|
286
|
+
end
|
287
|
+
|
288
|
+
def end_polygon(opt={})
|
289
|
+
@curr_win << prime_object(@curr_polygon,opt)
|
290
|
+
@curr_polygon=nil
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
def line(x1,y1,x2,y2, opt={})
|
295
|
+
@curr_win << prime_object(SVGLine.new(x1,y1,x2,y2), opt)
|
296
|
+
end
|
297
|
+
|
298
|
+
def textout(x,y,str, opt={})
|
299
|
+
@curr_win << prime_object(SVGText.new(x,y,str), opt)
|
300
|
+
end
|
301
|
+
|
302
|
+
# utility method
|
303
|
+
# automatically adds the 'font-family: monospace" , "stroke :none", "fill: black"
|
304
|
+
# they can all be overridden by passing in an opt
|
305
|
+
#
|
306
|
+
def textout_monospace(x,y,str,opt={})
|
307
|
+
defopt = { "font-family" => "monospace", "stroke" => "none", "fill" => "black" }
|
308
|
+
defopt.merge!(opt) if opt
|
309
|
+
|
310
|
+
textout(x,y,str,defopt)
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
def rectangle(x,y,w,h, opt={})
|
316
|
+
@curr_win << prime_object(SVGRect.new(x,y,w,h), opt)
|
317
|
+
end
|
318
|
+
|
319
|
+
def rectangle_r(r, opt={} )
|
320
|
+
rectangle(r.left, r.top, r.width, r.height, opt)
|
321
|
+
end
|
322
|
+
|
323
|
+
|
324
|
+
def select_presentation(opt={})
|
325
|
+
@curr_presentation_context.store(:pen,opt[:pen]) if opt[:pen]
|
326
|
+
@curr_presentation_context.store(:brush,opt[:brush]) if opt[:brush]
|
327
|
+
end
|
328
|
+
|
329
|
+
def clear_presentation
|
330
|
+
@curr_presentation_context = []
|
331
|
+
end
|
332
|
+
|
333
|
+
end
|
334
|
+
|
335
|
+
end
|