dyi 1.1.1 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +7 -1
- data/lib/dyi.rb +3 -1
- data/lib/dyi/animation.rb +5 -4
- data/lib/dyi/canvas.rb +5 -8
- data/lib/dyi/chart.rb +1 -1
- data/lib/dyi/chart/array_reader.rb +104 -10
- data/lib/dyi/chart/axis_util.rb +31 -17
- data/lib/dyi/chart/base.rb +104 -7
- data/lib/dyi/chart/csv_reader.rb +56 -8
- data/lib/dyi/chart/excel_reader.rb +27 -4
- data/lib/dyi/chart/legend.rb +10 -8
- data/lib/dyi/chart/line_chart.rb +29 -25
- data/lib/dyi/chart/pie_chart.rb +192 -29
- data/lib/dyi/chart/table.rb +12 -10
- data/lib/dyi/color.rb +9 -7
- data/lib/dyi/coordinate.rb +177 -61
- data/lib/dyi/drawing.rb +1 -1
- data/lib/dyi/drawing/clipping.rb +9 -3
- data/lib/dyi/drawing/color_effect.rb +7 -4
- data/lib/dyi/drawing/filter.rb +10 -7
- data/lib/dyi/drawing/pen.rb +421 -11
- data/lib/dyi/drawing/pen_3d.rb +12 -7
- data/lib/dyi/element.rb +5 -4
- data/lib/dyi/event.rb +3 -3
- data/lib/dyi/font.rb +6 -4
- data/lib/dyi/formatter.rb +1 -1
- data/lib/dyi/formatter/base.rb +24 -15
- data/lib/dyi/formatter/emf_formatter.rb +6 -5
- data/lib/dyi/formatter/eps_formatter.rb +15 -14
- data/lib/dyi/formatter/svg_formatter.rb +16 -14
- data/lib/dyi/formatter/svg_reader.rb +4 -3
- data/lib/dyi/formatter/xaml_formatter.rb +9 -7
- data/lib/dyi/length.rb +213 -114
- data/lib/dyi/matrix.rb +4 -2
- data/lib/dyi/painting.rb +161 -87
- data/lib/dyi/script.rb +1 -1
- data/lib/dyi/script/ecmascript.rb +18 -29
- data/lib/dyi/script/simple_script.rb +4 -8
- data/lib/dyi/shape.rb +1 -1
- data/lib/dyi/shape/base.rb +8 -17
- data/lib/dyi/shape/path.rb +102 -19
- data/lib/dyi/stylesheet.rb +4 -3
- data/lib/dyi/svg_element.rb +9 -7
- data/lib/dyi/type.rb +5 -2
- data/lib/dyi/util.rb +36 -1
- data/lib/ironruby.rb +1 -1
- data/lib/util.rb +53 -5
- metadata +4 -19
data/lib/dyi/chart/csv_reader.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: UTF-8 -*-
|
2
2
|
|
3
|
-
# Copyright (c) 2009-
|
3
|
+
# Copyright (c) 2009-2012 Sound-F Co., Ltd. All rights reserved.
|
4
4
|
#
|
5
5
|
# Author:: Mamoru Yuo
|
6
6
|
#
|
@@ -27,8 +27,48 @@ require 'nkf'
|
|
27
27
|
module DYI
|
28
28
|
module Chart
|
29
29
|
|
30
|
-
# CsvReader class provides a interface to CSV file and data for a chart
|
30
|
+
# +CsvReader+ class provides a interface to CSV file and data for a chart
|
31
31
|
# object.
|
32
|
+
#
|
33
|
+
#= Basic Usage
|
34
|
+
#
|
35
|
+
# Using +PieChart+ and CsvReader, you can create the pie chart as the
|
36
|
+
# following:
|
37
|
+
# # contents of asian_gdp.csv
|
38
|
+
# # -------------------------
|
39
|
+
# # China,5878
|
40
|
+
# # Japan,5459
|
41
|
+
# # India,1538
|
42
|
+
# # South Koria,1007
|
43
|
+
# # Other Countries, 2863
|
44
|
+
#
|
45
|
+
# require 'rubygems'
|
46
|
+
# require 'dyi'
|
47
|
+
#
|
48
|
+
# reader = DYI::Chart::CsvReader.read('asian_gdp.csv',
|
49
|
+
# :schema => [:name, :value],
|
50
|
+
# :data_types => [:string, :number])
|
51
|
+
#
|
52
|
+
# # Creates the Pie Chart
|
53
|
+
# chart = DYI::Chart::PieChart.new(450,250)
|
54
|
+
# chart.load_data(reader)
|
55
|
+
# chart.save('asian_gdp.svg')
|
56
|
+
# Creating the instance, you should not call +new+ method but {.read} method.
|
57
|
+
#
|
58
|
+
# The optional argument +:schema+ means a field name. See {ArrayReader} for
|
59
|
+
# +:schema+ option. The optional argument +:data_types+ means data types of
|
60
|
+
# the field. Using this option, +CsvReader+ converts text data that the CSV
|
61
|
+
# data included into a appropriate ruby object. (+:data_types+ option has
|
62
|
+
# been implemented in +ArrayReader+, although +ArrayReader+ ignores this
|
63
|
+
# option.) If +:data_types+ option is not specified, the values of all the
|
64
|
+
# fields are converted into instances of +Float+. +:data_types+ option can
|
65
|
+
# specify the following values: +:string+, +:decimal+, +:number+(synonym of
|
66
|
+
# +:decimal+), +:float+, +:integer+, +:date+, +:datetime+, +:boolean+
|
67
|
+
#
|
68
|
+
# See {CsvReader.read CsvReader.read} for other optional arguments.
|
69
|
+
# @see ArrayReader
|
70
|
+
# @see ArrayReader.read
|
71
|
+
# @since 0.0.0
|
32
72
|
class CsvReader < ArrayReader
|
33
73
|
|
34
74
|
# @private
|
@@ -37,6 +77,7 @@ module DYI
|
|
37
77
|
# Parses CSV data and sets data.
|
38
78
|
# @param [String] csv CSV data
|
39
79
|
# @option (see ArrayReader#read)
|
80
|
+
# @option options [Array<Symbol>] :data_types array of field data types
|
40
81
|
# @option options [String] :date_format date format string of CSV data,
|
41
82
|
# parsing a date string in CSV at +Date#strptime+
|
42
83
|
# @option options [String] :datetime_format date-time format string of CSV
|
@@ -47,8 +88,10 @@ module DYI
|
|
47
88
|
# @option options [String] :col_sep a separator of columns, default to
|
48
89
|
# <tt>","</tt>
|
49
90
|
# @option options [String] :row_sep a separator of rows, default to
|
50
|
-
# +:auto
|
51
|
-
# or <tt>"\r"</tt> sequence
|
91
|
+
# +:auto+, which means that a separetor is <tt>"\r\n"</tt>,
|
92
|
+
# <tt>"\n"</tt>, or <tt>"\r"</tt> sequence
|
93
|
+
# @raise [ArgumentError] unknown encode is given for +:encode+
|
94
|
+
# @see ArrayReader#read
|
52
95
|
# @since 1.1.1
|
53
96
|
def parse(csv, options={})
|
54
97
|
options = options.clone
|
@@ -75,6 +118,8 @@ module DYI
|
|
75
118
|
# Parses CSV file and sets data.
|
76
119
|
# @param [String] path a path of the CSV file
|
77
120
|
# @option (see #parse)
|
121
|
+
# @raise (see #parse)
|
122
|
+
# @see (see #parse)
|
78
123
|
def read(path, options={})
|
79
124
|
parse(IO.read(path), options)
|
80
125
|
end
|
@@ -112,8 +157,9 @@ module DYI
|
|
112
157
|
# Parses CSV file and creates instance of CsvReader.
|
113
158
|
# @param (see #read)
|
114
159
|
# @option (see #read)
|
115
|
-
# @return
|
116
|
-
# @see
|
160
|
+
# @return (see .parse)
|
161
|
+
# @raise (see #read)
|
162
|
+
# @see (see .parse)
|
117
163
|
def read(path, options={})
|
118
164
|
new.read(path, options)
|
119
165
|
end
|
@@ -122,9 +168,11 @@ module DYI
|
|
122
168
|
# @param (see #parse)
|
123
169
|
# @option (see #parse)
|
124
170
|
# @return [CsvReader] a new instance of CsvReader
|
171
|
+
# @raise (see #parse)
|
125
172
|
# @see ArrayReader.read
|
126
|
-
|
127
|
-
|
173
|
+
# @since 1.1.1
|
174
|
+
def parse(csv, options={})
|
175
|
+
new.parse(csv, options)
|
128
176
|
end
|
129
177
|
end
|
130
178
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: UTF-8 -*-
|
2
2
|
|
3
|
-
# Copyright (c) 2009-
|
3
|
+
# Copyright (c) 2009-2012 Sound-F Co., Ltd. All rights reserved.
|
4
4
|
#
|
5
5
|
# Author:: Mamoru Yuo
|
6
6
|
#
|
@@ -28,12 +28,28 @@ end
|
|
28
28
|
require 'date'
|
29
29
|
require 'nkf'
|
30
30
|
|
31
|
-
module DYI
|
32
|
-
module Chart
|
31
|
+
module DYI
|
32
|
+
module Chart
|
33
33
|
|
34
|
+
# +ExcelReader+ class provides a interface to Microsoft Excel file and data
|
35
|
+
# for a chart object. Creating the instance, you should not call +new+
|
36
|
+
# method but {.read} method.
|
37
|
+
#
|
38
|
+
# This class requires that _win32ole_ has been installed your system.
|
39
|
+
# @see ArrayReader
|
40
|
+
# @since 0.0.0
|
34
41
|
class ExcelReader < ArrayReader
|
42
|
+
|
43
|
+
# @private
|
35
44
|
OFFSET = DateTime.now.offset
|
36
45
|
|
46
|
+
# Parses Excel file and sets data.
|
47
|
+
# @param [String] path a path of the Excel file
|
48
|
+
# @option (see ArrayReader#read)
|
49
|
+
# @option options [String, Integer] :sheet sheet name of data source or
|
50
|
+
# sheet number (starting from 1)
|
51
|
+
# @raise [NotImplementedError] _win32ole_ has not been installed
|
52
|
+
# @see ArrayReader#read
|
37
53
|
def read(path, options={})
|
38
54
|
if defined? WIN32OLE
|
39
55
|
# for Windows
|
@@ -45,7 +61,7 @@ module DYI #:nodoc:
|
|
45
61
|
sheet_values = sheet.range(sheet.cells(1,1), sheet.cells(range.end(4).row, range.end(2).column)).value
|
46
62
|
else
|
47
63
|
# except Windows
|
48
|
-
raise NotImplementedError, 'win32ole
|
64
|
+
raise NotImplementedError, 'win32ole has not been installed'
|
49
65
|
end
|
50
66
|
|
51
67
|
begin
|
@@ -91,6 +107,13 @@ module DYI #:nodoc:
|
|
91
107
|
end
|
92
108
|
|
93
109
|
class << self
|
110
|
+
|
111
|
+
# Parses Excel file and creates instance of ExcelReader.
|
112
|
+
# @param (see #read)
|
113
|
+
# @option (see #read)
|
114
|
+
# @return [ExcelReader] a new instance of ExcelReader
|
115
|
+
# @raise (see #read)
|
116
|
+
# @see ArrayReader.read
|
94
117
|
def read(path, options={})
|
95
118
|
new.read(path, options)
|
96
119
|
end
|
data/lib/dyi/chart/legend.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: UTF-8 -*-
|
2
2
|
|
3
|
-
# Copyright (c) 2009-
|
3
|
+
# Copyright (c) 2009-2012 Sound-F Co., Ltd. All rights reserved.
|
4
4
|
#
|
5
5
|
# Author:: Mamoru Yuo
|
6
6
|
#
|
@@ -19,14 +19,16 @@
|
|
19
19
|
# You should have received a copy of the GNU General Public License
|
20
20
|
# along with DYI. If not, see <http://www.gnu.org/licenses/>.
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
#
|
23
|
+
module DYI
|
24
|
+
module Chart
|
24
25
|
|
26
|
+
# @since 0.0.0
|
25
27
|
module Legend
|
26
28
|
|
27
29
|
private
|
28
30
|
|
29
|
-
def draw_legend(names, shapes=nil, records=nil, colors=nil)
|
31
|
+
def draw_legend(names, shapes=nil, records=nil, colors=nil)
|
30
32
|
legend_canvas.translate(legend_point.x, legend_point.y)
|
31
33
|
if show_legend?
|
32
34
|
pen = Drawing::Pen.black_pen(:font => legend_font)
|
@@ -53,15 +55,15 @@ module DYI #:nodoc:
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
def legend_font_size
|
58
|
+
def legend_font_size
|
57
59
|
legend_font ? legend_font.draw_size : Font::DEFAULT_SIZE
|
58
60
|
end
|
59
61
|
|
60
|
-
def default_legend_point
|
62
|
+
def default_legend_point
|
61
63
|
Coordinate.new(0,0)
|
62
64
|
end
|
63
65
|
|
64
|
-
def default_legend_format
|
66
|
+
def default_legend_format
|
65
67
|
"{name}"
|
66
68
|
end
|
67
69
|
|
@@ -69,7 +71,7 @@ module DYI #:nodoc:
|
|
69
71
|
|
70
72
|
private
|
71
73
|
|
72
|
-
def included(klass)
|
74
|
+
def included(klass)
|
73
75
|
klass.__send__(:opt_accessor, :show_legend, :type => :boolean, :default => true)
|
74
76
|
klass.__send__(:opt_accessor, :legend_font, :type => :font)
|
75
77
|
klass.__send__(:opt_accessor, :legend_format, :type => :string, :default_method => :default_legend_format)
|
data/lib/dyi/chart/line_chart.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: UTF-8 -*-
|
2
2
|
|
3
|
-
# Copyright (c) 2009-
|
3
|
+
# Copyright (c) 2009-2012 Sound-F Co., Ltd. All rights reserved.
|
4
4
|
#
|
5
5
|
# Author:: Mamoru Yuo
|
6
6
|
#
|
@@ -19,9 +19,12 @@
|
|
19
19
|
# You should have received a copy of the GNU General Public License
|
20
20
|
# along with DYI. If not, see <http://www.gnu.org/licenses/>.
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
#
|
23
|
+
module DYI
|
24
|
+
|
25
|
+
module Chart
|
24
26
|
|
27
|
+
# @since 0.0.0
|
25
28
|
class LineChart < Base
|
26
29
|
include AxisUtil
|
27
30
|
include Legend
|
@@ -50,7 +53,6 @@ module DYI #:nodoc:
|
|
50
53
|
opt_accessor :max_x_label_count, {:type => :integer, :default_proc => proc{|c| c.chart_width.div(Length.new(96))}}
|
51
54
|
opt_accessor :show_x_labels, {:type => :boolean, :default => true}
|
52
55
|
opt_accessor :legend_texts, {:type => :array, :item_type => :string}
|
53
|
-
# opt_accessor :data_columns, {:type => :array, :item_type => :integer}
|
54
56
|
opt_accessor :use_effect, {:type => :boolean, :default => true}
|
55
57
|
opt_accessor :bar_seriese_interval, {:type => :float, :default => 0.3}
|
56
58
|
opt_accessor :color_columns, {:type => :array, :item_type => :integer}
|
@@ -141,18 +143,19 @@ module DYI #:nodoc:
|
|
141
143
|
Drawing::Brush.new(:color => color)
|
142
144
|
end
|
143
145
|
|
144
|
-
|
145
|
-
|
146
|
+
# @since 1.1.0
|
146
147
|
def initialize(*args)
|
147
148
|
super
|
148
149
|
init_container
|
149
150
|
end
|
150
151
|
|
151
|
-
|
152
|
+
private
|
153
|
+
|
154
|
+
def default_legend_point
|
152
155
|
Coordinate.new(margin_left, 0)
|
153
156
|
end
|
154
157
|
|
155
|
-
def create_vector_image
|
158
|
+
def create_vector_image
|
156
159
|
super
|
157
160
|
|
158
161
|
main_series_data = []
|
@@ -177,11 +180,12 @@ module DYI #:nodoc:
|
|
177
180
|
second_axis_settings[:min],
|
178
181
|
second_axis_settings[:max]) if use_y_second_axis?
|
179
182
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
183
|
+
[:stackedbar, :bar, :area, :line].each do |chart_type|
|
184
|
+
data.values_size.times do |i|
|
185
|
+
if chart_type(i) == chart_type
|
186
|
+
draw_chart(i, chart_type(i), chart_color(i), use_y_second_axis?(i) ? sub_settings : settings)
|
187
|
+
end
|
188
|
+
end
|
185
189
|
end
|
186
190
|
|
187
191
|
draw_axis(settings, sub_settings)
|
@@ -189,7 +193,7 @@ module DYI #:nodoc:
|
|
189
193
|
draw_legend(texts, legend_shapes)
|
190
194
|
end
|
191
195
|
|
192
|
-
def init_container
|
196
|
+
def init_container
|
193
197
|
# mask = Drawing::ColorEffect::Mask.new(@canvas)
|
194
198
|
# mask.add_shapes(Shape::Rectangle.new(Drawing::Brush.new(:color => '#FFFFFF'), [margin_left, margin_top], chart_width, chart_height))
|
195
199
|
@axis_back_canvas = Shape::ShapeGroup.draw_on(@canvas) unless @axis_back_canvas
|
@@ -206,7 +210,7 @@ module DYI #:nodoc:
|
|
206
210
|
@chart_front_canvas.set_clipping(chart_clip)
|
207
211
|
end
|
208
212
|
|
209
|
-
def draw_axis(settings, sub_settings)
|
213
|
+
def draw_axis(settings, sub_settings)
|
210
214
|
line_options = {:linecap => 'square'}
|
211
215
|
line_pen = represent_3d? ? Drawing::CubicPen.new(line_options.merge(s_3d_pen_options)) : Drawing::Pen.new(line_options)
|
212
216
|
sub_pen = represent_3d? ? Drawing::Pen.new : line_pen
|
@@ -218,7 +222,7 @@ module DYI #:nodoc:
|
|
218
222
|
draw_scale(sub_pen, text_pen, settings, sub_settings, text_margin)
|
219
223
|
end
|
220
224
|
|
221
|
-
def draw_y_axis(pen)
|
225
|
+
def draw_y_axis(pen)
|
222
226
|
if use_y_second_axis? || main_y_axis == :left
|
223
227
|
start_point = [margin_left, height - margin_bottom]
|
224
228
|
end_point = [margin_left, margin_top]
|
@@ -232,7 +236,7 @@ module DYI #:nodoc:
|
|
232
236
|
end
|
233
237
|
end
|
234
238
|
|
235
|
-
def draw_scale(line_pen, text_pen, settings, sub_settings, text_margin)
|
239
|
+
def draw_scale(line_pen, text_pen, settings, sub_settings, text_margin)
|
236
240
|
if settings[:min] == settings[:min_scale_value] - settings[:scale_interval]
|
237
241
|
y = value_position_on_chart(margin_top, settings, settings[:min], true)
|
238
242
|
if use_y_second_axis? || main_y_axis == :left
|
@@ -321,7 +325,7 @@ module DYI #:nodoc:
|
|
321
325
|
i % ((data.records_size - 1) / [max_x_label_count - 1, 1].max) == 0
|
322
326
|
end
|
323
327
|
|
324
|
-
def draw_x_axis(main_pen, sub_pen, text_pen, text_margin)
|
328
|
+
def draw_x_axis(main_pen, sub_pen, text_pen, text_margin)
|
325
329
|
main_pen.draw_line(represent_3d? ? @axis_back_canvas : @axis_front_canvas, [margin_left, height - margin_bottom], [width - margin_right, height - margin_bottom])
|
326
330
|
|
327
331
|
data.records_size.times do |i|
|
@@ -342,7 +346,7 @@ module DYI #:nodoc:
|
|
342
346
|
end
|
343
347
|
end
|
344
348
|
|
345
|
-
def draw_chart(id, chart_type, color, settings)
|
349
|
+
def draw_chart(id, chart_type, color, settings)
|
346
350
|
case chart_type
|
347
351
|
when :line then draw_line(id, color, settings)
|
348
352
|
when :area then draw_area(id, color, settings)
|
@@ -351,7 +355,7 @@ module DYI #:nodoc:
|
|
351
355
|
end
|
352
356
|
end
|
353
357
|
|
354
|
-
def draw_line(id, color, settings)
|
358
|
+
def draw_line(id, color, settings)
|
355
359
|
values = data.series(id)
|
356
360
|
return if values.compact.size == 0
|
357
361
|
first_index = values.each_with_index {|value, i| break i if value}
|
@@ -371,7 +375,7 @@ module DYI #:nodoc:
|
|
371
375
|
pen.linejoin = 'bevel'
|
372
376
|
end
|
373
377
|
|
374
|
-
def draw_area(id, color, settings)
|
378
|
+
def draw_area(id, color, settings)
|
375
379
|
values = data.series(id)
|
376
380
|
return if values.compact.size == 0
|
377
381
|
first_index = values.each_with_index {|value, i| break i if value}
|
@@ -391,7 +395,7 @@ module DYI #:nodoc:
|
|
391
395
|
polygone.translate(back_translate_value[:dx], back_translate_value[:dy]) if represent_3d?
|
392
396
|
end
|
393
397
|
|
394
|
-
def draw_bar(id, color, settings)
|
398
|
+
def draw_bar(id, color, settings)
|
395
399
|
bar_group = Shape::ShapeGroup.new(@chart_options).draw_on(@chart_front_canvas)
|
396
400
|
values = data.series(id)
|
397
401
|
return if values.compact.size == 0
|
@@ -409,7 +413,7 @@ module DYI #:nodoc:
|
|
409
413
|
bar_group.translate(back_translate_value[:dx] / 2, back_translate_value[:dy] / 2) if represent_3d?
|
410
414
|
end
|
411
415
|
|
412
|
-
def draw_stackedbar(id, color, settings)
|
416
|
+
def draw_stackedbar(id, color, settings)
|
413
417
|
bar_group = Shape::ShapeGroup.new(@chart_options).draw_on(@chart_front_canvas)
|
414
418
|
|
415
419
|
values = data.series(id)
|
@@ -433,14 +437,14 @@ module DYI #:nodoc:
|
|
433
437
|
end
|
434
438
|
|
435
439
|
# @since 1.0.0
|
436
|
-
def chart_color(index)
|
440
|
+
def chart_color(index)
|
437
441
|
if chart_colors
|
438
442
|
color = chart_colors[index]
|
439
443
|
end
|
440
444
|
color || DEFAULT_CHART_COLOR[index % DEFAULT_CHART_COLOR.size]
|
441
445
|
end
|
442
446
|
|
443
|
-
def legend_shapes
|
447
|
+
def legend_shapes
|
444
448
|
result = []
|
445
449
|
(0...data.values_size).each_with_index do |id, index|
|
446
450
|
result <<
|
data/lib/dyi/chart/pie_chart.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# -*- encoding: UTF-8 -*-
|
2
2
|
|
3
|
-
# Copyright (c) 2009-
|
3
|
+
# Copyright (c) 2009-2012 Sound-F Co., Ltd. All rights reserved.
|
4
4
|
#
|
5
5
|
# Author:: Mamoru Yuo
|
6
6
|
#
|
@@ -19,43 +19,205 @@
|
|
19
19
|
# You should have received a copy of the GNU General Public License
|
20
20
|
# along with DYI. If not, see <http://www.gnu.org/licenses/>.
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
#
|
23
|
+
module DYI
|
24
|
+
module Chart
|
24
25
|
|
26
|
+
# +PieChart+ creates the image of pie chart.
|
27
|
+
#
|
28
|
+
#= Basic Usage
|
29
|
+
#
|
30
|
+
# Using +PieChart+ and ArrayReader (or sub class of ArrayReader), you can
|
31
|
+
# create the pie chart as the following:
|
32
|
+
# require 'rubygems'
|
33
|
+
# require 'dyi'
|
34
|
+
#
|
35
|
+
# # Nominal GDP of Asian Countries (2010)
|
36
|
+
# chart_data = [['China', 5878],
|
37
|
+
# ['Japan', 5459],
|
38
|
+
# ['India', 1538],
|
39
|
+
# ['South Koria', 1007],
|
40
|
+
# ['Other Countries', 2863]]
|
41
|
+
# reader = DYI::Chart::ArrayReader.read(chart_data, :schema => [:name, :value])
|
42
|
+
#
|
43
|
+
# # Creates the Pie Chart
|
44
|
+
# chart = DYI::Chart::PieChart.new(450,250)
|
45
|
+
# chart.load_data(reader)
|
46
|
+
# chart.save('asian_gdp.svg')
|
47
|
+
# See {ArrayReader} about how to set the chart data.
|
48
|
+
#
|
49
|
+
# The chart options of +PieChart+ are specified at the constractor. See
|
50
|
+
# <em>Instance Attribute</em> of this class, {Base} and {Legend} for the
|
51
|
+
# attributes that can be specified. The specified attributes can be refered
|
52
|
+
# and set.
|
53
|
+
# # Creates the Pie Chart
|
54
|
+
# chart = DYI::Chart::PieChart.new(500,250,
|
55
|
+
# :center_point => [130, 100],
|
56
|
+
# :legend_point => [250, 50],
|
57
|
+
# :represent_3d => true,
|
58
|
+
# :_3d_settings => {:dy => 20},
|
59
|
+
# :legend_format => "{?name}\t{!e}{?value:#,0}\t{!e}({?percent:0.0%})",
|
60
|
+
# :chart_stroke_color => 'white')
|
61
|
+
# puts chart.represent_3d? # => true
|
62
|
+
# chart.show_baloon = false
|
63
|
+
# puts chart.show_baloon? # => false
|
64
|
+
#
|
65
|
+
# chart.load_data(reader)
|
66
|
+
# chart.save('asian_gdp.svg')
|
67
|
+
#
|
68
|
+
#= Adds Custom Elements to Chart
|
69
|
+
#
|
70
|
+
# Using {#canvas canvas} attribute, you can add arbitrary graphical elements.
|
71
|
+
# # Creates the Pie Chart
|
72
|
+
# chart = DYI::Chart::PieChart.new(500,250,
|
73
|
+
# :center_point => [130, 100],
|
74
|
+
# :legend_point => [250, 50],
|
75
|
+
# :represent_3d => true,
|
76
|
+
# :_3d_settings => {:dy => 20},
|
77
|
+
# :legend_format => "{?name}\t{!e}{?value:#,0}\t{!e}({?percent:0.0%})",
|
78
|
+
# :chart_stroke_color => 'white')
|
79
|
+
#
|
80
|
+
# DYI::Drawing::Pen.black_pen.draw_text(chart.canvas,
|
81
|
+
# [250, 20],
|
82
|
+
# 'Nominal GDP of Asian Countries (2010)',
|
83
|
+
# :text_anchor => 'middle')
|
84
|
+
# chart.load_data(reader)
|
85
|
+
# chart.save('asian_gdp.svg')
|
86
|
+
# @see LineChart
|
87
|
+
# @see ArrayReader
|
88
|
+
# @since 0.0.0
|
25
89
|
class PieChart < Base
|
26
90
|
include Legend
|
27
91
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
92
|
+
# Returns the container element which body of chart is drawn on.
|
93
|
+
# @return [Shape::ShapeGroup] the container element which chart parts is
|
94
|
+
# drawn on
|
95
|
+
attr_reader :chart_canvas
|
96
|
+
|
97
|
+
# Returns the container element which data labels is drawn on.
|
98
|
+
# @return [Shape::ShapeGroup] the container element which chart parts is
|
99
|
+
# drawn on
|
100
|
+
attr_reader :data_label_canvas
|
101
|
+
|
102
|
+
# Returns the container element which legend is drawn on.
|
103
|
+
# @return [Shape::ShapeGroup] the container element which chart parts is
|
104
|
+
# drawn on
|
105
|
+
attr_reader :legend_canvas
|
106
|
+
|
107
|
+
# Returns or sets the center point of the pie chart.
|
108
|
+
opt_accessor :center_point, :type => :point, :default_method => :default_center_point
|
109
|
+
|
110
|
+
# Returns or sets the x-axis radius of the pie chart.
|
111
|
+
opt_accessor :chart_radius_x, :type => :length, :default_method => :default_chart_radius_x
|
112
|
+
|
113
|
+
# Returns or sets the y-axis radius of the pie chart.
|
114
|
+
opt_accessor :chart_radius_y, :type => :length, :default_method => :default_chart_radius_y
|
115
|
+
|
116
|
+
# Returns or sets the ratio of inner radius to outer radius of the
|
117
|
+
# doughnut chart. The value of +inner_radius+ should be a positive number
|
118
|
+
# or zero less than 1.0. Defalt to 0.0 (that means that chart is not
|
119
|
+
# doughnut).
|
120
|
+
opt_accessor :inner_radius, :type => :float, :default => 0.0, :range => 0.0 ... 1.0
|
121
|
+
|
122
|
+
# Returns or sets whether the chart is made three-dimensional. Defalt to
|
123
|
+
# false.
|
124
|
+
opt_accessor :represent_3d, :type => :boolean
|
125
|
+
|
126
|
+
# Returns or sets the three-demenal setting hash.
|
127
|
+
# This attribute is valid if the +respond_3d+ attribute equals true.
|
128
|
+
# The hash includes the following key:
|
129
|
+
# [+:dy+] ({Length}) the thickness of the pie
|
130
|
+
opt_accessor :_3d_settings, :type => :hash, :default => {}, :keys => [:dy], :item_type => :length
|
131
|
+
|
132
|
+
# Returns or sets specific colors for the slices.
|
133
|
+
opt_accessor :chart_colors, :type => :array, :item_type => :color
|
134
|
+
|
135
|
+
# Returns or sets the color of the outline of the slices.
|
136
|
+
opt_accessor :chart_stroke_color, :type => :color
|
137
|
+
|
138
|
+
# Returns or sets the width of the outline of the slices. Default to 1.0.
|
139
|
+
opt_accessor :chart_stroke_width, :type => :float, :default => 1.0
|
140
|
+
|
141
|
+
# Returns or sets the array of the ratio of the distance which the slices
|
142
|
+
# are moved from the center to the outside.
|
143
|
+
opt_accessor :moved_elements, :type => :array, :item_type => :float
|
144
|
+
|
145
|
+
# Returns or sets the CSS class of the pie area.
|
40
146
|
opt_accessor :pie_css_class, :type => :string
|
41
|
-
|
147
|
+
|
148
|
+
# Returns or sets whether the data labels are shown. Defalt to true.
|
149
|
+
opt_accessor :show_data_label, :type => :boolean, :default => true
|
150
|
+
|
151
|
+
# Returns or sets the CSS class of the data labels.
|
42
152
|
opt_accessor :data_label_css_class, :type => :string
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
153
|
+
|
154
|
+
# Returns or sets the position of the data labels. Zero means the data
|
155
|
+
# labels are shown at the center point, and 1.0 means they are shown on
|
156
|
+
# the circumference of the pie. Default to 0.8.
|
157
|
+
opt_accessor :data_label_position, :type => :float, :default => 0.8
|
158
|
+
|
159
|
+
# Returns or sets the font of the data labels.
|
160
|
+
opt_accessor :data_label_font, :type => :font
|
161
|
+
|
162
|
+
# Returns or sets the format string of the data labels. Default to <tt>"{?name}"</tt>.
|
163
|
+
opt_accessor :data_label_format, :type => :string, :default => "{?name}"
|
164
|
+
|
165
|
+
# Returns or sets the value to control showing the data labels. If the
|
166
|
+
# slice's percentage of the pie is less than this value, its label is not
|
167
|
+
# shown. Default to 0.0 (it means all the labels are shown).
|
168
|
+
opt_accessor :hide_data_label_ratio, :type => :float, :default => 0.0
|
169
|
+
|
170
|
+
# Returns or sets whether the baloons are shown when the mouse is over the
|
171
|
+
# slices. Defalt to true.
|
47
172
|
opt_accessor :show_baloon, :type => :boolean, :default => true
|
173
|
+
|
174
|
+
# Returns or sets the font of the baloons.
|
48
175
|
opt_accessor :baloon_font, :type => :font
|
49
|
-
|
176
|
+
|
177
|
+
# Returns or sets the position of the baloons. Zero means the baloons are
|
178
|
+
# shown at the center point, and 1.0 means they are shown on the
|
179
|
+
# circumference of the pie. Default to 0.8.
|
180
|
+
opt_accessor :baloon_position, :type => :float, :default => 0.8
|
181
|
+
|
182
|
+
# Returns or sets the format string of the baloons. Default to
|
183
|
+
# <tt>"{?name}\n{?value}"</tt>.
|
50
184
|
opt_accessor :baloon_format, :type => :string, :default => "{?name}\n{?value}"
|
185
|
+
|
186
|
+
# Returns or sets the hash of the vertical and horizontal paddings of the
|
187
|
+
# baloons. The hash includes the following key:
|
188
|
+
# [+:vertical+] ({Length}) the vertical padding of the baloons
|
189
|
+
# [+:horizontal+] ({Length}) the horizontal padding of the baloons
|
51
190
|
opt_accessor :baloon_padding, :type => :hash, :default => {}, :keys => [:vertical, :horizontal], :item_type => :length
|
191
|
+
|
192
|
+
# Returns or sets the radius of the circle used to round off the corners
|
193
|
+
# of the baloons.
|
52
194
|
opt_accessor :baloon_round, :type => :length, :default => 6
|
195
|
+
|
196
|
+
# Returns or sets the background color of the baloons. If this property
|
197
|
+
# has been set, the background color of all the baloons is the setting
|
198
|
+
# value. If +baloon_background_colors+ property has been set, the setting
|
199
|
+
# of +baloon_background_colors+ property is applied.
|
53
200
|
opt_accessor :baloon_background_color, :type => :color
|
201
|
+
|
202
|
+
# Returns or sets the background colors of the baloons of the each slices.
|
54
203
|
opt_accessor :baloon_background_colors, :type => :array, :item_type => :color
|
204
|
+
|
205
|
+
# Returns or sets the border color of the baloons. If this property has
|
206
|
+
# been set, the border color of all the baloons is the setting value. If
|
207
|
+
# +baloon_border_colors+ property has been set, the setting of
|
208
|
+
# +baloon_border_colors+ property is applied.
|
55
209
|
opt_accessor :baloon_border_color, :type => :color
|
210
|
+
|
211
|
+
# Returns or sets the border colors of the baloons of the each slices.
|
56
212
|
opt_accessor :baloon_border_colors, :type => :array, :item_type => :color
|
213
|
+
|
214
|
+
# Returns or sets the border width of the baloons.
|
57
215
|
opt_accessor :baloon_border_width, :type => :length, :default => 2
|
216
|
+
|
217
|
+
# Returns or sets the CSS class of the baloons.
|
58
218
|
opt_accessor :baloon_css_class, :type => :string
|
219
|
+
|
220
|
+
# Returns or sets the duration of the animations.
|
59
221
|
opt_accessor :animation_duration, :type => :float, :default => 0.5
|
60
222
|
|
61
223
|
def back_translate_value
|
@@ -78,20 +240,20 @@ module DYI #:nodoc:
|
|
78
240
|
|
79
241
|
private
|
80
242
|
|
81
|
-
def default_center_point
|
243
|
+
def default_center_point
|
82
244
|
margin = [width - chart_radius_x * 2, height - chart_radius_y * 2].min.quo(2)
|
83
245
|
Coordinate.new(margin + chart_radius_x, margin + chart_radius_y)
|
84
246
|
end
|
85
247
|
|
86
|
-
def default_chart_radius_x
|
248
|
+
def default_chart_radius_x
|
87
249
|
[width, height].min * 0.4
|
88
250
|
end
|
89
251
|
|
90
|
-
def default_chart_radius_y
|
252
|
+
def default_chart_radius_y
|
91
253
|
represent_3d? ? chart_radius_x.quo(2) : chart_radius_x
|
92
254
|
end
|
93
255
|
|
94
|
-
def default_legend_point
|
256
|
+
def default_legend_point
|
95
257
|
if width - chart_radius_x * 2 < height - chart_radius_y * 2
|
96
258
|
Coordinate.new(width * 0.1, chart_radius_y * 2 + (width - chart_radius_x * 2) * 0.8)
|
97
259
|
else
|
@@ -99,11 +261,11 @@ module DYI #:nodoc:
|
|
99
261
|
end
|
100
262
|
end
|
101
263
|
|
102
|
-
def default_legend_format
|
264
|
+
def default_legend_format
|
103
265
|
"{?name}\t{?percent}"
|
104
266
|
end
|
105
267
|
|
106
|
-
def create_vector_image
|
268
|
+
def create_vector_image
|
107
269
|
super
|
108
270
|
if represent_3d?
|
109
271
|
brush = Drawing::ColumnBrush.new(back_translate_value.merge(chart_stroke_color ? {:stroke_width => chart_stroke_width, :stroke => chart_stroke_color} : {}))
|
@@ -168,7 +330,7 @@ module DYI #:nodoc:
|
|
168
330
|
end
|
169
331
|
end
|
170
332
|
|
171
|
-
def draw_chart(brush, record, accumulation, total_value, index)
|
333
|
+
def draw_chart(brush, record, accumulation, total_value, index)
|
172
334
|
canvas = Shape::ShapeGroup.draw_on(@chart_canvas)
|
173
335
|
attrs = {}
|
174
336
|
if data.has_field?(:css_class) && (css_class = record.css_class)
|
@@ -231,7 +393,7 @@ module DYI #:nodoc:
|
|
231
393
|
text = Drawing::Pen.black_pen(:font => baloon_font, :opacity => 0.0).draw_text(
|
232
394
|
@data_label_canvas,
|
233
395
|
center_point + baloon_point,
|
234
|
-
format_string(
|
396
|
+
format_string(baloon_format, record, total_value),
|
235
397
|
baloon_options)
|
236
398
|
text.add_painting_animation(:to => {:opacity => 1},
|
237
399
|
:duration => animation_duration,
|
@@ -321,6 +483,7 @@ module DYI #:nodoc:
|
|
321
483
|
end
|
322
484
|
end
|
323
485
|
|
486
|
+
# @since 1.0.0
|
324
487
|
def format_string(format, record, total_value)
|
325
488
|
format = format.gsub(/\A\{!(\w)\}/, '')
|
326
489
|
format.gsub(/\{\?((?![0-9])\w+)(:[^}]*)?\}/){|m|
|