rchart 1.2.2 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +3 -3
- data/VERSION +1 -1
- data/lib/bar_chart.rb +166 -0
- data/lib/color_palette.rb +56 -0
- data/lib/cubic_chart.rb +271 -0
- data/lib/gd2_helper.rb +161 -0
- data/lib/graph.rb +24 -0
- data/lib/graph_helper.rb +414 -0
- data/lib/layout.rb +247 -0
- data/lib/legend.rb +243 -0
- data/lib/line_chart.rb +164 -0
- data/lib/pie_chart.rb +479 -0
- data/lib/plot_chart.rb +192 -0
- data/lib/rchart.rb +13 -3189
- data/lib/rchart_helper.rb +265 -0
- data/lib/rdata.rb +15 -14
- data/lib/scale.rb +538 -0
- metadata +49 -16
data/lib/plot_chart.rb
ADDED
@@ -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
|
data/lib/rchart.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
require
|
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 =
|
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
|
-
|
100
|
-
@
|
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
|
-
|
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
|
-
|