gerbilcharts 0.2.13 → 0.5.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. data/History.txt +35 -0
  2. data/Manifest.txt +8 -0
  3. data/README.txt +8 -8
  4. data/lib/gerbilcharts/charts.rb +3 -0
  5. data/lib/gerbilcharts/charts/bubble_chart.rb +30 -0
  6. data/lib/gerbilcharts/charts/conversation_ring.rb +31 -0
  7. data/lib/gerbilcharts/charts/line_chart.rb +1 -0
  8. data/lib/gerbilcharts/charts/matrix_chart.rb +32 -0
  9. data/lib/gerbilcharts/charts/square_line_chart.rb +7 -0
  10. data/lib/gerbilcharts/models.rb +1 -0
  11. data/lib/gerbilcharts/models/bucketized_timeseries_graph_model.rb +1 -1
  12. data/lib/gerbilcharts/models/graph_model_group.rb +19 -2
  13. data/lib/gerbilcharts/models/matrix_model.rb +85 -0
  14. data/lib/gerbilcharts/models/monotonous_graph_model.rb +5 -1
  15. data/lib/gerbilcharts/models/presets.rb +18 -11
  16. data/lib/gerbilcharts/models/raw_range.rb +1 -1
  17. data/lib/gerbilcharts/models/round_range.rb +3 -1
  18. data/lib/gerbilcharts/models/round_time_range.rb +19 -29
  19. data/lib/gerbilcharts/models/sampled_timeseries_graph_model.rb +1 -1
  20. data/lib/gerbilcharts/public/brushmetal.css +123 -74
  21. data/lib/gerbilcharts/public/gerbil.js +104 -64
  22. data/lib/gerbilcharts/surfaces.rb +3 -0
  23. data/lib/gerbilcharts/surfaces/bubble_surface.rb +105 -0
  24. data/lib/gerbilcharts/surfaces/chart.rb +4 -2
  25. data/lib/gerbilcharts/surfaces/conversation_ring.rb +64 -0
  26. data/lib/gerbilcharts/surfaces/detailed_legend.rb +35 -13
  27. data/lib/gerbilcharts/surfaces/graph_element.rb +8 -1
  28. data/lib/gerbilcharts/surfaces/grid.rb +8 -2
  29. data/lib/gerbilcharts/surfaces/horizontal_axis.rb +12 -3
  30. data/lib/gerbilcharts/surfaces/horizontal_time_axis.rb +5 -4
  31. data/lib/gerbilcharts/surfaces/impulse_surface.rb +1 -1
  32. data/lib/gerbilcharts/surfaces/legend.rb +43 -6
  33. data/lib/gerbilcharts/surfaces/mark_band.rb +17 -1
  34. data/lib/gerbilcharts/surfaces/matrix_surface.rb +87 -0
  35. data/lib/gerbilcharts/surfaces/pie_surface.rb +109 -96
  36. data/lib/gerbilcharts/surfaces/rect.rb +18 -0
  37. data/lib/gerbilcharts/surfaces/stacked_area_surface.rb +42 -2
  38. data/lib/gerbilcharts/surfaces/stacked_grid.rb +1 -3
  39. data/lib/gerbilcharts/surfaces/title_panel.rb +7 -2
  40. data/lib/gerbilcharts/surfaces/tracker.rb +4 -1
  41. data/lib/gerbilcharts/surfaces/vertical_axis.rb +2 -2
  42. data/lib/gerbilcharts/svgdc.rb +1 -0
  43. data/lib/gerbilcharts/svgdc/css_inliner.rb +2 -2
  44. data/lib/gerbilcharts/svgdc/svg_ellipse.rb +21 -0
  45. data/lib/gerbilcharts/svgdc/svg_polygon.rb +19 -0
  46. data/lib/gerbilcharts/svgdc/svgdc.rb +4 -1
  47. data/lib/gerbilcharts/version.rb +2 -3
  48. data/test/test_bar.rb +1 -1
  49. data/test/test_bubble.rb +52 -0
  50. data/test/test_conversation.rb +34 -0
  51. data/test/test_lines.rb +3 -3
  52. data/test/test_matrix.rb +34 -0
  53. data/test/test_noob.rb +9 -6
  54. data/test/test_pie.rb +2 -2
  55. data/test/test_ranges.rb +15 -2
  56. data/test/test_sa.rb +88 -0
  57. metadata +14 -2
@@ -4,6 +4,9 @@ module GerbilCharts::Surfaces
4
4
  # legend panel shows names/colors of items in a separate box (transparent)
