dyi 0.0.2 → 1.0.0

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.
@@ -79,10 +79,6 @@ module DYI #:nodoc:
79
79
  end
80
80
  end
81
81
 
82
- def primitive_title_value(value, type=nil)
83
- value
84
- end
85
-
86
82
  class << self
87
83
  def read(path, options={})
88
84
  new.read(path, options)
@@ -0,0 +1,82 @@
1
+ # -*- encoding: UTF-8 -*-
2
+
3
+ # Copyright (c) 2009-2011 Sound-F Co., Ltd. All rights reserved.
4
+ #
5
+ # Author:: Mamoru Yuo
6
+ #
7
+ # This file is part of DYI.
8
+ #
9
+ # DYI is free software: you can redistribute it and/or modify it
10
+ # under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation, either version 3 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # DYI is distributed in the hope that it will be useful,
15
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License
20
+ # along with DYI. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ module DYI #:nodoc:
23
+ module Chart #:nodoc:
24
+
25
+ module Legend
26
+
27
+ private
28
+
29
+ def draw_legend(names, shapes=nil, records=nil, colors=nil) #:nodoc:
30
+ legend_canvas.translate(legend_point.x, legend_point.y)
31
+ if show_legend?
32
+ pen = Drawing::Pen.black_pen(:font => legend_font)
33
+ brush = Drawing::Brush.new
34
+ names.each_with_index do |name, index|
35
+ y = legend_font_size * (1.2 * (index + 1))
36
+ group = Shape::ShapeGroup.draw_on(legend_canvas)
37
+ case shapes && shapes[index]
38
+ when Shape::Base
39
+ shapes[index].draw_on(group)
40
+ when NilClass
41
+ brush.color = colors && colors[index] || chart_color(index)
42
+ brush.draw_rectangle(
43
+ group,
44
+ Coordinate.new(legend_font_size * 0.2, y - legend_font_size * 0.8),
45
+ legend_font_size * 0.8,
46
+ legend_font_size * 0.8)
47
+ end
48
+ pen.draw_text(
49
+ group,
50
+ Coordinate.new(legend_font_size * 0.2 + legend_font_size, y),
51
+ name)
52
+ end
53
+ end
54
+ end
55
+
56
+ def legend_font_size #:nodoc:
57
+ legend_font ? legend_font.draw_size : Font::DEFAULT_SIZE
58
+ end
59
+
60
+ def default_legend_point #:nodoc:
61
+ Coordinate.new(0,0)
62
+ end
63
+
64
+ def default_legend_format #:nodoc:
65
+ "{name}"
66
+ end
67
+
68
+ class << self
69
+
70
+ private
71
+
72
+ def included(klass) #:nodoc:
73
+ klass.__send__(:opt_accessor, :show_legend, :type => :boolean, :default => true)
74
+ klass.__send__(:opt_accessor, :legend_font, :type => :font)
75
+ klass.__send__(:opt_accessor, :legend_format, :type => :string, :default_method => :default_legend_format)
76
+ klass.__send__(:opt_accessor, :legend_point, :type => :point, :default_method => :default_legend_point)
77
+ klass.__send__(:opt_accessor, :legend_css_class, :type => :string)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -50,7 +50,7 @@ module DYI #:nodoc:
50
50
  opt_accessor :max_x_label_count, {:type => :integer, :default_proc => proc{|c| c.chart_width.div(Length.new(96))}}
51
51
  opt_accessor :show_x_labels, {:type => :boolean, :default => true}
52
52
  opt_accessor :legend_texts, {:type => :array, :item_type => :string}
53
- opt_accessor :data_columns, {:type => :array, :item_type => :integer}
53
+ # opt_accessor :data_columns, {:type => :array, :item_type => :integer}
54
54
  opt_accessor :use_effect, {:type => :boolean, :default => true}
55
55
  opt_accessor :bar_seriese_interval, {:type => :float, :default => 0.3}
56
56
  opt_accessor :color_columns, {:type => :array, :item_type => :integer}
@@ -130,7 +130,7 @@ module DYI #:nodoc:
130
130
 
131
131
  def bar_chart_brush(color, bar_width=nil)
132
132
  if represent_3d?
