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,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
|
+
|