dyi 0.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.
Files changed (48) hide show
  1. data/COPYING +674 -0
  2. data/README +28 -0
  3. data/examples/class_diagram.rb +151 -0
  4. data/examples/data/03311056.xlsx +0 -0
  5. data/examples/data/currency.xlsx +0 -0
  6. data/examples/data/money.csv +12 -0
  7. data/examples/line_and_bar.rb +26 -0
  8. data/examples/line_chart.rb +30 -0
  9. data/examples/logo.rb +68 -0
  10. data/examples/pie_chart.rb +19 -0
  11. data/examples/simple_shapes.rb +15 -0
  12. data/lib/dyi.rb +49 -0
  13. data/lib/dyi/chart.rb +34 -0
  14. data/lib/dyi/chart/array_reader.rb +136 -0
  15. data/lib/dyi/chart/base.rb +580 -0
  16. data/lib/dyi/chart/csv_reader.rb +93 -0
  17. data/lib/dyi/chart/excel_reader.rb +100 -0
  18. data/lib/dyi/chart/line_chart.rb +468 -0
  19. data/lib/dyi/chart/pie_chart.rb +141 -0
  20. data/lib/dyi/chart/table.rb +201 -0
  21. data/lib/dyi/color.rb +218 -0
  22. data/lib/dyi/coordinate.rb +224 -0
  23. data/lib/dyi/drawing.rb +32 -0
  24. data/lib/dyi/drawing/canvas.rb +100 -0
  25. data/lib/dyi/drawing/clipping.rb +61 -0
  26. data/lib/dyi/drawing/color_effect.rb +118 -0
  27. data/lib/dyi/drawing/filter.rb +74 -0
  28. data/lib/dyi/drawing/pen.rb +231 -0
  29. data/lib/dyi/drawing/pen_3d.rb +270 -0
  30. data/lib/dyi/font.rb +132 -0
  31. data/lib/dyi/formatter.rb +36 -0
  32. data/lib/dyi/formatter/base.rb +245 -0
  33. data/lib/dyi/formatter/emf_formatter.rb +253 -0
  34. data/lib/dyi/formatter/eps_formatter.rb +397 -0
  35. data/lib/dyi/formatter/svg_formatter.rb +260 -0
  36. data/lib/dyi/formatter/svg_reader.rb +113 -0
  37. data/lib/dyi/formatter/xaml_formatter.rb +317 -0
  38. data/lib/dyi/length.rb +399 -0
  39. data/lib/dyi/matrix.rb +122 -0
  40. data/lib/dyi/painting.rb +177 -0
  41. data/lib/dyi/shape.rb +1332 -0
  42. data/lib/dyi/svg_element.rb +149 -0
  43. data/lib/dyi/type.rb +104 -0
  44. data/lib/ironruby.rb +326 -0
  45. data/lib/util.rb +231 -0
  46. data/test/path_command_test.rb +217 -0
  47. data/test/test_length.rb +91 -0
  48. metadata +114 -0