5
5
  class DetailedLegend < GraphElement
6
6
 
7
+ WIDTH_MAX = 500
8
+ STAT_TABLE_OFFSET=120
9
+
7
10
  attr_reader :width
8
11
  attr_reader :showvalues
9
12
 
@@ -15,16 +18,34 @@ class DetailedLegend < GraphElement
15
18
 
16
19
  def int_render(g)
17
20
 
21
+ return unless parent.get_global_option(:enable_detailed_legend,true)
22
+
18
23
  w=g.newwin("legendpanel_detail", {:visibility => 'hidden'} )
19
24
  g.setactivewindow(w)
20
25
 
26
+
27
+ # get max modname, used to calculate width of detailed panel
28
+ max_name_length=0
29
+ parent.modelgroup.each_model do | mod |
30
+ max_name_length = [max_name_length,mod.name.length].max
31
+ end
32
+
33
+ @bounds.left = @bounds.right-WIDTH_MAX if @bounds.width > WIDTH_MAX
34
+
21
35
  # count determines the bounds
22
36
  @bounds.bottom = @bounds.top + 16 + 15 * parent.modelgroup.count
23
37
  g.rectangle_r(@bounds, {:class => @class})
24
38
 
25
39
  # toggle detail/mini legend
26
40
  g.rectangle(@bounds.left-5,@bounds.top,5,5, {:href => "javascript:void(0);",
27
- :onclick => "showMiniLegend();" })
41
+ :onclick => "showMiniLegend();",
42
+ :fill => "white",
43
+ :stroke => "none",
44
+ :gerbiltooltip1 => "Click to show compact legend" })
45
+ g.textout(@bounds.left-4,@bounds.top+5,'>', {'font-size' => '9', :href => "javascript:void(0);",
46
+ :onclick => "showMiniLegend();", :stroke => '#DDDDDD',
47
+ :gerbiltooltip1 => "Click to show compact legend" })
48
+
28
49
 
29
50
  rbox = Rect.new
30
51
  rbox.initfrom(@bounds)
@@ -34,12 +55,10 @@ class DetailedLegend < GraphElement
34
55
  rbox.bottom = rbox.top+10
35
56
 
36
57
 
37
- stat_label_pos = rbox.right + [140,@bounds.width-200].max
38
- stat_label_width = 45
39
- ["Min", "Max", "Avg", "Latest"].each do |lab|
40
- g.textout(stat_label_pos, rbox.bottom-2, lab, {:class => "legendstats"} )
41
- stat_label_pos += stat_label_width
42
- end
58
+
59
+ stat_label_pos = rbox.right + STAT_TABLE_OFFSET
60
+ lab = %w(Max Min Avg Latest).inject("") { |m,ai| m += ai.rjust(9)}
61
+ g.textout(stat_label_pos, rbox.bottom-2, lab, {'xml:space' => 'preserve', :class => "legendstats"} )
43
62
 
44
63
  rbox.top += 16
45
64
  rbox.bottom = rbox.top+10
@@ -52,16 +71,19 @@ class DetailedLegend < GraphElement
52
71
  opts.store(:gerbiltooltip1, mod.name)
53
72
  opts.store(:gerbiltooltip2, "Latest Value = #{mod.latest_val}")
54
73
 
55
- g.rectangle_r(rbox, :id => "item#{i}")
74
+ boxopts = { :id => "item#{i}" }
75
+ boxopts.store(:fill , color_for_id(i)) if i > 10
76
+ g.rectangle_r(rbox, boxopts )
56
77
  g.textout(rbox.right+5, rbox.bottom-2, mod.name,opts)
57
78
 
58
79
  stat_ana = mod.get_statistical_analysis
59
80
 
60
- stat_label_pos = rbox.right + [140,@bounds.width-200].max
61
- [0,1,2,4].each do |sid|
62
- g.textout(stat_label_pos, rbox.bottom-2, mod.formatted_val(stat_ana[sid]), {:class => 'legendstats'} )
63
- stat_label_pos += stat_label_width
64
- end
81
+ stat_label_pos = rbox.right + STAT_TABLE_OFFSET
82
+ outs = mod.formatted_val(stat_ana[1]).to_s.rjust(9) +
83
+ mod.formatted_val(stat_ana[0]).to_s.rjust(9) +
84
+ mod.formatted_val(stat_ana[2]).to_s.rjust(9) +
85
+ mod.formatted_val(stat_ana[4]).to_s.rjust(9)
86
+ g.textout(stat_label_pos, rbox.bottom-2, outs, {'xml:space' => 'preserve', :class => 'legendstats'} )
65
87
 
