gerbilcharts 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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,30 @@
|
|
1
|
+
module GerbilCharts::Charts
|
2
|
+
|
3
|
+
# =Impulse Chart
|
4
|
+
#
|
5
|
+
# Each data point is represented by a thin line whose height is proportional to the value.
|
6
|
+
class ImpulseChart < ChartBase
|
7
|
+
|
8
|
+
def initialize(opt={})
|
9
|
+
super(opt)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_chart_elements
|
13
|
+
|
14
|
+
# other elements
|
15
|
+
@thechart.add_child(GerbilCharts::Surfaces::SurfaceBackground.new(:orient => ORIENT_OVERLAY))
|
16
|
+
@thechart.add_child(GerbilCharts::Surfaces::BasicGrid.new(:orient => ORIENT_OVERLAY))
|
17
|
+
@thechart.add_child(GerbilCharts::Surfaces::TitlePanel.new(:orient => ORIENT_OVERLAY, :dim => 30))
|
18
|
+
@thechart.add_child(GerbilCharts::Surfaces::ImpulseSurface.new(:orient => ORIENT_OVERLAY),:anchor => true)
|
19
|
+
@thechart.add_child(GerbilCharts::Surfaces::Legend.new(:orient=> ORIENT_OVERLAY, :dim => 100))
|
20
|
+
@thechart.add_child(GerbilCharts::Surfaces::VerticalAxis.new(:orient => ORIENT_WEST, :dim => 40 ))
|
21
|
+
@thechart.add_child(GerbilCharts::Surfaces::HorizontalTimeAxis.new(:orient => ORIENT_SOUTH, :dim => 25 ))
|
22
|
+
|
23
|
+
# optional features
|
24
|
+
if @feature_timetracker
|
25
|
+
@thechart.add_child(GerbilCharts::Surfaces::Tracker.new(:orient => ORIENT_SOUTH, :dim => 10 ))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module GerbilCharts::Charts
|
2
|
+
|
3
|
+
# =Line Chart
|
4
|
+
# Each model is a separate line.
|
5
|
+
#
|
6
|
+
# options
|
7
|
+
#
|
8
|
+
# [+width+] Width of the chart (pixels)
|
9
|
+
# [+height+] Width of the chart (pixels)
|
10
|
+
# [+style+] Stylesheet file to be applied
|
11
|
+
#
|
12
|
+
# global visual options
|
13
|
+
# [+circle_data_points] draw a solid circle around each data point
|
14
|
+
#
|
15
|
+
class LineChart < ChartBase
|
16
|
+
|
17
|
+
|
18
|
+
def initialize(opt={})
|
19
|
+
super(opt)
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_chart_elements
|
23
|
+
|
24
|
+
# other elements
|
25
|
+
@thechart.add_child(GerbilCharts::Surfaces::SurfaceBackground.new(:orient => ORIENT_OVERLAY))
|
26
|
+
@thechart.add_child(GerbilCharts::Surfaces::BasicGrid.new(:orient => ORIENT_OVERLAY))
|
27
|
+
@thechart.add_child(GerbilCharts::Surfaces::TitlePanel.new(:orient => ORIENT_OVERLAY, :dim => 30))
|
28
|
+
@thechart.add_child(GerbilCharts::Surfaces::LineSurface.new(:orient => ORIENT_OVERLAY),:anchor => true)
|
29
|
+
@thechart.add_child(GerbilCharts::Surfaces::Legend.new(:orient=> ORIENT_OVERLAY, :dim => 100))
|
30
|
+
@thechart.add_child(GerbilCharts::Surfaces::VerticalAxis.new(:orient => ORIENT_WEST, :dim => 30 ))
|
31
|
+
@thechart.add_child(GerbilCharts::Surfaces::HorizontalTimeAxis.new(:orient => ORIENT_SOUTH, :dim => 25 ))
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module GerbilCharts::Charts
|
2
|
+
|
3
|
+
# = StackedAreaChart
|
4
|
+
# The models are stacked on top of each other !
|
5
|
+
#
|
6
|
+
class StackedAreaChart < ChartBase
|
7
|
+
|
8
|
+
def initialize(opt={})
|
9
|
+
super(opt)
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_chart_elements
|
13
|
+
|
14
|
+
# other elements
|
15
|
+
@thechart.add_child(GerbilCharts::Surfaces::SurfaceBackground.new(:orient => ORIENT_OVERLAY))
|
16
|
+
@thechart.add_child(GerbilCharts::Surfaces::StackedGrid.new(:orient => ORIENT_OVERLAY))
|
17
|
+
@thechart.add_child(GerbilCharts::Surfaces::TitlePanel.new(:orient => ORIENT_OVERLAY, :dim => 30))
|
18
|
+
@thechart.add_child(GerbilCharts::Surfaces::StackedAreaSurface.new(:orient => ORIENT_OVERLAY),:anchor => true)
|
19
|
+
@thechart.add_child(GerbilCharts::Surfaces::Legend.new(:orient=> ORIENT_OVERLAY, :dim => 100))
|
20
|
+
@thechart.add_child(GerbilCharts::Surfaces::VerticalAxis.new(:orient => ORIENT_WEST, :dim => 40 , :cumulative => true ))
|
21
|
+
@thechart.add_child(GerbilCharts::Surfaces::HorizontalTimeAxis.new(:orient => ORIENT_SOUTH, :dim => 25 ))
|
22
|
+
|
23
|
+
# optional features
|
24
|
+
if @feature_timetracker
|
25
|
+
@thechart.add_child(GerbilCharts::Surfaces::Tracker.new(:orient => ORIENT_SOUTH, :dim => 10 ))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# == GerbilCharts data models
|
2
|
+
#
|
3
|
+
# Models feeds your gerbil charts with data
|
4
|
+
#
|
5
|
+
|
6
|
+
module GerbilCharts::Models; end;
|
7
|
+
|
8
|
+
require 'gerbilcharts/models/presets'
|
9
|
+
require 'gerbilcharts/models/raw_range'
|
10
|
+
require 'gerbilcharts/models/round_range'
|
11
|
+
require 'gerbilcharts/models/round_time_range'
|
12
|
+
require 'gerbilcharts/models/discrete_time_range'
|
13
|
+
require 'gerbilcharts/models/graph_model'
|
14
|
+
require 'gerbilcharts/models/graph_model_group'
|
15
|
+
require 'gerbilcharts/models/monotonous_graph_model'
|
16
|
+
require 'gerbilcharts/models/time_series_graph_model'
|
17
|
+
require 'gerbilcharts/models/bucketized_timeseries_graph_model'
|
18
|
+
require 'gerbilcharts/models/sampled_timeseries_graph_model'
|
19
|
+
require 'gerbilcharts/models/simple_timeseries_model_group'
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module GerbilCharts::Models
|
2
|
+
|
3
|
+
# == BucketizedTimeSeriedGraphMode
|
4
|
+
#
|
5
|
+
# Automatically bucketizes incoming timeseries data into predefined buckets
|
6
|
+
#
|
7
|
+
# [+name+] Name of the model
|
8
|
+
# [+bucketsec+] Bucket size in seconds
|
9
|
+
# [+opts+] Model options hash
|
10
|
+
#
|
11
|
+
class BucketizedTimeSeriesGraphModel < TimeSeriesGraphModel
|
12
|
+
|
13
|
+
attr_reader :bucket_size_secs # current bucket size
|
14
|
+
attr_reader :behavior # :average or :max
|
15
|
+
attr_reader :last_sweep_pos # :nodoc:
|
16
|
+
|
17
|
+
def initialize(name,bucketsec, opt={})
|
18
|
+
super(name,opt)
|
19
|
+
@bucket_size_secs=bucketsec
|
20
|
+
@samp_count =0
|
21
|
+
@behavior = :average
|
22
|
+
@last_sweep_pos=0
|
23
|
+
end
|
24
|
+
|
25
|
+
def sweep_interval
|
26
|
+
return @bucket_size_secs
|
27
|
+
end
|
28
|
+
|
29
|
+
# add
|
30
|
+
# [+x_val+] A Time object
|
31
|
+
# [+y_val+] Value
|
32
|
+
#
|
33
|
+
# This will be bucketized by the model automatically
|
34
|
+
#
|
35
|
+
def add(x_tm,y_val)
|
36
|
+
buckettm_in = to_buckettime(x_tm)
|
37
|
+
|
38
|
+
# first time
|
39
|
+
if @xarr.length==0
|
40
|
+
super(buckettm_in,y_val)
|
41
|
+
@samp_count=1
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# subsequent times
|
47
|
+
if buckettm_in== latest_x
|
48
|
+
ynew = bucketize(y_val)
|
49
|
+
else
|
50
|
+
npad = bucket_diff(latest_x,buckettm_in)
|
51
|
+
if (npad > 1)
|
52
|
+
pad_empty_buckets(latest_x,npad-1)
|
53
|
+
end
|
54
|
+
super(buckettm_in,y_val)
|
55
|
+
@samp_count=1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# to_buckettime
|
60
|
+
#
|
61
|
+
# [+tv+] A Time object
|
62
|
+
#
|
63
|
+
# returns the time floor of the bucket this belongs to
|
64
|
+
# example 8:06 AM will belong to the 8:05AM bucket if bucketsize = 5 min
|
65
|
+
#
|
66
|
+
def to_buckettime(tv)
|
67
|
+
exp=tv.tv_sec.divmod(@bucket_size_secs)
|
68
|
+
|
69
|
+
if exp[1] >= @bucket_size_secs/2
|
70
|
+
return Time.at(exp[0]*@bucket_size_secs + @bucket_size_secs)
|
71
|
+
else
|
72
|
+
return Time.at(exp[0]*@bucket_size_secs)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# how many buckets separate the two buckettimes
|
77
|
+
def bucket_diff(tv1,tv2)
|
78
|
+
return (tv2-tv1).abs / @bucket_size_secs
|
79
|
+
end
|
80
|
+
|
81
|
+
# insert zero values to represent missing time buckets
|
82
|
+
def pad_empty_buckets(tv_first,count)
|
83
|
+
for i in (1..count)
|
84
|
+
@yarr << 0
|
85
|
+
@xarr << tv_first + i*@bucket_size_secs
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# accumulate last item
|
90
|
+
def bucketize(val)
|
91
|
+
|
92
|
+
if @behavior == :average
|
93
|
+
cval = @yarr.last
|
94
|
+
cval = (cval * @samp_count) + val
|
95
|
+
cval /= (@samp_count+1)
|
96
|
+
@yarr[@yarr.length-1]=cval
|
97
|
+
@samp_count += 1
|
98
|
+
elsif @behavior == :maxima
|
99
|
+
cval = @yarr.last
|
100
|
+
@yarr[@yarr.length-1]=max(cval,val)
|
101
|
+
end
|
102
|
+
return @yarr.last
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# begin a sweep session
|
107
|
+
def begin_sweep
|
108
|
+
@last_sweep_pos=0
|
109
|
+
end
|
110
|
+
|
111
|
+
# sweep this bucket
|
112
|
+
def sweep(tval)
|
113
|
+
|
114
|
+
return 0 if @xarr.length == 0
|
115
|
+
return 0 if @last_sweep_pos >= @xarr.length
|
116
|
+
|
117
|
+
|
118
|
+
xv=@xarr[@last_sweep_pos]
|
119
|
+
if tval < xv
|
120
|
+
return 0
|
121
|
+
elsif tval == xv
|
122
|
+
@last_sweep_pos+=1
|
123
|
+
rval = @yarr[@last_sweep_pos-1]
|
124
|
+
else
|
125
|
+
nBucks=bucket_diff(xv,tval)
|
126
|
+
@last_sweep_pos+= nBucks
|
127
|
+
end
|
128
|
+
return rval.nil? ? 0:rval
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module GerbilCharts::Models
|
2
|
+
|
3
|
+
# =DiscreteTimeRange
|
4
|
+
# The range is exactly as specified by individual values.
|
5
|
+
# The labels are simply those values formatted based on overall time window
|
6
|
+
#
|
7
|
+
class DiscreteTimeRange
|
8
|
+
|
9
|
+
attr_reader :points #discrete points
|
10
|
+
|
11
|
+
def initialize(points_arr=[])
|
12
|
+
@points=points_arr
|
13
|
+
end
|
14
|
+
|
15
|
+
# provide labels
|
16
|
+
# Yields two items (value - seconds since Jan 1 1970, string label)
|
17
|
+
def each_label
|
18
|
+
@points.each do |t|
|
19
|
+
yield t, format_value(t)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# provide ticks (per label interval)
|
24
|
+
def each_tick(tpl)
|
25
|
+
@points.each do |t|
|
26
|
+
yield v
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# format min value completely
|
31
|
+
def format_min_value
|
32
|
+
return format_value(@points.first)
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# scales a value with respect to the range
|
37
|
+
def scale_factor(val)
|
38
|
+
df = val - @points.first
|
39
|
+
rg = @points.last - @points.first
|
40
|
+
return 0 if rg==0.0
|
41
|
+
return df/rg
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# format the discrete time value
|
46
|
+
def format_value(val)
|
47
|
+
df = @points.last - @points.first
|
48
|
+
|
49
|
+
if df > 2*24*30 # > 2months get monthly labels
|
50
|
+
val.strftime("%b")
|
51
|
+
elsif df > 1*24*30 # 1-2 months get days
|
52
|
+
val.strftime("%b %d")
|
53
|
+
elsif df > 1*24*7 # > 1 week get days
|
54
|
+
val.strftime("%a")
|
55
|
+
else
|
56
|
+
val.to_s
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module GerbilCharts::Models
|
2
|
+
|
3
|
+
# GraphModel - Basic interface to a model in GerbilCharts
|
4
|
+
#
|
5
|
+
# You can create your own model as long as all the methods here are implemented
|
6
|
+
# or you can use one of the predefined graph models.
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class GraphModel
|
10
|
+
|
11
|
+
attr_accessor :name # name of the model (eg, "backup_server")
|
12
|
+
attr_accessor :altname # alternate name
|
13
|
+
attr_reader :href # href for interactive use
|
14
|
+
attr_reader :userdata # any user object
|
15
|
+
attr_reader :userlabel1 # map to tooltip 1
|
16
|
+
attr_reader :userlabel2 # map to tooltip 2
|
17
|
+
attr_reader :transformer # value transformer (a lambda function)
|
18
|
+
|
19
|
+
def initialize(n="Untitled")
|
20
|
+
@name=n
|
21
|
+
@transformer = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def min_max_x
|
25
|
+
yield 0,0
|
26
|
+
end
|
27
|
+
|
28
|
+
def min_max_y
|
29
|
+
yield 0,0
|
30
|
+
end
|
31
|
+
|
32
|
+
def each_value_pair
|
33
|
+
yield 0,0
|
34
|
+
end
|
35
|
+
|
36
|
+
def count
|
37
|
+
0
|
38
|
+
end
|
39
|
+
|
40
|
+
# clean up the href (todo: improve this)
|
41
|
+
def setHref(h)
|
42
|
+
h1=h.gsub("{","%7B")
|
43
|
+
@href=h1.gsub("}","%7D")
|
44
|
+
end
|
45
|
+
|
46
|
+
def hasHref?
|
47
|
+
return @href != nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def setUserData(d)
|
51
|
+
@userdata=d
|
52
|
+
end
|
53
|
+
|
54
|
+
def hasUserData?
|
55
|
+
return @userdata != nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def hasUserTips?
|
59
|
+
return @userlabel1 != nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def setUserTip1(t)
|
63
|
+
@userlabel1=t
|
64
|
+
@userlabel2="" if @userlabel2.nil?
|
65
|
+
end
|
66
|
+
|
67
|
+
def setUserTip2(t)
|
68
|
+
@userlabel2=t
|
69
|
+
@userlabel1="" if @userlabel1.nil?
|
70
|
+
end
|
71
|
+
|
72
|
+
def updateOptions(opts)
|
73
|
+
@name = opts[:name] if opts[:name]
|
74
|
+
end
|
75
|
+
|
76
|
+
def recreate
|
77
|
+
# no op (override this)
|
78
|
+
end
|
79
|
+
|
80
|
+
def transformer=(trlambda)
|
81
|
+
@transformer = trlambda
|
82
|
+
end
|
83
|
+
|
84
|
+
def is_timeseries?
|
85
|
+
return false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
module GerbilCharts::Models
|
2
|
+
|
3
|
+
# GraphModelGroup - a bunch of related models that are targeted at a
|
4
|
+
# single output surface
|
5
|
+
#
|
6
|
+
class GraphModelGroup
|
7
|
+
|
8
|
+
attr_accessor :models
|
9
|
+
attr_accessor :name
|
10
|
+
attr_accessor :href
|
11
|
+
attr_accessor :emptycaption
|
12
|
+
attr_accessor :units
|
13
|
+
|
14
|
+
def initialize(n="Untitled-Group")
|
15
|
+
@models=[]
|
16
|
+
@name=n
|
17
|
+
@units=""
|
18
|
+
end
|
19
|
+
|
20
|
+
def <<(m)
|
21
|
+
@models << m
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(m)
|
25
|
+
@models << m
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(m)
|
29
|
+
@models.delete(m)
|
30
|
+
end
|
31
|
+
|
32
|
+
def delete_by_index(i)
|
33
|
+
@models.delete_at(i)
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_null(i)
|
37
|
+
@models[i]=nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def compact_models
|
41
|
+
@models.compact!
|
42
|
+
end
|
43
|
+
|
44
|
+
def count
|
45
|
+
return @models.size
|
46
|
+
end
|
47
|
+
|
48
|
+
def each_model
|
49
|
+
@models.each do |m|
|
50
|
+
yield m
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def clear_models
|
55
|
+
@models.clear
|
56
|
+
end
|
57
|
+
|
58
|
+
# sort options
|
59
|
+
# :dir => (:ascending or :descending)
|
60
|
+
# :mode => (:latest, :total )
|
61
|
+
def sort(opts={})
|
62
|
+
|
63
|
+
raise "Missing sort direction" if not defined? opts[:dir]
|
64
|
+
raise "Missing sort mode" if not defined? opts[:mode]
|
65
|
+
|
66
|
+
@models.sort! { |m1,m2| m1.latest_val <=> m2.latest_val }
|
67
|
+
|
68
|
+
@models.reverse! if opts[:dir] == :descending
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
# each model, index over code block
|
73
|
+
def each_model_with_index
|
74
|
+
@models.each_with_index do |m,i|
|
75
|
+
yield m,i
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# each user data over code block
|
80
|
+
def each_user_data
|
81
|
+
each_model do |mod|
|
82
|
+
yield mod.userdata if mod.hasUserData?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def effective_round_range
|
87
|
+
|
88
|
+
if @models.length==0
|
89
|
+
return 0,0
|
90
|
+
end
|
91
|
+
|
92
|
+
reffx = RawRange.new
|
93
|
+
reffy = RawRange.new
|
94
|
+
@models.each do |m|
|
95
|
+
reffx.update_r(m.xrange)
|
96
|
+
reffy.update_r(m.yrange)
|
97
|
+
end
|
98
|
+
|
99
|
+
return models[0].rounderx.round_given(reffx), models[0].roundery.round_given(reffy)
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
def effective_round_range_x
|
104
|
+
|
105
|
+
reffx = RawRange.new
|
106
|
+
@models.each do |m|
|
107
|
+
reffx.update_r(m.xrange)
|
108
|
+
end
|
109
|
+
|
110
|
+
return models[0].round_given_x(reffx)
|
111
|
+
end
|
112
|
+
|
113
|
+
def effective_round_range_y0
|
114
|
+
reffy = RawRange.new
|
115
|
+
reffy.zeromin
|
116
|
+
@models.each do |m|
|
117
|
+
reffy.update_r(m.yrange)
|
118
|
+
end
|
119
|
+
|
120
|
+
return @models[0].round_given_y(reffy)
|
121
|
+
end
|
122
|
+
|
123
|
+
def sweep_interval
|
124
|
+
return @models[0].sweep_interval
|
125
|
+
end
|
126
|
+
|
127
|
+
# sum of model ranges
|
128
|
+
def cumulative_round_range_y0
|
129
|
+
reffy = RawRange.new
|
130
|
+
reffy.update(0)
|
131
|
+
@models.each do |m|
|
132
|
+
reffy.update(m.yrange.rmax+reffy.rmax)
|
133
|
+
end
|
134
|
+
|
135
|
+
return models[0].round_given_y(reffy)
|
136
|
+
end
|
137
|
+
|
138
|
+
# sweep for an interval with max
|
139
|
+
def cumulative_sweep_round_range_y0
|
140
|
+
|
141
|
+
rx = effective_round_range_x
|
142
|
+
reffy = RawRange.new
|
143
|
+
reffy.zeromin
|
144
|
+
|
145
|
+
# prepare models for sweeping
|
146
|
+
sweep_pos= rx.rmin
|
147
|
+
sweep_to = rx.rmax
|
148
|
+
|
149
|
+
@models.each do | mod|
|
150
|
+
mod.begin_sweep
|
151
|
+
end
|
152
|
+
|
153
|
+
# perform the sweep
|
154
|
+
while (sweep_pos<=sweep_to)
|
155
|
+
acc_y = 0
|
156
|
+
@models.each do | mod, i|
|
157
|
+
acc_y += mod.sweep(sweep_pos)
|
158
|
+
end
|
159
|
+
sweep_pos += sweep_interval
|
160
|
+
reffy.update(acc_y)
|
161
|
+
end
|
162
|
+
|
163
|
+
return models[0].round_given_y(reffy)
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
def cumulative_round_range
|
168
|
+
|
169
|
+
if @models.length==0
|
170
|
+
return 0,0
|
171
|
+
end
|
172
|
+
|
173
|
+
reffx = RawRange.new
|
174
|
+
reffy = RawRange.new
|
175
|
+
@models.each do |m|
|
176
|
+
reffx.update_r(m.xrange)
|
177
|
+
reffy.update(m.yrange.rmax+reffy.rmax)
|
178
|
+
end
|
179
|
+
|
180
|
+
return models[0].rounderx.round_given(reffx), models[0].roundery.round_given(reffy)
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
def models_digest
|
185
|
+
mnames = ""
|
186
|
+
@models.each do |m|
|
187
|
+
mnames << m.name
|
188
|
+
end
|
189
|
+
dig=Digest::MD5.hexdigest(mnames)
|
190
|
+
return dig
|
191
|
+
end
|
192
|
+
|
193
|
+
def setSessionKey(k)
|
194
|
+
@sessionKey=k
|
195
|
+
end
|
196
|
+
|
197
|
+
def contentKey(sessid,extension)
|
198
|
+
return sessid + @sessionKey + "." + extension
|
199
|
+
end
|
200
|
+
|
201
|
+
def setHref(h)
|
202
|
+
h1=h.gsub("{","%7B")
|
203
|
+
@href=h1.gsub("}","%7D")
|
204
|
+
end
|
205
|
+
|
206
|
+
def hasHref?
|
207
|
+
return @href != nil
|
208
|
+
end
|
209
|
+
|
210
|
+
def randomizeModels(mode=:latest_value)
|
211
|
+
@models.each do |m|
|
212
|
+
if mode==:latest_value
|
213
|
+
m.randomizeLastValue
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# recreate all models with new params
|
219
|
+
def recreateModels(new_opts)
|
220
|
+
@models.each do |m|
|
221
|
+
m.updateOptions(new_opts)
|
222
|
+
m.recreate
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
# empty ?
|
228
|
+
def empty?
|
229
|
+
return @models.empty?
|
230
|
+
end
|
231
|
+
|
232
|
+
# empty string
|
233
|
+
def empty_caption
|
234
|
+
return "No activity" if @emptycaption.nil?
|
235
|
+
return @emptycaption
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|