svg-graph19 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,444 +0,0 @@
1
- require 'SVG/Graph/Graph'
2
-
3
- module SVG
4
- module Graph
5
- # === Create presentation quality SVG line graphs easily
6
- #
7
- # = Synopsis
8
- #
9
- # require 'SVG/Graph/Line'
10
- #
11
- # fields = %w(Jan Feb Mar);
12
- # data_sales_02 = [12, 45, 21]
13
- # data_sales_03 = [15, 30, 40]
14
- #
15
- # graph = SVG::Graph::Line.new({
16
- # :height => 500,
17
- # :width => 300,
18
- # :fields => fields,
19
- # })
20
- #
21
- # graph.add_data({
22
- # :data => data_sales_02,
23
- # :title => 'Sales 2002',
24
- # })
25
- #
26
- # graph.add_data({
27
- # :data => data_sales_03,
28
- # :title => 'Sales 2003',
29
- # })
30
- #
31
- # print "Content-type: image/svg+xml\r\n\r\n";
32
- # print graph.burn();
33
- #
34
- # = Description
35
- #
36
- # This object aims to allow you to easily create high quality
37
- # SVG line graphs. You can either use the default style sheet
38
- # or supply your own. Either way there are many options which can
39
- # be configured to give you control over how the graph is
40
- # generated - with or without a key, data elements at each point,
41
- # title, subtitle etc.
42
- #
43
- # = Examples
44
- #
45
- # http://www.germane-software/repositories/public/SVG/test/single.rb
46
- #
47
- # = Notes
48
- #
49
- # The default stylesheet handles upto 10 data sets, if you
50
- # use more you must create your own stylesheet and add the
51
- # additional settings for the extra data sets. You will know
52
- # if you go over 10 data sets as they will have no style and
53
- # be in black.
54
- #
55
- # = See also
56
- #
57
- # * SVG::Graph::Graph
58
- # * SVG::Graph::BarHorizontal
59
- # * SVG::Graph::Bar
60
- # * SVG::Graph::Pie
61
- # * SVG::Graph::Plot
62
- # * SVG::Graph::TimeSeries
63
- #
64
- # == Author
65
- #
66
- # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
67
- #
68
- # Copyright 2004 Sean E. Russell
69
- # This software is available under the Ruby license[LICENSE.txt]
70
- #
71
- class Line < SVG::Graph::Graph
72
- # Show a small circle on the graph where the line
73
- # goes from one point to the next.
74
- attr_accessor :show_data_points
75
- # Accumulates each data set. (i.e. Each point increased by sum of
76
- # all previous series at same point). Default is 0, set to '1' to show.
77
- attr_accessor :stacked
78
- # Fill in the area under the plot if true
79
- attr_accessor :area_fill
80
-
81
- # The constructor takes a hash reference, fields (the names for each
82
- # field on the X axis) MUST be set, all other values are defaulted to
83
- # those shown above - with the exception of style_sheet which defaults
84
- # to using the internal style sheet.
85
- def initialize config
86
- raise "fields was not supplied or is empty" unless config[:fields] &&
87
- config[:fields].kind_of?(Array) &&
88
- config[:fields].length > 0
89
- super
90
- end
91
-
92
- # In addition to the defaults set in Graph::initialize, sets
93
- # [show_data_points] true
94
- # [show_data_values] true
95
- # [stacked] false
96
- # [area_fill] false
97
- def set_defaults
98
- init_with(
99
- :show_data_points => true,
100
- :show_data_values => true,
101
- :stacked => false,
102
- :area_fill => false
103
- )
104
-
105
- self.top_align = self.top_font = self.right_align = self.right_font = 1
106
- end
107
-
108
- protected
109
-
110
- def max_value
111
- max = 0
112
-
113
- if (stacked == true) then
114
- sums = Array.new(@config[:fields].length).fill(0)
115
-
116
- @data.each do |data|
117
- sums.each_index do |i|
118
- sums[i] += data[:data][i].to_f
119
- end
120
- end
121
-
122
- max = sums.max
123
- else
124
- max = @data.collect{|x| x[:data].max}.max
125
- end
126
-
127
- return max
128
- end
129
-
130
- def min_value
131
- min = 0
132
-
133
- if (min_scale_value.nil? == false) then
134
- min = min_scale_value
135
- elsif (stacked == true) then
136
- min = @data[-1][:data].min
137
- else
138
- min = @data.collect{|x| x[:data].min}.min
139
- end
140
-
141
- return min
142
- end
143
-
144
- def get_x_labels
145
- @config[:fields]
146
- end
147
-
148
- def calculate_left_margin
149
- super
150
- label_left = @config[:fields][0].length / 2 * font_size * 0.6
151
- @border_left = label_left if label_left > @border_left
152
- end
153
-
154
- def get_y_labels
155
- maxvalue = max_value
156
- minvalue = min_value
157
- range = maxvalue - minvalue
158
- top_pad = range == 0 ? 10 : range / 20.0
159
- scale_range = (maxvalue + top_pad) - minvalue
160
-
161
- scale_division = scale_divisions || (scale_range / 10.0)
162
-
163
- if scale_integers
164
- scale_division = scale_division < 1 ? 1 : scale_division.round
165
- end
166
-
167
- rv = []
168
- maxvalue = maxvalue%scale_division == 0 ?
169
- maxvalue : maxvalue + scale_division
170
- minvalue.step( maxvalue, scale_division ) {|v| rv << v}
171
- return rv
172
- end
173
-
174
- def calc_coords(field, value, width = field_width, height = field_height)
175
- coords = {:x => 0, :y => 0}
176
- coords[:x] = width * field
177
- coords[:y] = @graph_height - value * height
178
-
179
- return coords
180
- end
181
-
182
- def draw_data
183
- minvalue = min_value
184
- fieldheight = (@graph_height.to_f - font_size*2*top_font) /
185
- (get_y_labels.max - get_y_labels.min)
186
- fieldwidth = field_width
187
- line = @data.length
188
-
189
- prev_sum = Array.new(@config[:fields].length).fill(0)
190
- cum_sum = Array.new(@config[:fields].length).fill(-minvalue)
191
-
192
- for data in @data.reverse
193
- lpath = ""
194
- apath = ""
195
-
196
- if not stacked then cum_sum.fill(-minvalue) end
197
-
198
- data[:data].each_index do |i|
199
- cum_sum[i] += data[:data][i]
200
-
201
- c = calc_coords(i, cum_sum[i], fieldwidth, fieldheight)
202
-
203
- lpath << "#{c[:x]} #{c[:y]} "
204
- end
205
-
206
- if area_fill
207
- if stacked then
208
- (prev_sum.length - 1).downto 0 do |i|
209
- c = calc_coords(i, prev_sum[i], fieldwidth, fieldheight)
210
-
211
- apath << "#{c[:x]} #{c[:y]} "
212
- end
213
-
214
- c = calc_coords(0, prev_sum[0], fieldwidth, fieldheight)
215
- else
216
- apath = "V#@graph_height"
217
- c = calc_coords(0, 0, fieldwidth, fieldheight)
218
- end
219
-
220
- @graph.add_element("path", {
221
- "d" => "M#{c[:x]} #{c[:y]} L" + lpath + apath + "Z",
222
- "class" => "fill#{line}"
223
- })
224
- end
225
-
226
- @graph.add_element("path", {
227
- "d" => "M0 #@graph_height L" + lpath,
228
- "class" => "line#{line}"
229
- })
230
-
231
- if show_data_points || show_data_values
232
- cum_sum.each_index do |i|
233
- if show_data_points
234
- @graph.add_element( "circle", {
235
- "cx" => (fieldwidth * i).to_s,
236
- "cy" => (@graph_height - cum_sum[i] * fieldheight).to_s,
237
- "r" => "2.5",
238
- "class" => "dataPoint#{line}"
239
- })
240
- end
241
- make_datapoint_text(
242
- fieldwidth * i,
243
- @graph_height - cum_sum[i] * fieldheight - 6,
244
- cum_sum[i] + minvalue
245
- )
246
- end
247
- end
248
-
249
- prev_sum = cum_sum.dup
250
- line -= 1
251
- end
252
- end
253
-
254
-
255
- def get_css
256
- return <<EOL
257
- /* default line styles */
258
- .line1{
259
- fill: none;
260
- stroke: #ff0000;
261
- stroke-width: 1px;
262
- }
263
- .line2{
264
- fill: none;
265
- stroke: #0000ff;
266
- stroke-width: 1px;
267
- }
268
- .line3{
269
- fill: none;
270
- stroke: #00ff00;
271
- stroke-width: 1px;
272
- }
273
- .line4{
274
- fill: none;
275
- stroke: #ffcc00;
276
- stroke-width: 1px;
277
- }
278
- .line5{
279
- fill: none;
280
- stroke: #00ccff;
281
- stroke-width: 1px;
282
- }
283
- .line6{
284
- fill: none;
285
- stroke: #ff00ff;
286
- stroke-width: 1px;
287
- }
288
- .line7{
289
- fill: none;
290
- stroke: #00ffff;
291
- stroke-width: 1px;
292
- }
293
- .line8{
294
- fill: none;
295
- stroke: #ffff00;
296
- stroke-width: 1px;
297
- }
298
- .line9{
299
- fill: none;
300
- stroke: #ccc6666;
301
- stroke-width: 1px;
302
- }
303
- .line10{
304
- fill: none;
305
- stroke: #663399;
306
- stroke-width: 1px;
307
- }
308
- .line11{
309
- fill: none;
310
- stroke: #339900;
311
- stroke-width: 1px;
312
- }
313
- .line12{
314
- fill: none;
315
- stroke: #9966FF;
316
- stroke-width: 1px;
317
- }
318
- /* default fill styles */
319
- .fill1{
320
- fill: #cc0000;
321
- fill-opacity: 0.2;
322
- stroke: none;
323
- }
324
- .fill2{
325
- fill: #0000cc;
326
- fill-opacity: 0.2;
327
- stroke: none;
328
- }
329
- .fill3{
330
- fill: #00cc00;
331
- fill-opacity: 0.2;
332
- stroke: none;
333
- }
334
- .fill4{
335
- fill: #ffcc00;
336
- fill-opacity: 0.2;
337
- stroke: none;
338
- }
339
- .fill5{
340
- fill: #00ccff;
341
- fill-opacity: 0.2;
342
- stroke: none;
343
- }
344
- .fill6{
345
- fill: #ff00ff;
346
- fill-opacity: 0.2;
347
- stroke: none;
348
- }
349
- .fill7{
350
- fill: #00ffff;
351
- fill-opacity: 0.2;
352
- stroke: none;
353
- }
354
- .fill8{
355
- fill: #ffff00;
356
- fill-opacity: 0.2;
357
- stroke: none;
358
- }
359
- .fill9{
360
- fill: #cc6666;
361
- fill-opacity: 0.2;
362
- stroke: none;
363
- }
364
- .fill10{
365
- fill: #663399;
366
- fill-opacity: 0.2;
367
- stroke: none;
368
- }
369
- .fill11{
370
- fill: #339900;
371
- fill-opacity: 0.2;
372
- stroke: none;
373
- }
374
- .fill12{
375
- fill: #9966FF;
376
- fill-opacity: 0.2;
377
- stroke: none;
378
- }
379
- /* default line styles */
380
- .key1,.dataPoint1{
381
- fill: #ff0000;
382
- stroke: none;
383
- stroke-width: 1px;
384
- }
385
- .key2,.dataPoint2{
386
- fill: #0000ff;
387
- stroke: none;
388
- stroke-width: 1px;
389
- }
390
- .key3,.dataPoint3{
391
- fill: #00ff00;
392
- stroke: none;
393
- stroke-width: 1px;
394
- }
395
- .key4,.dataPoint4{
396
- fill: #ffcc00;
397
- stroke: none;
398
- stroke-width: 1px;
399
- }
400
- .key5,.dataPoint5{
401
- fill: #00ccff;
402
- stroke: none;
403
- stroke-width: 1px;
404
- }
405
- .key6,.dataPoint6{
406
- fill: #ff00ff;
407
- stroke: none;
408
- stroke-width: 1px;
409
- }
410
- .key7,.dataPoint7{
411
- fill: #00ffff;
412
- stroke: none;
413
- stroke-width: 1px;
414
- }
415
- .key8,.dataPoint8{
416
- fill: #ffff00;
417
- stroke: none;
418
- stroke-width: 1px;
419
- }
420
- .key9,.dataPoint9{
421
- fill: #cc6666;
422
- stroke: none;
423
- stroke-width: 1px;
424
- }
425
- .key10,.dataPoint10{
426
- fill: #663399;
427
- stroke: none;
428
- stroke-width: 1px;
429
- }
430
- .key11,.dataPoint11{
431
- fill: #339900;
432
- stroke: none;
433
- stroke-width: 1px;
434
- }
435
- .key12,.dataPoint12{
436
- fill: #9966FF;
437
- stroke: none;
438
- stroke-width: 1px;
439
- }
440
- EOL
441
- end
442
- end
443
- end
444
- end
data/lib/SVG/Graph/Pie.rb DELETED
@@ -1,395 +0,0 @@
1
- require 'SVG/Graph/Graph'
2
-
3
- module SVG
4
- module Graph
5
- # === Create presentation quality SVG pie graphs easily
6
- #
7
- # == Synopsis
8
- #
9
- # require 'SVG/Graph/Pie'
10
- #
11
- # fields = %w(Jan Feb Mar)
12
- # data_sales_02 = [12, 45, 21]
13
- #
14
- # graph = SVG::Graph::Pie.new({
15
- # :height => 500,
16
- # :width => 300,
17
- # :fields => fields,
18
- # })
19
- #
20
- # graph.add_data({
21
- # :data => data_sales_02,
22
- # :title => 'Sales 2002',
23
- # })
24
- #
25
- # print "Content-type: image/svg+xml\r\n\r\n"
26
- # print graph.burn();
27
- #
28
- # == Description
29
- #
30
- # This object aims to allow you to easily create high quality
31
- # SVG pie graphs. You can either use the default style sheet
32
- # or supply your own. Either way there are many options which can
33
- # be configured to give you control over how the graph is
34
- # generated - with or without a key, display percent on pie chart,
35
- # title, subtitle etc.
36
- #
37
- # = Examples
38
- #
39
- # http://www.germane-software/repositories/public/SVG/test/single.rb
40
- #
41
- # == See also
42
- #
43
- # * SVG::Graph::Graph
44
- # * SVG::Graph::BarHorizontal
45
- # * SVG::Graph::Bar
46
- # * SVG::Graph::Line
47
- # * SVG::Graph::Plot
48
- # * SVG::Graph::TimeSeries
49
- #
50
- # == Author
51
- #
52
- # Sean E. Russell <serATgermaneHYPHENsoftwareDOTcom>
53
- #
54
- # Copyright 2004 Sean E. Russell
55
- # This software is available under the Ruby license[LICENSE.txt]
56
- #
57
- class Pie < Graph
58
- # Defaults are those set by Graph::initialize, and
59
- # [show_shadow] true
60
- # [shadow_offset] 10
61
- # [show_data_labels] false
62
- # [show_actual_values] false
63
- # [show_percent] true
64
- # [show_key_data_labels] true
65
- # [show_key_actual_values] true
66
- # [show_key_percent] false
67
- # [expanded] false
68
- # [expand_greatest] false
69
- # [expand_gap] 10
70
- # [show_x_labels] false
71
- # [show_y_labels] false
72
- # [datapoint_font_size] 12
73
- def set_defaults
74
- init_with(
75
- :show_shadow => true,
76
- :shadow_offset => 10,
77
-
78
- :show_data_labels => false,
79
- :show_actual_values => false,
80
- :show_percent => true,
81
-
82
- :show_key_data_labels => true,
83
- :show_key_actual_values => true,
84
- :show_key_percent => false,
85
-
86
- :expanded => false,
87
- :expand_greatest => false,
88
- :expand_gap => 10,
89
-
90
- :show_x_labels => false,
91
- :show_y_labels => false,
92
- :datapoint_font_size => 12
93
- )
94
- @data = []
95
- end
96
-
97
- # Adds a data set to the graph.
98
- #
99
- # graph.add_data( { :data => [1,2,3,4] } )
100
- #
101
- # Note that the :title is not necessary. If multiple
102
- # data sets are added to the graph, the pie chart will
103
- # display the +sums+ of the data. EG:
104
- #
105
- # graph.add_data( { :data => [1,2,3,4] } )
106
- # graph.add_data( { :data => [2,3,5,9] } )
107
- #
108
- # is the same as:
109
- #
110
- # graph.add_data( { :data => [3,5,8,13] } )
111
- def add_data arg
112
- arg[:data].each_index {|idx|
113
- @data[idx] = 0 unless @data[idx]
114
- @data[idx] += arg[:data][idx]
115
- }
116
- end
117
-
118
- # If true, displays a drop shadow for the chart
119
- attr_accessor :show_shadow
120
- # Sets the offset of the shadow from the pie chart
121
- attr_accessor :shadow_offset
122
- # If true, display the data labels on the chart
123
- attr_accessor :show_data_labels
124
- # If true, display the actual field values in the data labels
125
- attr_accessor :show_actual_values
126
- # If true, display the percentage value of each pie wedge in the data
127
- # labels
128
- attr_accessor :show_percent
129
- # If true, display the labels in the key
130
- attr_accessor :show_key_data_labels
131
- # If true, display the actual value of the field in the key
132
- attr_accessor :show_key_actual_values
133
- # If true, display the percentage value of the wedges in the key
134
- attr_accessor :show_key_percent
135
- # If true, "explode" the pie (put space between the wedges)
136
- attr_accessor :expanded
137
- # If true, expand the largest pie wedge
138
- attr_accessor :expand_greatest
139
- # The amount of space between expanded wedges
140
- attr_accessor :expand_gap
141
- # The font size of the data point labels
142
- attr_accessor :datapoint_font_size
143
-
144
-
145
- protected
146
-
147
- def add_defs defs
148
- gradient = defs.add_element( "filter", {
149
- "id"=>"dropshadow",
150
- "width" => "1.2",
151
- "height" => "1.2",
152
- } )
153
- gradient.add_element( "feGaussianBlur", {
154
- "stdDeviation" => "4",
155
- "result" => "blur"
156
- })
157
- end
158
-
159
- # We don't need the graph
160
- def draw_graph
161
- end
162
-
163
- def get_y_labels
164
- [""]
165
- end
166
-
167
- def get_x_labels
168
- [""]
169
- end
170
-
171
- def keys
172
- total = 0
173
- max_value = 0
174
- @data.each {|x| total += x }
175
- percent_scale = 100.0 / total
176
- count = -1
177
- a = @config[:fields].collect{ |x|
178
- count += 1
179
- v = @data[count]
180
- perc = show_key_percent ? " "+(v * percent_scale).round.to_s+"%" : ""
181
- x + " [" + v.to_s + "]" + perc
182
- }
183
- end
184
-
185
- RADIANS = Math::PI/180
186
-
187
- def draw_data
188
- @graph = @root.add_element( "g" )
189
- background = @graph.add_element("g")
190
- midground = @graph.add_element("g")
191
-
192
- diameter = @graph_height > @graph_width ? @graph_width : @graph_height
193
- diameter -= expand_gap if expanded or expand_greatest
194
- diameter -= datapoint_font_size if show_data_labels
195
- diameter -= 10 if show_shadow
196
- radius = diameter / 2.0
197
-
198
- xoff = (width - diameter) / 2
199
- yoff = (height - @border_bottom - diameter)
200
- yoff -= 10 if show_shadow
201
- @graph.attributes['transform'] = "translate( #{xoff} #{yoff} )"
202
-
203
- wedge_text_pad = 5
204
- wedge_text_pad = 20 if show_percent and show_data_labels
205
-
206
- total = 0
207
- max_value = 0
208
- @data.each {|x|
209
- max_value = max_value < x ? x : max_value
210
- total += x
211
- }
212
- percent_scale = 100.0 / total
213
-
214
- prev_percent = 0
215
- rad_mult = 3.6 * RADIANS
216
- @config[:fields].each_index { |count|
217
- value = @data[count]
218
- percent = percent_scale * value
219
-
220
- radians = prev_percent * rad_mult
221
- x_start = radius+(Math.sin(radians) * radius)
222
- y_start = radius-(Math.cos(radians) * radius)
223
- radians = (prev_percent+percent) * rad_mult
224
- x_end = radius+(Math.sin(radians) * radius)
225
- x_end -= 0.00001 if @data.length == 1
226
- y_end = radius-(Math.cos(radians) * radius)
227
- path = "M#{radius},#{radius} L#{x_start},#{y_start} "+
228
- "A#{radius},#{radius} "+
229
- "0, #{percent >= 50 ? '1' : '0'},1, "+
230
- "#{x_end} #{y_end} Z"
231
-
232
-
233
- wedge = @foreground.add_element( "path", {
234
- "d" => path,
235
- "class" => "fill#{count+1}"
236
- })
237
-
238
- translate = nil
239
- tx = 0
240
- ty = 0
241
- half_percent = prev_percent + percent / 2
242
- radians = half_percent * rad_mult
243
-
244
- if show_shadow
245
- shadow = background.add_element( "path", {
246
- "d" => path,
247
- "filter" => "url(#dropshadow)",
248
- "style" => "fill: #ccc; stroke: none;"
249
- })
250
- clear = midground.add_element( "path", {
251
- "d" => path,
252
- "style" => "fill: #fff; stroke: none;"
253
- })
254
- end
255
-
256
- if expanded or (expand_greatest && value == max_value)
257
- tx = (Math.sin(radians) * expand_gap)
258
- ty = -(Math.cos(radians) * expand_gap)
259
- translate = "translate( #{tx} #{ty} )"
260
- wedge.attributes["transform"] = translate
261
- clear.attributes["transform"] = translate if clear
262
- end
263
-
264
- if show_shadow
265
- shadow.attributes["transform"] =
266
- "translate( #{tx+shadow_offset} #{ty+shadow_offset} )"
267
- end
268
-
269
- if show_data_labels and value != 0
270
- label = ""
271
- label += @config[:fields][count] if show_key_data_labels
272
- label += " ["+value.to_s+"]" if show_actual_values
273
- label += " "+percent.round.to_s+"%" if show_percent
274
-
275
- msr = Math.sin(radians)
276
- mcr = Math.cos(radians)
277
- tx = radius + (msr * radius)
278
- ty = radius -(mcr * radius)
279
-
280
- if expanded or (expand_greatest && value == max_value)
281
- tx += (msr * expand_gap)
282
- ty -= (mcr * expand_gap)
283
- end
284
- @foreground.add_element( "text", {
285
- "x" => tx.to_s,
286
- "y" => ty.to_s,
287
- "class" => "dataPointLabel",
288
- "style" => "stroke: #fff; stroke-width: 2;"
289
- }).text = label.to_s
290
- @foreground.add_element( "text", {
291
- "x" => tx.to_s,
292
- "y" => ty.to_s,
293
- "class" => "dataPointLabel",
294
- }).text = label.to_s
295
- end
296
-
297
- prev_percent += percent
298
- }
299
- end
300
-
301
-
302
- def round val, to
303
- up = 10**to.to_f
304
- (val * up).to_i / up
305
- end
306
-
307
-
308
- def get_css
309
- return <<EOL
310
- .dataPointLabel{
311
- fill: #000000;
312
- text-anchor:middle;
313
- font-size: #{datapoint_font_size}px;
314
- font-family: "Arial", sans-serif;
315
- font-weight: normal;
316
- }
317
-
318
- /* key - MUST match fill styles */
319
- .key1,.fill1{
320
- fill: #ff0000;
321
- fill-opacity: 0.7;
322
- stroke: none;
323
- stroke-width: 1px;
324
- }
325
- .key2,.fill2{
326
- fill: #0000ff;
327
- fill-opacity: 0.7;
328
- stroke: none;
329
- stroke-width: 1px;
330
- }
331
- .key3,.fill3{
332
- fill-opacity: 0.7;
333
- fill: #00ff00;
334
- stroke: none;
335
- stroke-width: 1px;
336
- }
337
- .key4,.fill4{
338
- fill-opacity: 0.7;
339
- fill: #ffcc00;
340
- stroke: none;
341
- stroke-width: 1px;
342
- }
343
- .key5,.fill5{
344
- fill-opacity: 0.7;
345
- fill: #00ccff;
346
- stroke: none;
347
- stroke-width: 1px;
348
- }
349
- .key6,.fill6{
350
- fill-opacity: 0.7;
351
- fill: #ff00ff;
352
- stroke: none;
353
- stroke-width: 1px;
354
- }
355
- .key7,.fill7{
356
- fill-opacity: 0.7;
357
- fill: #00ff99;
358
- stroke: none;
359
- stroke-width: 1px;
360
- }
361
- .key8,.fill8{
362
- fill-opacity: 0.7;
363
- fill: #ffff00;
364
- stroke: none;
365
- stroke-width: 1px;
366
- }
367
- .key9,.fill9{
368
- fill-opacity: 0.7;
369
- fill: #cc6666;
370
- stroke: none;
371
- stroke-width: 1px;
372
- }
373
- .key10,.fill10{
374
- fill-opacity: 0.7;
375
- fill: #663399;
376
- stroke: none;
377
- stroke-width: 1px;
378
- }
379
- .key11,.fill11{
380
- fill-opacity: 0.7;
381
- fill: #339900;
382
- stroke: none;
383
- stroke-width: 1px;
384
- }
385
- .key12,.fill12{
386
- fill-opacity: 0.7;
387
- fill: #9966FF;
388
- stroke: none;
389
- stroke-width: 1px;
390
- }
391
- EOL
392
- end
393
- end
394
- end
395
- end