133
- bar_width ||= chart_width * bar_width_ratio / data.column_values(data_columns[0]).size
133
+ bar_width ||= chart_width * bar_width_ratio / data.records_size
134
134
  Drawing::CylinderBrush.new(:color => color, :ry => bar_width * (back_translate_value[:dy] * bar_width_ratio).quo(back_translate_value[:dx] * 2))
135
135
  else
136
136
  Drawing::Brush.new(:color => color)
@@ -153,9 +153,9 @@ module DYI #:nodoc:
153
153
  main_series_data = []
154
154
  sub_series_data = []
155
155
  @bar_series = []
156
- data_columns.size.times do |i|
157
- main_series_data.push(*data.column_values(data_columns[i])) unless use_y_second_axis?(i)
158
- sub_series_data.push(*data.column_values(data_columns[i])) if use_y_second_axis?(i)
156
+ data.values_size.times do |i|
157
+ main_series_data.push(*data.series(i)) unless use_y_second_axis?(i)
158
+ sub_series_data.push(*data.series(i)) if use_y_second_axis?(i)
159
159
  @bar_series.push(i) if chart_type(i) == :bar
160
160
  end
161
161
  settings =
@@ -172,15 +172,15 @@ module DYI #:nodoc:
172
172
  second_axis_settings[:min],
173
173
  second_axis_settings[:max]) if use_y_second_axis?
174
174
 
175
- data_columns.size.times do |i|
176
- draw_chart(data_columns[i], chart_type(i), chart_color(i), use_y_second_axis?(i) ? sub_settings : settings) if chart_type(i) == :stackedbar
175
+ data.values_size.times do |i|
176
+ draw_chart(i, chart_type(i), chart_color(i), use_y_second_axis?(i) ? sub_settings : settings) if chart_type(i) == :stackedbar
177
177
  end
178
- (data_columns.size-1).downto(0) do |i|
179
- draw_chart(data_columns[i], chart_type(i), chart_color(i), use_y_second_axis?(i) ? sub_settings : settings) if chart_type(i) != :stackedbar
178
+ (data.values_size - 1).downto(0) do |i|
179
+ draw_chart(i, chart_type(i), chart_color(i), use_y_second_axis?(i) ? sub_settings : settings) if chart_type(i) != :stackedbar
180
180
  end
181
181
 
182
182
  draw_axis(settings, sub_settings)
183
- texts = legend_texts || data_columns.map{|i| data.column_title(i)}
183
+ texts = legend_texts # || data_columns.map{|i| data.column_title(i)}
184
184
  draw_legend(texts, legend_shapes)
185
185
  end
186
186
 
@@ -314,28 +314,28 @@ module DYI #:nodoc:
314
314
  end
315
315
 
316
316
  def needs_x_scale?(i)
317
- return true if data.row_count < max_x_label_count
318
- i % ((data.row_count - 1) / [max_x_label_count - 1, 1].max) == 0
317
+ return true if data.records_size < max_x_label_count
318
+ i % ((data.records_size - 1) / [max_x_label_count - 1, 1].max) == 0
319
319
  end
320
320
 
321
321
  def draw_x_axis(main_pen, sub_pen, text_pen, text_margin) #:nodoc:
322
322
  main_pen.draw_line(represent_3d? ? @axis_back_canvas : @axis_front_canvas, [margin_left, height - margin_bottom], [width - margin_right, height - margin_bottom])
323
323
 
324
- data.row_count.times do |i|
324
+ data.records_size.times do |i|
325
325
  next unless needs_x_scale?(i)
326
- text_x = order_position_on_chart(margin_left, chart_width, data.row_count, i, x_axis_type)
327
- scale_x = x_axis_type == :range ? order_position_on_chart(margin_left, chart_width, data.row_count + 1, i) : text_x
326
+ text_x = order_position_on_chart(margin_left, chart_width, data.records_size, i, x_axis_type)
327
+ scale_x = x_axis_type == :range ? order_position_on_chart(margin_left, chart_width, data.records_size + 1, i) : text_x
328
328
  text_pen.draw_text(
329
329
  @axis_front_canvas,
330
330
  [text_x, height - margin_bottom + text_margin],
331
- format_x_label(data.row_title(i)),
331
+ format_x_label(data.name_values[i]),
332
332
  :text_anchor => 'middle', :alignment_baseline => 'top') if show_x_labels?
333
333
 