@@ -0,0 +1,93 @@
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
+ require 'csv'
23
+ require 'date'
24
+ require 'bigdecimal'
25
+ require 'nkf'
26
+
27
+ module DYI #:nodoc:
28
+ module Chart #:nodoc:
29
+
30
+ class CsvReader < ArrayReader
31
+ def read(path, options={})
32
+ options = options.dup
33
+ @date_format = options.delete(:date_format)
34
+ @datetime_format = options.delete(:datetime_format)
35
+ nkf_options =
36
+ case (options[:encode] || :utf8).to_sym
37
+ when :utf8 then nil
38
+ when :sjis then '-w -S -m0 -x --cp932'
39
+ when :euc then '-w -E -m0 -x --cp932'
40
+ when :jis then '-w -J -m0 -x'
41
+ when :utf16 then '-w -W16 -m0 -x'
42
+ else raise ArgumentError,"Unknown encode: `#{@encode}'"
43
+ end
44
+ parsed_array =
45
+ if RUBY_VERSION >= '1.9'
46
+ CSV.parse(nkf_options ? NKF.nkf(nkf_options, IO.read(path)) : IO.read(path), :col_sep => options[:col_sep] || ',', :row_sep => options[:row_sep] || :auto)
47
+ else
48
+ CSV.parse(nkf_options ? NKF.nkf(nkf_options, IO.read(path)) : IO.read(path), options[:col_sep], options[:row_sep])
49
+ end
50
+ super(parsed_array, options)
51
+ end
52
+
53
+ private
54
+
55
+ def primitive_value(value, type)
56
+ if type.is_a?(Symbol) || type.is_a?(String)
57
+ case type.to_sym
58
+ when :string
59
+ value || ''
60
+ when :number, :decimal
61
+ value ? BigDecimal.new(value) : nil
62
+ when :float
63
+ value ? value.to_f : nil
64
+ when :integer
65
+ value ? value.to_i : nil
66
+ when :date
67
+ return nil if value.nil?
68
+ @date_format ? Date.strptime(value, @date_format) : Date.parse(value)
69
+ when :datetime
70
+ return nil if value.nil?
71
+ @datetime_format ? DateTime.strptime(value, @datetime_format) : DateTime.parse(value)
72
+ when :boolean
73
+ value ? true : value
74
+ else
75
+ value ? value.to_f : nil
76
+ end
77
+ else
78
+ value ? value.to_f : nil
79
+ end
80
+ end
81
+
82
+ def primitive_title_value(value, type=nil)
83
+ value
84
+ end
85
+
86
+ class << self
87
+ def read(path, options={})
88
+ new.read(path, options)
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,100 @@
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
+ begin
23
+ require 'win32ole' # for Windows
24
+ rescue LoadError
25
+ # do notiong
26
+ end
27
+
28
+ require 'date'
29
+ require 'nkf'
30
+
31
+ module DYI #:nodoc:
32
+ module Chart #:nodoc:
33
+
34
+ class ExcelReader < ArrayReader
35
+ OFFSET = DateTime.now.offset
36
+
37
+ def read(path, options={})
38
+ if defined? WIN32OLE
39
+ # for Windows
40
+ path = WIN32OLE.new('Scripting.FileSystemObject').getAbsolutePathName(path)
41
+ excel = WIN32OLE.new('Excel.Application')
42
+ book = excel.workbooks.open(path)
43
+ sheet = book.worksheets.item(options[:sheet] || 1)
44
+ range = sheet.usedRange
45
+ sheet_values = sheet.range(sheet.cells(1,1), sheet.cells(range.end(4).row, range.end(2).column)).value
46
+ else
47
+ # except Windows
48
+ raise NotImplementedError, 'win32ole is not installed'
49
+ end
50
+
51
+ begin
52
+ super(sheet_values, options)
53
+ ensure
54
+ if defined? WIN32OLE
55
+ book.close(false)
56
+ excel.quit
57
+ excel = sheet = nil
58
+ end
59
+ book = sheet_values = nil
60
+ GC.start
61
+ end
62
+ self
63
+ end
64
+
65
+ private
66
+
67
+ def primitive_value(value, type=nil)
68
+ if defined? WIN32OLE
69
+ # for Windows
70
+ case value
71
+ when String
72
+ if value =~ %r(^(\d{4})/(\d{2})/(\d{2}) (\d{2}):(\d{2}):(\d{2})$)
73
+ DateTime.new($1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, OFFSET)
74
+ elsif value.size == 0
75
+ nil
76
+ else
77
+ NKF.nkf('-w -S -m0 -x --cp932', value)
78
+ end
79
+ when Numeric, nil, true, false
80
+ value
81
+ when System::DateTime
82
+ # for IronRuby
83
+ DateTime.new(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second, OFFSET)
84
+ else
85
+ value
86
+ end rescue value
87
+ else
88
+ # except Windows
89
+ raise NotImplementedError, 'win32ole is not installed'
90
+ end
91
+ end
92
+
93
+ class << self
94
+ def read(path, options={})
95
+ new.read(path, options)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,468 @@
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
+ class LineChart < Base
26
+ include AxisUtil
27
+ include Legend
28
+ CHART_TYPES = [:line, :area, :bar, :stackedbar]
29
+ attr_reader :axis_back_canvas, :chart_back_canvas, :scale_canvas, :chart_front_canvas, :axis_front_canvas, :legend_canvas
30
+
31
+ opt_accessor :chart_margins, {:type => :hash, :default => {}, :keys => [:top,:right,:bottom,:left], :item_type => :length}
32
+ opt_accessor :chart_colors, {:type => :array, :item_type => :color}
33
+ opt_accessor :chart_type, {:type => :symbol, :default => :line, :valid_values => CHART_TYPES}
34
+ opt_accessor :chart_types, {:type => :array, :item_type => :symbol, :valid_values => CHART_TYPES.clone.unshift('')}
35
+ opt_accessor :represent_3d, {:type => :boolean}
36
+ opt_accessor :_3d_settings, {:type => :hash, :default => {}, :keys => [:background_opacity,:dx,:dy], :item_type => :float}
37
+ opt_accessor :show_dropshadow, {:type => :boolean}
38
+ opt_accessor :dropshadow_settings, {:type => :hash, :default => {}, :keys => [:blur_std,:dx,:dy], :item_type => :float}
39
+ opt_accessor :x_axis_type, {:type => :symbol, :default => :range, :valid_values => [:point,:range]}
40
+ opt_accessor :line_width, {:type => :integer}
41
+ opt_accessor :bar_width_ratio, {:type => :float, :default => 0.6, :range => 0..1}
42
+ opt_accessor :main_y_axis, {:type => :symbol, :default => :left, :valid_values => [:left,:right]}
43
+ opt_accessor :axis_font, {:type => :font}
44
+ opt_accessor :axis_settings, {:type => :hash, :default => {}, :keys => [:max, :min, :min_scale_value, :scale_count, :scale_interval], :item_type => :integer}
45
+ opt_accessor :x_axis_format, {:type => :string}
46
+ opt_accessor :axis_format, {:type => :string}
47
+ opt_accessor :use_y_second_axises, {:type => :array, :item_type => :boolean}
48
+ opt_accessor :second_axis_settings, {:type => :hash, :default => {}, :keys => [:max, :min], :item_type => :integer}
49
+ opt_accessor :second_axis_format, {:type => :string, :default_method => :axis_format}
50
+ opt_accessor :max_x_label_count, {:type => :integer, :default_proc => proc{|c| c.chart_width.div(Length.new(96))}}
51
+ opt_accessor :show_x_labels, {:type => :boolean, :default => true}
52
+ opt_accessor :legend_texts, {:type => :array, :item_type => :string}
53
+ opt_accessor :data_columns, {:type => :array, :item_type => :integer}
54
+ opt_accessor :use_effect, {:type => :boolean, :default => true}
55
+ opt_accessor :bar_seriese_interval, {:type => :float, :default => 0.3}
56
+ opt_accessor :color_columns, {:type => :array, :item_type => :integer}
57
+
58
+ def margin_top
59
+ chart_margins[:top] || Length.new(16)
60
+ end
61
+
62
+ def margin_right
63
+ chart_margins[:right] || Length.new(64)
64
+ end
65
+
66
+ def margin_bottom
67
+ chart_margins[:bottom] || Length.new(32)
68
+ end
69
+
70
+ def margin_left
71
+ chart_margins[:left] || Length.new(64)
72
+ end
73
+
74
+ alias __org_chart_type__ chart_type
75
+
76
+ def chart_type(index = nil)
77
+ if index
78
+ (chart_types && chart_types[index]) || __org_chart_type__
79
+ else
80
+ __org_chart_type__
81
+ end
82
+ end
83
+
84
+ def s_3d_pen_options
85
+ {:background_opacity => 0.3}.merge(_3d_settings)
86
+ end
87
+
88
+ def back_translate_value
89
+ {
90
+ :dx => (Length.new_or_nil(_3d_settings[:dx]) || Length.new(24)),
91
+ :dy => (Length.new_or_nil(_3d_settings[:dy]) || Length.new(-8))
92
+ }
93
+ end
94
+
95
+ def dropshadow_blur_std
96
+ dropshadow_settings[:blur_std] || 4
97
+ end
98
+
99
+ def dropshadow_dx
100
+ dropshadow_settings[:dx] || back_translate_value[:dx] / 2
101
+ end
102
+
103
+ def dropshadow_dy
104
+ dropshadow_settings[:dy] || back_translate_value[:dy] / 2
105
+ end
106
+
107
+ def use_y_second_axis?(index = nil)
108
+ if index
109
+ use_y_second_axises && use_y_second_axises[index]
110
+ else
111
+ use_y_second_axises && use_y_second_axises.any?
112
+ end
113
+ end
114
+
115
+ def chart_width
116
+ width - margin_left - margin_right
117
+ end
118
+
119
+ def chart_height
120
+ height - margin_top - margin_bottom
121
+ end
122
+
123
+ def line_chart_pen(color)
124
+ if represent_3d?
125
+ Drawing::CubicPen.new({:color => color, :width => line_width}.merge(s_3d_pen_options))
126
+ else
127
+ Drawing::Pen.new(:color => color, :width => line_width, :stroke_linecap => 'square')
128
+ end
129
+ end
130
+
131
+ def bar_chart_brush(color, bar_width=nil)
132
+ if represent_3d?
133
+ bar_width ||= chart_width * bar_width_ratio / data.column_values(data_columns[0]).size
134
+ Drawing::CylinderBrush.new(:color => color, :ry => bar_width * (back_translate_value[:dy] * bar_width_ratio).quo(back_translate_value[:dx] * 2))
135
+ else
136
+ Drawing::Brush.new(:color => color)
137
+ end
138
+ end
139
+
140
+ def area_chart_brush(color)
141
+ Drawing::Brush.new(:color => color)
142
+ end
143
+
144
+ private
145
+
146
+ def default_legend_point #:nodoc:
147
+ Coordinate.new(margin_left, 0)
148
+ end
149
+
150
+ def create_vector_image #:nodoc:
151
+ init_container
152
+
153
+ main_series_data = []
154
+ sub_series_data = []
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)
159
+ @bar_series.push(i) if chart_type(i) == :bar
160
+ end
161
+ settings =
162
+ moderate_axis(
163
+ main_series_data,
164
+ chart_height,
165
+ axis_settings[:min],
166
+ axis_settings[:max],
167
+ axis_settings[:scale_count])
168
+ sub_settings =
169
+ moderate_sub_axis(
170
+ sub_series_data,
171
+ settings,
172
+ second_axis_settings[:min],
173
+ second_axis_settings[:max]) if use_y_second_axis?
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
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
180
+ end
181
+
182
+ draw_axis(settings, sub_settings)
183
+ texts = legend_texts || data_columns.map{|i| data.column_title(i)}
184
+ draw_legend(texts, legend_shapes)
185
+ end
186
+
187
+ def init_container #:nodoc:
188
+ # mask = Drawing::ColorEffect::Mask.new(@canvas)
189
+ # mask.add_shapes(Shape::Rectangle.new(Drawing::Brush.new(:color => '#FFFFFF'), [margin_left, margin_top], chart_width, chart_height))
190
+ @axis_back_canvas = Shape::ShapeGroup.draw_on(@canvas) unless @axis_back_canvas
191
+ # @chart_front_canvas = Shape::ShapeGroup.draw_on(@canvas, :mask => "url(##{mask.id})") unless @chart_front_canvas
192
+ @chart_back_canvas = Shape::ShapeGroup.draw_on(@canvas) unless @chart_back_canvas
193
+ @scale_canvas = Shape::ShapeGroup.draw_on(@canvas) unless @scale_canvas
194
+ @chart_front_canvas = Shape::ShapeGroup.draw_on(@canvas) unless @chart_front_canvas
195
+ @axis_front_canvas = Shape::ShapeGroup.draw_on(@canvas) unless @axis_front_canvas
196
+ @legend_canvas = Shape::ShapeGroup.draw_on(@canvas) unless @legend_canvas
197
+ @chart_options = {}
198
+ # @chart_options[:filter] = "url(##{Drawing::Filter::DropShadow.new(@canvas, dropshadow_blur_std, dropshadow_dx, dropshadow_dy).id})" if show_dropshadow?
199
+ chart_clip = Drawing::Clipping.new(Shape::Rectangle.new([margin_left, margin_top], width - margin_left - margin_right, height - margin_top - margin_bottom))
200
+ @chart_back_canvas.set_clipping(chart_clip)
201
+ @chart_front_canvas.set_clipping(chart_clip)
202
+ end
203
+
204
+ def draw_axis(settings, sub_settings) #:nodoc:
205
+ line_options = {:linecap => 'square'}
206
+ line_pen = represent_3d? ? Drawing::CubicPen.new(line_options.merge(s_3d_pen_options)) : Drawing::Pen.new(line_options)
207
+ sub_pen = represent_3d? ? Drawing::Pen.new : line_pen
208
+ text_pen = Drawing::Pen.new(:font => axis_font)
209
+ text_margin = axis_font && (axis_font.draw_size.quo(4)) || Font::DEFAULT_SIZE.quo(4)
210
+
211
+ draw_y_axis(line_pen)
212
+ draw_x_axis(line_pen, sub_pen, text_pen, text_margin)
213
+ draw_scale(sub_pen, text_pen, settings, sub_settings, text_margin)
214
+ end
215
+
216
+ def draw_y_axis(pen) #:nodoc:
217
+ if use_y_second_axis? || main_y_axis == :left
218
+ start_point = [margin_left, height - margin_bottom]
219
+ end_point = [margin_left, margin_top]
220
+ pen.draw_line(represent_3d? ? @axis_back_canvas : @axis_front_canvas, start_point, end_point)
221
+ end
222
+
223
+ if use_y_second_axis? || main_y_axis == :right
224
+ start_point = [width - margin_right, height - margin_bottom]
225
+ end_point = [width - margin_right, margin_top]
226
+ pen.draw_line(@axis_front_canvas, start_point, end_point)
227
+ end
228
+ end
229
+
230
+ def draw_scale(line_pen, text_pen, settings, sub_settings, text_margin) #:nodoc:
231
+ if settings[:min] == settings[:min_scale_value] - settings[:scale_interval]
232
+ y = value_position_on_chart(margin_top, settings, settings[:min], true)
233
+ if use_y_second_axis? || main_y_axis == :left
234
+ text_pen.draw_text(
235
+ @axis_front_canvas,
236
+ [margin_left - text_margin, y],
237
+ main_y_axis == :left ? settings[:min] : sub_settings[:min],
238
+ :alignment_baseline=>'middle',
239
+ :text_anchor=>'end',
240
+ :format => (main_y_axis == :left ? axis_format : second_axis_format))
241
+ end
242
+ if use_y_second_axis? || main_y_axis == :right
243
+ text_pen.draw_text(
244
+ @axis_front_canvas,
245
+ [width - margin_right + text_margin, y],
246
+ main_y_axis == :right ? settings[:min] : sub_settings[:min],
247
+ :alignment_baseline=>'middle',
248
+ :format => (main_y_axis == :right ? axis_format : second_axis_format))
249
+ end
250
+ end
251
+
252
+ if represent_3d? && (use_y_second_axis? || main_y_axis == :left)
253
+ line_pen.draw_line(
254
+ @axis_back_canvas,
255
+ [margin_left, height - margin_bottom],
256
+ [margin_left + back_translate_value[:dx], height - margin_bottom + back_translate_value[:dy]])
257
+ end
258
+
259
+ sub_axis_value = sub_settings[:min_scale_value] if use_y_second_axis?
260
+ settings[:min_scale_value].step(settings[:max], settings[:scale_interval]) do |value|
261
+ y = value_position_on_chart(margin_top, settings, value, true)
262
+
263
+ if settings[:min] != value
264
+ if represent_3d?
265
+ if use_y_second_axis? || main_y_axis == :left
266
+ draw_y_scale_line(
267
+ line_pen,
268
+ [margin_left, y],
269
+ [margin_left + back_translate_value[:dx], y + back_translate_value[:dy]])
270
+ end
271
+ draw_y_scale_line(
272
+ line_pen,
273
+ [margin_left + back_translate_value[:dx], y + back_translate_value[:dy]],
274
+ [width - margin_right + back_translate_value[:dx], y + back_translate_value[:dy]])
275
+ if use_y_second_axis? || main_y_axis == :right
276
+ draw_y_scale_line(
277
+ line_pen,
278
+ [width - margin_right + back_translate_value[:dx], y + back_translate_value[:dy]],
279
+ [width - margin_right, y])
280
+ end
281
+ else
282
+ line_pen.dasharray = '2,6'
283
+ draw_y_scale_line(line_pen, [margin_left, y], [width - margin_right, y])
284
+ line_pen.dasharray = nil
285
+ end
286
+ end
287
+
288
+ if use_y_second_axis? || main_y_axis == :left
289
+ text_pen.draw_text(
290
+ @axis_back_canvas,
291
+ [margin_left - text_margin, y],
292
+ main_y_axis == :left ? value : sub_axis_value,
293
+ :alignment_baseline=>'middle',
294
+ :text_anchor=>'end',
295
+ :font=>axis_font,
296
+ :format => (main_y_axis == :left ? axis_format : second_axis_format))
297
+ end
298
+
299
+ if use_y_second_axis? || main_y_axis == :right
300
+ text_pen.draw_text(
301
+ @axis_front_canvas,
302
+ [width - margin_right + text_margin, y],
303
+ main_y_axis == :right ? value : sub_axis_value,
304
+ :alignment_baseline=>'middle',
305
+ :font=>axis_font,
306
+ :format => (main_y_axis == :right ? axis_format : second_axis_format))
307
+ end
308
+ sub_axis_value += sub_settings[:scale_interval] if use_y_second_axis?
309
+ end
310
+ end
311
+
312
+ def draw_y_scale_line(pen, left_point, right_point)
313
+ pen.draw_line(@scale_canvas, left_point, right_point)
314
+ end
315
+
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
319
+ end
320
+
321
+ def draw_x_axis(main_pen, sub_pen, text_pen, text_margin) #:nodoc:
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
+
324
+ data.row_count.times do |i|
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
328
+ text_pen.draw_text(
329
+ @axis_front_canvas,
330
+ [text_x, height - margin_bottom + text_margin],
331
+ format_x_label(data.row_title(i)),
332
+ :text_anchor => 'middle', :alignment_baseline => 'top') if show_x_labels?
333
+
334
+ sub_pen.draw_line_on_direction(
335
+ @axis_front_canvas,
336
+ [scale_x, height - margin_bottom],
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)
339
+ end
340
+ end
341
+
342
+ def draw_chart(id, chart_type, color, settings) #:nodoc:
343
+ case chart_type
344
+ when :line then draw_line(id, color, settings)
345
+ when :area then draw_area(id, color, settings)
346
+ when :bar then draw_bar(id, color, settings)
347
+ when :stackedbar then draw_stackedbar(id, color, settings)
348
+ end
349
+ end
350
+
351
+ def draw_line(id, color, settings) #:nodoc:
352
+ values = data.column_values(id)
353
+ return if values.compact.size == 0
354
+ first_index = values.each_with_index {|value, i| break i if value}
355
+ pen_options = {:color => color, :width => line_width}
356
+ pen = line_chart_pen(color)
357
+
358
+ x = order_position_on_chart(margin_left, chart_width, values.size, first_index, x_axis_type)
359
+ y = value_position_on_chart(margin_top, settings, values[first_index], true)
360
+ pen.linejoin = 'bevel'
361
+ pen.draw_polyline(@chart_front_canvas, [x, y], @chart_options) {|polyline|
362
+ ((first_index + 1)...values.size).each do |i|
363
+ x = order_position_on_chart(margin_left, chart_width, values.size, i, x_axis_type)
364
+ y = value_position_on_chart(margin_top, settings, values[i], true)
365
+ polyline.line_to([x, y])
366
+ end
367
+ }
368
+ pen.linejoin = 'bevel'
369
+ end
370
+
371
+ def draw_area(id, color, settings) #:nodoc:
372
+ values = data.column_values(id)
373
+ return if values.compact.size == 0
374
+ first_index = values.each_with_index {|value, i| break i if value}
375
+ brush = area_chart_brush(color)
376
+
377
+ x = order_position_on_chart(margin_left, chart_width, values.size, first_index, x_axis_type)
378
+ y = value_position_on_chart(margin_top, settings, settings[:min], true)
379
+ polygone = brush.draw_polygon(@chart_front_canvas, [x, y], @chart_options) {|polygon|
380
+ (first_index...values.size).each do |i|
381
+ x = order_position_on_chart(margin_left, chart_width, values.size, i, x_axis_type)
382
+ y = value_position_on_chart(margin_top, settings, values[i], true)
383
+ polygon.line_to([x, y])
384
+ end
385
+ y = value_position_on_chart(margin_top, settings, settings[:min], true)
386
+ polygon.line_to([x, y])
387
+ }
388
+ polygone.translate(back_translate_value[:dx], back_translate_value[:dy]) if represent_3d?
389
+ end
390
+
391
+ def draw_bar(id, color, settings) #:nodoc:
392
+ bar_group = Shape::ShapeGroup.new(@chart_options).draw_on(@chart_front_canvas)
393
+ values = data.column_values(id)
394
+ return if values.compact.size == 0
395
+ bar_width = chart_width * bar_width_ratio / values.size / (@bar_series.size + (@bar_series.size - 1) * bar_seriese_interval)
396
+
397
+ brush = bar_chart_brush(color, bar_width)
398
+
399
+ values.each_with_index do |value, i|
400
+ next if value.nil?
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
+ 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]
404
+ brush.draw_rectangle(bar_group, [x, y], bar_width, height - margin_bottom - y)
405
+ end
406
+ bar_group.translate(back_translate_value[:dx] / 2, back_translate_value[:dy] / 2) if represent_3d?
407
+ end
408
+
409
+ def draw_stackedbar(id, color, settings) #:nodoc:
410
+ bar_group = Shape::ShapeGroup.new(@chart_options).draw_on(@chart_front_canvas)
411
+
412
+ values = data.column_values(id)
413
+ return if values.compact.size == 0
414
+ bar_width = chart_width * bar_width_ratio / values.size
415
+
416
+ brush = bar_chart_brush(color, bar_width)
417
+
418
+ @stacked_values ||= []
419
+
420
+ values.each_with_index do |value, i|
421
+ @stacked_values[i] ||= 0
422
+ next if value.nil?
423
+ x = order_position_on_chart(margin_left, chart_width, values.size, i, x_axis_type, bar_width_ratio)
424
+ y = value_position_on_chart(margin_top, settings, (@stacked_values[i] += value), true)
425
+ bar_height = value_position_on_chart(margin_top, settings, (@stacked_values[i] - value), true) - y
426
+ # brush.color = data[:$color][i] if data[:$color]
427
+ brush.draw_rectangle(bar_group, [x, y], bar_width, bar_height)
428
+ end
429
+ bar_group.translate(back_translate_value[:dx] / 2, back_translate_value[:dy] / 2) if represent_3d?
430
+ end
431
+
432
+ def legend_shapes #:nodoc:
433
+ result = []
434
+ data_columns.each_with_index do |id, index|
435
+ result <<
436
+ case chart_type(index)
437
+ when :line, nil
438
+ Shape::Line.create_on_start_end(
439
+ [legend_font_size * 0.2, legend_font_size * (1.2 * index + 0.8)],
440
+ [legend_font_size, legend_font_size * (1.2 * index + 0.8)],
441
+ :painting => {:stroke => chart_color(index), :stroke_width => line_width})
442
+ when :bar, :stackedbar
443
+ nil
444
+ when :area
445
+ nil
446
+ else
447
+ nil
448
+ end
449
+ end
450
+ result
451
+ end
452
+
453
+ def format_x_label(obj)
454
+ if x_axis_format
455
+ if obj.kind_of?(Numeric)
456
+ obj.strfnum(x_axis_format)
457
+ elsif obj.respond_to?(:strftime)
458
+ obj.strftime(x_axis_format)
459
+ else
460
+ obj.to_s
461
+ end
462
+ else
463
+ obj.to_s
464
+ end
465
+ end
466
+ end
467
+ end
468
+ end