rchart 1.2.2 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,192 @@
1
+ module PlotChart
2
+ # This function will draw a plot graph using all the registered series.
3
+ # Giving only the data & data_description structure will draw the basic plot graph,
4
+ # You can specify the radius ( external & internal ) of the plots.
5
+ # You can also specify the color of the points ( will be unique in case of multiple series ).
6
+ # Setting Shadow to true will draw a shadow under the plots.
7
+
8
+ def draw_plot_graph(data,data_description,big_radius=5,small_radius=2,r2=-1,g2=-1,b2=-1,shadow=false)
9
+ #/* Validate the Data and data_description array */
10
+ data_description = self.validate_data_description("draw_plot_graph",data_description)
11
+ self.validate_data("draw_plot_graph",data)
12
+ graph_id = 0
13
+ ro = r2
14
+ go = g2
15
+ bo = b2
16
+ id =0
17
+ color_id =0
18
+ data_description["values"].each do |col_name|
19
+ data_description["description"].each do |key_i,value_i|
20
+ if ( key_i == col_name )
21
+ color_id = id
22
+ id = id+1
23
+ end
24
+ end
25
+ r = @palette[color_id]["r"]
26
+ g = @palette[color_id]["g"]
27
+ b = @palette[color_id]["b"]
28
+ r2 = ro
29
+ g2 = go
30
+ b2 = bo
31
+ #TODO convert this function
32
+ im_symbol =""
33
+ if ( !data_description["symbol"].nil? && !data_description["symbol"][col_name].nil?)
34
+ is_alpha = false # ((ord ( file_get_contents (data_description["symbol"][col_name], false, NULL, 25, 1)) & 6) & 4) == 4
35
+ im_symbol = image_create_from_png(data_description["symbol"][col_name])
36
+ infos = get_image_size(im_symbol)
37
+ image_width = infos[0]
38
+ image_height = infos[1]
39
+ #
40
+ end
41
+
42
+ x_pos = @g_area_x1 + @g_area_x_offset
43
+ h_size = (big_radius/2).round
44
+ r3 = -1
45
+ g3 = -1
46
+ b3 = -1
47
+ data.each do |key|
48
+ value= key[col_name]
49
+ if value.is_a?(Numeric)
50
+ y_pos = @g_area_y2 - ((value-@vmin) * @division_ratio)
51
+ else
52
+ y_pos = @g_area_y2 - ((0-@vmin) * @division_ratio)
53
+ end
54
+
55
+
56
+ # Save point into the image map if option activated
57
+ if ( @build_map )
58
+ #add_to_image_map(x_pos-h_size,y_pos-h_size,x_pos+1+h_size,y_pos+h_size+1,data_description["description"][col_name],key[col_name].data_description["unit"]["y"],"Plot")
59
+ end
60
+
61
+ if(value.is_a?(Numeric))
62
+ #MY Hack
63
+ if (data_description["symbol"].nil? || data_description["symbol"][col_name].nil? )
64
+ if ( shadow )
65
+ if ( r3 !=-1 && g3 !=-1 && b3 !=-1 )
66
+ self.draw_filled_circle(x_pos+2,y_pos+2,big_radius,r3,g3,b3)
67
+ else
68
+ r3 = @palette[color_id]["r"]-20
69
+ r3 = 0 if ( r3 < 0 )
70
+ g3 = @palette[color_id]["g"]-20
71
+ g3 = 0 if ( g3 < 0 )
72
+ b3 = @palette[color_id]["b"]-20
73
+ b3 = 0 if ( b3 < 0 )
74
+ self.draw_filled_circle(x_pos+2,y_pos+2,big_radius,r3,g3,b3)
75
+ end
76
+ end
77
+ self.draw_filled_circle(x_pos+1,y_pos+1,big_radius,r,g,b)
78
+ if ( small_radius != 0 )
79
+ if ( r2 !=-1 && g2 !=-1 && b2 !=-1 )
80
+ self.draw_filled_circle(x_pos+1,y_pos+1,small_radius,r2,g2,b2)
81
+ else
82
+ r2 = @palette[color_id]["r"]-15
83
+ r2 = 0 if ( r2 < 0 )
84
+ g2 = @palette[color_id]["g"]-15
85
+ g2 = 0 if ( g2 < 0 )
86
+ b2 = @palette[color_id]["b"]-15
87
+ b2 = 0 if ( b2 < 0 )
88
+ self.draw_filled_circle(x_pos+1,y_pos+1,small_radius,r2,g2,b2)
89
+ end
90
+ end
91
+ else
92
+ image_copy_merge(im_symbol,@picture,x_pos+1-image_width/2,y_pos+1-image_height/2,0,0,image_width,image_height,100)
93
+
94
+ end
95
+ end
96
+ x_pos = x_pos + @division_width
97
+ end
98
+ graph_id+=1
99
+ end
100
+ end
101
+
102
+ # This function is very similar as the draw_plot_graph function.
103
+ # You must specify the name of the two series that will be used as x and y coordinates and the color id to use.
104
+
105
+ def draw_xy_plot_graph(data,data_description,y_serie_name,x_serie_name,palette_id=0,big_radius=5,small_radius=2,r2=-1,g2=-1,b2=-1,shadow=true)
106
+ r = @palette[palette_id]["r"]
107
+ g = @palette[palette_id]["g"]
108
+ b = @palette[palette_id]["b"]
109
+ r3 = -1
110
+ g3 = -1
111
+ b3 = -1
112
+
113
+ y_last = -1
114
+ x_last = -1
115
+ data.each do |key|
116
+ if (!key[y_serie_name].nil? && !key[x_serie_name])
117
+ x = key[x_serie_name]
118
+ y = key[y_serie_name]
119
+ y = @g_area_y2 - ((y-@vmin) * @division_ratio)
120
+ x = @g_area_x1 + ((x-@v_x_min) * @x_division_ratio)
121
+ if ( shadow )
122
+ if ( r3 !=-1 && g3 !=-1 && b3 !=-1 )
123
+ self.draw_filled_circle(x+2,y+2,big_radius,r3,g3,b3)
124
+ else
125
+ r3 = @palette[palette_id]["r"]-20
126
+ r = 0 if ( r < 0 )
127
+ g3 = @palette[palette_id]["g"]-20
128
+ g = 0 if ( g < 0 )
129
+ b3 = @palette[palette_id]["b"]-20
130
+ b = 0 if ( b < 0 )
131
+ draw_filled_circle(x+2,y+2,big_radius,r3,g3,b3)
132
+ end
133
+ end
134
+ draw_filled_circle(x+1,y+1,big_radius,r,g,b)
135
+
136
+ if ( r2 !=-1 && g2 !=-1 && b2 !=-1 )
137
+ draw_filled_circle(x+1,y+1,small_radius,r2,g2,b2)
138
+ else
139
+ r2 = @palette[palette_id]["r"]+20
140
+ r = 255 if ( r > 255 )
141
+ g2 = @palette[palette_id]["g"]+20
142
+ g = 255 if ( g > 255 )
143
+ b2 = @palette[palette_id]["b"]+20
144
+ b = 255 if ( b > 255 )
145
+ draw_filled_circle(x+1,y+1,small_radius,r2,g2,b2)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ def draw_limits_graph(data,data_description,r=0,g=0,b=0)
151
+ data_description = self.validate_data_description("draw_limits_graph",data_description)
152
+ self.validate_data("draw_limits_graph",data)
153
+ x_width = @division_width / 4
154
+ xpos = @g_area_x1 + @g_area_x_offset
155
+ data.each do |key|
156
+ min = key[data_description["values"][0]]
157
+ max = key[data_description["values"][0]]
158
+ graph_id = 0
159
+ max_id = 0
160
+ min_id = 0
161
+ data_description["values"].each do |col_name|
162
+ if (!key[col_name].nil?)
163
+ if ( key[col_name] > max && key[col_name].is_a?(Numeric))
164
+ max = key[col_name]
165
+ max_id = graph_id
166
+ end
167
+ end
168
+ if ( !key[col_name].nil? && key[col_name].is_a?(Numeric))
169
+ if ( key[col_name] < min )
170
+ min = key[col_name]
171
+ min_id = graph_id
172
+ end
173
+ graph_id+=1
174
+ end
175
+ end
176
+
177
+ ypos = @g_area_y2 - ((max-@vmin) * @division_ratio)
178
+ x1 = (xpos - x_width).floor
179
+ y1 = (ypos).floor - 0.2
180
+ x2 = (xpos + x_width).floor
181
+ x1 = @g_area_x1 + 1 if ( x1 <= @g_area_x1 )
182
+ x2 = @g_area_x2 - 1 if ( x2 >= @g_area_x2 )
183
+ ypos = @g_area_y2 - ((min-@vmin) * @division_ratio)
184
+ y2 = ypos.floor + 0.2
185
+ draw_line(xpos.floor-0.2,y1+1,xpos.floor-0.2,y2-1,r,g,b,true)
186
+ draw_line(xpos.floor+0.2,y1+1,xpos.floor+0.2,y2-1,r,g,b,true)
187
+ draw_line(x1,y1,x2,y1,@palette[max_id]["r"],@palette[max_id]["g"],@palette[max_id]["b"],false)
188
+ draw_line(x1,y2,x2,y2,@palette[min_id]["r"],@palette[min_id]["g"],@palette[min_id]["b"],false)
189
+ xpos = xpos + @division_width
190
+ end
191
+ end
192
+ end
@@ -1,7 +1,11 @@
1
- require "GD"
1
+ require 'rubygems'
2
+ require "gd2_helper"
3
+ require "graph"
4
+ require "gd2-ffij"
2
5
  require 'rdata'
3
-
4
6
  class Rchart
7
+ include GD2
8
+ include Graph
5
9
  SCALE_NORMAL = 1
6
10
  SCALE_ADDALL = 2
7
11
  SCALE_START0 = 3
@@ -21,13 +25,12 @@ class Rchart
21
25
  ALIGN_BOTTOM_LEFT = 7
22
26
  ALIGN_BOTTOM_CENTER = 8
23
27
  ALIGN_BOTTOM_RIGHT = 9
24
- FONT_PATH = File.expand_path(File.join(File.dirname(__FILE__),"..","fonts"))
28
+ FONT_PATH = File.expand_path(File.join(File.dirname(__FILE__),"..","fonts"))
25
29
  attr_accessor :antialias_quality,:picture
26
30
  # This function create a new chart object.
27
31
  # This object will be used during all the steps of the graph creation.
28
- # This object will embed all the pChart functions.
29
-
30
- def initialize(x_size,y_size,options={})
32
+ # This object will embed all the pChart functions
33
+ def initialize(x_size,y_size,options={})
31
34
  # Initialize variables
32
35
  # q raise ArgumentError if (options[:x_size].nil? && options[:y_size].nil?)
33
36
  # Error management
@@ -96,3190 +99,11 @@ class Rchart
96
99
  {"r"=>224,"g"=>46,"b"=>117},
97
100
  {"r"=>92,"g"=>224,"b"=>46},
98
101
  {"r"=>224,"g"=>176,"b"=>46}]
99
- @picture = GD::Image.newTrueColor(@x_size, @y_size)
100
- @c_white = @picture.colorAllocate(255,255,255)
102
+
103
+ @picture = image_create_true_color(@x_size, @y_size)
104
+ @c_white = allocate_color(@picture,255,255,255)
101
105
  image_filled_rectangle(@picture, 0, 0, @x_size, @y_size, 255,255,255)
102
106
  #image_color_transparent(@picture, 255,255,255)
