gerbilcharts 0.2.13 → 0.5.9

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.
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