334
334
  sub_pen.draw_line_on_direction(
335
335
  @axis_front_canvas,
336
336
  [scale_x, height - margin_bottom],
337
337
  0,
338
- -(axis_font ? axis_font.draw_size : Font::DEFAULT_SIZE) * 0.5) if i > 0 && i < data.row_count - (x_axis_type == :range ? 0 : 1)
338
+ -(axis_font ? axis_font.draw_size : Font::DEFAULT_SIZE) * 0.5) if i > 0 && i < data.records_size - (x_axis_type == :range ? 0 : 1)
339
339
  end
340
340
  end
341
341
 
@@ -349,7 +349,7 @@ module DYI #:nodoc:
349
349
  end
350
350
 
351
351
  def draw_line(id, color, settings) #:nodoc:
352
- values = data.column_values(id)
352
+ values = data.series(id)
353
353
  return if values.compact.size == 0
354
354
  first_index = values.each_with_index {|value, i| break i if value}
355
355
  pen_options = {:color => color, :width => line_width}
@@ -369,7 +369,7 @@ module DYI #:nodoc:
369
369
  end
370
370
 
371
371
  def draw_area(id, color, settings) #:nodoc:
372
- values = data.column_values(id)
372
+ values = data.series(id)
373
373
  return if values.compact.size == 0
374
374
  first_index = values.each_with_index {|value, i| break i if value}
375
375
  brush = area_chart_brush(color)
@@ -390,7 +390,7 @@ module DYI #:nodoc:
390
390
 
391
391
  def draw_bar(id, color, settings) #:nodoc:
392
392
  bar_group = Shape::ShapeGroup.new(@chart_options).draw_on(@chart_front_canvas)
393
- values = data.column_values(id)
393
+ values = data.series(id)
394
394
  return if values.compact.size == 0
395
395
  bar_width = chart_width * bar_width_ratio / values.size / (@bar_series.size + (@bar_series.size - 1) * bar_seriese_interval)
396
396
 
@@ -400,7 +400,7 @@ module DYI #:nodoc:
400
400
  next if value.nil?
401
401
  x = order_position_on_chart(margin_left, chart_width, values.size, i, x_axis_type, bar_width_ratio) + bar_width * (1 + bar_seriese_interval) * @bar_series.index(id)
402
402
  y = value_position_on_chart(margin_top, settings, value, true)
403
- brush = bar_chart_brush(data[i, color_columns[id]], bar_width) if color_columns && color_columns[id]
403
+ brush = bar_chart_brush(data.has_field?(:color) ? data.records[i].color : color, bar_width) if data.has_field?(:color)
404
404
  brush.draw_rectangle(bar_group, [x, y], bar_width, height - margin_bottom - y)
405
405
  end
406
406
  bar_group.translate(back_translate_value[:dx] / 2, back_translate_value[:dy] / 2) if represent_3d?
@@ -409,7 +409,7 @@ module DYI #:nodoc:
409
409
  def draw_stackedbar(id, color, settings) #:nodoc:
410
410
  bar_group = Shape::ShapeGroup.new(@chart_options).draw_on(@chart_front_canvas)
411
411
 
412
- values = data.column_values(id)
412
+ values = data.series(id)
413
413
  return if values.compact.size == 0
414
414
  bar_width = chart_width * bar_width_ratio / values.size
415
415
 
@@ -429,9 +429,17 @@ module DYI #:nodoc:
429
429
  bar_group.translate(back_translate_value[:dx] / 2, back_translate_value[:dy] / 2) if represent_3d?
430
430
  end
431
431
 
432
+ # @since 1.0.0
433
+ def chart_color(index) #:nodoc:
434
+ if chart_colors
435
+ color = chart_colors[index]
436
+ end
437
+ color || DEFAULT_CHART_COLOR[index % DEFAULT_CHART_COLOR.size]
438
+ end
439
+
432
440
  def legend_shapes #:nodoc:
433
441
  result = []
434
- data_columns.each_with_index do |id, index|
442
+ (0...data.values_size).each_with_index do |id, index|
435
443
  result <<
436
444
  case chart_type(index)
437
445
  when :line, nil
@@ -24,6 +24,8 @@ module DYI #:nodoc:
24
24
 
25
25
  class PieChart < Base
26
26
  include Legend