103
- self.set_font_properties("tahoma.ttf",8)
104
- end
105
- # Use this function to enable error reporting during the chart rendering.
106
- # By default messages are redirected to the console while using the render command and using GD while using the stroke command.
107
- # You can force the errors to be redirected to either cli or gd specifying it as parameter.
108
- def report_warnings(interface="cli")
109
- @error_reporting = true
110
- @error_interface = interface
111
- end
112
-
113
- # Set font Properties font_name,font_size
114
- # font_name is
115
- # * GeosansLight.ttf,
116
- # * MankSans.ttf,
117
- # * pf_arma_five.ttf,
118
- # * Silkscreen.ttf,
119
- # * tahoma.ttf
120
- def set_font_properties(font_name, font_size)
121
- @font_size = font_size
122
- @font_name = "#{FONT_PATH}/#{font_name}"
123
- end
124
-
125
-
126
- #Use this function to set shadow properties.
127
- def set_shadow_properties(x_distance=1,y_distance=1,r=60,g=60,b=60,alpha=50,blur=0)
128
- @shadow_active = true
129
- @shadow_x_distance = x_distance
130
- @shadow_y_distance = y_distance
131
- @shadow_r_color = r
132
- @shadow_g_color = g
133
- @shadow_b_color = b
134
- @shadow_alpha = alpha
135
- @shadow_blur = blur
136
- end
137
-
138
- # Use this function to deactivate the shadow options.
139
- # Drawing shadows is time and CPU intensive.
140
- def clear_shadow
141
- @shadow_active = false
142
- end
143
-
144
- def validate_color(b, g, r)
145
- r = 0 if ( r < 0 )
146
- r = 255 if ( r > 255 )
147
- g = 0 if ( g < 0 )
148
- g = 255 if ( g > 255 )
149
- b = 0 if ( b < 0 )
150
- b = 255 if ( b > 255 )
151
- return b, g, r
152
- end
153
-
154
- # This function can be used to change the color of one series.
155
- # series id are starting at 0 for associated data serie #1.
156
- # You must provide an rgb color.
157
- def set_color_palette(id,r,g,b)
158
- b,g,r=validate_color(b, g, r)
159
- @palette[id]["r"] = r
160
- @palette[id]["g"] = g
161
- @palette[id]["b"] = b
162
- end
163
-
164
- # Create a color palette shading from one color to another
165
- # This function will fill the color palette with 10 shades between the two RGB colors 0,0,0 and 100,100,100.This will produce grey shades. (Palette id 0-9 will be filled)
166
- def create_color_gradient_palette(r1,g1,b1,r2,g2,b2,shades)
167
- r_factor = (r2-r1)/shades
168
- g_factor = (g2-g1)/shades
169
- b_factor = (b2-b1)/shades
170
- i= 0
171
- while(i<= shades-1)
172
- @palette[i]["r"] = r1+r_factor*i
173
- @palette[i]["g"] = g1+g_factor*i
174
- @palette[i]["b"] = b1+b_factor*i
175
- i = i+1
176
- end
177
- end
178
-
179
- # This function will load the color scheme from a text file.
180
- # This file must be formated with three values per line ( r,g,b ).
181
- # By default the delimiter is a coma but you can specify it.
182
- def load_color_palette_from_file(file_name)
183
- color_id = 0
184
- File.open(file_name,"r") do |infile|
185
- while (line = infile.gets)
186
- values = line.split(",")
187
- if ( values.length == 3 )
188
- @palette[color_id]["r"] = values[0].to_i
189
- @palette[color_id]["g"] = values[1].to_i
190
- @palette[color_id]["b"] = values[2].to_i
191
- color_id+=1
192
- end
193
- end
194
- end
195
- end
196
-
197
- # Load palette from array [[r,g,b],[r1,g1,b1]]
198
- def load_color_palette(color_palette)
199
- color_id = 0
200
- color_palette.each do |palette|
201
- if palette.length == 3
202
- @palette[color_id]["r"] = palette[0].to_i
203
- @palette[color_id]["g"] = palette[1].to_i
204
- @palette[color_id]["b"] = palette[2].to_i
205
- color_id+=1
206
- end
207
- end
208
- end
209
-
210
- # This function allow you to customise the way lines are drawn in charts.
211
- # This function only applies during chart drawing calls ( line charts,.. ).
212
- # You can specify the width of the lines & if they are dotted.
213
- def set_line_style(width=1,dot_size=0)
214
- @line_width = width
215
- @line_dot_size = dot_size
216
- end
217
-
218
- # Set currency symbol
219
- def set_currency(currency)
220
- @currency = currency
221
- end
222
-
223
- # A call to this function is mandatory when creating a graph.
224
- # The upper left and bottom right border positions are used as arguments.
225
- # This area will be used to draw graphs, grid, axis & more.
226
- # Calling this function will not draw anything this will only set the graph area boundaries.
227
- def set_graph_area(x1,y1,x2,y2)
228
- @g_area_x1 = x1
229
- @g_area_y1 = y1
230
- @g_area_x2 = x2
231
- @g_area_y2 = y2
232
- end
233
-
234
- # Prepare the graph area
235
- def draw_graph_area(r,g,b,stripe=false)
236
- self.draw_filled_rectangle(@g_area_x1,@g_area_y1,@g_area_x2,@g_area_y2,r,g,b,false)
237
- self.draw_rectangle(@g_area_x1,@g_area_y1,@g_area_x2,@g_area_y2,r-40,g-40,b-40)
238
- i=0
239
- if stripe
240
- r2 = r-15
241
- r2 = 0 if r2<0
242
- g2 = r-15
243
- g2 = 0 if g2 < 0
244
- b2 = r-15
245
- b2 = 0 if b2 < 0
246
- line_color = allocate_color(@picture,r2,g2,b2)
247
- skew_width = @g_area_y2-@g_area_y1-1
248
-
249
- i = @g_area_x1-skew_width
250
-
251
- while i.to_f<=@g_area_x2.to_f
252
- x1 = i
253
- y1 = @g_area_y2
254
- x2 = i+skew_width
255
- y2 = @g_area_y1
256
- if ( x1 < @g_area_x1 )
257
- x1 = @g_area_x1
258
- y1 = @g_area_y1 + x2 - @g_area_x1 + 1
259
- end
260
- if ( x2 >= @g_area_x2 )
261
- y2 = @g_area_y1 + x2 - @g_area_x2 +1
262
- x2 = @g_area_x2 - 1
263
- end
264
- image_line(@picture,x1,y1,x2,y2+1,r2,g2,b2)
265
- i = i+4
266
- end
267
-
268
- end
269
- end
270
-
271
- # Allow you to clear the scale : used if drawing multiple charts
272
- # You'll need to call this function only if you're planning to draw a second chart in the rendered picture.
273
- # Calling this function will clear the current scaling parameters thus you'll need to call again the draw_scale function before drawing any new chart.
274
- def clear_scale
275
- @vmin = nil
276
- @vmax = nil
277
- @v_x_min = nil
278
- @v_x_max = nil
279
- @divisions = 0
280
- @x_divisions = 0
281
- end
282
-
283
- # Allow you to fix the scale, use this to bypass the automatic scaling
284
- # You can use this function to skip the automatic scaling.
285
- # vmin and vmax will be used to render the graph.
286
- def set_fixed_scale(v_min,v_max,divisions=5,v_x_min=0,v_x_max=0,x_divisions=5)
287
- @vmin = v_min.to_f
288
- @vmax = v_max.to_f
289
- @divisions = divisions.to_f
290
-
291
- if (!v_x_min == 0 )
292
- @v_x_min = v_x_min.to_f
293
- @v_x_max = v_x_max.to_f
294
- @x_divisions = x_divisions.to_f
295
- end
296
- end
297
-
298
- # Wrapper to the draw_scale function allowing a second scale to be drawn
299
- # It takes the same parameters of the draw_scale function.
300
- # The scale values will be written on the right side of the graph area.
301
- def draw_right_scale(data,data_description,scale_mode,r,g,b,draw_ticks=true,angle=0,decimals=1,with_margin=false,skip_labels=1)
302
- self. draw_scale(data, data_description, scale_mode, r, g, b,draw_ticks,angle,decimals,with_margin,skip_labels,true)
303
- end
304
-
305
- # This function will draw both axis and write values on it. You can disable the labelling of the axis setting draw_ticks to false. angle can be used to rotate the vertical ticks labels.
306
- # decimal specify the number of decimal values we want to keep. Setting draw_ticks to false will not draw vertical & horizontal ticks on the axis ( labels will also not be written ).
307
- # There is four way of computing scales :
308
- # * Getting Max & Min values per serie : scale_mode = Rchart::SCALE_NORMAL
309
- # * Like the previous one but setting the min value to 0 : scale_mode = Rchart::SCALE_START0
310
- # * Getting the series cumulative Max & Min values : scale_mode = Rchart::SCALE_ADDALL
311
- # * Like the previous one but setting the min value to 0 : scale_mode = Rchart::SCALE_ADDALLSTART0
312
- # This will depends on the kind of graph you are drawing, Drawing graphs were you want to fix the min value to 0 you must use the Rchart::SCALE_START0 option.
313
- # You can display only one x label every xi labels using the skip_labels parameter.
314
- # Keeping with_margin to false will make the chart use all the width of the graph area. For most graphs the rendering will be better. In some circumstances you'll have to set it to true ( introducing left & right margin ) : bar charts will require it.
315
- def draw_scale(data,data_description,scale_mode,r,g,b,draw_ticks=true,angle=0,decimals=1,with_margin=false,skip_labels=1,right_scale=false)
316
- # Validate the Data and DataDescription array
317
- data = self.validate_data("draw_scale",data)
318
- c_text_color = allocate_color(@picture,r,g,b)
319
- self.draw_line(@g_area_x1,@g_area_y1,@g_area_x1,@g_area_y2,r,g,b)
320
- self.draw_line(@g_area_x1,@g_area_y2,@g_area_x2,@g_area_y2,r,g,b)
321
- scale =0
322
- divisions =0
323
- if(@vmin.nil? && @vmax.nil?)
324
- if (!data_description["values"][0].nil?)
325
- #My hack TODO for LINE GRAPH
326
- if data_description["values"].is_a?(Array)
327
- @vmin =data[0][data_description["values"][0]]
328
- @vmax =data[0][data_description["values"][0]]
329
- else
330
- @vmin =data[0][data_description["values"][0]]
331
- @vmax =data[0][data_description["values"]]
332
- end
333
-
334
- else
335
- @vmin = 2147483647
336
- @vmax = -2147483647
337
- end
338
- # /* Compute Min and Max values */
339
- if(scale_mode == SCALE_NORMAL || scale_mode == SCALE_START0)
340
- @vmin = 0 if (scale_mode == SCALE_START0 )
341
-
342
- data.each do |key|
343
- data_description["values"].each do |col_name|
344
- if(!key[col_name].nil?)
345
- value = key[col_name]
346
- if (value.is_a?(Numeric))
347
- @vmax = value if ( @vmax < value)
348
- @vmin = value if ( @vmin > value)
349
- end
350
- end
351
- end
352
- end
353
- elsif ( scale_mode == SCALE_ADDALL || scale_mode == SCALE_ADDALLSTART0 ) # Experimental
354
- @vmin = 0 if (scale_mode == SCALE_ADDALLSTART0)
355
- data.each do |key|
356
- sum = 0
357
- data_description["values"].each do|col_name|
358
- if (!key[col_name].nil?)
359
- value =key[col_name]
360
- sum += value if ((value).is_a?(Numeric))
361
- end
362
- end
363
- @vmax = sum if (@vmax < sum)
364
- @vmin = sum if (@vmin > sum)
365
- end
366
-
367
- end
368
-
369
- if(@vmax.is_a?(String))
370
- @vmax = @vmax.gsub(/\.[0-9]+/,'')+1 if (@vmax > @vmax.gsub(/\.[0-9]+/,'') )
371
- end
372
- # If all values are the same */
373
- if ( @vmax == @vmin )
374
- if ( @vmax >= 0 )
375
- @vmax = @vmax+1
376
- else
377
- @vmin = @vmin-1
378
- end
379
- end
380
-
381
- data_range = @vmax - @vmin
382
- data_range = 0.1 if (data_range == 0 )
383
-
384
- #Compute automatic scaling */
385
- scale_ok = false
386
- factor = 1
387
- min_div_height = 25
388
- max_divs = (@g_area_y2 - @g_area_y1)*1.0 / min_div_height
389
-
390
- if (@vmin == 0 && @vmax == 0 )
391
- @vmin = 0
392
- @vmax = 2
393
- scale = 1
394
- divisions = 2
395
- elsif (max_divs > 1)
396
- while(!scale_ok)
397
- scale1 = ( @vmax - @vmin )*1.0 / factor
398
- scale2 = ( @vmax - @vmin )*1.0 /factor / 2
399
- scale4 = ( @vmax - @vmin )*1.0 / factor / 4
400
- if ( scale1 > 1 && scale1 <= max_divs && !scale_ok)
401
- scale_ok = true
402
- divisions = (scale1).floor
403
- scale = 1
404
- end
405
- if (scale2 > 1 && scale2 <= max_divs && !scale_ok)
406
- scale_ok = true
407
- divisions = (scale2).floor
408
- scale = 2
409
- end
410
- if (!scale_ok)
411
- factor = factor * 10 if ( scale2 > 1 )
412
- factor = factor / 10 if ( scale2 < 1 )
413
- end
414
- end # while end
415
- if ((((@vmax*1.0 / scale) / factor)).floor != ((@vmax*1.0 / scale) / factor))
416
- grid_id = ( @vmax*1.0 / scale / factor).floor + 1
417
- @vmax = grid_id * scale * factor
418
- divisions = divisions+1
419
- end
420
-
421
- if (((@vmin*1.0 / scale) / factor).floor != ((@vmin*1.0 / scale) / factor))
422
-
423
- grid_id = ( @vmin*1.0 / scale / factor).floor
424
- @vmin = grid_id * scale * factor*1.0
425
- divisions = divisions+1
426
- end
427
-
428
- else #/* Can occurs for small graphs */
429
- scale = 1
430
- end
431
- divisions = 2 if ( divisions.nil? )
432
-
433
- divisions = divisions-1 if (scale == 1 && divisions%2 == 1)
434
-
435
- else
436
- divisions = @divisions
437
- end
438
-
439
- @division_count = divisions
440
- data_range = @vmax - @vmin
441
- data_range = 0.1 if (data_range == 0 )
442
- @division_height = ( @g_area_y2 - @g_area_y1 )*1.0 / divisions
443
- @division_ratio = ( @g_area_y2 - @g_area_y1 )*1.0 /data_range
444
- @g_area_x_offset = 0
445
- if ( data.count > 1 )
446
- if ( with_margin == false)
447
- @division_width = ( @g_area_x2 - @g_area_x1 )*1.0 / ((data).count-1)
448
- else
449
- @division_width = ( @g_area_x2 - @g_area_x1 ) *1.0/ (data).count
450
- @g_area_x_offset = @division_width*1.0 / 2
451
- end
452
- else
453
- @division_width = (@g_area_x2 - @g_area_x1)*1.0
454
- @g_area_x_offset = @division_width*1.0 / 2
455
- end
456
-
457
- @data_count = (data).count
458
- return(0) if (draw_ticks == false )
459
- ypos = @g_area_y2
460
- xmin = nil
461
- i =1
462
-
463
- while(i<= divisions+1)
464
- if (right_scale )
465
- self.draw_line(@g_area_x2,ypos,@g_area_x2+5,ypos,r,g,b)
466
- else
467
- self.draw_line(@g_area_x1,ypos,@g_area_x1-5,ypos,r,g,b)
468
- end
469
- value = @vmin*1.0 + (i-1) * (( @vmax - @vmin ) / divisions)
470
- value = (round_of(value * (10**decimals),2)) / (10**decimals)
471
- value= value.round if value.floor == value.ceil
472
- value = "#{value} #{data_description['unit']['y']}" if ( data_description["format"]["y"]== "number")
473
- value = self.to_time(value) if ( data_description["format"]["y"] == "time" )
474
- value = self.to_date(value) if ( data_description["format"]["y"] == "date" )
475
- value = self.to_metric(value) if ( data_description["format"]["Y"] == "metric" )
476
- value = self.to_currency(value) if ( data_description["format"]["Y"] == "currency" )
477
- position = image_ftb_box(@font_size,0,@font_name,value)
478
- text_width =position[2]-position[0]
479
- if ( right_scale )
480
- image_ttf_text(@picture,@font_size,0,@g_area_x2+10,ypos+(@font_size/2),c_text_color,@font_name,value)
481
- xmin = @g_area_x2+15+text_width if (xmin.nil? || xmin < @g_area_x2+15+text_width )
482
- else
483
- image_ttf_text(@picture,@font_size,0,@g_area_x1-10-text_width,ypos+(@font_size/2),c_text_color,@font_name,value)
484
- xmin = @g_area_x1-10-text_width if ( xmin.nil? || xmin > @g_area_x1-10-text_width)
485
- end
486
- ypos = ypos - @division_height
487
- i = i+1
488
- end
489
- # Write the Y Axis caption if set */
490
-
491
- if (!data_description["axis"].nil? && !data_description["axis"]["y"].nil? )
492
- position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["y"])
493
- text_height = (position[1]).abs+(position[3]).abs
494
- text_top = ((@g_area_y2 - @g_area_y1) / 2) + @g_area_y1 + (text_height/2)
495
-
496
- if (right_scale )
497
- image_ttf_text(@picture,@font_size,90,xmin+@font_size,text_top,c_text_color,@font_name,data_description["axis"]["y"])
498
- else
499
- image_ttf_text(@picture,@font_size,90,xmin-@font_size,text_top,c_text_color,@font_name,data_description["axis"]["y"])
500
- end
501
- end
502
- # Horizontal Axis */
503
- xpos = @g_area_x1 + @g_area_x_offset
504
- id = 1
505
- ymax = nil
506
- data.each do |key|
507
- if ( id % skip_labels == 0 )
508
- self.draw_line((xpos).floor,@g_area_y2,(xpos).floor,@g_area_y2+5,r,g,b)
509
- value =key[data_description["position"]]
510
- value = "#{value} #{data_description['unit']['x']}" if ( data_description["format"]["x"] == "number" )
511
- value = self.to_time(value) if ( data_description["format"]["x"] == "time" )
512
- value = self.to_date(value) if ( data_description["format"]["x"] == "date" )
513
- value = self.to_metric(value) if ( data_description["format"]["x"] == "metric" )
514
- value = self.to_currency(value) if ( data_description["format"]["x"] == "currency" )
515
- position = image_ftb_box(@font_size,angle,@font_name,value.to_s)
516
- text_width = (position[2]).abs+(position[0]).abs
517
- text_height = (position[1]).abs+(position[3]).abs
518
- if ( angle == 0 )
519
- ypos = @g_area_y2+18
520
- image_ttf_text(@picture,@font_size,angle,(xpos).floor-(text_width/2).floor,ypos,c_text_color,@font_name,value.to_s)
521
- else
522
- ypos = @g_area_y2+10+text_height
523
- if ( angle <= 90 )
524
- image_ttf_text(@picture,@font_size,angle,(xpos).floor-text_width+5,ypos,c_text_color,@font_name,value.to_s)
525
- else
526
- image_ttf_text(@picture,@font_size,angle,(xpos).floor+text_width+5,ypos,c_text_color,@font_name,value.to_s)
527
- end
528
- end
529
- ymax = ypos if (ymax.nil? ||(!ymax.nil? && ymax < ypos))
530
- end
531
- xpos = xpos + @division_width
532
- id = id+1
533
- end #loop ended
534
- #Write the X Axis caption if set */
535
-
536
- if ((!data_description["axis"].nil? && !data_description["axis"]["x"].nil?) )
537
- position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["x"])
538
- text_width = (position[2]).abs+(position[0]).abs
539
- text_left = ((@g_area_x2 - @g_area_x1) / 2) + @g_area_x1 + (text_width/2)
540
- image_ttf_text(@picture,@font_size,0,text_left,ymax+@font_size+5,c_text_color,@font_name,data_description["axis"]["x"].to_s)
541
- end
542
-
543
- end
544
-
545
- # This function is used by scatter charts.
546
- # It will compute everything needed to draw the associated line and plot charts.
547
- # You must specify the name of the two series that will be used as X and Y data. By default this function will compute the min & max values of both series, anyway you can override the automatic scaling by calling first the setFixedScale function.
548
- def draw_xy_scale(data,data_description,y_serie_name,x_serie_name,r,g,b,with_margin=0,angle=0,decimals=1)
549
-
550
- self.validate_data("draw_xy_scale",data)
551
- c_text_color = allocate_color(@picture,r,g,b)
552
- self.draw_line(@g_area_x1,@g_area_y1,@g_area_x1,@g_area_y2,r,g,b)
553
- self.draw_line(@g_area_x1,@g_area_y2,@g_area_x2,@g_area_y2,r,g,b)
554
-
555
- # Process Y scale */
556
- if(@vmin.nil? && @vmax.nil?)
557
- @vmin = data[0][y_serie_name]
558
- @vmax = data[0][y_serie_name]
559
- data.each do |key|
560
- if !key[y_serie_name].nil?
561
- value = key[y_serie_name]
562
- if (value.is_a?(Numeric))
563
- @vmax = value if ( @vmax < value)
564
- @vmin = value if ( @vmin > value)
565
- end
566
- end
567
- end
568
-
569
- if(@vmax.is_a?(String))
570
- @vmax = @vmax.gsub(/\.[0-9]+/,'')+1 if (@vmax > @vmax.gsub(/\.[0-9]+/,'') )
571
- end
572
- data_range = @vmax - @vmin
573
- data_range = 0.1 if (data_range == 0 )
574
-
575
- #Compute automatic scaling
576
- scale_ok = false
577
- factor = 1
578
- min_div_height = 25
579
- max_divs = (@g_area_y2 - @g_area_y1)*1.0 / min_div_height
580
- if (@vmin == 0 && @vmax == 0 )
581
- @vmin = 0
582
- @vmax = 2
583
- scale = 1
584
- divisions = 2
585
- elsif (max_divs > 1)
586
- while(!scale_ok)
587
- scale1 = ( @vmax - @vmin )*1.0 / factor
588
- scale2 = ( @vmax - @vmin )*1.0 /factor / 2
589
- # scale4 = ( @vmax - @vmin )*1.0 / factor / 4
590
-
591
- if ( scale1 > 1 && scale1 <= max_divs && !scale_ok)
592
- scale_ok = true
593
- divisions = (scale1).floor
594
- scale = 1
595
- end
596
- if ( scale2 > 1 && scale2 <= max_divs && !scale_ok)
597
- scale_ok = true
598
- divisions = (scale2).floor
599
- scale = 2
600
- end
601
- if (!scale_ok)
602
- factor = factor * 10 if ( scale2 > 1 )
603
- factor = factor / 10 if ( scale2 < 1 )
604
- end
605
- end
606
- if ((((@vmax*1.0 / scale) / factor)).floor != ((@vmax*1.0 / scale) / factor))
607
- grid_id = ( @vmax*1.0 / scale / factor).floor + 1
608
- @vmax = grid_id * scale * factor
609
- divisions = divisions+1
610
- end
611
-
612
- if (((@vmin*1.0 / scale) / factor).floor != ((@vmin*1.0 / scale) / factor))
613
-
614
- grid_id = ( @vmin*1.0 / scale / factor).floor
615
- @vmin = grid_id * scale * factor*1.0
616
- divisions = divisions+1
617
- end
618
-
619
- else #/* Can occurs for small graphs */
620
- scale = 1
621
- end
622
- divisions = 2 if ( divisions.nil? )
623
-
624
- if ( is_real_int((@vmax-@vmin)/(divisions-1)))
625
- divisions-=1
626
- elsif ( is_real_int((@vmax-@vmin)/(divisions+1)))
627
- divisions+=1
628
- end
629
- else
630
- divisions =@divisions
631
- end
632
- @division_count = divisions
633
-
634
- data_range = @vmax - @vmin
635
- data_range = 0.1 if (data_range == 0 )
636
- @division_height = ( @g_area_y2 - @g_area_y1 )*1.0 / divisions
637
- @division_ratio = ( @g_area_y2 - @g_area_y1 )*1.0 /data_range
638
- ypos = @g_area_y2
639
- xmin = nil
640
- i =1
641
-
642
- while(i<= divisions+1)
643
- self.draw_line(@g_area_x1,ypos,@g_area_x1-5,ypos,r,g,b)
644
- value = @vmin*1.0 + (i-1) * (( @vmax - @vmin ) / divisions)
645
- value = (round_of(value * (10**decimals),2)) / (10**decimals)
646
- value= value.round if value.floor == value.ceil
647
- value = "#{value} #{data_description['unit']['y']}" if ( data_description["format"]["y"]== "number")
648
- value = self.to_time(value) if ( data_description["format"]["y"] == "time" )
649
- value = self.to_date(value) if ( data_description["format"]["y"] == "date" )
650
- value = self.to_metric(value) if ( data_description["format"]["Y"] == "metric" )
651
- value = self.to_currency(value) if ( data_description["format"]["Y"] == "currency" )
652
-
653
- position = image_ftb_box(@font_size,0,@font_name,value)
654
- text_width =position[2]-position[0]
655
- image_ttf_text(@picture,@font_size,0,@g_area_x1-10-text_width,ypos+(@font_size/2),c_text_color,@font_name,value)
656
- xmin = @g_area_x1-10-text_width if ( xmin.nil? || xmin > @g_area_x1-10-text_width)
657
- ypos = ypos - @division_height
658
- i = i+1
659
-
660
- end
661
-
662
- # Process X scale */
663
- if(@v_x_min.nil? && @v_x_max.nil?)
664
-
665
- @v_x_min =data[0][x_serie_name]
666
- @v_x_max =data[0][x_serie_name]
667
- data.each do |key|
668
-
669
- if !key[x_serie_name].nil?
670
- value = key[x_serie_name]
671
- if (value.is_a?(Numeric))
672
-
673
- @v_x_max = value if ( @v_x_max < value)
674
- @v_x_min = value if ( @v_x_min > value)
675
- end
676
- end
677
- end
678
-
679
- if (@v_x_max.is_a?(String))
680
- @v_x_max = @v_x_max.gsub(/\.[0-9]+/,'')+1 if (@v_x_max > @v_x_max.gsub(/\.[0-9]+/,'') )
681
- end
682
-
683
- data_range = @vmax - @vmin
684
- data_range = 0.1 if (data_range.to_f == 0.0)
685
-
686
- # Compute automatic scaling
687
- scale_ok = false
688
- factor = 1
689
- min_div_width = 25
690
- max_divs = (@g_area_x2 - @g_area_x1) / min_div_width
691
-
692
- if ( @v_x_min == 0 && @v_x_max == 0 )
693
- @v_x_min = 0
694
- @v_x_max = 2
695
- scale = 1
696
- x_divisions = 2
697
- elsif (max_divs > 1)
698
-
699
- while(!scale_ok)
700
- scale1 = ( @v_x_max - @v_x_min ) / factor
701
- scale2 = ( @v_x_max - @v_x_min ) / factor / 2
702
- scale4 = ( @v_x_max - @v_x_min ) / factor / 4
703
- if ( scale1 > 1 && scale1 <= max_divs && !scale_ok)
704
- scale_ok = true
705
- x_divisions = (scale1).floor
706
- scale = 1
707
- end
708
-
709
- if ( scale2 > 1 && scale2 <= max_divs && !scale_ok)
710
- scale_ok = true
711
- x_divisions = (scale2).floor
712
-
713
- scale = 2
714
- end
715
- if (!scale_ok)
716
- factor = factor * 10 if ( scale2 > 1 )
717
- factor = factor / 10 if ( scale2 < 1 )
718
- end
719
- end
720
-
721
- if ( (@v_x_max*1.0 / scale / factor).floor != @v_x_max / scale / factor)
722
- grid_id = ( @v_x_max*1.0 / scale / factor).floor + 1
723
- @v_x_max = grid_id * scale * factor
724
- x_divisions+=1
725
- end
726
-
727
- if ( (@v_x_min*1.0 / scale / factor).floor != @v_x_min / scale / factor)
728
- grid_id = ( @v_x_min / scale / factor).floor
729
- @v_x_min = grid_id * scale * factor
730
- x_divisions+=1
731
- end
732
- else #/* Can occurs for small graphs */
733
- scale = 1;
734
- end
735
- x_divisions = 2 if ( x_divisions.nil? )
736
-
737
- if ( is_real_int((@v_x_max-@v_x_min)/(x_divisions-1)))
738
- x_divisions-=1
739
- elsif ( is_real_int((@v_x_max-@v_x_min)/(x_divisions+1)))
740
- x_divisions+=1
741
- end
742
- else
743
-
744
- x_divisions = @x_divisions
745
- end
746
-
747
- @x_division_count = divisions
748
- @data_count = divisions + 2
749
-
750
- x_data_range = @v_x_max - @v_x_min
751
- x_data_range = 0.1 if ( x_data_range == 0 )
752
-
753
- @division_width = ( @g_area_x2 - @g_area_x1 ) / x_divisions
754
- @x_division_ratio = ( @g_area_x2 - @g_area_x1 ) / x_data_range
755
- xpos = @g_area_x1
756
- ymax =nil
757
- i=1
758
-
759
- while(i<= x_divisions+1)
760
- self.draw_line(xpos,@g_area_y2,xpos,@g_area_y2+5,r,g,b)
761
- value = @v_x_min + (i-1) * (( @v_x_max - @v_x_min ) / x_divisions)
762
- value = (round_of(value * (10**decimals),2)) / (10**decimals)
763
- value= value.round if value.floor == value.ceil
764
- value = "#{value}#{data_description['unit']['y']}" if ( data_description["format"]["y"]== "number")
765
- value = self.to_time(value) if ( data_description["format"]["y"] == "time" )
766
- value = self.to_date(value) if ( data_description["format"]["y"] == "date" )
767
- value = self.to_metric(value) if ( data_description["format"]["Y"] == "metric" )
768
- value = self.to_currency(value) if ( data_description["format"]["Y"] == "currency" )
769
- position = image_ftb_box(@font_size,angle,@font_name,value)
770
- text_width =position[2].abs+position[0].abs
771
- text_height = position[1].abs+position[3].abs
772
-
773
- if ( angle == 0 )
774
- ypos = @g_area_y2+18
775
- image_ttf_text(@picture,@font_size,angle,(xpos).floor-(text_width/2).floor,ypos,c_text_color,@font_name,value)
776
- else
777
-
778
- ypos = @g_area_y2+10+text_height
779
- if ( angle <= 90 )
780
- image_ttf_text(@picture,@font_size,angle,(xpos).floor-text_width+5,ypos,c_text_color,@font_name,value)
781
- else
782
- image_ttf_text(@picture,@font_size,angle,(xpos).floor+text_width+5,ypos,c_text_color,@font_name,value)
783
- end
784
-
785
- end
786
-
787
- ymax = ypos if (ymax.nil? || ymax < ypos)
788
- i=i+1
789
- xpos = xpos + @division_width
790
- end
791
- # Write the Y Axis caption if set
792
- if ((!data_description["axis"].nil? && !data_description["axis"]["y"].nil?) )
793
- position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["y"])
794
- # text_height = (position[1]).abs+(position[3]).abs
795
- text_top = ((@g_area_y2 - @g_area_y1) / 2) + @g_area_y1 + (text_width/2)
796
- image_ttf_text(@picture,@font_size,90,xmin-@font_size,text_top,c_text_color,@font_name,data_description["axis"]["y"].to_s)
797
- end
798
- if ((!data_description["axis"].nil? && !data_description["axis"]["x"].nil?) )
799
- position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["x"])
800
- text_width = (position[2]).abs+(position[0]).abs
801
- text_left = ((@g_area_x2 - @g_area_x1) / 2) + @g_area_x1 + (text_width/2)
802
- image_ttf_text(@picture,@font_size,0,text_left,ymax+@font_size+5,c_text_color,@font_name,data_description["axis"]["x"].to_s)
803
- end
804
-
805
- end
806
-
807
- # This function will draw a grid over the graph area.
808
- # line_width will be passed to the draw_dotted_line function.
809
- # The r,g,b 3 parameters are used to set the grid color.
810
- # Setting mosaic to true will draw grey area between two lines.
811
- # You can define the transparency factor of the mosaic area playing with the alpha parameter.
812
-
813
- def draw_grid(line_width,mosaic=true,r=220,g=220,b=220,alpha=100)
814
- # Draw mosaic */
815
- if (mosaic)
816
- layer_width = @g_area_x2-@g_area_x1
817
- layer_height = @g_area_y2-@g_area_y1
818
-
819
- @layers[0] = image_create_true_color(layer_width,layer_height)
820
- #c_white = allocate_color(@layers[0],255,255,255);
821
- image_filled_rectangle(@layers[0],0,0,layer_width,layer_height,255,255,255)
822
- image_color_transparent(@layers[0],255,255,255)
823
-
824
- #c_rectangle =allocate_color(@layers[0],250,250,250);
825
-
826
- y_pos = layer_height #@g_area_y2-1
827
- last_y = y_pos
828
- i =0
829
- while(i<=@division_count)
830
- last_y= y_pos
831
- y_pos = y_pos - @division_height
832
- y_pos = 1 if ( y_pos <= 0 )
833
- image_filled_rectangle(@layers[0],1, y_pos,layer_width-1,last_y,250,250,250) if ( i % 2 == 0 )
834
- i = i+1
835
- end
836
- image_copy_merge(@layers[0],@picture,@g_area_x1,@g_area_y1,0,0,layer_width,layer_height,alpha);
837
- @layers[0].destroy
838
- end
839
-
840
- #Horizontal lines
841
- y_pos = @g_area_y2 - @division_height
842
- i=1
843
- while(i<=@division_count)
844
- self.draw_dotted_line(@g_area_x1,y_pos,@g_area_x2,y_pos,line_width,r,g,b) if ( y_pos > @g_area_y1 && y_pos < @g_area_y2 )
845
- y_pos = y_pos - @division_height
846
- i = i+1
847
- end
848
- # Vertical lines
849
- if (@g_area_x_offset == 0 )
850
- x_pos = @g_area_x1 + (@division_width) +@g_area_x_offset
851
- col_count = (@data_count.to_f-2).floor
852
- else
853
-
854
- x_pos = @g_area_x1 +@g_area_x_offset
855
- col_count = ( (@g_area_x2 - @g_area_x1) / @division_width )
856
- end
857
- i= 1
858
-
859
- while (i<=col_count)
860
- if ( x_pos > @g_area_x1 && x_pos < @g_area_x2 )
861
- self.draw_dotted_line((x_pos).floor,@g_area_y1,(x_pos).floor,@g_area_y2,line_width,r,g,b)
862
- end
863
- x_pos = x_pos + @division_width
864
- i= i+1
865
- end
866
- end
867
-
868
-
869
- # This function evaluate the width and height of the box generated by the draw_legend.
870
- # This will help you to calculate dynamicaly the position where you want to print it (eg top-right).
871
- # You must provide the data_description array as only parameter.
872
- # This function will return and array containing in the first row the width of the box and in the second row the height of the box.
873
-
874
- def get_legend_box_size(data_description)
875
- return(-1) if data_description["description"].nil?
876
- # <-10->[8]<-4->Text<-10->
877
- max_width = 0
878
- max_height = 8
879
- data_description["description"].each do |key,value|
880
- position = image_ftb_box(@font_size,0,@font_name,value)
881
- text_width = position[2]-position[0]
882
- text_height = position[1]-position[7]
883
- max_width = text_width if (text_width > max_width)
884
- max_height = max_height + text_height + 4
885
- end
886
- max_height = max_height - 3
887
- max_width = max_width + 32
888
-
889
- [max_width,max_height]
890
- end
891
- # This function will draw the legend of the graph ( serie color & serie name ) at the specified position.
892
- # The r,g,bparameters are used to set the background color. You can optionally provide the shadow color using the rs,gs,bs parameters.
893
- # You can also customize the text color using the rt,gt,bt.
894
- # Setting Border to false remove the surrounding box.
895
-
896
- def draw_legend(x_pos,y_pos,data_description,r,g,b,rs=-1,gs=-1,bs=-1,rt=0,gt=0,bt=0,border=true)
897
- #Validate the Data and data_description array
898
- data_description = self.validate_data_description("draw_legend",data_description)
899
- return(-1) if (data_description["description"].nil?)
900
- c_text_color = allocate_color(@picture, rt, gt, bt)
901
- # <-10->[8]<-4->Text<-10->
902
- max_width = 0
903
- max_height = 8
904
- data_description["description"].each do |key,value|
905
- position = image_ftb_box(@font_size,0,@font_name,value)
906
- text_width = position[2]-position[6].abs
907
- text_height = position[1]-position[7]
908
- max_width = text_width if ( text_width > max_width)
909
- max_height = max_height + text_height + 4
910
- end
911
- max_height = max_height - 5
912
- max_width = max_width + 32
913
- if ( rs == -1 || gs == -1 || bs == -1 )
914
- rs = r-30
915
- gs = g-30
916
- bs = b-30
917
- end
918
-
919
- if ( border )
920
-
921
- self.draw_filled_rounded_rectangle(x_pos+1,y_pos+1,x_pos+max_width+1,y_pos+max_height+1,5,rs,gs,bs)
922
- self.draw_filled_rounded_rectangle(x_pos,y_pos,x_pos+max_width,y_pos+max_height,5,r,g,b)
923
- end
924
- y_offset = 4 + @font_size
925
- id = 0
926
-
927
- data_description["description"].each do |key,value|
928
- self.draw_filled_rounded_rectangle(x_pos+10,y_pos+y_offset-4 , x_pos+14, y_pos+y_offset-4, 2, @palette[id]["r"], @palette[id]["g"], @palette[id]["b"])
929
- image_ttf_text(@picture, @font_size,0, x_pos+22, y_pos+y_offset, c_text_color, @font_name, value)
930
- position = image_ftb_box(@font_size,0,@font_name,value);
931
- text_height = position[1]-position[7]
932
- y_offset = y_offset + text_height + 4
933
- id=id+1
934
- end
935
- end
936
-
937
- # This function will draw the legend of a pie graph ( serie color & value name ).
938
- # Be carrefull, dataset used for pie chart are not the same than for other line / curve / plot graphs.
939
- # You can specify the position of the legend box and the background color.
940
- def draw_pie_legend(x_pos,y_pos,data,data_description,r,g,b)
941
- data_description = self.validate_data_description("draw_pie_legend",data_description,false)
942
- self.validate_data("draw_pie_legend",data)
943
- return(-1) if (data_description["position"].nil?)
944
- c_text_color = allocate_color(@picture,0,0,0)
945
-
946
- # <-10->[8]<-4->Text<-10-> */
947
- max_width = 0
948
- max_height = 8
949
- data.each do |key|
950
- value = key[data_description["position"]]
951
- position = image_ftb_box(@font_size,0,@font_name,value)
952
- text_width = position[2]-position[0]
953
- text_height = position[1]-position[7]
954
- max_width = text_width if ( text_width > max_width)
955
- max_height = max_height + text_height + 4
956
- end
957
- max_height = max_height - 3
958
- max_width = max_width + 32
959
- self.draw_filled_rounded_rectangle(x_pos+1,y_pos+1,x_pos+max_width+1,y_pos+max_height+1,5,r-30,g-30,b-30)
960
- self.draw_filled_rounded_rectangle(x_pos,y_pos,x_pos+max_width,y_pos+max_height,5,r,g,b)
961
- y_offset = 4 + @font_size
962
- id = 0
963
- data.each do |key|
964
- value = key[data_description["position"]]
965
- position = image_ftb_box(@font_size,0,@font_name,value);
966
- text_height = position[1]-position[7]
967
- self.draw_filled_rectangle(x_pos+10,y_pos+y_offset-6,x_pos+14,y_pos+y_offset-2,@palette[id]["r"],@palette[id]["g"],@palette[id]["b"]);
968
- image_ttf_text(@picture,@font_size,0,x_pos+22,y_pos+y_offset,c_text_color,@font_name,value)
969
- y_offset = y_offset + text_height + 4
970
- id= id+1
971
- end
972
- end
973
-
974
- # This function is used to write the graph title.
975
- # Used with default parameters you must specify the bottom left position of the text.
976
- # if you are specifying x2 and y2 the text will be centered horizontaly and verticaly in the box of coordinates (x1,y1)-(x2,y2).
977
- # value correspond to the text that will be written on the graph.
978
- # r, g and b are used to set the text color.
979
- # Setting shadow to true will makes a shadow behind the text.
980
- def draw_title(x_pos,y_pos,value,r,g,b,x_pos2=-1,y_pos2=-1,shadow=false)
981
- c_text_color = allocate_color(@picture, r, g, b)
982
- if ( x_pos2 != -1 )
983
- position = image_ftb_box(@font_size,0,@font_name,value)
984
- text_width = position[2]-position[0]
985
- x_pos =(( x_pos2 - x_pos -text_width ) / 2 ).floor + x_pos
986
- end
987
- if ( y_pos2 != -1 )
988
- position = image_ftb_box(@font_size,0,@font_name,value)
989
- text_height = position[5]-position[3]
990
- y_pos =(( y_pos2 - y_pos - text_height ) / 2 ).floor + y_pos
991
- end
992
- if ( shadow )
993
- c_shadow_color = allocate_color(@picture,@shadow_r_color,@shadow_g_color,@shadow_b_color)
994
- image_ttf_text(@picture,@font_size,0,x_pos+@shadow_x_distance,y_pos+@shadow_y_distance, c_shadow_color ,@font_name,value)
995
- end
996
- image_ttf_text(@picture,@font_size,0,x_pos,y_pos,c_text_color,@font_name,value);
997
- end
998
-
999
- # Use this function to write text over the picture.
1000
- # You must specify the coordinate of the box where the text will be written using the (x1,y1)-(x2,y2) parameters, the text angle and the text color with the r,g,b parameters.
1001
- # You can choose how the text will be aligned with the align parameter :
1002
- # * Rchart:: ALIGN_TOP_LEFT Use the box top left corner.
1003
- # * Rchart:: ALIGN_TOP_CENTER Use the box top center corner.
1004
- # * Rchart:: ALIGN_TOP_RIGHT Use the box top right corner.
1005
- # * Rchart:: ALIGN_LEFT Use the center left.
1006
- # * Rchart:: ALIGN_CENTER Use the center.
1007
- # * Rchart:: ALIGN_RIGHT Use the center right.
1008
- # * Rchart:: ALIGN_BOTTOM_LEFT Use the box bottom left corner.
1009
- # * Rchart:: ALIGN_BOTTOM_CENTER Use the box bottom center corner.
1010
- # * Rchart:: ALIGN_BOTTOM_RIGHT Use the box bottom right corner.
1011
-
1012
- def draw_text_box(x1,y1,x2,y2,text,angle=0,r=255,g=255,b=255,align=ALIGN_LEFT,shadow=true,bgr=-1,bgg=-1,bgb=-1,alpha=100)
1013
- position = image_ftb_box(@font_size,angle,@font_name,text)
1014
- text_width = position[2]-position[0]
1015
- text_height = position[5]-position[3]
1016
- area_width = x2 - x1
1017
- area_height = y2 - y1
1018
- x =nil
1019
- y = nil
1020
-
1021
- if ( bgr != -1 && bgg != -1 && bgb != -1 )
1022
- self.draw_filled_rectangle(x1,y1,x2,y2,bgr,bgg,bgb,false,alpha)
1023
- end
1024
-
1025
- if ( align == ALIGN_TOP_LEFT )
1026
- x = x1+1
1027
- y = y1+@font_size+1
1028
- end
1029
-
1030
- if ( align == ALIGN_TOP_CENTER )
1031
- x = x1+(area_width/2)-(text_width/2)
1032
- y = y1+@font_size+1
1033
- end
1034
-
1035
- if ( align == ALIGN_TOP_RIGHT )
1036
- x = x2-text_width-1
1037
- y = y1+@font_size+1
1038
- end
1039
- if ( align == ALIGN_LEFT )
1040
- x = x1+1
1041
- y = y1+(area_height/2)-(text_height/2)
1042
- end
1043
- if ( align == ALIGN_CENTER )
1044
- x = x1+(area_width/2)-(text_width/2)
1045
- y = y1+(area_height/2)-(text_height/2)
1046
- end
1047
- if ( align == ALIGN_RIGHT )
1048
- x = x2-text_width-1
1049
- y = y1+(area_height/2)-(text_height/2)
1050
- end
1051
- if ( align == ALIGN_BOTTOM_LEFT )
1052
- x = x1+1
1053
- y = y2-1
1054
- end
1055
- if ( align == ALIGN_BOTTOM_CENTER )
1056
- x = x1+(area_width/2)-(text_width/2)
1057
- y = y2-1
1058
- end
1059
- if ( align == ALIGN_BOTTOM_RIGHT )
1060
- x = x2-text_width-1
1061
- y = y2-1
1062
- end
1063
- c_text_color =allocate_color(@picture,r,g,b)
1064
- c_shadow_color =allocate_color(@picture,0,0,0)
1065
- if ( shadow )
1066
- image_ttf_text(@picture,@font_size,angle,x+1,y+1,c_shadow_color,@font_name,text)
1067
- end
1068
-
1069
- image_ttf_text(@picture,@font_size,angle,x,y,c_text_color,@font_name,text)
1070
- end
1071
-
1072
- # This function will draw an horizontal treshold ( this is an easy way to draw the 0 line ).
1073
- # If show_label is set to true, the value of the treshold will be written over the graph.
1074
- # If show_on_right is set to true, the value will be written on the right side of the graph.
1075
- # r, g and b are used to set the line and text color.
1076
- # Use tick_width to set the width of the ticks, if set to 0 this will draw a solid line.
1077
- # You can optionnaly provide the caption of the treshold (by default the treshold value is used)
1078
-
1079
- def draw_treshold(value,r,g,b,show_label=false,show_on_right=false,tick_width=4,free_text=nil)
1080
- b, g, r = validate_color(b, g, r)
1081
-
1082
- c_text_color =allocate_color(@picture,r,g,b)
1083
- # c_text_color = GD2::Color.new(r,g,b)
1084
- y = @g_area_y2 - (value - @vmin.to_f) * @division_ratio.to_f
1085
-
1086
- return(-1) if ( y <= @g_area_y1 || y >= @g_area_y2 )
1087
- if ( tick_width == 0 )
1088
- self.draw_line(@g_area_x1,y,@g_area_x2,y,r,g,b)
1089
- else
1090
- self.draw_dotted_line(@g_area_x1,y,@g_area_x2,y,tick_width,r,g,b)
1091
- end
1092
- if (show_label )
1093
- if ( free_text.nil? )
1094
- label = value
1095
- else
1096
- label = free_text
1097
- end
1098
-
1099
- if ( show_on_right )
1100
- image_ttf_text(@picture,@font_size,0,@g_area_x2+2,y+(@font_size/2),c_text_color,@font_name,label.to_s)
1101
- else
1102
- image_ttf_text(@picture,@font_size,0,@g_area_x1+2,y-(@font_size/2),c_text_color,@font_name,label.to_s)
1103
- end
1104
- end
1105
- end
1106
-
1107
- # This function will draw a label over the graph.
1108
- # You must specify the data & data_description structures, the serie name ( "Serie1" by default if only one ),
1109
- # the x position of the value in the data array (will be numeric starting at 0 if no abscise_label are defined or the value of the selected abscise serie if specified), the caption that will displayed and optionally the color of the label
1110
-
1111
- def set_label(data,data_description,serie_name,value_name,caption,r=210,g=210,b=210)
1112
- data_description = self.validate_data_description("set_label",data_description)
1113
- self.validate_data("set_label",data)
1114
- shadow_factor = 100
1115
- c_label =allocate_color(@picture,r,g,b)
1116
- c_shadow =allocate_color(@picture,r-shadow_factor,g-shadow_factor,b-shadow_factor)
1117
- c_text_color =allocate_color(@picture,0,0,0)
1118
- cp = 0
1119
- found = false
1120
- numerical_value = 0
1121
- data.each do |key|
1122
- if key[data_description["position"]].to_s == value_name.to_s
1123
- numerical_value = key[serie_name]
1124
- found = true
1125
- end
1126
- cp +=1 if !found
1127
- end
1128
-
1129
- xpos = @g_area_x1 + @g_area_x_offset + ( @division_width * cp ) + 2
1130
- ypos = @g_area_y2 - (numerical_value - @vmin) *@division_ratio
1131
- position = image_ftb_box(@font_size,0,@font_name,caption)
1132
- text_height = position[3] - position[5]
1133
- text_width = position[2]-position[0] + 2
1134
- text_offset = (text_height/2).floor
1135
- # Shadow
1136
- poly = [xpos+1,ypos+1,xpos + 9,ypos - text_offset,xpos + 8,ypos + text_offset + 2]
1137
- image_filled_polygon(@picture,poly,r-shadow_factor,g-shadow_factor,b-shadow_factor,3)
1138
- self.draw_line(xpos,ypos+1,xpos + 9,ypos - text_offset - 0.2,r-shadow_factor,g-shadow_factor,b-shadow_factor)
1139
- self.draw_line(xpos,ypos+1,xpos + 9,ypos + text_offset + 2.2,r-shadow_factor,g-shadow_factor,b-shadow_factor)
1140
- self.draw_filled_rectangle(xpos + 9,ypos - text_offset-0.2,xpos + 13 + text_width,ypos + text_offset + 2.2,r-shadow_factor,g-shadow_factor,b-shadow_factor)
1141
-
1142
- #Label background
1143
- poly = [xpos,ypos,xpos + 8,ypos - text_offset - 1,xpos + 8,ypos + text_offset + 1]
1144
- image_filled_polygon(@picture,poly,r,g,b,3)
1145
- self.draw_line(xpos-1,ypos,xpos + 8,ypos - text_offset - 1.2,r,g,b)
1146
- self.draw_line(xpos-1,ypos,xpos + 8,ypos + text_offset + 1.2,r,g,b)
1147
- self.draw_filled_rectangle(xpos + 8,ypos - text_offset - 1.2,xpos + 12 + text_width,ypos + text_offset + 1.2,r,g,b)
1148
-
1149
- image_ttf_text(@picture,@font_size,0,xpos + 10,ypos + text_offset,c_text_color,@font_name,caption)
1150
- end
1151
-
1152
- # This function will draw a plot graph using all the registered series.
1153
- # Giving only the data & data_description structure will draw the basic plot graph,
1154
- # You can specify the radius ( external & internal ) of the plots.
1155
- # You can also specify the color of the points ( will be unique in case of multiple series ).
1156
- # Setting Shadow to true will draw a shadow under the plots.
1157
-
1158
- def draw_plot_graph(data,data_description,big_radius=5,small_radius=2,r2=-1,g2=-1,b2=-1,shadow=false)
1159
- #/* Validate the Data and data_description array */
1160
- data_description = self.validate_data_description("draw_plot_graph",data_description)
1161
- self.validate_data("draw_plot_graph",data)
1162
- graph_id = 0
1163
- ro = r2
1164
- go = g2
1165
- bo = b2
1166
- id =0
1167
- color_id =0
1168
- data_description["values"].each do |col_name|
1169
- data_description["description"].each do |key_i,value_i|
1170
- if ( key_i == col_name )
1171
- color_id = id
1172
- id = id+1
1173
- end
1174
- end
1175
- r = @palette[color_id]["r"];
1176
- g = @palette[color_id]["g"];
1177
- b = @palette[color_id]["b"];
1178
- r2 = ro
1179
- g2 = go
1180
- b2 = bo
1181
- #TODO convert this function
1182
-
1183
- if ( !data_description["symbol"].nil? && !data_description["symbol"][col_name].nil?)
1184
- is_alpha = false # ((ord ( file_get_contents (data_description["symbol"][col_name], false, NULL, 25, 1)) & 6) & 4) == 4;
1185
- im_symbol = image_create_from_png(data_description["symbol"][col_name])
1186
- infos = get_image_size(im_symbol)
1187
- image_width = infos[0]
1188
- image_height = infos[1]
1189
- #
1190
- end
1191
-
1192
- x_pos = @g_area_x1 + @g_area_x_offset
1193
- h_size = (big_radius/2).round
1194
- r3 = -1
1195
- g3 = -1
1196
- b3 = -1
1197
- data.each do |key|
1198
- value= key[col_name]
1199
- if value.is_a?(Numeric)
1200
- y_pos = @g_area_y2 - ((value-@vmin) * @division_ratio)
1201
- else
1202
- y_pos = @g_area_y2 - ((0-@vmin) * @division_ratio)
1203
- end
1204
-
1205
-
1206
- # Save point into the image map if option activated
1207
- if ( @build_map )
1208
- #add_to_image_map(x_pos-h_size,y_pos-h_size,x_pos+1+h_size,y_pos+h_size+1,data_description["description"][col_name],key[col_name].data_description["unit"]["y"],"Plot");
1209
- end
1210
-
1211
- if(value.is_a?(Numeric))
1212
- #MY Hack
1213
- if (data_description["symbol"].nil? || data_description["symbol"][col_name].nil? )
1214
- if ( shadow )
1215
- if ( r3 !=-1 && g3 !=-1 && b3 !=-1 )
1216
- self.draw_filled_circle(x_pos+2,y_pos+2,big_radius,r3,g3,b3)
1217
- else
1218
- r3 = @palette[color_id]["r"]-20
1219
- r3 = 0 if ( r3 < 0 )
1220
- g3 = @palette[color_id]["g"]-20
1221
- g3 = 0 if ( g3 < 0 )
1222
- b3 = @palette[color_id]["b"]-20
1223
- b3 = 0 if ( b3 < 0 )
1224
- self.draw_filled_circle(x_pos+2,y_pos+2,big_radius,r3,g3,b3)
1225
- end
1226
- end
1227
- self.draw_filled_circle(x_pos+1,y_pos+1,big_radius,r,g,b)
1228
- if ( small_radius != 0 )
1229
- if ( r2 !=-1 && g2 !=-1 && b2 !=-1 )
1230
- self.draw_filled_circle(x_pos+1,y_pos+1,small_radius,r2,g2,b2);
1231
- else
1232
- r2 = @palette[color_id]["r"]-15
1233
- r2 = 0 if ( r2 < 0 )
1234
- g2 = @palette[color_id]["g"]-15
1235
- g2 = 0 if ( g2 < 0 )
1236
- b2 = @palette[color_id]["b"]-15
1237
- b2 = 0 if ( b2 < 0 )
1238
- self.draw_filled_circle(x_pos+1,y_pos+1,small_radius,r2,g2,b2)
1239
- end
1240
- end
1241
- else
1242
- image_copy_merge(im_symbol,@picture,x_pos+1-image_width/2,y_pos+1-image_height/2,0,0,image_width,image_height,100)
1243
- end
1244
- end
1245
- x_pos = x_pos + @division_width
1246
- end
1247
- graph_id+=1
1248
- end
1249
- end
1250
-
1251
- # This function is very similar as the draw_plot_graph function.
1252
- # You must specify the name of the two series that will be used as x and y coordinates and the color id to use.
1253
-
1254
- def draw_xy_plot_graph(data,data_description,y_serie_name,x_serie_name,palette_id=0,big_radius=5,small_radius=2,r2=-1,g2=-1,b2=-1,shadow=true)
1255
- r = @palette[palette_id]["r"]
1256
- g = @palette[palette_id]["g"]
1257
- b = @palette[palette_id]["b"]
1258
- r3 = -1
1259
- g3 = -1
1260
- b3 = -1
1261
-
1262
- y_last = -1
1263
- x_last = -1
1264
- data.each do |key|
1265
- next if (key[y_serie_name].nil? or key[x_serie_name].nil?)
1266
-
1267
- x = key[x_serie_name]
1268
- y = key[y_serie_name]
1269
- y = @g_area_y2 - ((y-@vmin) * @division_ratio)
1270
- x = @g_area_x1 + ((x-@v_x_min) * @x_division_ratio)
1271
- if ( shadow )
1272
- if ( r3 !=-1 && g3 !=-1 && b3 !=-1 )
1273
- self.draw_filled_circle(x+2,y+2,big_radius,r3,g3,b3)
1274
- else
1275
- r3 = @palette[palette_id]["r"]-20
1276
- r = 0 if ( r < 0 )
1277
- g3 = @palette[palette_id]["g"]-20
1278
- g = 0 if ( g < 0 )
1279
- b3 = @palette[palette_id]["b"]-20
1280
- b = 0 if ( b < 0 )
1281
- draw_filled_circle(x+2,y+2,big_radius,r3,g3,b3)
1282
- end
1283
- end
1284
- draw_filled_circle(x+1,y+1,big_radius,r,g,b)
1285
-
1286
- if ( r2 !=-1 && g2 !=-1 && b2 !=-1 )
1287
- draw_filled_circle(x+1,y+1,small_radius,r2,g2,b2)
1288
- else
1289
- r2 = @palette[palette_id]["r"]+20
1290
- r = 255 if ( r > 255 )
1291
- g2 = @palette[palette_id]["g"]+20
1292
- g = 255 if ( g > 255 )
1293
- b2 = @palette[palette_id]["b"]+20
1294
- b = 255 if ( b > 255 )
1295
- draw_filled_circle(x+1,y+1,small_radius,r2,g2,b2)
1296
- end
1297
- end
1298
- end
1299
-
1300
- # This function will draw an area between two data series.
1301
- # extracting the minimum and maximum value for each X positions.
1302
- # You must specify the two series name and the area color.
1303
- # You can specify the transparency which is set to 50% by default.
1304
-
1305
- def draw_area(data,serie1,serie2,r,g,b,alpha = 50)
1306
- self.validate_data("draw_area",data)
1307
- layer_width = @g_area_x2-@g_area_x1
1308
- layer_height = @g_area_y2-@g_area_y1
1309
-
1310
- @layers[0] = image_create_true_color(layer_width,layer_height)
1311
- image_filled_rectangle(@layers[0],0,0,layer_width,layer_height,255,255,255)
1312
- image_color_transparent(@layers[0],255,255,255)
1313
-
1314
- x_pos = @g_area_x_offset
1315
- last_x_pos = -1
1316
- last_y_pos1 = nil
1317
- last_y_pos2= nil
1318
- data.each do |key|
1319
- value1 = key[serie1]
1320
- value2 = key[serie2]
1321
- y_pos1 = layer_height - ((value1-@vmin) * @division_ratio)
1322
- y_pos2 = layer_height - ((value2-@vmin) * @division_ratio)
1323
-
1324
- if ( last_x_pos != -1 )
1325
- points = []
1326
- points << last_x_pos
1327
- points << last_y_pos1
1328
- points << last_x_pos
1329
- points << last_y_pos2
1330
- points << x_pos
1331
- points << y_pos2
1332
- points << x_pos
1333
- points << y_pos1
1334
- image_filled_polygon(@layers[0],points,r,g,b,4)
1335
- end
1336
- last_y_pos1 = y_pos1
1337
- last_y_pos2 = y_pos2
1338
- last_x_pos = x_pos
1339
- x_pos= x_pos+ @division_width
1340
- end
1341
- image_copy_merge(@layers[0],@picture,@g_area_x1,@g_area_y1,0,0,layer_width,layer_height,alpha);
1342
- image_destroy(@layers[0])
1343
- end
1344
-
1345
- # You can use this function to display the values contained in the series on top of the charts.
1346
- # It is possible to specify one or multiple series to display using and array.
1347
- def write_values(data,data_description,series)
1348
-
1349
- data_description = self.validate_data_description("write_values",data_description)
1350
- self.validate_data("write_values",data)
1351
- series = [series] if ( !series.is_a?(Array))
1352
- id = 0
1353
- color_id =0
1354
- series.each do |col_name|
1355
- data_description["description"].each do |key_i,value_i|
1356
- if ( key_i == col_name )
1357
- color_id = id
1358
- id = id+1
1359
- end
1360
- end
1361
- xpos = @g_area_x1 + @g_area_x_offset
1362
- xlast = -1
1363
- data.each do |key|
1364
- if ((!key[col_name].nil?) && (key[col_name].is_a?(Numeric)))
1365
- value = key[col_name]
1366
- ypos = @g_area_y2 - ((value-@vmin) * @division_ratio)
1367
- positions = image_ftb_box(@font_size,0,@font_name,value.to_s)
1368
- width = positions[2] - positions[6]
1369
- x_offset = xpos - (width/2)
1370
- height = positions[3] - positions[7]
1371
- y_offset = ypos - 4
1372
-
1373
- c_text_color = allocate_color(@picture,@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"]);
1374
- image_ttf_text(@picture,@font_size,0,x_offset,y_offset,c_text_color,@font_name,value.to_s)
1375
- end
1376
- xpos = xpos + @division_width
1377
- end
1378
- end
1379
- end
1380
-
1381
- # This function will draw a line graph using all the registered series.
1382
- def draw_line_graph(data,data_description,serie_name="")
1383
- data_description = self.validate_data_description("draw_line_graph",data_description)
1384
- self.validate_data("draw_line_graph",data)
1385
- graph_id = 0
1386
- color_id =0
1387
- id =0
1388
- data_description["values"].each do |col_name|
1389
- data_description["description"].each do |key_i,value_i|
1390
- if ( key_i == col_name )
1391
- color_id = id
1392
- id = id+1
1393
- end
1394
- end
1395
- if ( serie_name == "" || serie_name == col_name )
1396
- x_pos = @g_area_x1 + @g_area_x_offset
1397
- x_last = -1
1398
- y_last = -1
1399
- data.each do |key|
1400
- if(!key[col_name].nil?)
1401
- value = key[col_name]
1402
- if(value.is_a?(Numeric))
1403
- y_pos= @g_area_y2 - ((value-@vmin) * @division_ratio)
1404
- else
1405
- y_pos= @g_area_y2 - ((0-@vmin) * @division_ratio)
1406
- end
1407
- # /* Save point into the image map if option activated */
1408
- if ( @build_map )
1409
- #self.add_to_image_map(x_pos-3,y_pos-3,x_pos+3,y_pos+3,data_description["description"][col_name],data[key][col_name].data_description["unit"]["y"],"Line");
1410
- end
1411
- x_last = -1 if(!value.is_a?(Numeric))
1412
- if ( x_last != -1 )
1413
- self.draw_line(x_last,y_last,x_pos,y_pos,@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],true)
1414
- end
1415
- x_last = x_pos
1416
- y_last = y_pos
1417
- x_last = -1 if(!value.is_a?(Numeric))
1418
- end
1419
- x_pos = x_pos + @division_width
1420
- end
1421
- graph_id+=1
1422
- end
1423
- end
1424
- end
1425
-
1426
- # This function will draw a scatter line graph.
1427
- # You must specify the x and y series that will be used.
1428
- # You can optionnaly set the color index in the current palette.
1429
- def draw_xy_graph(data,data_description,y_serie_name,x_serie_name,palette_id=0)
1430
- y_last = -1
1431
- x_last = -1
1432
- data.each do |key|
1433
- if ( !key[y_serie_name].nil? && !key[x_serie_name].nil? )
1434
- x= key[x_serie_name]
1435
- y = key[y_serie_name]
1436
- y = @g_area_y2 - ((y-@vmin) * @division_ratio);
1437
- x= @g_area_x1 + ((x-@v_x_min) * @x_division_ratio);
1438
- if (x_last != -1 && y_last != -1)
1439
- self.draw_line(x_last,y_last,x,y,@palette[palette_id]["r"],@palette[palette_id]["g"],@palette[palette_id]["b"],true)
1440
- end
1441
- x_last = x
1442
- y_last = y
1443
- end
1444
- end
1445
- end
1446
-
1447
- # This function will draw a curved line graph using all the registered series.
1448
- # This curve is using a cubic algorythm to process the average values between two points.
1449
- # You have to specify the accuracy between two points, typicaly a 0.1 value is acceptable. the smaller the value is, the longer it will take to process the graph.
1450
- def draw_cubic_curve(data,data_description,accuracy=0.1,serie_name="")
1451
-
1452
- data_description = self.validate_data_description("draw_cubic_curve",data_description)
1453
- self.validate_data("draw_cubic_curve",data)
1454
- graph_id = 0
1455
- id = 0
1456
- color_id =0
1457
-
1458
- data_description["values"].each do |col_name|
1459
- if ( serie_name == "" || serie_name == col_name )
1460
- x_in = []
1461
- y_in =[]
1462
- y_t = []
1463
- u = []
1464
- x_in[0] = 0
1465
- y_in[0] = 0
1466
-
1467
- data_description["description"].each do |key_i,value_i|
1468
- if ( key_i == col_name )
1469
- color_id = id
1470
- id = id+1
1471
- end
1472
- end
1473
- index = 1
1474
- x_last = -1
1475
- missing = []
1476
- data.each do |key|
1477
- if(!key[col_name].nil?)
1478
- val = key[col_name]
1479
-
1480
- x_in[index] = index
1481
- #y_in[index] = val
1482
- #my hack TODO "" convet missing values to zero
1483
- y_in[index] = val if ((val).is_a?(Numeric))
1484
- y_in[index] = 0 if (!(val).is_a?(Numeric))
1485
- ######
1486
- missing[index]=true if (!(val).is_a?(Numeric))
1487
- index=index+1
1488
- end
1489
- end
1490
- index= index-1
1491
- y_t[0] = 0
1492
- y_t[1] = 0
1493
- u[0] = 0
1494
- u[1] = 0
1495
- i =2
1496
- y_last =0
1497
-
1498
- while(i<=index-1)
1499
- sig = (x_in[i]-x_in[i-1])*1.0/(x_in[i+1]-x_in[i-1]) #rescue 0
1500
- p=sig*y_t[i-1]+2
1501
- y_t[i]=(sig-1)/p
1502
- u[i]=(y_in[i+1]-y_in[i])*1.0/(x_in[i+1]-x_in[i])-(y_in[i]-y_in[i-1])*1.0/(x_in[i]-x_in[i-1]) #rescue 0
1503
- u[i]=(6*u[i]/(x_in[i+1]-x_in[i-1])-sig*u[i-1])/p #rescue 0
1504
- i=i+1
1505
- end
1506
- qn = 0
1507
- un = 0
1508
- y_t[index] = (un - qn * u[index-1]) / (qn * y_t[index-1] + 1)
1509
- k = index-1
1510
- while k>=1
1511
- y_t[k]=y_t[k]* y_t[k+1]+u[k]
1512
- k=k-1
1513
- end
1514
- x_pos = @g_area_x1 + @g_area_x_offset
1515
- x =1
1516
- while x<=index
1517
- klo=1
1518
- khi=index
1519
- k = khi-klo
1520
- while k>1
1521
- k=khi-klo
1522
- if x_in[k]>=x
1523
- khi=k
1524
- else
1525
- klo=k
1526
- end
1527
- end
1528
- klo=khi-1
1529
- h = x_in[khi]-x_in[klo]
1530
- a = (x_in[khi]-x)/h rescue 1
1531
- b = (x-x_in[klo])/h rescue 1
1532
- value = a*y_in[klo]+b*y_in[khi]+((a*a*a-a)*y_t[klo]+(b*b*b-b)*y_t[khi])*(h*h)/6
1533
- y_pos = @g_area_y2-((value-@vmin)*@division_ratio)
1534
- #TODO Check(x_last!=-1 && !missing[x.floor].nil? && !missing[(x+1).floor].nil? )
1535
- #UPDATED
1536
- if (x_last!=-1 && missing[x.floor].nil? && missing[(x+1).floor].nil? )
1537
- self.draw_line(x_last,y_last,x_pos,y_pos, @palette[id]["r"],@palette[id]["g"],@palette[id]["b"],true)
1538
- end
1539
- x_last = x_pos
1540
- y_last = y_pos
1541
- x_pos = x_pos +@division_width*accuracy
1542
- x=x+accuracy
1543
- end
1544
- #Add potentialy missing values
1545
- x_pos = x_pos - @division_width * accuracy
1546
- if ( x_pos < (@g_area_x2 - @g_area_x_offset) )
1547
- y_pos = @g_area_y2 - ((y_in[index]-@vmin) * @division_ratio)
1548
- self.draw_line(x_last,y_last,@g_area_x2-@g_area_x_offset,y_pos,@palette[id]["r"],@palette[id]["g"],@palette[id]["b"],true)
1549
- end
1550
- graph_id += 1
1551
- end
1552
- end
1553
- end
1554
- # This function will draw a filled curved line graph using all the registered series.
1555
- # This curve is using a cubic algorythm to process the average values between two points.
1556
- # You have to specify the accuracy between two points, typicaly a 0.1 value is acceptable. the smaller the value is, the longer it will take to process the graph.
1557
- # You can provide the alpha value used when merging all series layers.
1558
- # If around_zero is set to true, the area drawn will be between the 0 axis and the line graph value.
1559
-
1560
- def draw_filled_cubic_curve(data,data_description,accuracy=0.1,alpha=100,around_zero=false)
1561
- data_description = self.validate_data_description("draw_filled_cubic_curve",data_description)
1562
- self.validate_data("draw_filled_cubic_curve",data)
1563
- layer_width = @g_area_x2-@g_area_x1
1564
- layer_height = @g_area_y2-@g_area_y1
1565
- y_zero = layer_height - ((0-@vmin) * @division_ratio)
1566
- y_zero = layer_height if ( y_zero > layer_height )
1567
- graph_id = 0
1568
- id = 0
1569
- color_id =0
1570
- data_description["values"].each do |col_name|
1571
- x_in = []
1572
- y_in =[]
1573
- y_t = []
1574
- u = []
1575
- x_in[0] = 0
1576
- y_in[0] = 0
1577
- data_description["description"].each do |key_i,value_i|
1578
- if ( key_i == col_name )
1579
- color_id = id
1580
- id = id+1
1581
- end
1582
- end
1583
- index = 1
1584
- x_last = -1
1585
- missing = []
1586
- data.each do |key|
1587
- if(!key[col_name].nil?)
1588
- val = key[col_name]
1589
- x_in[index] = index
1590
- y_in[index] = val
1591
- missing[index]=true if ((val).is_a?(Numeric))
1592
- index=index+1
1593
- end
1594
- end
1595
- index= index-1
1596
- y_t[0] = 0
1597
- y_t[1] = 0
1598
- u[1] = 0
1599
- i =2
1600
- y_last =0
1601
-
1602
- while(i<index)
1603
- sig = (x_in[i]-x_in[i-1])*1.0/(x_in[i+1]-x_in[i-1]) #rescue 0
1604
- p=sig*y_t[i-1]+2
1605
- y_t[i]=(sig-1)/p
1606
- u[i]=(y_in[i+1]-y_in[i])*1.0/(x_in[i+1]-x_in[i])-(y_in[i]-y_in[i-1])*1.0/(x_in[i]-x_in[i-1]) #rescue 0
1607
- u[i]=(6*u[i]/(x_in[i+1]-x_in[i-1])-sig*u[i-1])/p #rescue 0
1608
- i=i+1
1609
- end
1610
- qn = 0
1611
- un = 0
1612
- y_t[index] = (un - qn * u[index-1]) / (qn * y_t[index-1] + 1)
1613
- k = index-1
1614
- while k>=1
1615
- y_t[k]=y_t[k]* y_t[k+1]+u[k]
1616
- k=k-1
1617
- end
1618
- points = []
1619
- points << @g_area_x_offset
1620
- points << layer_height
1621
- @layers[0] = image_create_true_color(layer_width,layer_height)
1622
- image_filled_rectangle(@layers[0],0,0,layer_width,layer_height, 255,255,255)
1623
- image_color_transparent(@layers[0], 255,255,255)
1624
- y_last = nil
1625
- x_pos = @g_area_x_offset
1626
- points_count= 2
1627
- x=1
1628
- while(x<=index)
1629
- klo=1
1630
- khi=index
1631
- k = khi-klo
1632
- while k>1
1633
- k=khi-klo
1634
- if x_in[k]>=x
1635
- khi=k
1636
- else
1637
- klo=k
1638
- end
1639
- end
1640
- klo=khi-1
1641
- h = x_in[khi]-x_in[klo]
1642
- a = (x_in[khi]-x)/h rescue 1
1643
- b = (x-x_in[klo])/h rescue 1
1644
- value = a*y_in[klo]+b*y_in[khi]+((a*a*a-a)*y_t[klo]+(b*b*b-b)*y_t[khi])*(h*h)/6
1645
- y_pos = layer_height - ((value-@vmin) * @division_ratio);
1646
-
1647
- a_points = []
1648
- if ( !y_last.nil? && around_zero && (missing[x.floor].nil?) && (missing[(x+1).floor].nil?))
1649
-
1650
- a_points << x_last
1651
- a_points << y_last
1652
- a_points << x_pos
1653
- a_points << y_pos
1654
- a_points << x_pos
1655
- a_points << y_zero
1656
- a_points << x_last
1657
- a_points << y_zero
1658
- #check No of points here 4 is pass check in image filled_polygon
1659
- image_filled_polygon(@layers[0], a_points, @palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],4)
1660
- end
1661
- if ( missing[(x.floor)].nil? || y_last.nil?)
1662
- points_count = points_count+1
1663
- points << x_pos
1664
- points << y_pos
1665
- else
1666
- points_count = points_count+1
1667
- points << x_last
1668
- points << y_last
1669
- end
1670
- y_last = y_pos
1671
- x_last = x_pos
1672
- x_pos = x_pos + @division_width * accuracy
1673
- x=x+accuracy
1674
- end
1675
-
1676
- #// Add potentialy missing values
1677
- # a_points = []
1678
- x_pos = x_pos - @division_width * accuracy
1679
- if ( x_pos < (layer_width-@g_area_x_offset) )
1680
- y_pos = layer_height - ((y_in[index]-@vmin) * @division_ratio)
1681
- if ( !y_last.nil? && around_zero )
1682
- a_points << x_last
1683
- a_points << y_last
1684
- a_points << (layer_width-@g_area_x_offset)
1685
- a_points << y_pos
1686
- a_points << (layer_width-@g_area_x_offset)
1687
- a_points << y_zero
1688
- a_points << x_last
1689
- a_points << y_zero
1690
- # imagefilledpolygon(@layers[0],a_points,4,$C_Graph);
1691
- image_filled_polygon(@layers[0], a_points, @palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],4)
1692
- end
1693
-
1694
- if ( y_in[klo] != "" && y_in[khi] != "" || y_last.nil? )
1695
-
1696
- points_count +=1
1697
- points << (layer_width-@g_area_x_offset).floor
1698
- points << (y_pos).floor
1699
- end
1700
- end
1701
-
1702
- points << (layer_width-@g_area_x_offset).floor
1703
- points << layer_height.floor
1704
-
1705
- if ( !around_zero )
1706
- image_filled_polygon(@layers[0], points, @palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],points_count)
1707
- end
1708
-
1709
- image_copy_merge(@layers[0],@picture,@g_area_x1,@g_area_y1,0,0,layer_width,layer_height,alpha);
1710
- image_destroy(@layers[0])
1711
-
1712
- self. draw_cubic_curve(data, data_description,accuracy,col_name)
1713
- graph_id+=1
1714
- end
107
+ set_font_properties("tahoma.ttf",8)
1715
108
  end