66
88
 
67
89
  rbox.top += 10 + 5
@@ -69,6 +69,7 @@ class GraphElement
69
69
  end
70
70
 
71
71
  def scale_y val,range
72
+ return 0 if range.invalid?
72
73
  return @bounds.bottom - @bounds.height * range.scale_factor(val)
73
74
  end
74
75
 
@@ -143,7 +144,7 @@ class GraphElement
143
144
 
144
145
  # query a global option, return the defval if option is not set
145
146
  def get_global_option(optsym, defval)
146
- @global_chart_options[optsym] || defval
147
+ @global_chart_options.has_key?(optsym)? @global_chart_options[optsym]: defval
147
148
  end
148
149
 
149
150
  # utility methods to derived classes
@@ -157,6 +158,12 @@ protected
157
158
  return (a<b)?a:b
158
159
  end
159
160
 
161
+ # random but consistent color for ID
162
+ # depends on a lazily generated map of 100 colors
163
+ def color_for_id(id)
164
+ @@mcolors ||= Array.new(100){ |t| "#%06x" % (rand * 0xffffff) }
165
+ return @@mcolors[id]
166
+ end
160
167
 
161
168
  end
162
169
 
@@ -32,10 +32,16 @@ class Grid < GraphElement
32
32
  end
33
33
 
34
34
 
35
+ scaling_x = parent.get_global_option(:scaling_x,:auto)
36
+ rwx = parent.modelgroup.effective_range_x(scaling_x)
37
+ if scaling_x.is_a? Array
38
+ rx = GerbilCharts::Models::RoundTimeRange.new(rwx)
39
+ end
40
+
35
41
  # vertical subticks
36
42
  g.newwin('vgrid', {:class => "gridlinev"} ) do |g|
37
43
  rx.each_label do |val,label|
38
- xp = scale_x val,rx
44
+ xp = scale_x val,rwx
39
45
  g.line(xp,@bounds.top,xp,@bounds.bottom)
40
46
  end
41
47
  end
@@ -43,7 +49,7 @@ class Grid < GraphElement
43
49
 
44
50
  g.newwin('vgridsub', {:class => "gridlinesub"} ) do |g|
45
51
  rx.each_tick(0) do |val|
46
- xp = scale_x val,rx
52
+ xp = scale_x val,rwx
47
53
  g.line(xp,@bounds.top,xp,@bounds.bottom)
48
54
  end
49
55
  end
@@ -15,8 +15,15 @@ class HorizontalAxis < Axis
15
15
  range_options_x = parent.get_global_option(:scaling_x,:auto)
16
16
  rawx = parent.modelgroup.effective_range_x(range_options_x)
17
17
 
18
+
18
19
  # need roundx for labels
19
- roundx = parent.modelgroup.effective_round_range_x
20
+ if range_options_x.is_a? Array
21
+ roundx = GerbilCharts::Models::RoundTimeRange.new rawx
22
+ else
23
+ roundx = parent.modelgroup.effective_round_range_x
24
+ end
25
+
26
+
20
27
  roundx.each_label do |val,label|
21
28
  xp = scale_x val,rawx
22
29
 
@@ -27,8 +34,10 @@ class HorizontalAxis < Axis
27
34
  xp = @bounds.right-10
28
35
  end
29
36
 
30
- g.textout(xp, @bounds.top+10, label, {:class => "axislabel", "text-anchor" => "middle"})
31
- g.line(xp,@bounds.top-2,xp,@bounds.top+3, {:class => "axistickmajor"})
37
+ if (xp>=15)
38
+ g.textout(xp, @bounds.top+11, label, {:class => "axislabel", "text-anchor" => "middle"})
39
+ g.line(xp,@bounds.top-2,xp,@bounds.top+1, {:class => "axistickmajor"})
40
+ end
32
41
  end
33
42
 
34
43
  end
@@ -13,12 +13,13 @@ class HorizontalTimeAxis < HorizontalAxis
13
13
  def int_render(g)
14
14
  super
15
15
 
16
- rx = parent.modelgroup.effective_round_range_x
17
- sfmt = rx.format_min_value
16
+ range_options_x = parent.get_global_option(:scaling_x,:auto)
17
+ rx = parent.modelgroup.effective_range_x(range_options_x)
18
+ sfmt = Time.at(rx.rmin).getlocal.to_s
18
19
 
19
20
 