27
+ include DYI::Script::EcmaScript::DomLevel2
28
+
27
29
  attr_reader :chart_canvas, :data_label_canvas, :legend_canvas
28
30
 
29
31
  opt_accessor :center_point, {:type => :point, :default_method => :default_center_point}
@@ -35,88 +37,153 @@ module DYI #:nodoc:
35
37
  opt_accessor :chart_stroke_color, {:type => :color}
36
38
  opt_accessor :chart_stroke_width, {:type => :float, :default => 1}
37
39
  opt_accessor :moved_elements, {:type => :array, :item_type => :float}
40
+ opt_accessor :pie_css_class, :type => :string
38
41
  opt_accessor :show_data_label, {:type => :boolean, :default => true}
42
+ opt_accessor :data_label_css_class, :type => :string
39
43
  opt_accessor :data_label_position, {:type => :float, :default => 0.8}
40
44
  opt_accessor :data_label_font, {:type => :font}
41
- opt_accessor :data_label_format, {:type => :string, :default => "{name}\n{value}"}
45
+ opt_accessor :data_label_format, {:type => :string, :default => "{?name}"}
42
46
  opt_accessor :hide_data_label_ratio, {:type => :float, :default => 0.00}
47
+ opt_accessor :show_baloon, :type => :boolean, :default => true
48
+ opt_accessor :baloon_font, :type => :font
49
+ opt_accessor :baloon_position, {:type => :float, :default => 0.8}
50
+ opt_accessor :baloon_format, :type => :string, :default => "{?name}\n{?value}"
51
+ opt_accessor :baloon_padding, :type => :hash, :default => {}, :keys => [:vertical, :horizontal], :item_type => :length
52
+ opt_accessor :baloon_round, :type => :length, :default => 6
53
+ opt_accessor :baloon_background_color, :type => :color
54
+ opt_accessor :baloon_background_colors, :type => :array, :item_type => :color
55
+ opt_accessor :baloon_border_color, :type => :color
56
+ opt_accessor :baloon_border_colors, :type => :array, :item_type => :color
57
+ opt_accessor :baloon_border_width, :type => :length, :default => 2
58
+ opt_accessor :baloon_css_class, :type => :string
59
+ opt_accessor :animation_duration, :type => :float, :default => 0.5
43
60
 
44
61
  def back_translate_value
45
62
  {:dy => (Length.new_or_nil(_3d_settings[:dy]) || chart_radius_y.quo(2))}
46
63
  end
47
64
 
65
+ # @since 1.0.0
66
+ def get_baloon_background_color(index)
67
+ (baloon_background_colors && baloon_background_colors[index]) ||
68
+ baloon_background_color ||
69
+ chart_color(index).merge('white', 0.7)
70
+ end
71
+
72
+ # @since 1.0.0
73
+ def get_baloon_border_color(index)
74
+ (baloon_border_colors && baloon_border_colors[index]) ||
75
+ baloon_border_color ||
76
+ chart_color(index).merge('black', 0.3)
77
+ end
78
+
48
79
  private
49
80
 
50
81
  def default_center_point #:nodoc:
51
- Coordinate.new(coordinate = ([width, height].min).quo(2), coordinate)
82
+ margin = [width - chart_radius_x * 2, height - chart_radius_y * 2].min.quo(2)
83
+ Coordinate.new(margin + chart_radius_x, margin + chart_radius_y)
52
84
  end
53
85
 
54
86
  def default_chart_radius_x #:nodoc:
55
- [[width, height].min / 2 - Length.new(32), [width, height].min * 0.4].max
87
+ [width, height].min * 0.4
56
88
  end
57
89
 
58
90
  def default_chart_radius_y #:nodoc:
59
91
  represent_3d? ? chart_radius_x.quo(2) : chart_radius_x
60
92
  end
61
93
 
62
- def default_csv_format #:nodoc:
63
- [:$name, 0, :$color]
64
- end
65
-
66
94
  def default_legend_point #:nodoc:
67
- Coordinate.new(width < height ? [width * 0.1, width] : [height, height * 0.1])
95
+ if width - chart_radius_x * 2 < height - chart_radius_y * 2
96
+ Coordinate.new(width * 0.1, chart_radius_y * 2 + (width - chart_radius_x * 2) * 0.8)
97
+ else
98
+ Coordinate.new(chart_radius_x * 2 + (height - chart_radius_y * 2) * 0.8, height * 0.1 + Length.new(10))
99
+ end
68
100
  end