1716
-
1717
- # This function will draw a filled line graph using all the registered series.
1718
- # You can provide the alpha value used when merging all series layers.
1719
- # If around_zero is set to true, the area drawn will be between the 0 axis and the line graph value.
1720
-
1721
- def draw_filled_line_graph(data,data_description,alpha=100,around_zero=false)
1722
- empty = -2147483647
1723
- data_description = self.validate_data_description("draw_filled_line_graph",data_description)
1724
- self.validate_data("draw_filled_line_graph",data)
1725
- layer_width = @g_area_x2-@g_area_x1
1726
- layer_height = @g_area_y2-@g_area_y1
1727
- graph_id = 0
1728
- id =0
1729
- color_id =0
1730
- data_description["values"].each do |col_name|
1731
- data_description["description"].each do |key_i,value_i|
1732
- if ( key_i == col_name )
1733
- color_id = id
1734
- id = id+1
1735
- end
1736
- end
1737
-
1738
- a_points = []
1739
- a_points << @g_area_x_offset
1740
- a_points << layer_height
1741
- @layers[0] = image_create_true_color(layer_width,layer_height)
1742
- c_white = allocate_color(@layers[0],255,255,255)
1743
- image_filled_rectangle(@layers[0],0,0,layer_width,layer_height,255,255,255)
1744
- image_color_transparent(@layers[0],255,255,255)
1745
-
1746
- xpos = @g_area_x_offset
1747
- xlast = -1
1748
- points_count = 2
1749
- y_zero = layer_height - ((0-@vmin) * @division_ratio)
1750
- y_zero = layer_height if ( y_zero > layer_height )
1751
- ylast = empty
1752
-
1753
- data.each do |key|
1754
- value = key[col_name]
1755
- if key[col_name].is_a?(Numeric)
1756
- ypos = layer_height - ((value-@vmin) * @division_ratio)
1757
- else
1758
- ypos = layer_height - ((0-@vmin) * @division_ratio)
1759
- end
1760
- # Save point into the image map if option activated */
1761
- if ( @build_map )
1762
- #self.add_to_image_map(xpos-3,ypos-3,xpos+3,ypos+3,data_description["description"][col_name],key[col_name].data_description["unit"]["Y"],"FLine");
1763
- end
1764
- if ( !(value.is_a?(Numeric)))
1765
- points_count+=1
1766
- a_points << xlast
1767
- a_points << layer_height
1768
- ylast = empty
1769
- else
1770
- points_count+=1
1771
- if ( ylast != empty )
1772
- a_points << xpos
1773
- a_points << ypos
1774
- else
1775
- points_count+=1
1776
- a_points << xpos
1777
- a_points << layer_height
1778
- a_points << xpos
1779
- a_points << ypos
1780
- end
1781
-
1782
- if (ylast !=empty && around_zero)
1783
- points = []
1784
- points << xlast
1785
- points << ylast
1786
- points << xpos
1787
- points << ypos
1788
- points << xpos
1789
- points << y_zero
1790
- points << xlast
1791
- points << y_zero
1792
- c_graph = allocate_color(@layers[0],@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"])
1793
- image_filled_polygon(@layers[0],points,@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],4)
1794
- end
1795
- ylast = ypos
1796
- end
1797
- xlast = xpos;
1798
- xpos = xpos + @division_width
1799
- end
1800
-
1801
- a_points << layer_width - @g_area_x_offset
1802
- a_points << layer_height;
1803
-
1804
- if ( around_zero == false )
1805
- # c_graph = allocate_color(@layers[0],@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"])
1806
- image_filled_polygon(@layers[0],a_points,@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],points_count);
1807
- end
1808
-
1809
- image_copy_merge(@layers[0],@picture,@g_area_x1,@g_area_y1,0,0,layer_width,layer_height,alpha);
1810
- image_destroy(@layers[0])
1811
- graph_id+=1
1812
- self.draw_line_graph(data,data_description,col_name)
1813
- end
1814
-
1815
- end
1816
- # This function will draw a bar graph using all the registered series.
1817
- # When creating a bar graph, don't forget to set the with_margin parameter of the draw_scale function to true.
1818
- # Setting shadow to true will draw a shadow behind each series, this will also slow down a bit the renderer engine.
1819
-
1820
- def draw_bar_graph(data,data_description,shadow=false,alpha=100)
1821
- data_description = self.validate_data_description("drawBarGraph",data_description)
1822
- self.validate_data("drawBarGraph",data)
1823
-
1824
- graph_id = 0
1825
- series = (data_description["values"]).count
1826
- series_width = @division_width / (series+1)
1827
- serie_x_offset = @division_width / 2 - series_width / 2
1828
-
1829
- y_zero = @g_area_y2 - ((0-@vmin) * @division_ratio)
1830
- y_zero = @g_area_y2 if ( y_zero> @g_area_y2 )
1831
- serie_id = 0
1832
- color_id =0
1833
- id = 0
1834
- data_description["values"].each do |col_name|
1835
- data_description["description"].each do |key_i,value_i|
1836
- if ( key_i == col_name )
1837
- color_id = id
1838
- id = id+1
1839
- end
1840
- end
1841
- x_pos = @g_area_x1 + @g_area_x_offset - serie_x_offset + series_width * serie_id
1842
- x_last = -1
1843
- data.each do |key|
1844
- if ( !key[col_name].nil?)
1845
- if ( key[col_name].is_a?(Numeric) )
1846
- value = key[col_name]
1847
- y_pos = @g_area_y2 - ((value-@vmin) * @division_ratio)
1848
- # Save point into the image map if option activated */
1849
- if (@build_map )
1850
- #self.add_to_image_map(x_pos+1,[y_zero,y_pos].min,x_pos+series_width-1,[y_zero,y_pos].max,data_description["description"][col_name],data[key][col_name].data_description["unit"]["y"],"Bar");
1851
- end
1852
- if ( shadow && alpha == 100 )
1853
- self.draw_rectangle(x_pos+1,y_zero,x_pos+series_width-1,y_pos,25,25,25)
1854
- end
1855
- self.draw_filled_rectangle(x_pos+1,y_zero,x_pos+series_width-1,y_pos,@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],true,alpha)
1856
- end
1857
- x_pos = x_pos + @division_width
1858
- end
1859
- end
1860
- serie_id = serie_id+1
1861
- end
1862
- end
1863
-
1864
- # This function will draw a stacked bar graph using all the registered series.
1865
- # When creating a bar graph, don't forget to set the with_margin parameter of the draw_scale function to true.
1866
- # Don't forget to change the automatic scaling to Rchart::SCALE_ADDALL to have an accurate scaling mode.
1867
- # You can specify the transparency and if the bars must be contiguous or with space (default)
1868
- def draw_stacked_bar_graph(data,data_description,alpha=50,contiguous=false)
1869
- # /* Validate the Data and data_description array */
1870
- data_description = self.validate_data_description("draw_bar_graph",data_description)
1871
- self.validate_data("draw_bar_graph",data)
1872
- graph_id = 0
1873
- series = (data_description["values"].count)
1874
- if ( contiguous )
1875
- series_width = @division_width
1876
- else
1877
- series_width = @division_width * 0.8;
1878
- end
1879
- y_zero = @g_area_y2 - ((0-@vmin) * @division_ratio)
1880
- y_zero = @g_area_y2 if ( y_zero > @g_area_y2 )
1881
- series_id = 0
1882
- last_value = {}
1883
- id = 0
1884
- color_id = 0
1885
- data_description["values"].each do |col_name|
1886
- data_description["description"].each do |key_i,value_i|
1887
- if ( key_i == col_name )
1888
- color_id = id
1889
- id = id+1
1890
- end
1891
- end
1892
- x_pos = @g_area_x1 + @g_area_x_offset - series_width / 2
1893
- x_last = -1
1894
- data.each do |key|
1895
- if ( !key[col_name].nil?)
1896
- if ( key[col_name].is_a?(Numeric) )
1897
- value = key[col_name]
1898
- if (!last_value[key].nil?)
1899
- y_pos = @g_area_y2 - (((value+last_value[key])-@vmin) * @division_ratio)
1900
- y_bottom = @g_area_y2 - ((last_value[key]-@vmin) * @division_ratio)
1901
- last_value[key] += value
1902
- else
1903
- y_pos = @g_area_y2 - ((value-@vmin) * @division_ratio)
1904
- y_bottom = y_zero
1905
- last_value[key] = value
1906
- end
1907
- # Save point into the image map if option activated
1908
- if ( @build_map )
1909
- #self.add_to_image_map(x_pos+1,[y_bottom,y_pos].min,x_pos+series_width-1,[y_bottom,y_pos].max,data_description["description"][col_name],data[key][col_name].data_description["unit"]["y"],"sBar");
1910
- end
1911
- self.draw_filled_rectangle(x_pos+1,y_bottom,x_pos+series_width-1,y_pos,@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],true,alpha)
1912
- end
1913
- end
1914
- x_pos = x_pos + @division_width
1915
- end
1916
- series_id+=1
1917
- end
1918
- end
1919
- # This function will draw a superposed bar graph using all the registered series.
1920
- # You can provide the alpha value used when merging all series layers.
1921
-
1922
- def draw_overlay_bar_graph(data,data_description,alpha=50)
1923
- data_description = self.validate_data_description("draw_overlay_bar_graph",data_description)
1924
- self.validate_data("draw_overlay_bar_graph",data)
1925
- layer_width = @g_area_x2-@g_area_x1
1926
- layer_height = @g_area_y2-@g_area_y1
1927
- graph_id = 0
1928
- color_id =0
1929
- id =0
1930
- data_description["values"].each do |col_name|
1931
- data_description["description"].each do |key_i,value_i|
1932
- if ( key_i == col_name )
1933
- color_id = id
1934
- id = id+1
1935
- end
1936
- end
1937
- @layers[graph_id] = image_create_true_color(layer_width,layer_height)
1938
- image_filled_rectangle(@layers[graph_id],0,0,layer_width,layer_height,255,255,255)
1939
- image_color_transparent(@layers[graph_id],255,255,255)
1940
- x_width = @division_width / 4
1941
- x_pos = @g_area_x_offset
1942
- y_zero = layer_height - ((0-@vmin) * @division_ratio)
1943
- x_last = -1
1944
- points_count = 2
1945
- data.each do |key|
1946
- if(!key[col_name].nil?)
1947
- if(key[col_name].is_a?(Numeric))
1948
- value = key[col_name]
1949
- if (value.is_a?(Numeric) )
1950
- y_pos = layer_height - ((value-@vmin) * @division_ratio)
1951
- image_filled_rectangle(@layers[graph_id],x_pos-x_width,y_pos,x_pos+x_width,y_zero,@palette[graph_id]["r"],@palette[graph_id]["g"],@palette[graph_id]["b"])
1952
- x1 = (x_pos - x_width + @g_area_x1).floor
1953
- y1 = (y_pos+@g_area_y1).floor + 0.2
1954
- x2 = (x_pos + x_width + @g_area_x1).floor
1955
- y2 = @g_area_y2 - ((0-@vmin) * @division_ratio)
1956
- x1 = @g_area_x1 + 1 if ( x1 <= @g_area_x1 )
1957
- x2 = @g_area_x2 - 1 if ( x2 >= @g_area_x2 )
1958
-
1959
- # Save point into the image map if option activated */
1960
- if ( @build_map )
1961
- #self.add_to_image_map(x1,[y1,y2].min,x2,[y1,y2].max,data_description["description"][col_name],data[key][col_name].data_description["unit"]["y"],"oBar");
1962
- end
1963
- self.draw_line(x1,y1,x2,y1,@palette[color_id]["r"],@palette[color_id]["g"],@palette[color_id]["b"],true)
1964
- end
1965
- end
1966
- end
1967
- x_pos = x_pos + @division_width
1968
- end
1969
- graph_id+=1
1970
- end
1971
- i=0
1972
- while (i<=(graph_id-1))
1973
- image_copy_merge(@layers[i],@picture,@g_area_x1,@g_area_y1,0,0,layer_width,layer_height,alpha)
1974
- image_destroy(@layers[i])
1975
- i=i+1
1976
- end
1977
- end
1978
-
1979
- # This function will draw the minimum & maximum values for a specific point using all the registered series
1980
- # You can optionaly specify the vertical line color.
1981
-
1982
- def draw_limits_graph(data,data_description,r=0,g=0,b=0)
1983
- data_description = self.validate_data_description("draw_limits_graph",data_description)
1984
- self.validate_data("draw_limits_graph",data)
1985
- x_width = @division_width / 4
1986
- xpos = @g_area_x1 + @g_area_x_offset
1987
- data.each do |key|
1988
- min = key[data_description["values"][0]]
1989
- max = key[data_description["values"][0]]
1990
- graph_id = 0
1991
- max_id = 0
1992
- min_id = 0
1993
- data_description["values"].each do |col_name|
1994
- if (!key[col_name].nil?)
1995
- if ( key[col_name] > max && key[col_name].is_a?(Numeric))
1996
- max = key[col_name]
1997
- max_id = graph_id
1998
- end
1999
- end
2000
- if ( !key[col_name].nil? && key[col_name].is_a?(Numeric))
2001
- if ( key[col_name] < min )
2002
- min = key[col_name]
2003
- min_id = graph_id
2004
- end
2005
- graph_id+=1
2006
- end
2007
- end
2008
-
2009
- ypos = @g_area_y2 - ((max-@vmin) * @division_ratio)
2010
- x1 = (xpos - x_width).floor
2011
- y1 = (ypos).floor - 0.2
2012
- x2 = (xpos + x_width).floor
2013
- x1 = @g_area_x1 + 1 if ( x1 <= @g_area_x1 )
2014
- x2 = @g_area_x2 - 1 if ( x2 >= @g_area_x2 )
2015
- ypos = @g_area_y2 - ((min-@vmin) * @division_ratio)
2016
- y2 = ypos.floor + 0.2
2017
- self.draw_line(xpos.floor-0.2,y1+1,xpos.floor-0.2,y2-1,r,g,b,true)
2018
- self.draw_line(xpos.floor+0.2,y1+1,xpos.floor+0.2,y2-1,r,g,b,true)
2019
- self.draw_line(x1,y1,x2,y1,@palette[max_id]["r"],@palette[max_id]["g"],@palette[max_id]["b"],false)
2020
- self.draw_line(x1,y2,x2,y2,@palette[min_id]["r"],@palette[min_id]["g"],@palette[min_id]["b"],false)
2021
- xpos = xpos + @division_width
2022
- end
2023
- end
2024
-
2025
- # This function will draw a classical non-exploded pie chart.
2026
- # * To do so you must specify the data & data_description array.Only one serie of data is allowed for pie graph.
2027
- # * You can associate a description of each value in another serie by marking it using the set_abscise_label_serie function.
2028
- # * You must specify the center position of the chart. You can also optionally specify the radius of the pie and if the percentage should be printed.
2029
- # * r,g,b can be used to set the color of the line that will surround each pie slices.
2030
- # * You can specify the number of decimals you want to be displayed in the labels (default is 0 )
2031
- # By default no labels are written around the pie chart. You can use the following modes for the draw_labels parameter
2032
- # * Rchart:: PIE_NOLABEL No labels displayed
2033
- # * Rchart:: PIE_PERCENTAGE Percentages are displayed
2034
- # * Rchart:: PIE_LABELS Series labels displayed
2035
- # * Rchart:: PIE_PERCENTAGE_LABEL Series labels & percentage displayed
2036
- # This will draw a pie graph centered at (150-150) with a radius of 100, no labels
2037
- # * chart.draw_basic_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150)
2038
- # This will draw a pie graph centered at (150-150) with a radius of 50 and percentages
2039
- # * chart.draw_basic_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150,50,Rchart::PIE_PERCENTAGE)
2040
- # This will draw a pie graph centered at (150-150) with a radius of 100, captions and black borders
2041
- # * chart.draw_basic_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150,100,Rchart::PIE_PERCENTAGE,0,0,0)
2042
- def draw_basic_pie_graph(data,data_description,x_pos,y_pos,radius=100,draw_labels=PIE_NOLABEL,r=255,g=255,b=255,decimals=0)
2043
- data_description = self.validate_data_description("draw_basic_pie_graph",data_description,false)
2044
- self.validate_data("drawBasicPieGraph",data)
2045
- # Determine pie sum
2046
- series = 0
2047
- pie_sum = 0
2048
- i_values = []
2049
- r_values = []
2050
- i_labels = []
2051
- data_description["values"].each do|col_name|
2052
- if (col_name != data_description["position"])
2053
- series = series+1
2054
- data.each do |key|
2055
- if (!key[col_name].nil?)
2056
- pie_sum = pie_sum + key[col_name]
2057
- i_values << key[col_name]
2058
- i_labels << key[data_description["position"]]
2059
- end
2060
- end
2061
- end
2062
- end
2063
-
2064
-
2065
- # Validate serie
2066
- if ( series != 1 )
2067
- raise_fatal("Pie chart can only accept one serie of data.");
2068
- end
2069
- splice_ratio = 360.0 / pie_sum
2070
- splice_percent = 100.0 / pie_sum
2071
-
2072
- #Calculate all polygons
2073
- angle = 0
2074
- top_plots = []
2075
- i_values.each_with_index do |value,key|
2076
-
2077
- top_plots[key]= [x_pos]
2078
- top_plots[key]<< y_pos
2079
- # Process labels position & size
2080
- caption = "";
2081
- if ( !(draw_labels == PIE_NOLABEL) )
2082
- t_angle = angle+(value*splice_ratio/2)
2083
- if (draw_labels == PIE_PERCENTAGE)
2084
- caption = ((value * (10**decimals) * splice_percent)/(10**decimals)).round.to_s+"%"
2085
- elsif (draw_labels == PIE_LABELS)
2086
- caption = i_labels[key]
2087
- elsif (draw_labels == PIE_PERCENTAGE_LABEL)
2088
- caption = i_labels[key].to_s+"\r\n"+"."+((value * (10**decimals) * splice_percent)/(10**decimals)).round.to_s+"%";
2089
- elsif (draw_labels == PIE_PERCENTAGE_LABEL)
2090
- caption = i_labels[key].to_s+"\r\n"+"."+((value * (10**decimals) * splice_percent)/(10**decimals)).round.to_s+"%";
2091
- end
2092
- position = image_ftb_box(@font_size,0,@font_name,caption)
2093
- text_width = position[2]-position[0]
2094
- text_height = (position[1].abs)+(position[3].abs)
2095
-
2096
- tx = Math.cos((t_angle) * Math::PI / 180 ) * (radius+10) + x_pos
2097
-
2098
- if ( t_angle > 0 && t_angle < 180 )
2099
- ty = Math.sin((t_angle) * Math::PI / 180 ) * (radius+10) + y_pos + 4
2100
- else
2101
- ty = Math.sin((t_angle) * Math::PI / 180 ) * (radius+4) + y_pos - (text_height/2)
2102
- end
2103
- tx = tx - text_width if ( t_angle > 90 && t_angle < 270 )
2104
-
2105
- c_text_color = allocate_color(@picture,70,70,70);
2106
- image_ttf_text(@picture,@font_size,0,tx,ty,c_text_color,@font_name,caption)
2107
- end
2108
- # Process pie slices
2109
- i_angle = angle
2110
- while(i_angle <=angle+value*splice_ratio)
2111
-
2112
- top_x = (Math.cos(i_angle * Math::PI / 180 )) * radius + x_pos
2113
- top_y = (Math.sin(i_angle * Math::PI/ 180 )) * radius + y_pos
2114
- top_plots[key] << (top_x)
2115
- top_plots[key] <<(top_y)
2116
- i_angle = i_angle+0.5
2117
- end
2118
- top_plots[key]<< x_pos
2119
- top_plots[key] << y_pos
2120
- angle = i_angle
2121
- end
2122
- poly_plots = top_plots
2123
- # Draw Top polygons
2124
- poly_plots.each_with_index do |value,key|
2125
- image_filled_polygon(@picture, poly_plots[key], @palette[key]["r"],@palette[key]["g"],@palette[key]["b"])
2126
- end
2127
- self.draw_circle(x_pos-0.5,y_pos-0.5,radius,r,g,b)
2128
- self.draw_circle(x_pos-0.5,y_pos-0.5,radius+0.5,r,g,b)
2129
- # Draw Top polygons
2130
- top_plots.each_with_index do |value,key|
2131
- j = 0
2132
- while(j<=top_plots[key].count-4 )
2133
- self.draw_line(top_plots[key][j],top_plots[key][j+1],top_plots[key][j+2],top_plots[key][j+3],r,g,b);
2134
- j =j+2
2135
- end
2136
- end
2137
- end
2138
-
2139
- # This function will draw a 3D pie graph.
2140
- # * To do so you must specify the data & data_description array.
2141
- # * Only one serie of data is allowed for pie graph.
2142
- # * You can associate a description of each value in another serie by marking it using the set_abscise_label_serie function. You must specify the center position of the chart.
2143
- # * You can also optionally specify the radius of the pie, if the percentage should be printed, the 3D skew factor and the height of all splices.
2144
- # * If enhance_colors is set to true, pie edges will be enhanced.
2145
- # * If splice_distance is greated than 0, the pie will be exploded.
2146
- # * You can specify the number of decimals you want to be displayed in the labels (default is 0 ).
2147
- # By default no labels are written around the pie chart. You can use the following modes for the draw_labels parameter:
2148
- # * Rchart:: PIE_NOLABEL No labels displayed
2149
- # * Rchart:: PIE_PERCENTAGE Percentages are displayed
2150
- # * Rchart:: PIE_LABELS Series labels displayed
2151
- # * Rchart:: PIE_PERCENTAGE_LABEL Series labels & percentage displayed
2152
- # This will draw a pie graph centered at (150-150) with a radius of 100, no labels
2153
- # * chart.draw_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150)
2154
- # This will draw a pie graph centered at (150-150) with a radius of 50 and percentages
2155
- # * chart.draw_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150,50,Rchart::PIE_PERCENTAGE)
2156
- # This will draw a pie graph centered at (150-150) with a radius of 100, captions and a skew factor of 30
2157
- # * chart.draw_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150,100,Rchart::PIE_PERCENTAGE,true,30)
2158
- # This will draw a pie graph (..) exploded
2159
- # * chart.draw_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150,100,Rchart::PIE_PERCENTAGE,true,30,10,10)
2160
- def draw_pie_graph(data,data_description,x_pos,y_pos,radius=100,draw_labels=PIE_NOLABEL,enhance_colors=true,skew=60,splice_height=20,splice_distance=0,decimals=0)
2161
- data_description = self.validate_data_description("draw_pie_graph",data_description,false)
2162
- self.validate_data("draw_pie_graph",data)
2163
-
2164
- #Determine pie sum
2165
- series = 0
2166
- pie_sum= 0
2167
- rpie_sum = 0
2168
- i_values = []
2169
- r_values = []
2170
- i_labels = []
2171
- series = 0
2172
-
2173
- data_description["values"].each do|col_name|
2174
- if (col_name != data_description["position"])
2175
- series = series+1
2176
- data.each do |key|
2177
- if (!key[col_name].nil?)
2178
- if (key[col_name] == 0)
2179
- i_values << 0
2180
- r_values << 0
2181
- i_labels << 0
2182
- i_labels<< key[data_description["position"]]
2183
- else
2184
- pie_sum+= key[col_name]
2185
- i_values << key[col_name]
2186
- i_labels << key[data_description["position"]]
2187
- r_values << key[col_name]
2188
- rpie_sum += key[col_name]
2189
- end
2190
- end
2191
- end
2192
- end
2193
- end
2194
-
2195
- # Validate serie
2196
-
2197
- #RaiseFatal("Pie chart can only accept one serie of data.");
2198
- #puts "Error Pie chart can only accept one serie of data." if ( series != 1 )
2199
- splice_distance_ratio = splice_distance
2200
- skew_height = (radius * skew) / 100;
2201
- splice_ratio = ((360 - splice_distance_ratio *i_values.count*1.0) / pie_sum)
2202
- splice_percent = 100.0 / pie_sum
2203
- r_splice_percent = 100.0 / rpie_sum
2204
- #Calculate all polygons
2205
- angle = 0
2206
- c_dev = 5;
2207
- top_plots = []
2208
- bot_plots = []
2209
- atop_plots = []
2210
- abot_plots = []
2211
- i_values.each_with_index do |value,key|
2212
-
2213
- x_cent_pos = Math.cos((angle-c_dev+(value*splice_ratio+splice_distance_ratio)/2) * 3.1418 / 180 ) * splice_distance + x_pos
2214
- y_cent_pos = Math.sin((angle-c_dev+(value*splice_ratio+splice_distance_ratio)/2) * 3.1418 / 180 ) * splice_distance + y_pos
2215
- x_cent_pos2 = Math.cos((angle+c_dev+(value*splice_ratio+splice_distance_ratio)/2) * 3.1418 / 180 ) * splice_distance + x_pos
2216
- y_cent_pos2 = Math.sin((angle+c_dev+(value*splice_ratio+splice_distance_ratio)/2) * 3.1418 / 180 ) * splice_distance + y_pos
2217
- top_plots[key] = [(x_cent_pos).round]
2218
- bot_plots[key] = [(x_cent_pos).round]
2219
- top_plots[key] << (y_cent_pos).round
2220
- bot_plots[key] << (y_cent_pos + splice_height).round
2221
- atop_plots[key] = [x_cent_pos]
2222
- abot_plots[key] = [x_cent_pos]
2223
- atop_plots[key] << y_cent_pos
2224
- abot_plots[key] << y_cent_pos + splice_height
2225
- # Process labels position & size
2226
- caption = ""
2227
- if ( !(draw_labels == PIE_NOLABEL) )
2228
-
2229
- t_angle = angle+(value*splice_ratio/2)
2230
- if (draw_labels == PIE_PERCENTAGE)
2231
- caption = ((r_values[key] * (10**decimals) * r_splice_percent)/(10**decimals)).round.to_s+"%"
2232
- elsif (draw_labels == PIE_LABELS)
2233
- caption = i_labels[key]
2234
- elsif (draw_labels == PIE_PERCENTAGE_LABEL)
2235
- caption = i_labels[key].to_s+"\r\n"+(((value * 10**decimals) * splice_percent)/(10**decimals)).round.to_s+"%"
2236
- end
2237
- position = image_ftb_box(@font_size,0,@font_name,caption)
2238
- text_width =position[2]-position[0]
2239
- text_height = ( position[1]).abs+(position[3]).abs
2240
-
2241
- tx = Math.cos((t_angle) * Math::PI / 180 ) * (radius + 10)+ x_pos
2242
-
2243
- if ( t_angle > 0 && t_angle < 180 )
2244
- ty = Math.sin((t_angle) * Math::PI / 180 ) * (skew_height + 10) + y_pos + splice_height + 4
2245
- else
2246
- ty = Math.sin((t_angle) * Math::PI / 180 ) * (skew_height + 4) + y_pos - (text_height/2)
2247
- end
2248
- if ( t_angle > 90 && t_angle < 270 )
2249
- tx = tx - text_width
2250
- end
2251
- #c_text_color = $this->AllocateColor(@picture,70,70,70);
2252
- c_text_color = allocate_color(@picture,70,70,70)
2253
- image_ttf_text(@picture,@font_size,0,tx,ty,c_text_color,@font_name,caption)
2254
- end
2255
-
2256
- # Process pie slices
2257
-
2258
- i_angle = angle
2259
- i_angle = i_angle.to_f
2260
-
2261
- while(i_angle <=angle+value*splice_ratio)
2262
-
2263
- top_x = (Math.cos(i_angle * Math::PI / 180 )) * radius + x_pos
2264
- top_y = (Math.sin(i_angle * Math::PI/ 180 )) * skew_height + y_pos
2265
-
2266
- top_plots[key] << (top_x).round
2267
- bot_plots[key] <<(top_x).round
2268
- top_plots[key] <<(top_y).round
2269
- bot_plots[key] << (top_y + splice_height).round
2270
- atop_plots[key] << top_x
2271
- abot_plots[key] << top_x
2272
- atop_plots[key] << top_y
2273
- abot_plots[key] << top_y + splice_height
2274
- i_angle=i_angle+0.5
2275
- end
2276
- top_plots[key] << (x_cent_pos2).round
2277
- bot_plots[key] << (x_cent_pos2).round
2278
- top_plots[key] << (y_cent_pos2).round
2279
- bot_plots[key] << (y_cent_pos2 + splice_height).round
2280
- atop_plots[key] << x_cent_pos2
2281
- abot_plots[key] << x_cent_pos2
2282
- atop_plots[key] << y_cent_pos2
2283
- abot_plots[key] << y_cent_pos2 + splice_height
2284
- angle = i_angle + splice_distance_ratio
2285
- end
2286
-
2287
- # Draw Bottom polygons
2288
- i_values.each_with_index do |val,key|
2289
- #c_graph_lo = allocate_color(@picture,@palette[key]["r"]-20,@palette[key]["g"]-20,@palette[key]["b"]-20)
2290
- image_filled_polygon(@picture,bot_plots[key],@palette[key]["r"]-20,@palette[key]["g"]-20,@palette[key]["b"]-20)
2291
- if (enhance_colors)
2292
- en = -10
2293
- else
2294
- en = 0
2295
- end
2296
- j =0
2297
- while(j<=(abot_plots[key].length)-4)
2298
- self.draw_line(abot_plots[key][j],abot_plots[key][j+1],abot_plots[key][j+2],abot_plots[key][j+3],@palette[key]["r"]+en,@palette[key]["g"]+en,@palette[key]["b"]+en);
2299
- j= j+2
2300
- end
2301
- end
2302
-
2303
- # Draw pie layers
2304
- if ( enhance_colors )
2305
- color_ratio = 30 / splice_height
2306
- else
2307
- color_ratio = 25 / splice_height
2308
- end
2309
- i = splice_height-1
2310
- while(i>=1)
2311
- i_values.each_with_index do |val,key|
2312
- # c_graph_lo = allocate_color(@picture,@palette[key]["r"]-10,@palette[key]["g"]-10,@palette[key]["b"]-10)
2313
- plots =[]
2314
- plot = 0
2315
- top_plots[key].each_with_index do |value2,key2|
2316
- plot = plot+1
2317
- if ( plot % 2 == 1 )
2318
- plots << value2
2319
- else
2320
- plots << value2+i
2321
- end
2322
- end
2323
- image_filled_polygon(@picture,plots,@palette[key]["r"]-10,@palette[key]["g"]-10,@palette[key]["b"]-10)
2324
- index = (plots).count
2325
- if (enhance_colors )
2326
- color_factor = -20 + (splice_height - $i) * color_ratio
2327
- else
2328
- color_factor = 0
2329
- end
2330
-
2331
- self.draw_antialias_pixel(plots[0],plots[1],@palette[key]["r"]+color_factor,@palette[key]["g"]+color_factor,@palette[key]["b"]+color_factor);
2332
- self.draw_antialias_pixel(plots[2],plots[3],@palette[key]["r"]+color_factor,@palette[key]["g"]+color_factor,@palette[key]["b"]+color_factor);
2333
- self.draw_antialias_pixel(plots[index-4],plots[index-3],@palette[key]["r"]+color_factor,@palette[key]["g"]+color_factor,@palette[key]["b"]+color_factor);
2334
- end
2335
- i = i-1
2336
- end
2337
- #Draw Top polygons
2338
- key = i_values.length-1
2339
- while(key>=0)
2340
- # c_graph_lo = allocate_color(@picture,@palette[key]["r"],@palette[key]["g"],@palette[key]["b"])
2341
- image_filled_polygon(@picture,top_plots[key],@palette[key]["r"],@palette[key]["g"],@palette[key]["b"])
2342
-
2343
- if ( enhance_colors )
2344
- en = 10
2345
- else
2346
- en = 0
2347
- end
2348
- j = 0
2349
-
2350
- while(j<=(atop_plots[key]).length-4)
2351
- self.draw_line(atop_plots[key][j],atop_plots[key][j+1],atop_plots[key][j+2],atop_plots[key][j+3],@palette[key]["r"]+en,@palette[key]["g"]+en,@palette[key]["b"]+en);
2352
- j = j+2
2353
- end
2354
- key = key -1
2355
- end
2356
- end
2357
- # This function is an alias of the draw_flat_pie_graph function.
2358
- def draw_flat_pie_graph_with_shadow(data,data_description,x_pos,y_pos,radius=100,draw_labels=PIE_NOLABEL,splice_distance=0,decimals=0)
2359
- self.draw_flat_pie_graph(data,data_description,x_pos+@shadow_x_distance,y_pos+@shadow_y_distance,radius,PIE_NOLABEL,splice_distance,decimals,true)
2360
- self.draw_flat_pie_graph(data,data_description,x_pos,y_pos,radius,draw_labels,splice_distance,decimals,false)
2361
- end
2362
-
2363
- # This function will draw a flat 2D pie graph.
2364
- # To do so you must specify the data & data_description array.
2365
- # * Only one serie of data is allowed for pie graph.
2366
- # * You can associate a description of each value in another serie by marking it using the set_abscise_label_serie function. You must specify the center position of the chart.
2367
- # * You can also optionally specify the radius of the pie and if the percentage should be printed.
2368
- # * If splice_distance is greated than 0, the pie will be exploded.
2369
- # * You can specify the number of decimals you want to be displayed in the labels (default is 0 )
2370
- # By default no labels are written around the pie chart. You can use the following modes for the draw_labels parameter:
2371
- # * Rchart:: PIE_NOLABEL No labels displayed
2372
- # * Rchart:: PIE_PERCENTAGE Percentages are displayed
2373
- # * Rchart:: PIE_LABELS Series labels displayed
2374
- # * Rchart:: PIE_PERCENTAGE_LABEL Series labels & percentage displayed
2375
- # This will draw a pie graph centered at (150-150) with a radius of 100, no labels
2376
- # * chart.draw_flat_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150);
2377
- # This will draw a pie graph centered at (150-150) with a radius of 50 and percentages
2378
- # * chart.draw_flat_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150,50,Rchart::PIE_PERCENTAGE)
2379
- # This will draw a pie graph centered at (150-150) with a radius of 100, captions and slightly exploded
2380
- # * chart.draw_flat_pie_graph(chart_data.get_data,chart_data.get_data_description,150,150,100,Rchart::PIE_PERCENTAGE,4)
2381
-
2382
- def draw_flat_pie_graph(data,data_description,x_pos,y_pos,radius=100,draw_labels=PIE_NOLABEL,splice_distance=0,decimals=0,all_black=false)
2383
- data_description = self.validate_data_description("draw_flat_pie_graph",data_description,false)
2384
- self.validate_data("draw_flat_pie_graph",data)
2385
- shadow_status = @shadow_active
2386
- @shadow_active = false
2387
- # Determine pie sum
2388
- series = 0
2389
- pie_sum = 0
2390
- i_values = []
2391
- r_values = []
2392
- i_labels = []
2393
- data_description["values"].each do|col_name|
2394
- if (col_name != data_description["position"])
2395
- series = series+1
2396
- data.each do |key|
2397
- if (!key[col_name].nil?)
2398
- pie_sum = pie_sum + key[col_name]
2399
- i_values << key[col_name]
2400
- i_labels << key[data_description["position"]]
2401
- end
2402
- end
2403
- end
2404
- end
2405
-
2406
- #Validate serie
2407
- if ( series != 1 )
2408
- raise_fatal("Pie chart can only accept one serie of data.");
2409
- return -1
2410
- end
2411
-
2412
- splice_ratio = 360.0 / pie_sum
2413
- splice_percent = 100.0 / pie_sum
2414
- # Calculate all polygons
2415
- angle = 0
2416
- top_plots = []
2417
- i_values.each_with_index do |value,key|
2418
-
2419
- x_offset = Math.cos((angle+(value*1.0/2*splice_ratio)) * Math::PI / 180 ) * splice_distance
2420
- y_offset = Math.sin((angle+(value*1.0/2*splice_ratio)) * Math::PI / 180 ) * splice_distance
2421
-
2422
- top_plots[key] = [(x_pos + x_offset).round]
2423
- top_plots[key] << (y_pos + y_offset).round
2424
- if ( all_black )
2425
- rc = @shadow_r_color
2426
- gc = @shadow_g_color
2427
- bc = @shadow_b_color
2428
- else
2429
- rc = @palette[key]["r"]
2430
- gc = @palette[key]["g"]
2431
- bc = @palette[key]["b"]
2432
- end
2433
- x_line_last = ""
2434
- y_line_last = ""
2435
- # Process labels position & size
2436
- caption = ""
2437
- if ( !(draw_labels == PIE_NOLABEL) )
2438
- t_angle = angle+(value*splice_ratio/2)
2439
- if (draw_labels == PIE_PERCENTAGE)
2440
- caption = ((value * (10**decimals) * splice_percent)/(10**decimals)).round.to_s+"%"
2441
- elsif (draw_labels == PIE_LABELS)
2442
- caption = i_labels[key]
2443
- elsif (draw_labels == PIE_PERCENTAGE_LABEL)
2444
- caption = i_labels[key].to_s+".\r\n"+((value * (10**decimals) * splice_percent)/(10**decimals)).round.to_s+"%"
2445
- elsif (draw_labels == PIE_PERCENTAGE_LABEL)
2446
- caption = i_labels[key].to_s+".\r\n"+((value * (10**decimals) * splice_percent)/(10**decimals)).round.to_s+"%"
2447
- end
2448
- position = image_ftb_box(@font_size,0,@font_name,caption)
2449
- text_width = position[2]-position[0]
2450
- text_height = (position[1].abs)+(position[3].abs)
2451
-
2452
- tx = Math.cos((t_angle) * Math::PI / 180 ) * (radius+10+splice_distance) + x_pos
2453
- if ( t_angle > 0 && t_angle < 180 )
2454
- ty = Math.sin((t_angle) * Math::PI / 180 ) * (radius+10+splice_distance) + y_pos + 4
2455
- else
2456
- ty = Math.sin((t_angle) * Math::PI / 180 ) * (radius+splice_distance+4) + y_pos - (text_height*1.0/2)
2457
- end
2458
- tx = tx - text_width if ( t_angle > 90 && t_angle < 270 )
2459
- c_text_color = allocate_color(@picture,70,70,70)
2460
- image_ttf_text(@picture,@font_size,0,tx,ty,c_text_color,@font_name,caption)
2461
- end
2462
-
2463
- # Process pie slices
2464
- if ( !all_black )
2465
- line_color =allocate_color(@picture,rc,gc,bc)
2466
- else
2467
- line_color = allocate_color(@picture,rc,gc,bc)
2468
- end
2469
- x_line_last = ""
2470
- y_line_last = ""
2471
- i_angle=angle
2472
- while(i_angle<=angle+value*splice_ratio)
2473
- pos_x = Math.cos(i_angle * Math::PI / 180 ) * radius + x_pos + x_offset
2474
- pos_y = Math.sin(i_angle * Math::PI / 180 ) * radius + y_pos + y_offset
2475
- top_plots[key]<< (pos_x).round
2476
- top_plots[key] << (pos_y).round
2477
- if ( i_angle == angle || i_angle == angle+value*splice_ratio || i_angle+0.5 > angle+value*splice_ratio)
2478
- self.draw_line(x_pos+x_offset,y_pos+y_offset,pos_x,pos_y,rc,gc,bc)
2479
- end
2480
- if ( x_line_last != "" )
2481
- self.draw_line(x_line_last,y_line_last,pos_x,pos_y,rc,gc,bc);
2482
- end
2483
- x_line_last = pos_x
2484
- y_line_last = pos_y
2485
- i_angle=i_angle+0.5
2486
- end
2487
-
2488
- top_plots[key] << (x_pos + x_offset).round
2489
- top_plots[key]<< (y_pos + y_offset).round
2490
- angle = i_angle
2491
- end
2492
- poly_plots = top_plots
2493
- # Draw Top polygons
2494
- poly_plots.each_with_index do |value,key|
2495
- if ( !all_black )
2496
- image_filled_polygon(@picture,poly_plots[key],@palette[key]["r"],@palette[key]["g"],@palette[key]["b"])
2497
- else
2498
- image_filled_polygon(@picture,poly_plots[key],@shadow_r_color,@shadow_g_color,@shadow_b_color)
2499
- end
2500
- end
2501
- @shadow_active = shadow_status
2502
-
2503
- end
2504
- # This function can be used to set the background color.
2505
- # The default graph background color is set to white.
2506
- def draw_background(r,g,b)
2507
- b,g,r= validate_color(b, g, r)
2508
- image_filled_rectangle(@picture,0,0,@x_size,@y_size,r,g,b)
2509
- end
2510
-
2511
- # You can use this function to fill the background of the picture or of the graph area with a color gradient pattern.
2512
- # You must specify the starting color with its r,g,b values, the number of shades to apply with the decay parameter and optionnaly the target that can be :
2513
- # * Rchart:: TARGET_GRAPHAREA The currently defined graph area
2514
- # * Rchart:: TARGET_BACKGROUND The whole picture background
2515
- def draw_graph_area_gradient(r,g,b,decay,target=TARGET_GRAPHAREA)
2516
- b, g, r = validate_color(b, g, r)
2517
- x1,y1,x2,y2 = 0,0,0,0
2518
- if ( target == TARGET_GRAPHAREA )
2519
- x1 = @g_area_x1+1
2520
- x2 = @g_area_x2-1
2521
- y1 = @g_area_y1+1
2522
- y2 = @g_area_y2
2523
- end
2524
-
2525
- if ( target == TARGET_BACKGROUND )
2526
- x1 = 0
2527
- x2 = @x_size
2528
- y1 = 0
2529
- y2 = @y_size
2530
- end
2531
- #Positive gradient
2532
- if ( decay > 0 )
2533
- y_step = (y2 - y1 - 2) / decay
2534
- i=0
2535
- while i<=decay
2536
- r-=1
2537
- g-=1
2538
- b-=1
2539
- yi1 = y1 + ( i * y_step );
2540
- yi2 = ( yi1 + ( i * y_step ) + y_step ).ceil
2541
- yi2 = y2-1 if ( yi2 >= yi2 )
2542
- image_filled_rectangle(@picture,x1,yi1,x2,yi2,r,g,b)
2543
- i=i+1
2544
- end
2545
- end
2546
- # Negative gradient
2547
- if ( decay < 0 )
2548
- y_step = (y2 - y1 - 2) / -decay
2549
- yi1 = y1
2550
- yi2 = y1+y_step
2551
- i= -decay
2552
- while i>=0
2553
- r+=1
2554
- g+=1
2555
- b+=1
2556
- image_filled_rectangle(@picture,x1,yi1,x2,yi2,r,g,b)
2557
- yi1+= y_step
2558
- yi2+= y_step
2559
- yi2 = y2-1 if ( yi2 >= yi2 )
2560
- i= i-1
2561
- end
2562
-
2563
- end
2564
- end
2565
-
2566
- # This function draw an aliased rectangle
2567
- # The upper left and bottom right border positions are used as first 4 arguments.
2568
- # The last 3 parameters are used to set the border color
2569
- def draw_rectangle(x1, y1, x2, y2, r, g, b)
2570
- b, g, r = validate_color(b, g, r)
2571
- c_rectangle = allocate_color(@picture,r, g, b)
2572
- x1=x1-0.2
2573
- y1=y1-0.2
2574
- x2=x2+0.2
2575
- y2=y2+0.2
2576
- self.draw_line(x1,y1,x2,y1,r,g,b)
2577
- self.draw_line(x2,y1,x2,y2,r,g,b)
2578
- self.draw_line(x2,y2,x1,y2,r,g,b)
2579
- self.draw_line(x1,y2,x1,y1,r,g,b)
2580
- end
2581
-
2582
- # This function draw an aliased filled rectangle
2583
- # The upper left and bottom right border positions are used as first 4 arguments. The last R,G,B parameters are used to set the border color.
2584
- # You can specify if the aliased border will be drawn and the transparency.
2585
- def draw_filled_rectangle(x1, y1, x2, y2, r, g, b, draw_border=true, alpha=100,no_fall_back=false)
2586
- x1, x2 = x2, x1 if x2.to_f < x1.to_f
2587
- y1, y2 = y2, y1 if y2.to_f < y1.to_f
2588
- b,g,r=validate_color(b, g, r)
2589
-
2590
- if(alpha == 100)
2591
- #Process shadows
2592
- if(@shadow_active && no_fall_back)
2593
- self.draw_filled_rectangle(x1+@shadow_x_distance,y1+@shadow_y_distance,x2+@shadow_x_distance,y2+@shadow_y_distance,@shadow_r_color,@shadow_g_color,@shadow_b_color,false,@shadow_alpha,true)
2594
- if(@shadow_blur != 0)
2595
- alpha_decay = (@shadow_alpha/ @shadow_blur)
2596
- i =1
2597
- while i<=@shadow_blur
2598
- self.draw_filled_rectangle(x1+@shadow_x_distance-i/2,y1+@shadow_y_distance-i/2,x2+@shadow_x_distance-i/2,y2+@shadow_y_distance-i/2,@shadow_r_color,@shadow_g_color,@shadow_b_color,false,@shadow_alpha-alpha_decay*i,true)
2599
- i = i+1
2600
- end
2601
- i = 1
2602
- while i<=@shadow_blur
2603
- self.draw_filled_rectangle(x1+@shadow_x_distance+i/2,y1+@shadow_y_distance+i/2,x2+@shadow_x_distance+i/2,y2+@shadow_y_distance+i/2,@shadow_r_color,@shadow_g_color,@shadow_b_color,false,@shadow_alpha-alpha_decay*i,true)
2604
- i = i+1
2605
- end
2606
- end
2607
- end
2608
- image_filled_rectangle(@picture,x1.to_f.round,y1.to_f.round,x2.to_f.round,y2.to_f.round,r,g,b)
2609
- else
2610
- layer_width = (x2-x1).abs+2
2611
- layer_height = (y2-y1).abs+2
2612
- @layers[0] = GD::Image.newTrueColor(layer_width,layer_height)
2613
- c_white = @layers[0].colorAllocate(255,255,255)
2614
- image_filled_rectangle(@layers[0],0,0,layer_width,layer_height,255,255,255)
2615
- @layers[0].transparent(c_white)
2616
- image_filled_rectangle(@layers[0],1.round,1.round,(layer_width-1).round,(layer_height-1).round,r,g,b)
2617
- image_copy_merge(@layers[0],@picture,([x1,x2].min-1).round,([y1,y2].min-1).round,0,0,layer_width,layer_height,alpha)
2618
- #TODO Find out equivalent method
2619
- @layers[0].destroy
2620
- end
2621
- if (draw_border )
2622
- shadow_settings = @shadow_active
2623
- @shadow_active = false
2624
- self.draw_rectangle(x1,y1,x2,y2,r,g,b)
2625
- @shadow_active = shadow_settings
2626
- end
2627
- end
2628
-
2629
- # This function draw an aliased rectangle with rounded corners
2630
- # The upper left and bottom right border positions are used as first 4 arguments.
2631
- # Argument #5 represents the radius of the rounded corner.
2632
- # The last 3 parameters are used to set the border color.
2633
- def draw_rounded_rectangle(x1, y1, x2, y2, radius,r, g, b)
2634
- b, g, r = validate_color(b, g, r)
2635
-
2636
- #c_rectangle = allocate_color(@picture,r,g,b)
2637
-
2638
- step = 90 / ((3.1418 * radius)/2)
2639
- i=0
2640
- while i<=90
2641
- x = Math.cos((i+180)*3.1418/180) * radius + x1 + radius
2642
- y = Math.sin((i+180)*3.1418/180) * radius + y1 + radius
2643
- self.draw_antialias_pixel(x,y,r,g,b)
2644
-
2645
- x = Math.cos((i-90)*3.1418/180) * radius + x2 - radius
2646
- y = Math.sin((i-90)*3.1418/180) * radius + y1 + radius
2647
- self.draw_antialias_pixel(x,y,r,g,b)
2648
-
2649
- x = Math.cos((i)*3.1418/180) * radius + x2 - radius
2650
- y = Math.sin((i)*3.1418/180) * radius + y2 - radius
2651
- self.draw_antialias_pixel(x,y,r,g,b)
2652
-
2653
- x = Math.cos((i+90)*3.1418/180) * radius + x1 + radius
2654
- y = Math.sin((i+90)*3.1418/180) * radius + y2 - radius
2655
- self.draw_antialias_pixel(x,y,r,g,b)
2656
- i=i+step
2657
- end
2658
-
2659
- x1=x1-0.2
2660
- y1=y1-0.2
2661
- x2=x2+0.2
2662
- y2=y2+0.2
2663
- self.draw_line(x1+radius,y1,x2-radius,y1,r,g,b)
2664
- self.draw_line(x2,y1+radius,x2,y2-radius,r,g,b)
2665
- self.draw_line(x2-radius,y2,x1+radius,y2,r,g,b)
2666
- self.draw_line(x1,y2-radius,x1,y1+radius,r,g,b)
2667
- end
2668
- # This function draw an aliased filled rectangle with rounded corners
2669
- # The upper left and bottom right border positions are used as first 4 arguments.
2670
- # Argument #5 represents the radius of the rounded corner.
2671
- # The last 3 parameters are used to set the border color.
2672
- def draw_filled_rounded_rectangle(x1, y1, x2, y2, radius,r, g, b, draw_border=true, alpha=100)
2673
- b, g, r = validate_color(b, g, r)
2674
- c_rectangle = allocate_color(@picture,r,g,b)
2675
-
2676
- step = 90 / ((3.1418 * radius)/2)
2677
- i=0
2678
- while i<=90
2679
- xi1 = Math.cos((i+180)*3.1418/180) * radius + x1 + radius
2680
- yi1 = Math.sin((i+180)*3.1418/180) * radius + y1 + radius
2681
-
2682
- xi2 = Math.cos((i-90)*3.1418/180) * radius + x2 - radius
2683
- yi2 = Math.sin((i-90)*3.1418/180) * radius + y1 + radius
2684
-
2685
- xi3 = Math.cos((i)*3.1418/180) * radius + x2 - radius
2686
- yi3 = Math.sin((i)*3.1418/180) * radius + y2 - radius
2687
-
2688
- xi4 = Math.cos((i+90)*3.1418/180) * radius + x1 + radius
2689
- yi4 = Math.sin((i+90)*3.1418/180) * radius + y2 - radius
2690
-
2691
- image_line(@picture,xi1,yi1,x1+radius,yi1,r,g,b)
2692
- image_line(@picture,x2-radius,yi2,xi2,yi2,r,g,b)
2693
- image_line(@picture,x2-radius,yi3,xi3,yi3,r,g,b)
2694
- image_line(@picture,xi4,yi4,x1+radius,yi4,r,g,b)
2695
-
2696
- self.draw_antialias_pixel(xi1,yi1,r,g,b)
2697
- self.draw_antialias_pixel(xi2,yi2,r,g,b)
2698
- self.draw_antialias_pixel(xi3,yi3,r,g,b)
2699
- self.draw_antialias_pixel(xi4,yi4,r,g,b)
2700
-
2701
- i=i+step
2702
- end
2703
-
2704
- image_filled_rectangle(@picture,x1,y1+radius,x2,y2-radius,r,g,b)
2705
-
2706
- image_filled_rectangle(@picture,x1+radius,y1,x2-radius,y2,r,g,b)
2707
-
2708
- x1=x1-0.2
2709
- y1=y1-0.2
2710
- x2=x2+0.2
2711
- y2=y2+0.2
2712
- self.draw_line(x1+radius,y1,x2-radius,y1,r,g,b)
2713
- self.draw_line(x2,y1+radius,x2,y2-radius,r,g,b)
2714
- self.draw_line(x2-radius,y2,x1+radius,y2,r,g,b)
2715
- self.draw_line(x1,y2-radius,x1,y1+radius,r,g,b)
2716
- end
2717
- # This function draw an aliased circle at position (xc,yc) with the specified radius.
2718
- # The last 3 parameters are used to set the border color.
2719
- # Width is used to draw ellipses.
2720
- def draw_circle(xc,yc,height,r,g,b,width=0)
2721
- width = height if ( width == 0 )
2722
- b, g, r = validate_color(b, g, r)
2723
- step = 360 / (2 * 3.1418 * [width,height].max)
2724
- i =0
2725
- while(i<=360)
2726
- x= Math.cos(i*3.1418/180) * height + xc
2727
- y = Math.sin(i*3.1418/180) * width + yc
2728
- self.draw_antialias_pixel(x,y,r,g,b)
2729
- i = i+step
2730
- end
2731
- end
2732
-
2733
- # This function draw a filled aliased circle at position (xc,yc) with the specified radius.
2734
- # The last 3 parameters are used to set the border and filling color.
2735
- # Width is used to draw ellipses.
2736
- def draw_filled_circle(xc,yc,height,r,g,b,width=0)
2737
- width = height if ( width == 0 )
2738
- b, g, r = validate_color(b, g, r)
2739
- step = 360 / (2 * 3.1418 * [width,height].max)
2740
- i =90
2741
- while i<=270
2742
- x1 = Math.cos(i*3.1418/180) * height + xc
2743
- y1 = Math.sin(i*3.1418/180) * width + yc
2744
- x2 = Math.cos((180-i)*3.1418/180) * height + xc
2745
- y2 = Math.sin((180-i)*3.1418/180) * width + yc
2746
- self.draw_antialias_pixel(x1-1,y1-1,r,g,b)
2747
- self.draw_antialias_pixel(x2-1,y2-1,r,g,b)
2748
- image_line(@picture,x1,y1-1,x2-1,y2-1,r,g,b) if ( (y1-1) > yc - [width,height].max )
2749
- i= i+step
2750
- end
2751
- end
2752
-
2753
- # This function draw an aliased ellipse at position (xc,yc) with the specified height and width.
2754
- # The last 3 parameters are used to set the border color.
2755
- def draw_ellipse(xc,yc,height,width,r,g,b)
2756
- self.draw_circle(xc,yc,height,r,g,b,width)
2757
- end
2758
-
2759
-
2760
- # This function draw a filled aliased ellipse at position (xc,yc) with the specified height and width.
2761
- # The last 3 parameters are used to set the border and filling color.
2762
- def draw_filled_ellipse(xc,yc,height,width,r,g,b)
2763
- self.draw_filled_circle(xc,yc,height,r,g,b,width)
2764
- end
2765
-
2766
- # This function will draw an aliased line between points (x1,y1) and (x2,y2).
2767
- # The last 3 parameters are used to set the line color.
2768
- # The last optional parameter is used for internal calls made by graphing function.If set to true, only portions of line inside the graph area will be drawn.
2769
-
2770
- def draw_line(x1,y1,x2,y2,r,g,b,graph_function=false)
2771
- if ( @line_dot_size > 1 )
2772
- self.draw_dotted_line(x1,y1,x2,y2,@line_dot_size,r,g,b,graph_function)
2773
- else
2774
- b, g, r = validate_color(b, g, r)
2775
- distance = Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)) rescue 0
2776
- if ( distance == 0 )
2777
- return -1
2778
- else
2779
- x_step = (x2-x1) / distance
2780
- y_step = (y2-y1) / distance
2781
- i =0
2782
- while i<=distance
2783
- x = i * x_step + x1
2784
- y = i * y_step + y1
2785
- if((x >= @g_area_x1.to_f && x <= @g_area_x2.to_f && y >= @g_area_y1.to_f && y <= @g_area_y2.to_f) || !graph_function )
2786
- if ( @line_width == 1 )
2787
- self.draw_antialias_pixel(x,y,r,g,b)
2788
- else
2789
- start_offset = -(@line_width/2)
2790
- end_offset = (@line_width/2)
2791
- j = start_offset
2792
-
2793
- while j<=end_offset
2794
- self.draw_antialias_pixel(x+j,y+j,r,g,b)
2795
- j+=1
2796
- end
2797
- end
2798
- end
2799
- i =i+1
2800
- end
2801
- end
2802
- end
2803
- end
2804
-
2805
- # This function will draw an aliased dotted line between points (x1,y1) and (x2,y2).
2806
- # Parameter #5 is used to specify the dot size ( 2 will draw 1 point every 2 points )
2807
- # The last 3 parameters are used to set the line color.
2808
- def draw_dotted_line(x1,y1,x2,y2,dot_size,r,g,b,graph_function=false)
2809
- b, g, r = validate_color(b, g, r)
2810
- distance = Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
2811
- x_step = (x2-x1) / distance
2812
- y_step = (y2-y1) / distance
2813
- dot_index = 0
2814
- i = 0
2815
- start_offset = 0
2816
-
2817
- while(i<=distance)
2818
- x = i * x_step + x1
2819
- y = i * y_step + y1
2820
- if ( dot_index <= dot_size)
2821
- if ( (x >= @g_area_x1 && x <= @g_area_x2 && y >= @g_area_y1 && y <= @g_area_y2) || !graph_function )
2822
- if (@line_width == 1 )
2823
- self.draw_antialias_pixel(x,y,r,g,b)
2824
- else
2825
- start_offset = start_offset -(@line_width/2)
2826
- end_offset = (@line_width/2)
2827
- j = start_offset
2828
- while(j<= end_offset)
2829
- self.draw_antialias_pixel(x+j,y+j,r,g,b)
2830
- j= j+1
2831
- end
2832
- end
2833
- end
2834
- end
2835
- dot_index = dot_index+1
2836
- dot_index = 0 if (dot_index == dot_size * 2)
2837
- i= i+1
2838
- end
2839
-
2840
- end
2841
-
2842
- # This function allows you to merge an external PNG picture with your graph specifying the position and the transparency
2843
- def draw_from_png(file_name,x,y,alpha=100)
2844
- self.draw_from_picture(1,file_name,x,y,alpha)
2845
- end
2846
-
2847
- #This function allows you to merge an external GIF picture with your graph specifying the position and the transparenc
2848
- #def draw_from_gif(file_name,x,y,alpha=100)
2849
- #self.draw_from_picture(2,file_name,x,y,alpha)
2850
- #end
2851
-
2852
- # This function allows you to merge an external JPG picture with your graph specifying the position and the transparency.
2853
- def draw_from_jpg(file_name,x,y,alpha=100)
2854
- self.draw_from_picture(3,file_name,x,y,alpha)
2855
- end
2856
-
2857
- # Generic loader function for external pictures accepts png format
2858
- def draw_from_picture(pic_type,file_name,x,y,alpha=100)
2859
- if ( File.exist?(file_name))
2860
- raster = image_create_from_png(file_name) if ( pic_type == 1 )
2861
- # raster = image_create_from_gif(file_name) if ( pic_type == 2 )
2862
- raster = image_create_from_jpeg(file_name) if ( pic_type == 3 )
2863
- infos = get_image_size(raster)
2864
- width = infos[0]
2865
- height = infos[1]
2866
- image_copy_merge(raster,@picture,x,y,0,0,width,height,alpha)
2867
- image_destroy(raster)
2868
- end
2869
- end
2870
-
2871
- # This function will draw an alpha pixel at position (x,y).
2872
- # alpha is used to specify the transparency factor ( between 0 and 100 )
2873
- # The last 3 parameters are used to set the pixel color.
2874
- def draw_alpha_pixel(x,y,alpha,r,g,b)
2875
- b, g, r = validate_color(b, g, r)
2876
- if ( x < 0 || y < 0 || x >= @x_size || y >= @y_size )
2877
- #eturn(-1)
2878
- #TODO check image_color_at method is right?
2879
- else
2880
- rgb2= image_color_at(@picture, x, y)
2881
-
2882
- r2 = (rgb2 >> 16) & 0xFF
2883
- g2 = (rgb2 >> 8) & 0xFF
2884
- b2 = rgb2 & 0xFF
2885
- i_alpha = (100 - alpha)/100
2886
- alpha = alpha / 100
2887
- ra = (r*alpha+r2*i_alpha).floor
2888
- ga = (g*alpha+g2*i_alpha).floor
2889
- ba = (b*alpha+b2*i_alpha).floor
2890
- image_set_pixel(@picture,x,y,ra,ga,ba)
2891
- end
2892
- end
2893
- # color helper
2894
- def allocate_color(picture,r,g,b,factor=0)
2895
- r = r + factor
2896
- g = g + factor
2897
- b = b + factor
2898
- r = 0 if ( r < 0 )
2899
- r = 255 if ( r > 255 )
2900
- g = 0 if ( g < 0 )
2901
- g = 255 if ( g > 255 )
2902
- b = 0 if ( b < 0 )
2903
- b = 255 if ( b > 255 )
2904
- image_color_allocate(picture,r,g,b)
2905
- end
2906
-
2907
- # Use this function to add a border to your picture. Be carefull, drawing a border will change all the chart components positions, thus this call must be the last one before one of the rendering methods!!!
2908
- # You can specify the size of the border and its color.
2909
- # The width and height of the picture will be modified by 2x the size value.
2910
- def add_border(size=3,r=0,g=0,b=0)
2911
- width = @x_size+2*size
2912
- height = @y_size+2*size
2913
- resampled = image_create_true_color(width,height)
2914
- image_filled_rectangle(resampled,0,0,width,height, r, g, b)
2915
- image_copy(@picture,resampled,size,size,0,0,@x_size,@y_size)
2916
- image_destroy(@picture)
2917
- @x_size = width
2918
- @y_size = height
2919
- @picture = image_create_true_color(@x_size,@y_size)
2920
- image_filled_rectangle(@picture,0,0,@x_size,@y_size,255,255,255)
2921
- image_color_transparent(@picture,255,255,255)
2922
- image_copy(resampled,@picture,0,0,0,0,@x_size,@y_size)
2923
- end
2924
-
2925
- # Private functions for internal processing Internal function.
2926
- def draw_antialias_pixel(x,y,r,g,b,alpha=100,no_fall_back=false)
2927
- #Process shadows
2928
- if(@shadow_active && !no_fall_back)
2929
- self.draw_antialias_pixel(x+@shadow_x_distance,y+@shadow_y_distance,@shadow_r_color,@shadow_g_color,@shadow_b_color,@shadow_alpha,true)
2930
- if(@shadow_blur != 0)
2931
- alpha_decay = (@shadow_alpha*1.0 / @shadow_blur)
2932
- i=1
2933
- while i<=@shadow_blur
2934
- self.draw_antialias_pixel(x+@shadow_x_distance-i/2,y+@shadow_y_distance-i/2,@shadow_r_color,@shadow_g_color,@shadow_b_color,@shadow_alpha-alpha_decay*i,true)
2935
- i = i+1
2936
- end
2937
- i =1
2938
- while i<=@shadow_blur
2939
- self.draw_antialias_pixel(x+@shadow_x_distance+i/2,y+@shadow_y_distance+i/2,@shadow_r_color,@shadow_g_color,@shadow_b_color,@shadow_alpha-alpha_decay*i,true)
2940
- i = i+1
2941
- end
2942
- end
2943
- end
2944
- b, g, r = validate_color(b, g, r)
2945
- plot = ""
2946
- xi = x.floor rescue 0
2947
- yi = y.floor rescue 0
2948
- if ( xi == x && yi == y)
2949
- if ( alpha == 100 )
2950
- image_set_pixel(@picture,x,y,r,g,b)
2951
- else
2952
- self.draw_alpha_pixel(x,y,alpha,r,g,b)
2953
- end
2954
- else
2955
- if xi > 0 || yi > 0 #soe error occures therefor added condtion
2956
- alpha1 = (((1 - (x - x.floor)) * (1 - (y - y.floor)) * 100) / 100) * alpha
2957
- self.draw_alpha_pixel(xi,yi,alpha1,r,g,b) if alpha1 > @anti_alias_quality
2958
- alpha2 = (((x - x.floor) * (1 - (y - y.floor)) * 100) / 100) * alpha
2959
- self.draw_alpha_pixel(xi+1,yi,alpha2,r,g,b) if alpha2 > @anti_alias_quality
2960
- alpha3 = (((1 - (x - x.floor)) * (y - y.floor) * 100) / 100) * alpha
2961
- self.draw_alpha_pixel(xi,yi+1,alpha3,r,g,b) if alpha3 > @anti_alias_quality
2962
- alpha4 = (((x - x.floor) * (y - y.floor) * 100) / 100) * alpha
2963
- self.draw_alpha_pixel(xi+1,yi+1,alpha4,r,g,b) if alpha4 > @anti_alias_quality
2964
- end
2965
- end
2966
- end
2967
-
2968
- # Validate data contained in the description array Internal function
2969
- def validate_data_description(function_name,data_description,description_required=true)
2970
- if (data_description["position"].nil?)
2971
- @errors << "[Warning] #{function_name} - Y Labels are not set."
2972
- data_description["position"] = "name"
2973
- end
2974
-
2975
- if (description_required)
2976
- if ((data_description["description"].nil?))
2977
- @errors << "[Warning] #{function_name} - Series descriptions are not set."
2978
- data_description["values"].each do |value|
2979
- if data_description["description"].nil?
2980
- data_description["description"]={value=> value}
2981
- else
2982
- data_description["description"]=data_description["description"].merge(value=>value)
2983
- end
2984
- end
2985
- end
2986
-
2987
- data_desc_count = data_description["values"].is_a?(Array) ? data_description["values"].count : 1
2988
- if ((data_description["description"].count) < data_desc_count)
2989
- @errors << "[Warning] #{function_name} - Some series descriptions are not set."
2990
- data_description["values"].each do |value|
2991
- data_description["description"][value] = value if ( data_description["description"][value].nil?)
2992
- end
2993
- end
2994
- end
2995
- return data_description
2996
- end
2997
-
2998
- #Validate data contained in the data array Internal function
2999
- def validate_data(function_name,data)
3000
- data_summary = {}
3001
- data.each do |v|
3002
- v.each do |key,val|
3003
-
3004
- if (data_summary[key].nil?)
3005
- data_summary[key] = 1
3006
- else
3007
- data_summary[key] = data_summary[key]+1
3008
- end
3009
- end
3010
- end
3011
- if ( data_summary.max.last == 0 ) #TODO Check method
3012
- @errors << "[Warning] #{function_name} No data set."
3013
- end
3014
- data_summary.each do |k,v|
3015
- if v < data_summary.max.last
3016
- @errors << "#{function_name} Missing Data in serie #{key}"
3017
- end
3018
- end
3019
- return data
3020
- end
3021
- # Activate the image map creation process Internal function
3022
- def set_image_map(mode=true,graph_id="MyGraph")
3023
- @build_map = mode
3024
- @map_id = graph_id
3025
- end
3026
- # Add a box into the image map Internal function
3027
- def add_to_image_map(x1,y1,x2,y2,serie_name,value,caller_function)
3028
- if ( @map_function == nil || @map_function == caller_function )
3029
- @image_map << (x1.round).to_s+","+(y1.round).to_s+","+(x2.round).to_s+","+(y2.round).to_s+","+serie_name+","+value.to_s
3030
- @map_function = caller_function
3031
- end
3032
- end
3033
-
3034
- #Convert seconds to a time format string
3035
- def to_time(value)
3036
- hour = (value/3600).floor
3037
- minute = ((value - hour*3600)/60).floor
3038
- second =(value - hour*3600 - minute*60).floor
3039
-
3040
- hour = "0.#{Hour}" if (hour.length == 1 )
3041
- minute = "0.#{minute}" if (minute.length == 1 )
3042
- second = "0.#{second}" if (second.length == 1 )
3043
-
3044
- return ("#{hour}.:.#{minute}}.:.#{second}")
3045
- end
3046
-
3047
- # Convert to metric system */
3048
- def to_metric(value)
3049
- go = (value/1000000000).floor
3050
- mo = ((value - go*1000000000)/1000000).floor
3051
- ko = ((value - go*1000000000 - mo*1000000)/1000).floor
3052
- o = (value - go*1000000000 - mo*1000000 - ko*1000).floor
3053
-
3054
- return("#{go}..#{mo}.g") if (go != 0)
3055
- return("#{mo}...#{ko}.m") if (mo != 0)
3056
- return("#{ko}...#{o}).k") if (ko != 0)
3057
- return(o)
3058
- end
3059
-
3060
- # Convert to curency
3061
- def to_currency(value)
3062
- go = (value/1000000000).floor
3063
- mo = ((value - go*1000000000)/1000000).floor
3064
- ko = ((value - go*1000000000 - mo*1000000)/1000).floor
3065
- o = (value - go*1000000000 - mo*1000000 - ko*1000).floor
3066
-
3067
- o = "00.#{o}" if ( (o.length) == 1 )
3068
- o = "0.#{o}" if ( (o.length) == 2 )
3069
-
3070
- result_string = o
3071
- result_string = "#{ko}...#{result_string}" if ( ko != 0 )
3072
- result_string = "#{mo}...#{result_string}" if ( mo != 0 )
3073
- result_string = "#{go}...#{result_string}" if ( go != 0 )
3074
-
3075
- result_string = @currency.result_strin
3076
- return(result_string)
3077
- end
3078
- # Set date format for axis labels TODO
3079
- def set_date_format(format)
3080
- @date_format = format
3081
- end
3082
-
3083
- def to_date(value)
3084
- #return(Time.parse(value))
3085
- end
3086
- # Check if a number is a full integer (for scaling)
3087
- def is_real_int(value)
3088
- value.ceil == value.floor
3089
- end
3090
- # round of particular decimal
3091
- def round_of(no,n=0)
3092
- (no * (10.0 ** n)).round * (10.0 ** (-n))
3093
- end
3094
-
3095
- #convert degree to radian
3096
- def deg2rad(deg)
3097
- deg*Math::PI/180
3098
- end
3099
-
3100
- def raise_fatal(message)
3101
- puts "[FATAL] "+message
3102
- return -1
3103
- end
3104
- # Print all error messages on the CLI or graphically
3105
- def print_errors(mode="cli")
3106
- return(0) if (@errors.count == 0)
3107
-
3108
- if mode == "cli"
3109
- @errors.each do |value|
3110
- puts value
3111
- end
3112
- elsif ( mode == "gd" )
3113
- self.set_line_style(width=1)
3114
- max_width = 0
3115
- @errors.each do |value|
3116
- position = image_ftb_box(@error_font_size,0,@error_font_name,value)
3117
- text_width = position[2]-position[0]
3118
- max_width = text_width if ( text_width > max_width )
3119
- end
3120
- self.draw_filled_rounded_rectangle(@x_size-(max_width+20),@y_size-(20+((@error_font_size+4)*(@errors.count))),@x_size-10,@y_size-10,6,233,185,185)
3121
- self.draw_rounded_rectangle(@x_size-(max_width+20),@y_size-(20+((@error_font_size+4)*(@errors.count))),@x_size-10,@y_size-10,6,193,145,145)
3122
- c_text_color = allocate_color(@picture,133,85,85)
3123
- ypos = @y_size - (18 + ((@errors.count)-1) * (@error_font_size + 4))
3124
- @errors.each do |value|
3125
- image_ttf_text(@picture,@error_font_size,0,@x_size-(max_width+15),ypos,c_text_color,@error_font_name,value)
3126
- ypos = ypos + (@error_font_size + 4)
3127
- end
3128
- end
3129
- end
3130
- # render Graph as png format
3131
- def render_png(file_name)
3132
- self.print_errors(@error_interface) if ( @error_reporting )
3133
- file = File.new(file_name,"wb")
3134
- @picture.png(file)
3135
- file.close
3136
- end
3137
- # render Graph as jpeg format
3138
- def render_jpeg(file_name,quality=0)
3139
- self.print_errors(@error_interface) if ( @error_reporting )
3140
- file = File.new(file_name,"wb")
3141
- @picture.jpeg(file,quality)
3142
- file.close
3143
- end
3144
-
3145
- #Outputs the image in PNG format as String object.
3146
- #This method will be especially useful when you want to transmit an image directly to an user(i.e, without first writing it to a file)
3147
-
3148
- def render_png_str(img=self.picture)
3149
- img.pngStr
3150
- end
3151
-
3152
-
3153
- # resize image on passing png,jpeg,or gd image
3154
- # pass file_name/gd image,new_file_name,percentage,or resize width,resize height
3155
- def resize_image(file_name,resize_file_name="test",percentage=0,resized_width=0,resized_height=0)
3156
- image = GD::Image.new_from_png(file_name) rescue ""
3157
- render_file_as = "png"
3158
- if !image.is_a?(GD::Image)
3159
- image = GD::Image.new_from_jpeg(file_name) rescue ""
3160
- render_file_as = "jpeg"
3161
- elsif !image.is_a?(GD::Image)
3162
- image = GD::Image.new_from_gd(file_name) rescue ""
3163
- render_file_as = "png"
3164
- end
3165
-
3166
- if image.is_a?(GD::Image)
3167
- width=image.width
3168
- height=image.height
3169
- if percentage >0
3170
- resized_width = (width*percentage)/100.0
3171
- resized_height = (height*percentage)/100.0
3172
- elsif(resized_width != 0 && resized_height ==0)
3173
-
3174
- resized_height = (100 /(width*1.0/resized_width) ) * 0.01
3175
- resized_height = (height * resized_height).round
3176
- elsif( resized_height != 0 && resized_width ==0)
3177
-
3178
- resized_width = (100 /(height*1.0/resized_height) ) * 0.01
3179
- resized_width = (width * resized_width).round
3180
- else
3181
- resized_width = 100
3182
- resized_height = 100
3183
- end
3184
-
3185
- resize_image = GD::Image.newTrueColor(resized_width, resized_height)
3186
- image.copyResized(resize_image, 0,0,0,0, resized_width,resized_height, width, height)
3187
- file=File.new(resize_file_name,"wb")
3188
- if render_file_as == "png"
3189
- resize_image.png(file)
3190
- elsif render_file_as == "jpeg"
3191
- resize_image.jpeg(file)
3192
- end
3193
- file.close
3194
- else
3195
- puts "Provide proper image"
3196
- end
3197
- end
3198
- ##########################################3
3199
- #GD MAP FUNCTION HELPER
3200
- #ON NEXT VERSION TRY TO MAP THIS FUNCTION WITH GD2 Gem
3201
- def image_ttf_text(picture,font_size,angle,x_pos,y_pos,fg_color,font_name,str)
3202
- angle = deg2rad(angle)
3203
- err,brect=picture.stringTTF(fg_color, font_name, font_size, angle, x_pos, y_pos, str.to_s)
3204
- end
3205
-
3206
- def image_ftb_box(font_size,angle,font_name,str,x=0,y=0)
3207
- angle = deg2rad(angle)
3208
- err,brect = GD::Image.stringFT(0, font_name, font_size, angle, x, y, str)
3209
- brect
3210
- end #Compute and draw the scale
3211
-
3212
- def image_color_allocate(picture,r,g,b)
3213
- picture.colorAllocate(r,g,b)
3214
- end
3215
-
3216
- def image_set_pixel(picture,x,y,r,g,b)
3217
- color=image_color_allocate(picture,r,g,b)
3218
- picture.setPixel(x,y,color)
3219
- end
3220
-
3221
- def image_color_at(picture,x,y)
3222
- color = picture.getPixel(x, y)
3223
- end
3224
-
3225
- def image_line(picture,x1,y1,x2,y2,r,g,b)
3226
- picture.line(x1, y1, x2, y2, allocate_color(picture,r,g,b))
3227
- end
3228
-
3229
- def image_filled_rectangle(picture,x1,y1,x2,y2,r,g,b)
3230
- color = picture.colorAllocate(r,g,b)
3231
- picture.filledRectangle(x1, y1, x2, y2, color)
3232
- end
3233
-
3234
- def image_create_true_color(width,height)
3235
- GD::Image.newTrueColor(width, height)
3236
- end
3237
-
3238
- def image_copy_merge(src_pic,dest_pic, dst_x, dst_y, src_x, src_y, w, h, pct, gray = false)
3239
- src_pic.copyMerge(dest_pic, dst_x, dst_y, src_x, src_y, w, h, pct)
3240
- end
3241
-
3242
- def image_copy(src_pic,dst_pic,dest_x, dest_y, self_x, self_y, width, height)
3243
- src_pic.copy(dst_pic,dest_x, dest_y, self_x, self_y, width, height)
3244
- end
3245
-
3246
- def image_color_transparent(im,r,g,b)
3247
- color=allocate_color(im, r, g, b)
3248
- im.transparent(color)
3249
- end
3250
-
3251
- def image_destroy(image)
3252
- image.destroy
3253
- end
3254
-
3255
- def image_create_from_png(file_name)
3256
- GD::Image.new_from_png(file_name)
3257
- end
3258
- def image_create_from_jpeg(file_name)
3259
- GD::Image.new_from_jpeg(file_name)
3260
- end
3261
-
3262
- def get_image_size(image)
3263
- [image.width,image.height]
3264
- end
3265
-
3266
- def image_filled_polygon(picture,points,r,g,b,points_count=0)
3267
- color = allocate_color(picture,r,g,b)
3268
- polygon=GD::Polygon.new
3269
- i=0
3270
- if points_count == 0
3271
- num_points = (points.length+1)
3272
- else
3273
- num_points = points_count+points_count
3274
- end
3275
- while(i<=num_points)
3276
- j =i
3277
- polygon.addPt(points[j],points[j+1]) if(!points[j+1].nil?)
3278
- i = i+2
3279
- end
3280
- picture.filledPolygon(polygon, color)
3281
- end
3282
-
3283
109
  end
3284
-
3285
-