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.
- data/COPYING +674 -0
- data/README +28 -0
- data/examples/class_diagram.rb +151 -0
- data/examples/data/03311056.xlsx +0 -0
- data/examples/data/currency.xlsx +0 -0
- data/examples/data/money.csv +12 -0
- data/examples/line_and_bar.rb +26 -0
- data/examples/line_chart.rb +30 -0
- data/examples/logo.rb +68 -0
- data/examples/pie_chart.rb +19 -0
- data/examples/simple_shapes.rb +15 -0
- data/lib/dyi.rb +49 -0
- data/lib/dyi/chart.rb +34 -0
- data/lib/dyi/chart/array_reader.rb +136 -0
- data/lib/dyi/chart/base.rb +580 -0
- data/lib/dyi/chart/csv_reader.rb +93 -0
- data/lib/dyi/chart/excel_reader.rb +100 -0
- data/lib/dyi/chart/line_chart.rb +468 -0
- data/lib/dyi/chart/pie_chart.rb +141 -0
- data/lib/dyi/chart/table.rb +201 -0
- data/lib/dyi/color.rb +218 -0
- data/lib/dyi/coordinate.rb +224 -0
- data/lib/dyi/drawing.rb +32 -0
- data/lib/dyi/drawing/canvas.rb +100 -0
- data/lib/dyi/drawing/clipping.rb +61 -0
- data/lib/dyi/drawing/color_effect.rb +118 -0
- data/lib/dyi/drawing/filter.rb +74 -0
- data/lib/dyi/drawing/pen.rb +231 -0
- data/lib/dyi/drawing/pen_3d.rb +270 -0
- data/lib/dyi/font.rb +132 -0
- data/lib/dyi/formatter.rb +36 -0
- data/lib/dyi/formatter/base.rb +245 -0
- data/lib/dyi/formatter/emf_formatter.rb +253 -0
- data/lib/dyi/formatter/eps_formatter.rb +397 -0
- data/lib/dyi/formatter/svg_formatter.rb +260 -0
- data/lib/dyi/formatter/svg_reader.rb +113 -0
- data/lib/dyi/formatter/xaml_formatter.rb +317 -0
- data/lib/dyi/length.rb +399 -0
- data/lib/dyi/matrix.rb +122 -0
- data/lib/dyi/painting.rb +177 -0
- data/lib/dyi/shape.rb +1332 -0
- data/lib/dyi/svg_element.rb +149 -0
- data/lib/dyi/type.rb +104 -0
- data/lib/ironruby.rb +326 -0
- data/lib/util.rb +231 -0
- data/test/path_command_test.rb +217 -0
- data/test/test_length.rb +91 -0
- metadata +114 -0
@@ -0,0 +1,141 @@
|
|
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 PieChart < Base
|
26
|
+
include Legend
|
27
|
+
attr_reader :chart_canvas, :data_label_canvas, :legend_canvas
|
28
|
+
|
29
|
+
opt_accessor :center_point, {:type => :point, :default_method => :default_center_point}
|
30
|
+
opt_accessor :chart_radius_x, {:type => :length, :default_method => :default_chart_radius_x}
|
31
|
+
opt_accessor :chart_radius_y, {:type => :length, :default_method => :default_chart_radius_y}
|
32
|
+
opt_accessor :represent_3d, {:type => :boolean}
|
33
|
+
opt_accessor :_3d_settings, {:type => :hash, :default => {}, :keys => [:dy], :item_type => :float}
|
34
|
+
opt_accessor :chart_colors, {:type => :array, :item_type => :color}
|
35
|
+
opt_accessor :chart_stroke_color, {:type => :color}
|
36
|
+
opt_accessor :chart_stroke_width, {:type => :float, :default => 1}
|
37
|
+
opt_accessor :moved_elements, {:type => :array, :item_type => :float}
|
38
|
+
opt_accessor :show_data_label, {:type => :boolean, :default => true}
|
39
|
+
opt_accessor :data_label_position, {:type => :float, :default => 0.8}
|
40
|
+
opt_accessor :data_label_font, {:type => :font}
|
41
|
+
opt_accessor :data_label_format, {:type => :string, :default => "{name}\n{value}"}
|
42
|
+
opt_accessor :hide_data_label_ratio, {:type => :float, :default => 0.00}
|
43
|
+
|
44
|
+
def back_translate_value
|
45
|
+
{:dy => (Length.new_or_nil(_3d_settings[:dy]) || chart_radius_y.quo(2))}
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def default_center_point #:nodoc:
|
51
|
+
Coordinate.new(coordinate = ([width, height].min).quo(2), coordinate)
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_chart_radius_x #:nodoc:
|
55
|
+
[[width, height].min / 2 - Length.new(32), [width, height].min * 0.4].max
|
56
|
+
end
|
57
|
+
|
58
|
+
def default_chart_radius_y #:nodoc:
|
59
|
+
represent_3d? ? chart_radius_x.quo(2) : chart_radius_x
|
60
|
+
end
|
61
|
+
|
62
|
+
def default_csv_format #:nodoc:
|
63
|
+
[:$name, 0, :$color]
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_legend_point #:nodoc:
|
67
|
+
Coordinate.new(width < height ? [width * 0.1, width] : [height, height * 0.1])
|
68
|
+
end
|
69
|
+
|
70
|
+
def default_legend_format #:nodoc:
|
71
|
+
"{name}\t{percent}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_vector_image #:nodoc:
|
75
|
+
if represent_3d?
|
76
|
+
brush = Drawing::ColumnBrush.new(back_translate_value.merge(chart_stroke_color ? {:stroke_width => chart_stroke_width, :stroke => chart_stroke_color} : {}))
|
77
|
+
else
|
78
|
+
brush = Drawing::Brush.new(chart_stroke_color ? {:stroke_width => chart_stroke_width, :stroke => chart_stroke_color, :stroke_miterlimit => chart_stroke_width / 2.0} : {})
|
79
|
+
end
|
80
|
+
@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)}
|
84
|
+
accumulation = 0.0
|
85
|
+
accumulations = []
|
86
|
+
stop_index = -1
|
87
|
+
data.column_values(0).each_with_index do |value, i|
|
88
|
+
accumulations.push(accumulation)
|
89
|
+
if value && total_value > (accumulation + value) * 2 && value != 0.0
|
90
|
+
# brush.color = data[:$color] && data[:$color][i] || chart_color(i)
|
91
|
+
brush.color = chart_color(i)
|
92
|
+
name = data.row_title(i)
|
93
|
+
draw_chart(brush, name, value, accumulation, total_value, i)
|
94
|
+
stop_index = i
|
95
|
+
end
|
96
|
+
accumulation += value if value
|
97
|
+
end
|
98
|
+
(data.column_values(0).size - 1).downto(stop_index + 1) do |i|
|
99
|
+
value = data.column_values(0)[i]
|
100
|
+
if value && value != 0.0
|
101
|
+
# brush.color = data[:$color] && data[:$color][i] || chart_color(i)
|
102
|
+
brush.color = chart_color(i)
|
103
|
+
name = data.row_title(i)
|
104
|
+
draw_chart(brush, name, value, accumulations[i], total_value, i)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
# draw_legend(data.row_titles, nil, nil, data[:$color])
|
108
|
+
draw_legend(data.row_titles, nil, nil, nil)
|
109
|
+
end
|
110
|
+
|
111
|
+
def draw_chart(brush, name, value, accumulation, total_value, index) #:nodoc:
|
112
|
+
canvas = Shape::ShapeGroup.draw_on(@chart_canvas)
|
113
|
+
brush.draw_sector(
|
114
|
+
canvas,
|
115
|
+
center_point,
|
116
|
+
chart_radius_x,
|
117
|
+
chart_radius_y,
|
118
|
+
accumulation * 360.0 / total_value - 90,
|
119
|
+
value * 360.0 / total_value)
|
120
|
+
|
121
|
+
if moved_elements && (dr = moved_elements[index])
|
122
|
+
canvas.translate(
|
123
|
+
chart_radius_x * dr * Math.cos(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI),
|
124
|
+
chart_radius_y * dr * Math.sin(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI))
|
125
|
+
end
|
126
|
+
|
127
|
+
ratio = value.to_f.quo(total_value)
|
128
|
+
if show_data_label?
|
129
|
+
legend_point = Coordinate.new(
|
130
|
+
chart_radius_x * (data_label_position + (dr || 0)) * Math.cos(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI),
|
131
|
+
chart_radius_y * (data_label_position + (dr || 0)) * Math.sin(((accumulation * 2.0 + value) / total_value - 0.5) * Math::PI))
|
132
|
+
Drawing::Pen.black_pen(:font => legend_font).draw_text(
|
133
|
+
@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', :font => data_label_font)
|
137
|
+
end if hide_data_label_ratio < ratio
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,201 @@
|
|
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 Table < Base
|
26
|
+
attr_reader :frame_canvas, :data_canvas
|
27
|
+
|
28
|
+
def font
|
29
|
+
@options[:font]
|
30
|
+
end
|
31
|
+
|
32
|
+
def font=(font)
|
33
|
+
if font && !font.empty?
|
34
|
+
@options[:font] = Font.new(font)
|
35
|
+
else
|
36
|
+
@options.delete(:font)
|
37
|
+
end
|
38
|
+
font
|
39
|
+
end
|
40
|
+
|
41
|
+
def row_height
|
42
|
+
@options[:row_height] ||= (font && font.draw_size || Font::DEFAULT_SIZE) * 1.4
|
43
|
+
end
|
44
|
+
|
45
|
+
def row_height=(height)
|
46
|
+
if heights
|
47
|
+
@options[:row_height] = Length.new(height)
|
48
|
+
else
|
49
|
+
@options.delete(:row_height)
|
50
|
+
end
|
51
|
+
point
|
52
|
+
end
|
53
|
+
|
54
|
+
def column_widths
|
55
|
+
@options[:column_widths]
|
56
|
+
end
|
57
|
+
|
58
|
+
def column_widths=(widths)
|
59
|
+
if widths.kind_of?(Array)
|
60
|
+
@options[:column_widths] = widths.map {|width| Length.new_or_nil(width)}
|
61
|
+
elsif widths
|
62
|
+
@options[:column_widths] = Length.new(widths)
|
63
|
+
else
|
64
|
+
@options.delete(:column_widths)
|
65
|
+
end
|
66
|
+
point
|
67
|
+
end
|
68
|
+
|
69
|
+
def column_width(index)
|
70
|
+
case column_widths
|
71
|
+
when Length then column_widths
|
72
|
+
when Array then column_widths[index]
|
73
|
+
else width / series.size
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def table_width
|
78
|
+
series.inject(Length.new(0)) do |width, i|
|
79
|
+
width + column_width(i)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def table_height
|
84
|
+
row_height * data[series.first].size
|
85
|
+
end
|
86
|
+
|
87
|
+
def horizontal_positions
|
88
|
+
@options[:horizontal_positions]
|
89
|
+
end
|
90
|
+
|
91
|
+
def horizontal_positions=(positions)
|
92
|
+
if positions && !positions.empty?
|
93
|
+
@options[:horizontal_positions] = positions
|
94
|
+
else
|
95
|
+
@options.delete(:horizontal_positions)
|
96
|
+
end
|
97
|
+
positions
|
98
|
+
end
|
99
|
+
|
100
|
+
def horizontal_position(index)
|
101
|
+
@options[:horizontal_positions] && @options[:horizontal_positions][index]
|
102
|
+
end
|
103
|
+
|
104
|
+
def column_colors
|
105
|
+
@options[:column_colors]
|
106
|
+
end
|
107
|
+
|
108
|
+
def column_colors=(colors)
|
109
|
+
if colors && !colors.empty?
|
110
|
+
@options[:column_colors] = colors
|
111
|
+
else
|
112
|
+
@options.delete(:column_colors)
|
113
|
+
end
|
114
|
+
colors
|
115
|
+
end
|
116
|
+
=begin
|
117
|
+
def precedence_attribute
|
118
|
+
@options[:precedence] || :column
|
119
|
+
end
|
120
|
+
|
121
|
+
def precedence=(row_or_column)
|
122
|
+
case row_or_column.to_sym
|
123
|
+
when :column then @options[:precedence] = :column
|
124
|
+
when :row then @options[:precedence] = :row
|
125
|
+
when nil, false then @options.delete(:precedence)
|
126
|
+
else raise ArgumentError, "\"#{row_or_column}\" is invalid value"
|
127
|
+
end
|
128
|
+
row_or_column
|
129
|
+
end
|
130
|
+
=end
|
131
|
+
private
|
132
|
+
|
133
|
+
def options #:nodoc:
|
134
|
+
@options
|
135
|
+
end
|
136
|
+
|
137
|
+
def default_csv_format #:nodoc:
|
138
|
+
[0, 1]
|
139
|
+
end
|
140
|
+
|
141
|
+
def convert_data(value) #:nodoc:
|
142
|
+
value.strip
|
143
|
+
end
|
144
|
+
|
145
|
+
def create_vector_image #:nodoc:
|
146
|
+
pen = Drawing::Pen.new
|
147
|
+
@frame_canvas = Shape::ShapeGroup.draw_on(@canvas)
|
148
|
+
@data_canvas = Shape::ShapeGroup.draw_on(@canvas)
|
149
|
+
draw_frame(pen)
|
150
|
+
draw_data(pen)
|
151
|
+
end
|
152
|
+
|
153
|
+
def draw_frame(pen) #:nodoc:
|
154
|
+
w = table_width
|
155
|
+
h = table_height
|
156
|
+
|
157
|
+
draw_column_colors
|
158
|
+
|
159
|
+
pen.draw_rectangle(@frame_canvas, [0, 0], w, h)
|
160
|
+
(1...data[series.first].size).each do |i|
|
161
|
+
pen.draw_line(@frame_canvas, [0, row_height * i], [w, row_height * i])
|
162
|
+
end
|
163
|
+
series.inject(Length.new(0)) do |x, j|
|
164
|
+
pen.draw_line(@frame_canvas, [x, 0], [x, h]) if x.nonzero?
|
165
|
+
x + column_width(j)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def draw_column_colors #:nodoc:
|
170
|
+
if column_colors
|
171
|
+
brush = Drawing::Brush.new
|
172
|
+
h = table_height
|
173
|
+
|
174
|
+
series.inject(Length.new(0)) do |x, j|
|
175
|
+
if column_colors[j]
|
176
|
+
brush.color = Color.new(column_colors[j])
|
177
|
+
brush.draw_rectangle(@frame_canvas, [x, 0], column_width(j), h)
|
178
|
+
x + column_width(j)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def draw_data(pen) #:nodoc:
|
185
|
+
cell_margin = (row_height - (font && font.draw_size || Font::DEFAULT_SIZE)) / 2
|
186
|
+
series.inject(cell_margin) do |x, column_index|
|
187
|
+
y = row_height - cell_margin
|
188
|
+
data[column_index].each do |value|
|
189
|
+
case horizontal_position(column_index)
|
190
|
+
when 'middle' then pen.draw_text(@data_canvas, [x + column_width(column_index) / 2 - cell_margin, y], value, :text_anchor=>'middle')
|
191
|
+
when 'end' then pen.draw_text(@data_canvas, [x + column_width(column_index) - cell_margin * 2, y], value, :text_anchor=>'end')
|
192
|
+
else pen.draw_text(@data_canvas, [x, y], value)
|
193
|
+
end
|
194
|
+
y += row_height
|
195
|
+
end
|
196
|
+
x + column_width(column_index)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
data/lib/dyi/color.rb
ADDED
@@ -0,0 +1,218 @@
|
|
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
|
+
|
24
|
+
class Color
|
25
|
+
@@named_colors = {'aliceblue'=>[240,248,255],'antiquewhite'=>[250,235,215],'aqua'=>[0,255,255],'aquamarine'=>[127,255,212],'azure'=>[240,255,255],'beige'=>[245,245,220],'bisque'=>[255,228,196],'black'=>[0,0,0],'blanchedalmond'=>[255,235,205],'blue'=>[0,0,255],'blueviolet'=>[138,43,226],'brown'=>[165,42,42],'burlywood'=>[222,184,135],'cadetblue'=>[95,158,160],'chartreuse'=>[127,255,0],'chocolate'=>[210,105,30],'coral'=>[255,127,80],'cornflowerblue'=>[100,149,237],'cornsilk'=>[255,248,220],'crimson'=>[220,20,60],'cyan'=>[0,255,255],'darkblue'=>[0,0,139],'darkcyan'=>[0,139,139],'darkgoldenrod'=>[184,134,11],'darkgray'=>[169,169,169],'darkgreen'=>[0,100,0],'darkgrey'=>[169,169,169],'darkkhaki'=>[189,183,107],'darkmagenta'=>[139,0,139],'darkolivegreen'=>[85,107,47],'darkorange'=>[255,140,0],'darkorchid'=>[153,50,204],'darkred'=>[139,0,0],'darksalmon'=>[233,150,122],'darkseagreen'=>[143,188,143],'darkslateblue'=>[72,61,139],'darkslategray'=>[47,79,79],'darkslategrey'=>[47,79,79],'darkturquoise'=>[0,206,209],'darkviolet'=>[148,0,211],'deeppink'=>[255,20,147],'deepskyblue'=>[0,191,255],'dimgray'=>[105,105,105],'dimgrey'=>[105,105,105],'dodgerblue'=>[30,144,255],'firebrick'=>[178,34,34],'floralwhite'=>[255,250,240],'forestgreen'=>[34,139,34],'fuchsia'=>[255,0,255],'gainsboro'=>[220,220,220],'ghostwhite'=>[248,248,255],'gold'=>[255,215,0],'goldenrod'=>[218,165,32],'gray'=>[128,128,128],'grey'=>[128,128,128],'green'=>[0,128,0],'greenyellow'=>[173,255,47],'honeydew'=>[240,255,240],'hotpink'=>[255,105,180],'indianred'=>[205,92,92],'indigo'=>[75,0,130],'ivory'=>[255,255,240],'khaki'=>[240,230,140],'lavender'=>[230,230,250],'lavenderblush'=>[255,240,245],'lawngreen'=>[124,252,0],'lemonchiffon'=>[255,250,205],'lightblue'=>[173,216,230],'lightcoral'=>[240,128,128],'lightcyan'=>[224,255,255],'lightgoldenrodyellow'=>[250,250,210],'lightgray'=>[211,211,211],'lightgreen'=>[144,238,144],'lightgrey'=>[211,211,211],'lightpink'=>[255,182,193],'lightsalmon'=>[255,160,122],'lightseagreen'=>[32,178,170],'lightskyblue'=>[135,206,250],'lightslategray'=>[119,136,153],'lightslategrey'=>[119,136,153],'lightsteelblue'=>[176,196,222],'lightyellow'=>[255,255,224],'lime'=>[0,255,0],'limegreen'=>[50,205,50],'linen'=>[250,240,230],'magenta'=>[255,0,255],'maroon'=>[128,0,0],'mediumaquamarine'=>[102,205,170],'mediumblue'=>[0,0,205],'mediumorchid'=>[186,85,211],'mediumpurple'=>[147,112,219],'mediumseagreen'=>[60,179,113],'mediumslateblue'=>[123,104,238],'mediumspringgreen'=>[0,250,154],'mediumturquoise'=>[72,209,204],'mediumvioletred'=>[199,21,133],'midnightblue'=>[25,25,112],'mintcream'=>[245,255,250],'mistyrose'=>[255,228,225],'moccasin'=>[255,228,181],'navajowhite'=>[255,222,173],'navy'=>[0,0,128],'oldlace'=>[253,245,230],'olive'=>[128,128,0],'olivedrab'=>[107,142,35],'orange'=>[255,165,0],'orangered'=>[255,69,0],'orchid'=>[218,112,214],'palegoldenrod'=>[238,232,170],'palegreen'=>[152,251,152],'paleturquoise'=>[175,238,238],'palevioletred'=>[219,112,147],'papayawhip'=>[255,239,213],'peachpuff'=>[255,218,185],'peru'=>[205,133,63],'pink'=>[255,192,203],'plum'=>[221,160,221],'powderblue'=>[176,224,230],'purple'=>[128,0,128],'red'=>[255,0,0],'rosybrown'=>[188,143,143],'royalblue'=>[65,105,225],'saddlebrown'=>[139,69,19],'salmon'=>[250,128,114],'sandybrown'=>[244,164,96],'seagreen'=>[46,139,87],'seashell'=>[255,245,238],'sienna'=>[160,82,45],'silver'=>[192,192,192],'skyblue'=>[135,206,235],'slateblue'=>[106,90,205],'slategray'=>[112,128,144],'slategrey'=>[112,128,144],'snow'=>[255,250,250],'springgreen'=>[0,255,127],'steelblue'=>[70,130,180],'tan'=>[210,180,140],'teal'=>[0,128,128],'thistle'=>[216,191,216],'tomato'=>[255,99,71],'turquoise'=>[64,224,208],'violet'=>[238,130,238],'wheat'=>[245,222,179],'white'=>[255,255,255],'whitesmoke'=>[245,245,245],'yellow'=>[255,255,0],'yellowgreen'=>[154,205,50]}
|
26
|
+
@@default_format = ['rgb(%d,%d,%d)', false]
|
27
|
+
attr_reader :name
|
28
|
+
|
29
|
+
# :call-seq:
|
30
|
+
# new (color_string)
|
31
|
+
# new (rgb_array)
|
32
|
+
# new (rgb_hash)
|
33
|
+
# new (red, green, blue)
|
34
|
+
# new (color)
|
35
|
+
def initialize(*args)
|
36
|
+
case args.size
|
37
|
+
when 1 then color = args.first
|
38
|
+
when 3 then color = args
|
39
|
+
else raise ArgumentError, "wrong number of arguments (#{args.size} for #{args.size == 0 ? 1 : 3})"
|
40
|
+
end
|
41
|
+
|
42
|
+
case color
|
43
|
+
when Color
|
44
|
+
@r = color.red
|
45
|
+
@g = color.green
|
46
|
+
@b = color.blue
|
47
|
+
@name = color.name
|
48
|
+
when Array
|
49
|
+
raise ArgumentError, "illegal size of Array: #{color.size}" if color.size != 3
|
50
|
+
@r, @g, @b = color.map {|c| c.to_i & 0xff}
|
51
|
+
@name = nil
|
52
|
+
when Hash
|
53
|
+
@r, @g, @b = [:r, :g, :b].map {|key| color[key].to_i & 0xff}
|
54
|
+
@name = nil
|
55
|
+
when String, Symbol
|
56
|
+
color = color.to_s
|
57
|
+
if color =~ /^\s*#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})\s*$/ # #ffffff
|
58
|
+
@r, @g, @b = [$1, $2, $3].map {|s| s.hex}
|
59
|
+
@name = nil
|
60
|
+
elsif color =~ /^\s*#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\s*$/ # #fff
|
61
|
+
@r, @g, @b = [$1, $2, $3].map {|s| (s * 2).hex}
|
62
|
+
@name = nil
|
63
|
+
elsif color =~ /^\s*rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*$/ # rgb(255,255,255)
|
64
|
+
@r, @g, @b = [$1, $2, $3].map {|s| s.to_i & 0xff}
|
65
|
+
@name = nil
|
66
|
+
elsif color =~ /^\s*rgb\s*\(\s*(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)\s*$/ # rgb(100%,100%,100%)
|
67
|
+
@r, @g, @b = [$1, $2, $3].map {|s| (0xff * s.to_f / 100).to_i & 0xff}
|
68
|
+
@name = nil
|
69
|
+
else
|
70
|
+
raise ArgumentError, "argument is empty" if color.size == 0
|
71
|
+
raise ArgumentError, "`#{color}' is unknown color" unless rgb = @@named_colors[color.downcase]
|
72
|
+
@r, @g, @b = rgb
|
73
|
+
@name = color.downcase
|
74
|
+
end
|
75
|
+
else
|
76
|
+
raise TypeError, "#{color.class} can't be coerced into #{self.class}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def ==(other)
|
81
|
+
return false unless other.instance_of?(self.class)
|
82
|
+
@r == other.red && @g == other.green && @b = other.blue
|
83
|
+
end
|
84
|
+
|
85
|
+
def eql?(other)
|
86
|
+
return false unless self.class == other.class
|
87
|
+
self == other
|
88
|
+
end
|
89
|
+
|
90
|
+
def hash #:nodoc:
|
91
|
+
(@r << 16) + (@g << 8) + @b
|
92
|
+
end
|
93
|
+
|
94
|
+
def named?
|
95
|
+
not @name.nil?
|
96
|
+
end
|
97
|
+
|
98
|
+
def red
|
99
|
+
@r
|
100
|
+
end
|
101
|
+
|
102
|
+
def green
|
103
|
+
@g
|
104
|
+
end
|
105
|
+
|
106
|
+
def blue
|
107
|
+
@b
|
108
|
+
end
|
109
|
+
|
110
|
+
def r_red
|
111
|
+
@r.quo(0.255).floor.quo(1000.0)
|
112
|
+
end
|
113
|
+
|
114
|
+
def r_green
|
115
|
+
@g.quo(0.255).floor.quo(1000.0)
|
116
|
+
end
|
117
|
+
|
118
|
+
def r_blue
|
119
|
+
@b.quo(0.255).floor.quo(1000.0)
|
120
|
+
end
|
121
|
+
|
122
|
+
def merge(other, ratio)
|
123
|
+
raise ArgumentError, "ratio should be number between 0 and 1" if ratio < 0 || 1 < ratio
|
124
|
+
other = self.class.new(other)
|
125
|
+
r = @r * (1.0 - ratio) + other.red * ratio
|
126
|
+
g = @g * (1.0 - ratio) + other.green * ratio
|
127
|
+
b = @b * (1.0 - ratio) + other.blue * ratio
|
128
|
+
self.class.new(r,g,b)
|
129
|
+
end
|
130
|
+
|
131
|
+
def color?
|
132
|
+
true
|
133
|
+
end
|
134
|
+
|
135
|
+
# :call-seq:
|
136
|
+
# to_s ()
|
137
|
+
# to_s (fmt, disp_ratio=false)
|
138
|
+
def to_s(*args)
|
139
|
+
args[0] = self.class.check_format(args[0]) if args[0]
|
140
|
+
args = @@default_format if args.empty?
|
141
|
+
args[0] % (args[1] ? [r_red, r_green, r_blue] : [@r,@g,@b])
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_s16(opacity=nil)
|
145
|
+
opacity ? '#%02X%02X%02X%02X' % [0xff && (0xff * opacity), @r,@g,@b] : to_s('#%02X%02X%02X')
|
146
|
+
end
|
147
|
+
|
148
|
+
class << self
|
149
|
+
|
150
|
+
public
|
151
|
+
|
152
|
+
def new(*args) #:nodoc:
|
153
|
+
if args.size == 1
|
154
|
+
case args.first
|
155
|
+
when self
|
156
|
+
return args.first
|
157
|
+
when String, Symbol
|
158
|
+
if color = named_color(args.first)
|
159
|
+
return color
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
super
|
164
|
+
end
|
165
|
+
|
166
|
+
def new_or_nil(*args)
|
167
|
+
(args.size == 1 && args.first.nil?) ? nil : new(*args)
|
168
|
+
end
|
169
|
+
|
170
|
+
def method_missing(name, *args) #:nodoc:
|
171
|
+
if args.size == 0 && color = named_color(name)
|
172
|
+
instance_eval %{
|
173
|
+
def self.#{name}
|
174
|
+
@#{name}
|
175
|
+
end
|
176
|
+
}
|
177
|
+
return color
|
178
|
+
end
|
179
|
+
super
|
180
|
+
end
|
181
|
+
|
182
|
+
def set_default_format(fmt, disp_ratio=false)
|
183
|
+
org_format = @@default_format
|
184
|
+
@@default_format = [check_format(fmt), disp_ratio]
|
185
|
+
if block_given?
|
186
|
+
yield
|
187
|
+
@@default_format = org_format
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def default_format
|
192
|
+
@@default_format
|
193
|
+
end
|
194
|
+
|
195
|
+
def check_format(fmt) #:nodoc:
|
196
|
+
begin
|
197
|
+
(fmt = fmt.to_s) % [0.0, 0.0, 0.0]
|
198
|
+
fmt
|
199
|
+
rescue
|
200
|
+
raise ArgumentError, "wrong format: `#{fmt}'"
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
private
|
205
|
+
|
206
|
+
def named_color(name) #:nodoc:
|
207
|
+
name = name.to_s.downcase
|
208
|
+
color = instance_variable_get('@' + name) rescue (return nil)
|
209
|
+
return color if color
|
210
|
+
if @@named_colors[name]
|
211
|
+
color = allocate
|
212
|
+
color.__send__(:initialize, name)
|
213
|
+
instance_variable_set('@' + name, color)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|