20
- g.textout(@bounds.left-20, @bounds.top+20, sfmt, {:class => "axislabelt0" })
21
- g.line(@bounds.left,@bounds.top,@bounds.left,@bounds.top+10,{:class => "axistickmajor"})
21
+ g.textout(@bounds.left-20, @bounds.top+22, sfmt, {:class => "axislabelt0" })
22
+ g.line(@bounds.left,@bounds.top,@bounds.left,@bounds.top+2,{:class => "axistickmajor"})
22
23
 
23
24
  end
24
25
 
@@ -30,7 +30,7 @@ class ImpulseSurface < Surface
30
30
  g.setactivewindow(w)
31
31
 
32
32
  parent.modelgroup.each_model_with_index do | mod, i|
33
- opts = {:id => "item#{i}"}
33
+ opts = {:id => "lineitem#{i}"}
34
34
  firstpoint=true
35
35
  xpos=0
36
36
  ypos=0
@@ -14,6 +14,7 @@ class Legend < GraphElement
14
14
  end
15
15
 
16
16
  def int_render(g)
17
+ return if not parent.get_global_option(:enable_legend,true)
17
18
 
18
19
  w=g.newwin("legendpanel_mini")
19
20
  g.setactivewindow(w)
@@ -24,11 +25,38 @@ class Legend < GraphElement
24
25
 
25
26
  # toggle detail/mini legend
26
27
  g.rectangle(@bounds.left-5,@bounds.top,5,5, {:href => "javascript:void(0);",
27
- :onclick => "showDetailedLegend();" })
28
-
28
+ :onclick => "showDetailedLegend();",
29
+ :fill => "white",
30
+ :stroke => "none",
31
+ :gerbiltooltip1 => "Click to show a detailed legend" })
32
+
33
+ g.textout(@bounds.left-7,@bounds.top+5,'+', {'font-size' => '9', :href => "javascript:void(0);",
34
+ :onclick => "showDetailedLegend();", :stroke => '#DDDDDD' ,
35
+ :gerbiltooltip1 => "Click to show a detailed legend" })
36
+
37
+ # shift
38
+ g.rectangle(@bounds.left-5,@bounds.top+15,5,5, {:href => "javascript:void(0);",
39
+ :onclick => "shiftLegend(#{-@bounds.left+50});",
40
+ :fill => "white",
41
+ :stroke => "none",
42
+ :gerbiltooltip1 => "Click to move legend to left side" })
43
+ g.textout(@bounds.left-7,@bounds.top+15,'<', {'font-size' => '9', :href => "javascript:void(0);",
44
+ :onclick => "shiftLegend(#{-@bounds.left+50});", :stroke => '#DDDDDD',
45
+ :gerbiltooltip1 => "Click to move legend to left side" })
46
+
47
+
48
+ # shift
49
+ g.rectangle(@bounds.left-5,@bounds.top+25,5,5, {:href => "javascript:void(0);",
50
+ :onclick => "shiftLegend(0);",
51
+ :fill => "white",
52
+ :stroke => "none" ,
53
+ :gerbiltooltip1 => "Click to move legend to right side"})
54
+ g.textout(@bounds.left-7,@bounds.top+25,'>', {'font-size' => '9', :href => "javascript:void(0);",
55
+ :onclick => "shiftLegend(0);", :stroke => '#DDDDDD',
56
+ :gerbiltooltip1 => "Click to move legend to right side"})
29
57
  rbox = Rect.new
30
58
  rbox.initfrom(@bounds)
31
- rbox.left += 2
59
+ rbox.left += 20
32
60
  rbox.right = rbox.left + 10
33
61
  rbox.top += 2
34
62
  rbox.bottom = rbox.top+10
@@ -41,9 +69,18 @@ class Legend < GraphElement
41
69
  opts.store(:gerbiltooltip1, mod.name)
42
70
  opts.store(:gerbiltooltip2, "Latest Value = #{mod.latest_val}")
43
71
 
44
- g.rectangle_r(rbox, :id => "item#{i}")
45
- g.textout(rbox.right+5, rbox.bottom-2, mod.name,opts)
46
-
72
+ # Selector
73
+ ctlbox = Rect.new
74
+ ctlbox.initfrom(rbox)
75
+ ctlbox.offset_x(-16)
76
+ ctlbox.deflate(1)
77
+ g.circle_r(ctlbox, {:id => "lbx#{i}", :fill => 'gray', :stroke => 'none', :href => "javascript:void(0);", :onclick => "ToggleVisibility(#{i})"})
78
+
79
+ boxopts = {:id => "item#{i}"}
80
+ boxopts.store(:fill , color_for_id(i)) if i > 10
81
+ g.rectangle_r(rbox, boxopts )
82
+ g.textout(rbox.right+5, rbox.bottom-2, mod.name,opts)
83
+
47
84
  rbox.top += 10 + 5
