dyi 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|