69
101
 
70
102
  def default_legend_format #:nodoc:
71
- "{name}\t{percent}"
103
+ "{?name}\t{?percent}"
72
104
  end
73
105
 
74
106
  def create_vector_image #:nodoc:
107
+ super
75
108
  if represent_3d?
76
109
  brush = Drawing::ColumnBrush.new(back_translate_value.merge(chart_stroke_color ? {:stroke_width => chart_stroke_width, :stroke => chart_stroke_color} : {}))
77
110
  else
78
111
  brush = Drawing::Brush.new(chart_stroke_color ? {:stroke_width => chart_stroke_width, :stroke => chart_stroke_color, :stroke_miterlimit => chart_stroke_width} : {})
79
112
  end
113
+ attrs = if pie_css_class && !pie_css_class.empty?
114
+ {:css_class => pie_css_class}
115
+ else
116
+ {}
117
+ end
80
118
  @chart_canvas = Shape::ShapeGroup.draw_on(@canvas)
81
- @data_label_canvas = Shape::ShapeGroup.draw_on(@canvas)
82
- @legend_canvas = Shape::ShapeGroup.draw_on(@canvas)
83
- total_value = data.column_values(0).inject(0.0) {|sum, value| sum + (value || 0)}
119
+ attrs = if data_label_css_class && !data_label_css_class.empty?
120
+ {:css_class => data_label_css_class}
121
+ else
122
+ {}
123
+ end
124
+ @data_label_canvas = Shape::ShapeGroup.draw_on(@canvas, attrs)
125
+ attrs = if legend_css_class && !legend_css_class.empty?
126
+ {:css_class => legend_css_class}
127
+ else
128
+ {}
129
+ end
130
+ @legend_canvas = Shape::ShapeGroup.draw_on(@canvas, attrs)
131
+ @legends = []
132
+ @sectors = []
133
+ draw_legend(data.records, nil)
134
+ total_value = data.inject(0.0) {|sum, record| sum + (record.value || 0)}
84
135
  accumulation = 0.0
85
136
  accumulations = []
86
137
  stop_index = -1
87
- data.column_values(0).each_with_index do |value, i|
138
+ data.each_with_index do |record, i|
88
139
  accumulations.push(accumulation)
140
+ value = record.value
89
141
  if value && total_value > (accumulation + value) * 2 && value != 0.0
90
- # brush.color = data[:$color] && data[:$color][i] || chart_color(i)
91
142
  brush.color = chart_color(i)
92
- name = data.row_title(i)
93
- draw_chart(brush, name, value, accumulation, total_value, i)
143
+ draw_chart(brush, record, accumulation, total_value, i)
94
144
  stop_index = i
95
145
  end
96
146
  accumulation += value if value
97
147
  end
98
- (data.column_values(0).size - 1).downto(stop_index + 1) do |i|
99
- value = data.column_values(0)[i]
148
+ (data.records_size - 1).downto(stop_index + 1) do |i|
149
+ value = (record = data.records[i]).value
100
150
  if value && value != 0.0
101
- # brush.color = data[:$color] && data[:$color][i] || chart_color(i)
102
151
  brush.color = chart_color(i)
103
- name = data.row_title(i)
104
- draw_chart(brush, name, value, accumulations[i], total_value, i)
152
+ draw_chart(brush, record, accumulations[i], total_value, i)
153
+ end
154
+ end
155
+ @sectors.each_with_index do |sector, i|
156
+ @legends.each_with_index do |legend, j|
157
+ if i != j
158
+ sector.parent.add_painting_animation(:to => {:opacity => 0.35},
159
+ :duration => animation_duration,
160
+ :fill => 'freeze',
161
+ :begin_event => Event.mouseover(legend),
162
+ :end_event => Event.mouseout(legend))
163
+ sector.parent.add_painting_animation(:to => {:opacity => 1},
164
+ :fill => 'freeze',
165
+ :begin_event => Event.mouseout(legend))
166
+ end
105
167
  end
106
168
  end
107
- # draw_legend(data.row_titles, nil, nil, data[:$color])
108
- draw_legend(data.row_titles, nil, nil, nil)
109
169
  end
110
170
 