48
85
  rbox.bottom = rbox.top+10
49
86
 
@@ -9,7 +9,23 @@ class MarkBand < GraphElement
9
9
  end
10
10
 
11
11
  def int_render(g)
12
- g.rectangle_r(@bounds, {:class => @class})
12
+
13
+ return unless parent.modelgroup.has_x_markers?
14
+
15
+ range_options_x = parent.get_global_option(:scaling_x,:auto)
16
+ range_options_y = parent.get_global_option(:scaling_y,:auto)
17
+
18
+ rx = parent.modelgroup.effective_range_x(range_options_x)
19
+ ry = parent.modelgroup.effective_range_y(range_options_y)
20
+
21
+ mx_arr = parent.modelgroup.x_markers
22
+
23
+ band_r=@bounds.clone
24
+ band_r.left = scale_x mx_arr[0],rx
25
+ band_r.right = scale_x mx_arr[1],rx
26
+
27
+ g.rectangle_r(band_r, {:class => 'x_mk'})
28
+
13
29
  end
14
30
  end
15
31
 
@@ -0,0 +1,87 @@
1
+ module GerbilCharts::Surfaces
2
+
3
+ # Matrix Surface
4
+ # Conversation Chart is drawn
5
+ #
6
+ class MatrixSurface < Surface
7
+
8
+ def initialize(opts={})
9
+ super(opts)
10
+ end
11
+
12
+ def int_render(g)
13
+ # any filters ?
14
+ if parent.get_global_option(:filter,false)
15
+ g.curr_win.add_options({:filter => "url(##{parent.get_global_option(:filter,false)})" })
16
+ end
17
+
18
+ # An Outer Rectangle
19
+ g.rectangle(@bounds.left, @bounds.top, @bounds.right, @bounds.bottom)
20
+
21
+ # Adding horizontal and vertical lines to the rectangle
22
+ # Vertical Lines
23
+ vline_spacing = @bounds.width / (parent.modelgroup.zendlen+1)
24
+ vline_next = 0
25
+ for i in 0...(parent.modelgroup.zendlen)
26
+ g.line(vline_spacing+vline_next,@bounds.top,vline_spacing+vline_next,@bounds.bottom,:class => "gridlinev")
27
+ vline_next += vline_spacing
28
+ end
29
+
30
+ # Horizontal Lines
31
+ hline_spacing = (@bounds.height)/ (parent.modelgroup.aendlen+1)
32
+ hline_next = @bounds.top
33
+ for i in 0...(parent.modelgroup.aendlen)
34
+ g.line(@bounds.left,hline_spacing+hline_next,@bounds.right,hline_spacing+hline_next,:class => "gridlineh")
35
+ hline_next += hline_spacing
36
+ end
37
+
38
+ # X - Axis
39
+ aend = hline_spacing/2 + @bounds.top
40
+ parent.modelgroup.aenduniq.each_with_index do |item,i|
41
+ g.textout(@bounds.left,@bounds.left+(hline_spacing)+aend,item, {:class => "elementlabel"})
42
+ aend += hline_spacing
43
+ end
44
+
45
+ # Y - Axis
46
+ zend = vline_spacing/2
47
+ parent.modelgroup.zenduniq.each_with_index do |item,i|
48
+ xpos = @bounds.left+vline_spacing+zend
49
+ ypos = @bounds.left+(hline_spacing/2)+@bounds.top
50
+ opts = {:class => "elementlabel",
51
+ "text-anchor" => "middle",
52
+ :transform => "rotate(-45 #{xpos} #{ypos})"}
53
+ g.textout(@bounds.left+vline_spacing+zend,@bounds.left+(hline_spacing/2)+@bounds.top,item,opts)
54
+ zend += vline_spacing
55
+ end
56
+
57
+ # Drawing circle based on the values
58
+ cy_value = 0
59
+ parent.modelgroup.hash.each_pair do |key,value|
60
+ cx_value = 0
61
+ value.each_with_index do |item,i|
62
+ if item == 0
63
+ opts = {:id => "item20"}
64
+ else
65
+ opts = {:id => "item#{i}"}
66
+ end
67
+ # Adding Tool Tips
68
+ string ="(" + key + "," + parent.modelgroup.zenduniq[i] +")"
69
+ if parent.get_global_option(:auto_tooltips,false)
70
+ opts.merge!(:onmouseover => "OpacityDown(evt)", :onmouseout => "OpacityUp(evt)")
71
+ opts.store(:gerbiltooltip1, string)
72
+ opts.store(:gerbiltooltip2, "Val = #{item}")
73
+ end
74
+ # Calculating Radius of the circle based on values
75
+ radius = (((item.to_f)/parent.modelgroup.sort[0].to_f).to_f * (hline_spacing/2)).to_f
76
+ radius = radius * parent.modelgroup.multiply_factor
77
+ g.addshape(GerbilCharts::SVGDC::SVGCircle.new(@bounds.left+vline_spacing+(vline_spacing/2)+cx_value,
78
+ @bounds.left+hline_spacing+(hline_spacing/2)+cy_value+@bounds.top,
79
+ radius),
80
+ opts)
81
+ cx_value += vline_spacing
82
+ end
83
+ cy_value += hline_spacing
84
+ end
85
+ end
86
+ end
87
+ end
@@ -5,116 +5,129 @@ class PieSurface < Surface
5
5
 
6
6
  MIN_INSIDE_LABEL_ANGLE = 8 # do not draw outer label for small angles
7
7
  MIN_OUTSIDE_LABEL_ANGLE = 3 # do not draw inner percentages (pie slice) for small angles
8
- OUTER_OFFSET_X = 10 # x - distance offset from pie boundary
9
- OUTER_OFFSET_Y = 10 # y - y offset from pie boundary
8
+ OUTER_OFFSET_X = 10 # x - distance offset from pie boundary
9
+ OUTER_OFFSET_Y = 10 # y - y offset from pie boundary
10
10
  LEFT_LABEL_OFFSET = 30 # labels on the left of the PIE offset by this (90-270 deg)
11
+ PERCENT_OFFSET_X = -4 # pull slice label this much (tweak)
11
12
 
12
- def initialize(opts={})
13
+ def initialize(opts={})
13
14
  super(opts)
14
15
  end
15
16
 
16
- def int_render(g)
17
+ def int_render(g)
17
18
  g.rectangle_r(@bounds, {:class => @class})
18
19
  end
19
20
 
20
21
 
21
- def int_render(g)
22
-
23
- # bail out of empty models quickly
24
- if parent.modelgroup.empty?
25
- g.textout(@bounds.left + @bounds.width/2, @bounds.height/2,
26
- parent.modelgroup.empty_caption,{"text-anchor" => "middle"})
27
- return
28
- end
29
-
30
- # any filters ?
31
- if parent.get_global_option(:filter,false)
32
- g.curr_win.add_options({:filter => "url(##{parent.get_global_option(:filter,false)})" })
33
- end
22
+ def int_render(g)
23
+
24
+ # bail out of empty models quickly
25
+ if parent.modelgroup.empty?
26
+ g.textout(@bounds.left + @bounds.width/2, @bounds.height/2,
27
+ parent.modelgroup.empty_caption,{"text-anchor" => "middle"})
28
+ return
29
+ end
30
+
31
+ # any filters ?
32
+ if parent.get_global_option(:filter,false)
33
+ g.curr_win.add_options({:filter => "url(##{parent.get_global_option(:filter,false)})" })
34
+ end
34
35
 
35
- # compute totals
36
- y_total = 0
37
- parent.modelgroup.each_model_with_index do | mod, i|
38
- y_total = y_total + mod.latest_val
39
- end
40
-
41
- radius = @bounds.height * 0.35
42
- radius_label = radius + 10
43
- cx = @bounds.width/2
44
- cy = @bounds.height/2
45
- current_pos_x = cx + radius
46
- current_pos_y = cy
47
-
48
- # draw each slice
49
- tot_angle =0
50
- parent.modelgroup.each_model_with_index do | mod, i|
51
-
52
- mod_angle = ((mod.latest_val*360).to_f)/(y_total.to_f)
53
- half_angle = tot_angle + mod_angle/2
54
- tot_angle = tot_angle + mod_angle
55
-
56
- new_pos_x = cx + (Math.cos((Math::PI/180)*tot_angle)*radius)
57
- new_pos_y = cy + (Math.sin((Math::PI/180)*tot_angle)*radius)
58
- label_pos_x = cx + (Math.cos((Math::PI/180)*half_angle)*radius_label)
59
- label_pos_y = cy + (Math.sin((Math::PI/180)*half_angle)*radius_label)
60
-
61
- percent_mod = ((mod.latest_val*360).to_i/y_total.to_i)
62
- percent = (percent_mod*100/360)
63
- percent_pos_x = cx + ((Math.cos((Math::PI/180)*half_angle)*radius_label)*0.6)
64
- percent_pos_y = cy + ((Math.sin((Math::PI/180)*half_angle)*radius_label)*0.6)
65
-
66
-
67
- # if tooltips enabled, user can position on pie slice
68
- opts = {:id => "item#{i}"}
69
- if parent.get_global_option(:auto_tooltips,false)
70
- opts.merge!(:onmouseover => "OpacityDown(evt)", :onmouseout => "OpacityUp(evt)")
71
- opts.store(:gerbiltooltip1, mod.name)
72
- opts.store(:gerbiltooltip2, "Val = #{mod.latest_formatted_val}")
73
- end
74
- opts.merge!(:href => mod.href) if mod.hasHref?
36
+ # compute totals
37
+ y_total = 0
38
+ parent.modelgroup.each_model_with_index do | mod, i|
39
+ y_total = y_total + mod.latest_val
40
+ end
75
41
 