111
- def draw_chart(brush, name, value, accumulation, total_value, index) #:nodoc:
171
+ def draw_chart(brush, record, accumulation, total_value, index) #:nodoc:
112
172
  canvas = Shape::ShapeGroup.draw_on(@chart_canvas)
113
- brush.draw_sector(
173
+ attrs = {}
174
+ if data.has_field?(:css_class) && (css_class = record.css_class)
175
+ attrs[:css_class] = record.css_class
176
+ end
177
+ value = record.value
178
+ pie_sector = brush.draw_sector(
114
179
  canvas,
115
180
  center_point,
116
181
  chart_radius_x,
117
182
  chart_radius_y,
118
183
  accumulation * 360.0 / total_value - 90,
119
- value * 360.0 / total_value)
184
+ value * 360.0 / total_value,
185
+ attrs)
186
+ @sectors[index] = pie_sector
120
187
 
121
188
  if moved_elements && (dr = moved_elements[index])
122
189
  canvas.translate(
@@ -126,15 +193,155 @@ module DYI #:nodoc:
126
193
 
127
194
  ratio = value.to_f.quo(total_value)
128
195
  if show_data_label?
129
- legend_point = Coordinate.new(
196
+ label_point = Coordinate.new(
130
197
  chart_radius_x * (data_label_position + (dr || 0)) * Math.cos(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI),
131
198
  chart_radius_y * (data_label_position + (dr || 0)) * Math.sin(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI))
132
199
  Drawing::Pen.black_pen(:font => data_label_font).draw_text(
133
200
  @data_label_canvas,
134
- center_point + legend_point,
135
- data_label_format.gsub(/\{name\}/, name).gsub(/\{value\}/, value.to_s).gsub(/\{percent\}/, '%.1f%' % (ratio * 100.0).to_s),
136
- :text_anchor => 'middle')
201
+ center_point + label_point,
202
+ format_string(data_label_format, record, total_value),
203
+ attrs.merge(:text_anchor => 'middle'))
137
204
  end if hide_data_label_ratio < ratio
205
+ draw_baloon(brush, record, accumulation, total_value, index, ratio, pie_sector)
206
+ end
207
+
208
+ # @since 1.0.0
209
+ def draw_baloon(brush, record, accumulation, total_value, index, ratio, pie_sector)
210
+ value = record.value
211
+ if show_baloon?
212
+ dr = moved_elements && moved_elements[index]
213
+ baloon_point = Coordinate.new(
214
+ chart_radius_x * (baloon_position + (dr || 0)) *
215
+ Math.cos(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI),
216
+ chart_radius_y * (baloon_position + (dr || 0)) *
217
+ Math.sin(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI))
218
+ baloon_options = {:text_anchor => 'middle', :show_border => true}
219
+ if data.has_field?(:css_class) && (css_class = record.css_class)
220
+ baloon_options[:css_class] = record.css_class
221
+ end
222
+ baloon_options[:vertical_padding] = baloon_padding[:vertical_padding] || 2
223
+ baloon_options[:horizontal_padding] = baloon_padding[:horizontal_padding] || 5
224
+ baloon_options[:background_color] = get_baloon_background_color(index)
225
+ baloon_options[:border_color] = get_baloon_border_color(index)
226
+ baloon_options[:border_width] = baloon_border_width
227
+ baloon_options[:border_rx] = baloon_round
228
+ if baloon_css_class && baloon_css_class.empty?
229
+ @data_label_canvas.add_css_class(baloon_css_class)
230
+ end
231
+ text = Drawing::Pen.black_pen(:font => baloon_font, :opacity => 0.0).draw_text(
232
+ @data_label_canvas,
233
+ center_point + baloon_point,
234
+ format_string(data_label_format, record, total_value),
235
+ baloon_options)
236
+ text.add_painting_animation(:to => {:opacity => 1},
237
+ :duration => animation_duration,
238
+ :fill => 'freeze',
239
+ :begin_event => Event.mouseover(pie_sector))
240
+ text.add_painting_animation(:to => {:opacity => 0},
241
+ :duration => animation_duration,
242
+ :fill => 'freeze',
243
+ :begin_event => Event.mouseout(pie_sector))
244
+ if @legends
245
+ text.add_painting_animation(:to => {:opacity => 1},
246
+ :duration => animation_duration,
247
+ :fill => 'freeze',
248
+ :begin_event => Event.mouseover(@legends[index]))
249
+ text.add_painting_animation(:to => {:opacity => 0},
250
+ :duration => animation_duration,
251
+ :fill => 'freeze',
252
+ :begin_event => Event.mouseout(@legends[index]))
253
+ end
254
+ end
255
+ end
256
+
257
+ # @since 1.0.0
258
+ def draw_legend(records, shapes=nil)
259
+ legend_canvas.translate(legend_point.x, legend_point.y)
260
+ if show_legend?
261
+ pen = Drawing::Pen.black_pen(:font => legend_font)
262
+ brush = Drawing::Brush.new
263
+ toatal = records.inject(0.0){|sum, record| sum + record.value}
264
+ formats = legend_format.split("\t")
265
+ legend_labels = []
266
+ records.each_with_index do |record, i|
267
+ legend_labels << formats.map do |format|
268
+ format_string(format, record, toatal)
269
+ end
270
+ end
271
+ require 'pp'
272
+ max_lengths = legend_labels.inject(Array.new(formats.size, 0)) do |maxs, labels|
273
+ (0...formats.size).each do |i|
274
+ maxs[i] = labels[i].bytesize if maxs[i] < labels[i].bytesize
275
+ end
276
+ maxs
277
+ end
278
+ canvas.add_initialize_script(form_legend_labels(legend_canvas))
279
+ records.each_with_index do |record, i|
280
+ y = legend_font_size * (1.2 * (i + 1))
281
+ attrs = {}
282
+ if data.has_field?(:css_class) && (css_class = record.css_class)
283
+ attrs[:css_class] = record.css_class
284
+ end
285
+ group = Shape::ShapeGroup.draw_on(legend_canvas, attrs)
286
+ @legends << group
287
+ case shapes && shapes[i]
288
+ when Shape::Base
289
+ shapes[i].draw_on(group)
290
+ when NilClass
291
+ brush.color = chart_color(i)
292
+ brush.draw_rectangle(
293
+ group,
294
+ Coordinate.new(legend_font_size * 0.2, y - legend_font_size * 0.8),
295
+ legend_font_size * 0.8,
296
+ legend_font_size * 0.8)
297
+ end
298
+ x = legend_font_size * 0.2 + legend_font_size
299
+ legend_labels[i].each_with_index do |label, j|
300
+ formats[j] =~ /\A\{!(\w)\}/
301
+ case $1
302
+ when 's'
303
+ attrs = {:text_anchor => 'start'}
304
+ pen.draw_text(group, Coordinate.new(x, y), label, attrs)
305
+ x += legend_font_size * max_lengths[j] * 0.5
306
+ when 'm'
307
+ attrs = {:text_anchor => 'middle'}
308
+ x += legend_font_size * max_lengths[j] * 0.25
309
+ pen.draw_text(group, Coordinate.new(x, y), label, attrs)
310
+ x += legend_font_size * max_lengths[j] * 0.25
311
+ when 'e'
312
+ attrs = {:text_anchor => 'end'}
313
+ x += legend_font_size * max_lengths[j] * 0.5
314
+ pen.draw_text(group, Coordinate.new(x, y), label, attrs)
315
+ else
316
+ attrs = {}
317
+ pen.draw_text(group, Coordinate.new(x, y), label, attrs)
318
+ x += legend_font_size * max_lengths[j] * 0.5
319
+ end
320
+ end
321
+ end
322
+ end
323
+ end
324
+
325
+ def format_string(format, record, total_value)
326
+ format = format.gsub(/\A\{!(\w)\}/, '')
327
+ format.gsub(/\{\?((?![0-9])\w+)(:[^}]*)?\}/){|m|
328
+ fmt = $2 ? $2[1..-1] : nil
329
+ if $1 == 'percent'
330
+ value = record.value.quo(total_value)
331
+ fmt ||= '0.0%'
332
+ else
333
+ value = record.__send__($1)
334
+ end
335
+ if fmt
336
+ case value
337
+ when Numeric then value.strfnum(fmt)
338
+ when DateTime, Time then value.strftime(fmt)
339
+ else fmt % value
340
+ end
341
+ else
342
+ value
343
+ end
344
+ }
138
345
  end
139
346
  end
140
347
  end