76
- # draw a circle if there is only one data
77
- if (mod_angle >= 360)
78
- g.addshape(GerbilCharts::SVGDC::SVGCircle.new(cx,cy,radius),opts)
79
- end
42
+ radius = @bounds.height * 0.35
43
+ radius_label = radius + 10
44
+ cx = @bounds.width/2
45
+ cy = @bounds.height/2
46
+ current_pos_x = cx + radius
47
+ current_pos_y = cy
48
+
49
+ # draw each slice
50
+ tot_angle =0
51
+ last_label_pos_y=0
52
+ parent.modelgroup.each_model_with_index do | mod, i|
53
+ mod_angle = ((mod.latest_val*360).to_f)/(y_total.to_f)
54
+ half_angle = tot_angle + mod_angle/2
55
+ tot_angle = tot_angle + mod_angle
56
+
57
+ new_pos_x = cx + (Math.cos((Math::PI/180)*tot_angle)*radius)
58
+ new_pos_y = cy + (Math.sin((Math::PI/180)*tot_angle)*radius)
59
+ label_pos_x = cx + (Math.cos((Math::PI/180)*half_angle)*radius_label)
60
+ label_pos_y = cy + (Math.sin((Math::PI/180)*half_angle)*radius_label)
80
61
 
81
- # draw the slice
82
- g.addshape(GerbilCharts::SVGDC::SVGArc.new(cx,cy,radius,radius,
83
- current_pos_x,current_pos_y,
84
- new_pos_x,new_pos_y,mod_angle),
85
- opts)
86
-
87
- if(percent >= MIN_OUTSIDE_LABEL_ANGLE)
88
- if(tot_angle > 270)
89
- if(label_pos_x > cx ) && (label_pos_y > cy )
90
- g.textout( label_pos_x, label_pos_y, "#{mod.latest_formatted_val}", :class => 'elementlabel')
91
- g.textout(label_pos_x,label_pos_y+OUTER_OFFSET_Y, "#{mod.name}", :class => 'elementlabel' )
92
- else
93
- g.textout( label_pos_x+OUTER_OFFSET_X, label_pos_y, "#{mod.latest_formatted_val}", :class => 'elementlabel' )
94
- g.textout( label_pos_x+OUTER_OFFSET_X, label_pos_y+OUTER_OFFSET_Y, "#{mod.name}", :class => 'elementlabel' )
95
- end
96
- elsif(label_pos_x > cx ) && (label_pos_y > cy)
97
- g.textout( label_pos_x, label_pos_y, "#{mod.latest_formatted_val}", :class => 'elementlabel' )
98
- g.textout( label_pos_x, label_pos_y+OUTER_OFFSET_Y, "#{mod.name}", :class => 'elementlabel' )
99
- else
100
- g.textout( label_pos_x-LEFT_LABEL_OFFSET, label_pos_y, "#{mod.latest_formatted_val}", :class => 'elementlabel' )
101
- g.textout( label_pos_x-LEFT_LABEL_OFFSET, label_pos_y+OUTER_OFFSET_Y, "#{mod.name}", :class => 'elementlabel' )
102
- end
103
- end
104
-
105
-
106
- if(percent > MIN_INSIDE_LABEL_ANGLE)
107
- if(tot_angle > 270)
108
- g.textout(percent_pos_x,percent_pos_y+15, "#{percent}%", :class => 'elementvalue')
109
- else
110
- g.textout(percent_pos_x,percent_pos_y, "#{percent}%", :class => 'elementvalue')
111
- end
112
- end
113
-
114
- current_pos_x = new_pos_x
115
- current_pos_y = new_pos_y
62
+ percent_mod = ((mod.latest_val*360).to_i/y_total.to_i)
63
+ percent = (percent_mod*100/360)
64
+ percent_pos_x = cx + ((Math.cos((Math::PI/180)*half_angle)*radius_label)*0.6) + PERCENT_OFFSET_X
65
+ percent_pos_y = cy + ((Math.sin((Math::PI/180)*half_angle)*radius_label)*0.6)
66
+
67
+
68
+ # if tooltips enabled, user can position on pie slice
69
+ opts = {:id => "item#{i}"}
70
+ if parent.get_global_option(:auto_tooltips,false)
71
+ opts.merge!(:onmouseover => "OpacityDown(evt)", :onmouseout => "OpacityUp(evt)")
72
+ opts.store(:gerbiltooltip1, mod.name)
73
+ opts.store(:gerbiltooltip2, "#{mod.latest_formatted_val}")
74
+ end
75
+ opts.merge!(:href => mod.href) if mod.hasHref?
76
+
77
+ # draw a circle if there is only one data
78
+ if (mod_angle >= 360)
79
+ g.addshape(GerbilCharts::SVGDC::SVGCircle.new(cx,cy,radius),opts)
80
+ else
81
+ # draw the slice
82
+ g.addshape(GerbilCharts::SVGDC::SVGArc.new(cx,cy,radius,radius,
83
+ current_pos_x,current_pos_y,
84
+ new_pos_x,new_pos_y,mod_angle),
85
+ opts)
86
+ end
116
87
 
88
+ elementlabel_clsn = [ [30,'elementlabel_large'], [60, 'elementlabel_huge'] ].inject('elementlabel') do |mem,it|
89
+ percent > it[0] ? it[1]:mem
90
+ end
91
+
92
+ if(percent >= MIN_OUTSIDE_LABEL_ANGLE)
93
+ if(tot_angle > 270)
94
+ if(label_pos_x > cx ) && (label_pos_y > cy )
95
+ g.textout(label_pos_x,label_pos_y+OUTER_OFFSET_Y, "#{mod.name}", :class => elementlabel_clsn )
96
+ else
97
+ label_pos_y_off = (last_label_pos_y-label_pos_y) < 5 ? 5:0
98
+ g.textout( label_pos_x+OUTER_OFFSET_X, label_pos_y+OUTER_OFFSET_Y+label_pos_y_off, "#{mod.name}", :class => elementlabel_clsn )
99
+ end
100
+ elsif(label_pos_x > cx ) && (label_pos_y > cy)
101
+ g.textout( label_pos_x, label_pos_y+OUTER_OFFSET_Y, "#{mod.name}", :class => elementlabel_clsn )
102
+ else
103
+ g.textout( label_pos_x-LEFT_LABEL_OFFSET, label_pos_y+OUTER_OFFSET_Y, " #{mod.name}", :class => elementlabel_clsn )
104
+ end
117
105
  end
106
+
107
+
108
+ if(percent > MIN_INSIDE_LABEL_ANGLE)
109
+ elementvalue_clsn = [ [30,'elementvalue_large'], [60, 'elementvalue_huge'] ].inject('elementvalue') do |mem,it|
110
+ percent > it[0] ? it[1]:mem
111
+ end
112
+ if (label_pos_y-percent_pos_y).abs < 10
113
+ percent_pos_y -= 10 if percent_pos_y < label_pos_y
114
+ percent_pos_y += 10 if percent_pos_y > label_pos_y
115
+ end
116
+ if(tot_angle > 270)
117
+ g.textout(percent_pos_x,percent_pos_y+5, "#{percent}%", :class => elementvalue_clsn)
118
+ g.textout(percent_pos_x,percent_pos_y+15, "#{mod.latest_formatted_val}", :class => 'elementlabel' )
119
+ else
120
+ g.textout(percent_pos_x,percent_pos_y, "#{percent}%", :class => elementvalue_clsn)
121
+ g.textout(percent_pos_x,percent_pos_y+10, "#{mod.latest_formatted_val}", :class => 'elementlabel' )
122
+ end
123
+ end
124
+
125
+ current_pos_x = new_pos_x
126
+ current_pos_y = new_pos_y
127
+
128
+ last_label_pos_y = label_pos_y
118
129
  end
130
+ end
131
+
119
132
  end
120
133
  end