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
@@ -0,0 +1,265 @@
|
|
1
|
+
|
2
|
+
module RchartHelper
|
3
|
+
|
4
|
+
# Set font Properties font_name,font_size
|
5
|
+
# font_name is
|
6
|
+
# * GeosansLight.ttf,
|
7
|
+
# * MankSans.ttf,
|
8
|
+
# * pf_arma_five.ttf,
|
9
|
+
# * Silkscreen.ttf,
|
10
|
+
# * tahoma.ttf
|
11
|
+
def set_font_properties(font_name, font_size)
|
12
|
+
@font_size = font_size
|
13
|
+
@font_name = "#{Rchart::FONT_PATH}/#{font_name}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate_color(b, g, r)
|
17
|
+
r = 0 if ( r < 0 )
|
18
|
+
r = 255 if ( r > 255 )
|
19
|
+
g = 0 if ( g < 0 )
|
20
|
+
g = 255 if ( g > 255 )
|
21
|
+
b = 0 if ( b < 0 )
|
22
|
+
b = 255 if ( b > 255 )
|
23
|
+
return b, g, r
|
24
|
+
end
|
25
|
+
#color Helper
|
26
|
+
def allocate_color(picture,r,g,b,factor=0)
|
27
|
+
r = r + factor
|
28
|
+
g = g + factor
|
29
|
+
b = b + factor
|
30
|
+
b,g,r= validate_color(b,g,r)
|
31
|
+
image_color_allocate(picture,r,g,b)
|
32
|
+
end
|
33
|
+
|
34
|
+
#Use this function to set shadow properties.
|
35
|
+
def set_shadow_properties(x_distance=1,y_distance=1,r=60,g=60,b=60,alpha=50,blur=0)
|
36
|
+
@shadow_active = true
|
37
|
+
@shadow_x_distance = x_distance
|
38
|
+
@shadow_y_distance = y_distance
|
39
|
+
@shadow_r_color = r
|
40
|
+
@shadow_g_color = g
|
41
|
+
@shadow_b_color = b
|
42
|
+
@shadow_alpha = alpha
|
43
|
+
@shadow_blur = blur
|
44
|
+
end
|
45
|
+
|
46
|
+
# Use this function to deactivate the shadow options.
|
47
|
+
# Drawing shadows is time and CPU intensive.
|
48
|
+
def clear_shadow
|
49
|
+
@shadow_active = false
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# This function allow you to customise the way lines are drawn in charts.
|
54
|
+
# This function only applies during chart drawing calls ( line charts,.. ).
|
55
|
+
# You can specify the width of the lines & if they are dotted.
|
56
|
+
def set_line_style(width=1,dot_size=0)
|
57
|
+
@line_width = width
|
58
|
+
@line_dot_size = dot_size
|
59
|
+
end
|
60
|
+
|
61
|
+
# Set currency symbol
|
62
|
+
def set_currency(currency)
|
63
|
+
@currency = currency
|
64
|
+
end
|
65
|
+
# This function allows you to merge an external PNG picture with your graph specifying the position and the transparency
|
66
|
+
def draw_from_png(file_name,x,y,alpha=100)
|
67
|
+
draw_from_picture(1,file_name,x,y,alpha)
|
68
|
+
end
|
69
|
+
|
70
|
+
#This function allows you to merge an external GIF picture with your graph specifying the position and the transparenc
|
71
|
+
#def draw_from_gif(file_name,x,y,alpha=100)
|
72
|
+
#self.draw_from_picture(2,file_name,x,y,alpha)
|
73
|
+
#end
|
74
|
+
|
75
|
+
# This function allows you to merge an external JPG picture with your graph specifying the position and the transparency.
|
76
|
+
def draw_from_jpg(file_name,x,y,alpha=100)
|
77
|
+
draw_from_picture(3,file_name,x,y,alpha)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Generic loader function for external pictures accepts png format
|
81
|
+
def draw_from_picture(pic_type,file_name,x,y,alpha=100)
|
82
|
+
if ( File.exist?(file_name))
|
83
|
+
raster = image_create_from_png(file_name) if ( pic_type == 1 )
|
84
|
+
# raster = image_create_from_gif(file_name) if ( pic_type == 2 )
|
85
|
+
raster = image_create_from_jpeg(file_name) if ( pic_type == 3 )
|
86
|
+
infos = get_image_size(raster)
|
87
|
+
width = infos[0]
|
88
|
+
height = infos[1]
|
89
|
+
image_copy_merge(raster,@picture,x,y,0,0,width,height,alpha)
|
90
|
+
image_destroy(raster)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# Validate data contained in the description array Internal function
|
96
|
+
def validate_data_description(function_name,data_description,description_required=true)
|
97
|
+
if (data_description["position"].nil?)
|
98
|
+
@errors << "[Warning] #{function_name} - Y Labels are not set."
|
99
|
+
data_description["position"] = "name"
|
100
|
+
end
|
101
|
+
|
102
|
+
if (description_required)
|
103
|
+
if ((data_description["description"].nil?))
|
104
|
+
@errors << "[Warning] #{function_name} - Series descriptions are not set."
|
105
|
+
data_description["values"].each do |value|
|
106
|
+
if data_description["description"].nil?
|
107
|
+
data_description["description"]={value=> value}
|
108
|
+
else
|
109
|
+
data_description["description"]=data_description["description"].merge(value=>value)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
data_desc_count = data_description["values"].is_a?(Array) ? data_description["values"].count : 1
|
115
|
+
if ((data_description["description"].count) < data_desc_count)
|
116
|
+
@errors << "[Warning] #{function_name} - Some series descriptions are not set."
|
117
|
+
data_description["values"].each do |value|
|
118
|
+
data_description["description"][value] = value if ( data_description["description"][value].nil?)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
return data_description
|
123
|
+
end
|
124
|
+
#Validate data contained in the data array Internal function
|
125
|
+
def validate_data(function_name,data)
|
126
|
+
data_summary = {}
|
127
|
+
data.each do |v|
|
128
|
+
v.each do |key,val|
|
129
|
+
|
130
|
+
if (data_summary[key].nil?)
|
131
|
+
data_summary[key] = 1
|
132
|
+
else
|
133
|
+
data_summary[key] = data_summary[key]+1
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
if ( data_summary.max.last == 0 ) #TODO Check method
|
138
|
+
@errors << "[Warning] #{function_name} No data set."
|
139
|
+
end
|
140
|
+
data_summary.each do |k,v|
|
141
|
+
if v < data_summary.max.last
|
142
|
+
@errors << "#{function_name} Missing Data in serie #{key}"
|
143
|
+
end
|
144
|
+
end
|
145
|
+
return data
|
146
|
+
end
|
147
|
+
#Convert seconds to a time format string
|
148
|
+
def to_time(value)
|
149
|
+
hour = (value/3600).floor
|
150
|
+
minute = ((value - hour*3600)/60).floor
|
151
|
+
second =(value - hour*3600 - minute*60).floor
|
152
|
+
|
153
|
+
hour = "0.#{Hour}" if (hour.length == 1 )
|
154
|
+
minute = "0.#{minute}" if (minute.length == 1 )
|
155
|
+
second = "0.#{second}" if (second.length == 1 )
|
156
|
+
|
157
|
+
return ("#{hour}.:.#{minute}}.:.#{second}")
|
158
|
+
end
|
159
|
+
|
160
|
+
# Convert to metric system */
|
161
|
+
def to_metric(value)
|
162
|
+
go = (value/1000000000).floor
|
163
|
+
mo = ((value - go*1000000000)/1000000).floor
|
164
|
+
ko = ((value - go*1000000000 - mo*1000000)/1000).floor
|
165
|
+
o = (value - go*1000000000 - mo*1000000 - ko*1000).floor
|
166
|
+
|
167
|
+
return("#{go}..#{mo}.g") if (go != 0)
|
168
|
+
return("#{mo}...#{ko}.m") if (mo != 0)
|
169
|
+
return("#{ko}...#{o}).k") if (ko != 0)
|
170
|
+
return o
|
171
|
+
end
|
172
|
+
|
173
|
+
# Convert to curency
|
174
|
+
def to_currency(value)
|
175
|
+
go = (value/1000000000).floor
|
176
|
+
mo = ((value - go*1000000000)/1000000).floor
|
177
|
+
ko = ((value - go*1000000000 - mo*1000000)/1000).floor
|
178
|
+
o = (value - go*1000000000 - mo*1000000 - ko*1000).floor
|
179
|
+
|
180
|
+
o = "00.#{o}" if ( (o.length) == 1 )
|
181
|
+
o = "0.#{o}" if ( (o.length) == 2 )
|
182
|
+
|
183
|
+
result_string = o
|
184
|
+
result_string = "#{ko}...#{result_string}" if ( ko != 0 )
|
185
|
+
result_string = "#{mo}...#{result_string}" if ( mo != 0 )
|
186
|
+
result_string = "#{go}...#{result_string}" if ( go != 0 )
|
187
|
+
|
188
|
+
result_string = @currency.result_string
|
189
|
+
result_string
|
190
|
+
end
|
191
|
+
# Set date format for axis labels TODO
|
192
|
+
def set_date_format(format)
|
193
|
+
@date_format = format
|
194
|
+
end
|
195
|
+
|
196
|
+
def to_date(value)
|
197
|
+
#return(Time.parse(value))
|
198
|
+
end
|
199
|
+
# Check if a number is a full integer (for scaling)
|
200
|
+
def is_real_int(value)
|
201
|
+
value.ceil == value.floor
|
202
|
+
end
|
203
|
+
# round of particular decimal
|
204
|
+
def round_of(no,n=0)
|
205
|
+
(no * (10.0 ** n)).round * (10.0 ** (-n))
|
206
|
+
end
|
207
|
+
|
208
|
+
#convert degree to radian
|
209
|
+
def deg2rad(deg)
|
210
|
+
deg*Math::PI/180
|
211
|
+
end
|
212
|
+
|
213
|
+
def raise_fatal(message)
|
214
|
+
puts "[FATAL] "+message
|
215
|
+
return -1
|
216
|
+
end
|
217
|
+
# Print all error messages on the CLI or graphically
|
218
|
+
def print_errors(mode="cli")
|
219
|
+
return(0) if (@errors.count == 0)
|
220
|
+
|
221
|
+
if mode == "cli"
|
222
|
+
@errors.each do |value|
|
223
|
+
puts value
|
224
|
+
end
|
225
|
+
elsif ( mode == "gd" )
|
226
|
+
set_line_style(width=1)
|
227
|
+
max_width = 0
|
228
|
+
@errors.each do |value|
|
229
|
+
position = image_ftb_box(@error_font_size,0,@error_font_name,value)
|
230
|
+
text_width = position[2]-position[0]
|
231
|
+
max_width = text_width if ( text_width > max_width )
|
232
|
+
end
|
233
|
+
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)
|
234
|
+
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)
|
235
|
+
c_text_color = allocate_color(@picture,133,85,85)
|
236
|
+
ypos = @y_size - (18 + ((@errors.count)-1) * (@error_font_size + 4))
|
237
|
+
@errors.each do |value|
|
238
|
+
image_ttf_text(@picture,@error_font_size,0,@x_size-(max_width+15),ypos,c_text_color,@error_font_name,value)
|
239
|
+
ypos = ypos + (@error_font_size + 4)
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# resize image on passing png,jpeg,or gd image
|
245
|
+
# pass file_name/gd image,new_file_name,percentage,or resize width,resize height
|
246
|
+
def resize_image(file_name,resize_file_name="test",resized_width=0,resized_height=0,render_file_as="png")
|
247
|
+
image = Image.import(file_name)
|
248
|
+
resize_image = image.resize(resized_width, resized_height,true)
|
249
|
+
|
250
|
+
file=File.new(resize_file_name,"wb")
|
251
|
+
if render_file_as == "png"
|
252
|
+
file.write resize_image.png
|
253
|
+
elsif render_file_as == "jpeg"
|
254
|
+
file.write resize_image.jpeg
|
255
|
+
elsif render_file_as == "gd"
|
256
|
+
file.write resize_image.gd
|
257
|
+
elsif render_file_as == "gd2"
|
258
|
+
file.write resize_image.gd2
|
259
|
+
else
|
260
|
+
puts "Provide proper image"
|
261
|
+
end
|
262
|
+
file.close
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
data/lib/rdata.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
1
3
|
class Rdata
|
2
4
|
# This function create a new Rdata object.
|
3
5
|
# This object will be used during all the steps of the data population.
|
4
|
-
# Data will be extracted from this object using get_data and get_data_description
|
6
|
+
# Data will be extracted from this object using get_data and get_data_description
|
5
7
|
def initialize
|
6
8
|
@data = []
|
7
9
|
@data_description = {}
|
@@ -36,7 +38,7 @@ class Rdata
|
|
36
38
|
@data[id]= @data[id].merge(serie => value)
|
37
39
|
end
|
38
40
|
if description != ""
|
39
|
-
@data[id]["name"] = description
|
41
|
+
@data[id]["name"] = description
|
40
42
|
elsif @data[id]["name"].nil?
|
41
43
|
@data[id]["name"] = id
|
42
44
|
end
|
@@ -85,9 +87,9 @@ class Rdata
|
|
85
87
|
# Generate some data...
|
86
88
|
# * chart_data.add_point([2,4,9,5,1,0],"Serie1")
|
87
89
|
# * chart_data.add_point([(1,1,2,2,3,3],"Serie2")
|
88
|
-
# This will mark both Serie1 & Serie2 as "graphable"
|
90
|
+
# This will mark both Serie1 & Serie2 as "graphable"
|
89
91
|
# * chart_data.add_all_series
|
90
|
-
|
92
|
+
|
91
93
|
def add_all_series
|
92
94
|
@data_description["values"] = []
|
93
95
|
if(!@data[0].nil?)
|
@@ -108,10 +110,10 @@ class Rdata
|
|
108
110
|
# * chart_data.add_all_series
|
109
111
|
# This will remove the "graphable" status of Serie2
|
110
112
|
# * chart_data.remove_serie("Serie2")
|
111
|
-
|
113
|
+
|
112
114
|
def remove_serie(serie_name="Serie1")
|
113
115
|
if (!@data_description["values"].nil?)
|
114
|
-
found = false
|
116
|
+
found = false
|
115
117
|
@data_description["values"].each do |v|
|
116
118
|
@data_description["values"].delete(v) if (v == serie_name )
|
117
119
|
end
|
@@ -126,7 +128,7 @@ class Rdata
|
|
126
128
|
# * chart_data.add_serie("Serie2")
|
127
129
|
# * chart_data.add_serie("Serie3")
|
128
130
|
# Set Serie as abcisse label
|
129
|
-
# * chart_data.set_abscise_label_serie("Serie1")
|
131
|
+
# * chart_data.set_abscise_label_serie("Serie1")
|
130
132
|
def set_abscise_label_serie(serie_name = "name")
|
131
133
|
@data_description["position"] = serie_name
|
132
134
|
end
|
@@ -139,7 +141,7 @@ class Rdata
|
|
139
141
|
# * chart_data.set_serie_name("January")
|
140
142
|
# This will set the name of Serie2 to "February"
|
141
143
|
# * chart_data.set_serie_name("February","Serie2")
|
142
|
-
|
144
|
+
|
143
145
|
def set_serie_name(name,serie_name="Serie1")
|
144
146
|
if @data_description["description"].nil?
|
145
147
|
@data_description["description"]={serie_name => name}
|
@@ -158,7 +160,7 @@ class Rdata
|
|
158
160
|
end
|
159
161
|
end
|
160
162
|
# This will give a name to the Y axis, writting it horizontally behind the chart
|
161
|
-
# * chart_data.set_y_axis_name("Temperature")
|
163
|
+
# * chart_data.set_y_axis_name("Temperature")
|
162
164
|
def set_y_axis_name(name="Y Axis")
|
163
165
|
if @data_description["axis"].nil?
|
164
166
|
@data_description["axis"]= {"y" => name}
|
@@ -187,11 +189,11 @@ class Rdata
|
|
187
189
|
def set_x_axis_unit(unit="")
|
188
190
|
@data_description["unit"]["x"] = unit
|
189
191
|
end
|
190
|
-
|
192
|
+
|
191
193
|
# Set the axis unit. This will be appended to the axis value
|
192
194
|
# Give the "m/s" unit to the Y axis
|
193
195
|
# * chart_data.set_x_axis_unit("m/s")
|
194
|
-
|
196
|
+
|
195
197
|
def set_y_axis_unit(unit="")
|
196
198
|
@data_description["unit"]["y"] = unit
|
197
199
|
end
|
@@ -219,7 +221,7 @@ class Rdata
|
|
219
221
|
# This function can be used to remove the description of a serie.
|
220
222
|
# This description will be written on the graph when calling the drawLegend function.
|
221
223
|
# Removing it's name using this function can be usefull to hide previously used series
|
222
|
-
|
224
|
+
|
223
225
|
def remove_all_series
|
224
226
|
@data_description["values"].each do |v|
|
225
227
|
@data_description["values"] = []
|
@@ -230,10 +232,9 @@ class Rdata
|
|
230
232
|
def get_data
|
231
233
|
@data
|
232
234
|
end
|
233
|
-
# This function is used everytime you want to retrieve the Data description stored in the Rdata structure
|
235
|
+
# This function is used everytime you want to retrieve the Data description stored in the Rdata structure
|
234
236
|
def get_data_description
|
235
237
|
@data_description
|
236
238
|
end
|
237
239
|
|
238
240
|
end
|
239
|
-
|
data/lib/scale.rb
ADDED
@@ -0,0 +1,538 @@
|
|
1
|
+
module Scale
|
2
|
+
# Allow you to clear the scale : used if drawing multiple charts
|
3
|
+
# You'll need to call this function only if you're planning to draw a second chart in the rendered picture.
|
4
|
+
# 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.
|
5
|
+
def clear_scale
|
6
|
+
@vmin = nil
|
7
|
+
@vmax = nil
|
8
|
+
@v_x_min = nil
|
9
|
+
@v_x_max = nil
|
10
|
+
@divisions = 0
|
11
|
+
@x_divisions = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
# Allow you to fix the scale, use this to bypass the automatic scaling
|
15
|
+
# You can use this function to skip the automatic scaling.
|
16
|
+
# vmin and vmax will be used to render the graph.
|
17
|
+
def set_fixed_scale(v_min,v_max,divisions=5,v_x_min=0,v_x_max=0,x_divisions=5)
|
18
|
+
@vmin = v_min.to_f
|
19
|
+
@vmax = v_max.to_f
|
20
|
+
@divisions = divisions.to_f
|
21
|
+
|
22
|
+
if (!v_x_min == 0 )
|
23
|
+
@v_x_min = v_x_min.to_f
|
24
|
+
@v_x_max = v_x_max.to_f
|
25
|
+
@x_divisions = x_divisions.to_f
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# Wrapper to the draw_scale function allowing a second scale to be drawn
|
30
|
+
# It takes the same parameters of the draw_scale function.
|
31
|
+
# The scale values will be written on the right side of the graph area.
|
32
|
+
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)
|
33
|
+
self. draw_scale(data, data_description, scale_mode, r, g, b,draw_ticks,angle,decimals,with_margin,skip_labels,true)
|
34
|
+
end
|
35
|
+
|
36
|
+
# 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.
|
37
|
+
# 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 ).
|
38
|
+
# There is four way of computing scales :
|
39
|
+
# * Getting Max & Min values per serie : scale_mode = Rchart::SCALE_NORMAL
|
40
|
+
# * Like the previous one but setting the min value to 0 : scale_mode = Rchart::SCALE_START0
|
41
|
+
# * Getting the series cumulative Max & Min values : scale_mode = Rchart::SCALE_ADDALL
|
42
|
+
# * Like the previous one but setting the min value to 0 : scale_mode = Rchart::SCALE_ADDALLSTART0
|
43
|
+
# 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.
|
44
|
+
# You can display only one x label every xi labels using the skip_labels parameter.
|
45
|
+
# 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.
|
46
|
+
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)
|
47
|
+
# Validate the Data and DataDescription array
|
48
|
+
data = self.validate_data("draw_scale",data)
|
49
|
+
c_text_color = allocate_color(@picture,r,g,b)
|
50
|
+
self.draw_line(@g_area_x1,@g_area_y1,@g_area_x1,@g_area_y2,r,g,b)
|
51
|
+
self.draw_line(@g_area_x1,@g_area_y2,@g_area_x2,@g_area_y2,r,g,b)
|
52
|
+
scale =0
|
53
|
+
divisions =0
|
54
|
+
if(@vmin.nil? && @vmax.nil?)
|
55
|
+
if (!data_description["values"][0].nil?)
|
56
|
+
#My hack TODO for LINE GRAPH
|
57
|
+
if data_description["values"].is_a?(Array)
|
58
|
+
@vmin =data[0][data_description["values"][0]]
|
59
|
+
@vmax =data[0][data_description["values"][0]]
|
60
|
+
else
|
61
|
+
@vmin =data[0][data_description["values"][0]]
|
62
|
+
@vmax =data[0][data_description["values"]]
|
63
|
+
end
|
64
|
+
|
65
|
+
else
|
66
|
+
@vmin = 2147483647
|
67
|
+
@vmax = -2147483647
|
68
|
+
end
|
69
|
+
# /* Compute Min and Max values */
|
70
|
+
if(scale_mode == Rchart::SCALE_NORMAL || scale_mode == Rchart::SCALE_START0)
|
71
|
+
@vmin = 0 if (scale_mode == Rchart::SCALE_START0 )
|
72
|
+
|
73
|
+
data.each do |key|
|
74
|
+
data_description["values"].each do |col_name|
|
75
|
+
if(!key[col_name].nil?)
|
76
|
+
value = key[col_name]
|
77
|
+
if (value.is_a?(Numeric))
|
78
|
+
@vmax = value if ( @vmax < value)
|
79
|
+
@vmin = value if ( @vmin > value)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
elsif ( scale_mode == Rchart::SCALE_ADDALL || scale_mode == Rchart::SCALE_ADDALLSTART0 ) # Experimental
|
85
|
+
@vmin = 0 if (scale_mode == Rchart::SCALE_ADDALLSTART0)
|
86
|
+
data.each do |key|
|
87
|
+
sum = 0
|
88
|
+
data_description["values"].each do|col_name|
|
89
|
+
if (!key[col_name].nil?)
|
90
|
+
value =key[col_name]
|
91
|
+
sum += value if ((value).is_a?(Numeric))
|
92
|
+
end
|
93
|
+
end
|
94
|
+
@vmax = sum if (@vmax < sum)
|
95
|
+
@vmin = sum if (@vmin > sum)
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
if(@vmax.is_a?(String))
|
101
|
+
@vmax = @vmax.gsub(/\.[0-9]+/,'')+1 if (@vmax > @vmax.gsub(/\.[0-9]+/,'') )
|
102
|
+
end
|
103
|
+
# If all values are the same */
|
104
|
+
if ( @vmax == @vmin )
|
105
|
+
if ( @vmax >= 0 )
|
106
|
+
@vmax = @vmax+1
|
107
|
+
else
|
108
|
+
@vmin = @vmin-1
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
data_range = @vmax - @vmin
|
113
|
+
data_range = 0.1 if (data_range.to_f == 0.0)
|
114
|
+
|
115
|
+
#Compute automatic scaling */
|
116
|
+
scale_ok = false
|
117
|
+
factor = 1
|
118
|
+
min_div_height = 25
|
119
|
+
max_divs = (@g_area_y2 - @g_area_y1)*1.0 / min_div_height
|
120
|
+
|
121
|
+
if (@vmin == 0 && @vmax == 0 )
|
122
|
+
@vmin = 0
|
123
|
+
@vmax = 2
|
124
|
+
scale = 1
|
125
|
+
divisions = 2
|
126
|
+
elsif (max_divs > 1)
|
127
|
+
while(!scale_ok)
|
128
|
+
scale1 = ( @vmax - @vmin )*1.0 / factor
|
129
|
+
scale2 = ( @vmax - @vmin )*1.0 /factor / 2
|
130
|
+
# scale4 = ( @vmax - @vmin )*1.0 / factor / 4
|
131
|
+
if ( scale1 > 1 && scale1 <= max_divs && !scale_ok)
|
132
|
+
scale_ok = true
|
133
|
+
divisions = (scale1).floor
|
134
|
+
scale = 1
|
135
|
+
end
|
136
|
+
if (scale2 > 1 && scale2 <= max_divs && !scale_ok)
|
137
|
+
scale_ok = true
|
138
|
+
divisions = (scale2).floor
|
139
|
+
scale = 2
|
140
|
+
end
|
141
|
+
if (!scale_ok)
|
142
|
+
factor = factor * 10 if ( scale2 > 1 )
|
143
|
+
factor = factor / 10 if ( scale2 < 1 )
|
144
|
+
end
|
145
|
+
end # while end
|
146
|
+
if ((((@vmax*1.0 / scale) / factor)).floor != ((@vmax*1.0 / scale) / factor))
|
147
|
+
grid_id = ( @vmax*1.0 / scale / factor).floor + 1
|
148
|
+
@vmax = grid_id * scale * factor
|
149
|
+
divisions = divisions+1
|
150
|
+
end
|
151
|
+
|
152
|
+
if (((@vmin*1.0 / scale) / factor).floor != ((@vmin*1.0 / scale) / factor))
|
153
|
+
|
154
|
+
grid_id = ( @vmin*1.0 / scale / factor).floor
|
155
|
+
@vmin = grid_id * scale * factor*1.0
|
156
|
+
divisions = divisions+1
|
157
|
+
end
|
158
|
+
|
159
|
+
else #/* Can occurs for small graphs */
|
160
|
+
scale = 1
|
161
|
+
end
|
162
|
+
divisions = 2 if ( divisions.nil? )
|
163
|
+
|
164
|
+
divisions = divisions-1 if (scale == 1 && divisions%2 == 1)
|
165
|
+
|
166
|
+
else
|
167
|
+
divisions = @divisions
|
168
|
+
end
|
169
|
+
|
170
|
+
@division_count = divisions
|
171
|
+
data_range = @vmax - @vmin
|
172
|
+
data_range = 0.1 if (data_range.to_f == 0.0 )
|
173
|
+
@division_height = ( @g_area_y2 - @g_area_y1 )*1.0 / divisions
|
174
|
+
@division_ratio = ( @g_area_y2 - @g_area_y1 )*1.0 /data_range
|
175
|
+
@g_area_x_offset = 0
|
176
|
+
if ( data.count > 1 )
|
177
|
+
if ( with_margin == false)
|
178
|
+
@division_width = ( @g_area_x2 - @g_area_x1 )*1.0 / ((data).count-1)
|
179
|
+
else
|
180
|
+
@division_width = ( @g_area_x2 - @g_area_x1 ) *1.0/ (data).count
|
181
|
+
@g_area_x_offset = @division_width*1.0 / 2
|
182
|
+
end
|
183
|
+
else
|
184
|
+
@division_width = (@g_area_x2 - @g_area_x1)*1.0
|
185
|
+
@g_area_x_offset = @division_width*1.0 / 2
|
186
|
+
end
|
187
|
+
|
188
|
+
@data_count = (data).count
|
189
|
+
return(0) if (draw_ticks == false )
|
190
|
+
ypos = @g_area_y2
|
191
|
+
xmin = nil
|
192
|
+
i =1
|
193
|
+
|
194
|
+
while(i<= divisions+1)
|
195
|
+
if (right_scale )
|
196
|
+
self.draw_line(@g_area_x2,ypos,@g_area_x2+5,ypos,r,g,b)
|
197
|
+
else
|
198
|
+
self.draw_line(@g_area_x1,ypos,@g_area_x1-5,ypos,r,g,b)
|
199
|
+
end
|
200
|
+
value = @vmin*1.0 + (i-1) * (( @vmax - @vmin ) / divisions)
|
201
|
+
value = (round_of(value * (10**decimals),2)) / (10**decimals)
|
202
|
+
value= value.round if value.floor == value.ceil
|
203
|
+
value = "#{value} #{data_description['unit']['y']}" if ( data_description["format"]["y"]== "number")
|
204
|
+
value = self.to_time(value) if ( data_description["format"]["y"] == "time" )
|
205
|
+
value = self.to_date(value) if ( data_description["format"]["y"] == "date" )
|
206
|
+
value = self.to_metric(value) if ( data_description["format"]["Y"] == "metric" )
|
207
|
+
value = self.to_currency(value) if ( data_description["format"]["Y"] == "currency" )
|
208
|
+
position = image_ftb_box(@font_size,0,@font_name,value)
|
209
|
+
text_width =position[2]-position[0]
|
210
|
+
if ( right_scale )
|
211
|
+
image_ttf_text(@picture,@font_size,0,@g_area_x2+10,ypos+(@font_size/2),c_text_color,@font_name,value)
|
212
|
+
xmin = @g_area_x2+15+text_width if (xmin.nil? || xmin < @g_area_x2+15+text_width )
|
213
|
+
else
|
214
|
+
image_ttf_text(@picture,@font_size,0,@g_area_x1-10-text_width,ypos+(@font_size/2),c_text_color,@font_name,value)
|
215
|
+
xmin = @g_area_x1-10-text_width if ( xmin.nil? || xmin > @g_area_x1-10-text_width)
|
216
|
+
end
|
217
|
+
ypos = ypos - @division_height
|
218
|
+
i = i+1
|
219
|
+
end
|
220
|
+
# Write the Y Axis caption if set */
|
221
|
+
|
222
|
+
if (!data_description["axis"].nil? && !data_description["axis"]["y"].nil? )
|
223
|
+
position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["y"])
|
224
|
+
text_height = (position[1]).abs+(position[3]).abs
|
225
|
+
text_top = ((@g_area_y2 - @g_area_y1) / 2) + @g_area_y1 + (text_height/2)
|
226
|
+
|
227
|
+
if (right_scale )
|
228
|
+
image_ttf_text(@picture,@font_size,90,xmin+@font_size,text_top,c_text_color,@font_name,data_description["axis"]["y"])
|
229
|
+
else
|
230
|
+
image_ttf_text(@picture,@font_size,90,xmin-@font_size,text_top,c_text_color,@font_name,data_description["axis"]["y"])
|
231
|
+
end
|
232
|
+
end
|
233
|
+
# Horizontal Axis */
|
234
|
+
xpos = @g_area_x1 + @g_area_x_offset
|
235
|
+
id = 1
|
236
|
+
ymax = nil
|
237
|
+
data.each do |key|
|
238
|
+
if ( id % skip_labels == 0 )
|
239
|
+
self.draw_line((xpos).floor,@g_area_y2,(xpos).floor,@g_area_y2+5,r,g,b)
|
240
|
+
value =key[data_description["position"]]
|
241
|
+
value = "#{value} #{data_description['unit']['x']}" if ( data_description["format"]["x"] == "number" )
|
242
|
+
value = self.to_time(value) if ( data_description["format"]["x"] == "time" )
|
243
|
+
value = self.to_date(value) if ( data_description["format"]["x"] == "date" )
|
244
|
+
value = self.to_metric(value) if ( data_description["format"]["x"] == "metric" )
|
245
|
+
value = self.to_currency(value) if ( data_description["format"]["x"] == "currency" )
|
246
|
+
position = image_ftb_box(@font_size,angle,@font_name,value.to_s)
|
247
|
+
text_width = (position[2]).abs+(position[0]).abs
|
248
|
+
text_height = (position[1]).abs+(position[3]).abs
|
249
|
+
if ( angle == 0 )
|
250
|
+
ypos = @g_area_y2+18
|
251
|
+
image_ttf_text(@picture,@font_size,angle,(xpos).floor-(text_width/2).floor,ypos,c_text_color,@font_name,value.to_s)
|
252
|
+
else
|
253
|
+
ypos = @g_area_y2+10+text_height
|
254
|
+
if ( angle <= 90 )
|
255
|
+
image_ttf_text(@picture,@font_size,angle,(xpos).floor-text_width+5,ypos,c_text_color,@font_name,value.to_s)
|
256
|
+
else
|
257
|
+
image_ttf_text(@picture,@font_size,angle,(xpos).floor+text_width+5,ypos,c_text_color,@font_name,value.to_s)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
ymax = ypos if (ymax.nil? ||(!ymax.nil? && ymax < ypos))
|
261
|
+
end
|
262
|
+
xpos = xpos + @division_width
|
263
|
+
id = id+1
|
264
|
+
end #loop ended
|
265
|
+
#Write the X Axis caption if set */
|
266
|
+
|
267
|
+
if ((!data_description["axis"].nil? && !data_description["axis"]["x"].nil?) )
|
268
|
+
position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["x"])
|
269
|
+
text_width = (position[2]).abs+(position[0]).abs
|
270
|
+
text_left = ((@g_area_x2 - @g_area_x1) / 2) + @g_area_x1 + (text_width/2)
|
271
|
+
image_ttf_text(@picture,@font_size,0,text_left,ymax+@font_size+5,c_text_color,@font_name,data_description["axis"]["x"].to_s)
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
# This function is used by scatter charts.
|
277
|
+
# It will compute everything needed to draw the associated line and plot charts.
|
278
|
+
# 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.
|
279
|
+
def draw_xy_scale(data,data_description,y_serie_name,x_serie_name,r,g,b,with_margin=0,angle=0,decimals=1)
|
280
|
+
|
281
|
+
self.validate_data("draw_xy_scale",data)
|
282
|
+
c_text_color = allocate_color(@picture,r,g,b)
|
283
|
+
self.draw_line(@g_area_x1,@g_area_y1,@g_area_x1,@g_area_y2,r,g,b)
|
284
|
+
self.draw_line(@g_area_x1,@g_area_y2,@g_area_x2,@g_area_y2,r,g,b)
|
285
|
+
|
286
|
+
# Process Y scale */
|
287
|
+
if(@vmin.nil? && @vmax.nil?)
|
288
|
+
@vmin = data[0][y_serie_name]
|
289
|
+
@vmax = data[0][y_serie_name]
|
290
|
+
data.each do |key|
|
291
|
+
if !key[y_serie_name].nil?
|
292
|
+
value = key[y_serie_name]
|
293
|
+
if (value.is_a?(Numeric))
|
294
|
+
@vmax = value if ( @vmax < value)
|
295
|
+
@vmin = value if ( @vmin > value)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
if(@vmax.is_a?(String))
|
301
|
+
@vmax = @vmax.gsub(/\.[0-9]+/,'')+1 if (@vmax > @vmax.gsub(/\.[0-9]+/,'') )
|
302
|
+
end
|
303
|
+
data_range = @vmax - @vmin
|
304
|
+
data_range = 0.1 if (data_range.to_f == 0.0 )
|
305
|
+
|
306
|
+
#Compute automatic scaling
|
307
|
+
scale_ok = false
|
308
|
+
factor = 1
|
309
|
+
min_div_height = 25
|
310
|
+
max_divs = (@g_area_y2 - @g_area_y1)*1.0 / min_div_height
|
311
|
+
if (@vmin == 0 && @vmax == 0 )
|
312
|
+
@vmin = 0
|
313
|
+
@vmax = 2
|
314
|
+
scale = 1
|
315
|
+
divisions = 2
|
316
|
+
elsif (max_divs > 1)
|
317
|
+
while(!scale_ok)
|
318
|
+
scale1 = ( @vmax - @vmin )*1.0 / factor
|
319
|
+
scale2 = ( @vmax - @vmin )*1.0 /factor / 2
|
320
|
+
scale4 = ( @vmax - @vmin )*1.0 / factor / 4
|
321
|
+
|
322
|
+
if ( scale1 > 1 && scale1 <= max_divs && !scale_ok)
|
323
|
+
scale_ok = true
|
324
|
+
divisions = (scale1).floor
|
325
|
+
scale = 1
|
326
|
+
end
|
327
|
+
if ( scale2 > 1 && scale2 <= max_divs && !scale_ok)
|
328
|
+
scale_ok = true
|
329
|
+
divisions = (scale2).floor
|
330
|
+
scale = 2
|
331
|
+
end
|
332
|
+
if (!scale_ok)
|
333
|
+
factor = factor * 10 if ( scale2 > 1 )
|
334
|
+
factor = factor / 10 if ( scale2 < 1 )
|
335
|
+
end
|
336
|
+
end
|
337
|
+
if ((((@vmax*1.0 / scale) / factor)).floor != ((@vmax*1.0 / scale) / factor))
|
338
|
+
grid_id = ( @vmax*1.0 / scale / factor).floor + 1
|
339
|
+
@vmax = grid_id * scale * factor
|
340
|
+
divisions = divisions+1
|
341
|
+
end
|
342
|
+
|
343
|
+
if (((@vmin*1.0 / scale) / factor).floor != ((@vmin*1.0 / scale) / factor))
|
344
|
+
|
345
|
+
grid_id = ( @vmin*1.0 / scale / factor).floor
|
346
|
+
@vmin = grid_id * scale * factor*1.0
|
347
|
+
divisions = divisions+1
|
348
|
+
end
|
349
|
+
|
350
|
+
else #/* Can occurs for small graphs */
|
351
|
+
scale = 1
|
352
|
+
end
|
353
|
+
divisions = 2 if ( divisions.nil? )
|
354
|
+
|
355
|
+
if ( is_real_int((@vmax-@vmin)/(divisions-1)))
|
356
|
+
divisions-=1
|
357
|
+
elsif ( is_real_int((@vmax-@vmin)/(divisions+1)))
|
358
|
+
divisions+=1
|
359
|
+
end
|
360
|
+
else
|
361
|
+
divisions =@divisions
|
362
|
+
end
|
363
|
+
@division_count = divisions
|
364
|
+
|
365
|
+
data_range = @vmax - @vmin
|
366
|
+
data_range = 0.1 if (data_range.to_f == 0.0 )
|
367
|
+
@division_height = ( @g_area_y2 - @g_area_y1 )*1.0 / divisions
|
368
|
+
@division_ratio = ( @g_area_y2 - @g_area_y1 )*1.0 /data_range
|
369
|
+
ypos = @g_area_y2
|
370
|
+
xmin = nil
|
371
|
+
i =1
|
372
|
+
|
373
|
+
while(i<= divisions+1)
|
374
|
+
self.draw_line(@g_area_x1,ypos,@g_area_x1-5,ypos,r,g,b)
|
375
|
+
value = @vmin*1.0 + (i-1) * (( @vmax - @vmin ) / divisions)
|
376
|
+
value = (round_of(value * (10**decimals),2)) / (10**decimals)
|
377
|
+
value= value.round if value.floor == value.ceil
|
378
|
+
value = "#{value} #{data_description['unit']['y']}" if ( data_description["format"]["y"]== "number")
|
379
|
+
value = self.to_time(value) if ( data_description["format"]["y"] == "time" )
|
380
|
+
value = self.to_date(value) if ( data_description["format"]["y"] == "date" )
|
381
|
+
value = self.to_metric(value) if ( data_description["format"]["Y"] == "metric" )
|
382
|
+
value = self.to_currency(value) if ( data_description["format"]["Y"] == "currency" )
|
383
|
+
|
384
|
+
position = image_ftb_box(@font_size,0,@font_name,value)
|
385
|
+
text_width =position[2]-position[0]
|
386
|
+
image_ttf_text(@picture,@font_size,0,@g_area_x1-10-text_width,ypos+(@font_size/2),c_text_color,@font_name,value)
|
387
|
+
xmin = @g_area_x1-10-text_width if ( xmin.nil? || xmin > @g_area_x1-10-text_width)
|
388
|
+
ypos = ypos - @division_height
|
389
|
+
i = i+1
|
390
|
+
|
391
|
+
end
|
392
|
+
|
393
|
+
# Process X scale */
|
394
|
+
if(@v_x_min.nil? && @v_x_max.nil?)
|
395
|
+
|
396
|
+
@v_x_min =data[0][x_serie_name]
|
397
|
+
@v_x_max =data[0][x_serie_name]
|
398
|
+
data.each do |key|
|
399
|
+
|
400
|
+
if !key[x_serie_name].nil?
|
401
|
+
value = key[x_serie_name]
|
402
|
+
if (value.is_a?(Numeric))
|
403
|
+
|
404
|
+
@v_x_max = value if ( @v_x_max < value)
|
405
|
+
@v_x_min = value if ( @v_x_min > value)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
if (@v_x_max.is_a?(String))
|
411
|
+
@v_x_max = @v_x_max.gsub(/\.[0-9]+/,'')+1 if (@v_x_max > @v_x_max.gsub(/\.[0-9]+/,'') )
|
412
|
+
end
|
413
|
+
|
414
|
+
data_range = @vmax - @vmin
|
415
|
+
data_range = 0.1 if (data_range.to_f == 0.0 )
|
416
|
+
|
417
|
+
# Compute automatic scaling
|
418
|
+
scale_ok = false
|
419
|
+
factor = 1
|
420
|
+
min_div_width = 25
|
421
|
+
max_divs = (@g_area_x2 - @g_area_x1) / min_div_width
|
422
|
+
|
423
|
+
if ( @v_x_min == 0 && @v_x_max == 0 )
|
424
|
+
@v_x_min = 0
|
425
|
+
@v_x_max = 2
|
426
|
+
scale = 1
|
427
|
+
x_divisions = 2
|
428
|
+
elsif (max_divs > 1)
|
429
|
+
|
430
|
+
while(!scale_ok)
|
431
|
+
scale1 = ( @v_x_max - @v_x_min ) / factor
|
432
|
+
scale2 = ( @v_x_max - @v_x_min ) / factor / 2
|
433
|
+
scale4 = ( @v_x_max - @v_x_min ) / factor / 4
|
434
|
+
if ( scale1 > 1 && scale1 <= max_divs && !scale_ok)
|
435
|
+
scale_ok = true
|
436
|
+
x_divisions = (scale1).floor
|
437
|
+
scale = 1
|
438
|
+
end
|
439
|
+
|
440
|
+
if ( scale2 > 1 && scale2 <= max_divs && !scale_ok)
|
441
|
+
scale_ok = true
|
442
|
+
x_divisions = (scale2).floor
|
443
|
+
|
444
|
+
scale = 2
|
445
|
+
end
|
446
|
+
if (!scale_ok)
|
447
|
+
factor = factor * 10 if ( scale2 > 1 )
|
448
|
+
factor = factor / 10 if ( scale2 < 1 )
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
if ( (@v_x_max*1.0 / scale / factor).floor != @v_x_max / scale / factor)
|
453
|
+
grid_id = ( @v_x_max*1.0 / scale / factor).floor + 1
|
454
|
+
@v_x_max = grid_id * scale * factor
|
455
|
+
x_divisions+=1
|
456
|
+
end
|
457
|
+
|
458
|
+
if ( (@v_x_min*1.0 / scale / factor).floor != @v_x_min / scale / factor)
|
459
|
+
grid_id = floor( @v_x_min / scale / factor)
|
460
|
+
@v_x_min = grid_id * scale * factor
|
461
|
+
x_divisions+=1
|
462
|
+
end
|
463
|
+
else #/* Can occurs for small graphs */
|
464
|
+
scale = 1
|
465
|
+
end
|
466
|
+
x_divisions = 2 if ( x_divisions.nil? )
|
467
|
+
|
468
|
+
if ( is_real_int((@v_x_max-@v_x_min)/(x_divisions-1)))
|
469
|
+
x_divisions-=1
|
470
|
+
elsif ( is_real_int((@v_x_max-@v_x_min)/(x_divisions+1)))
|
471
|
+
x_divisions+=1
|
472
|
+
end
|
473
|
+
else
|
474
|
+
|
475
|
+
x_divisions = @x_divisions
|
476
|
+
end
|
477
|
+
|
478
|
+
@x_division_count = divisions
|
479
|
+
@data_count = divisions + 2
|
480
|
+
|
481
|
+
x_data_range = @v_x_max - @v_x_min
|
482
|
+
x_data_range = 0.1 if ( x_data_range == 0 )
|
483
|
+
|
484
|
+
@division_width = ( @g_area_x2 - @g_area_x1 ) / x_divisions
|
485
|
+
@x_division_ratio = ( @g_area_x2 - @g_area_x1 ) / x_data_range
|
486
|
+
xpos = @g_area_x1
|
487
|
+
ymax =nil
|
488
|
+
i=1
|
489
|
+
|
490
|
+
while(i<= x_divisions+1)
|
491
|
+
self.draw_line(xpos,@g_area_y2,xpos,@g_area_y2+5,r,g,b)
|
492
|
+
value = @v_x_min + (i-1) * (( @v_x_max - @v_x_min ) / x_divisions)
|
493
|
+
value = (round_of(value * (10**decimals),2)) / (10**decimals)
|
494
|
+
value= value.round if value.floor == value.ceil
|
495
|
+
value = "#{value}#{data_description['unit']['y']}" if ( data_description["format"]["y"]== "number")
|
496
|
+
value = self.to_time(value) if ( data_description["format"]["y"] == "time" )
|
497
|
+
value = self.to_date(value) if ( data_description["format"]["y"] == "date" )
|
498
|
+
value = self.to_metric(value) if ( data_description["format"]["Y"] == "metric" )
|
499
|
+
value = self.to_currency(value) if ( data_description["format"]["Y"] == "currency" )
|
500
|
+
position = image_ftb_box(@font_size,angle,@font_name,value)
|
501
|
+
text_width =position[2].abs+position[0].abs
|
502
|
+
text_height = position[1].abs+position[3].abs
|
503
|
+
|
504
|
+
if ( angle == 0 )
|
505
|
+
ypos = @g_area_y2+18
|
506
|
+
image_ttf_text(@picture,@font_size,angle,(xpos).floor-(text_width/2).floor,ypos,c_text_color,@font_name,value)
|
507
|
+
else
|
508
|
+
|
509
|
+
ypos = @g_area_y2+10+text_height
|
510
|
+
if ( angle <= 90 )
|
511
|
+
image_ttf_text(@picture,@font_size,angle,(xpos).floor-text_width+5,ypos,c_text_color,@font_name,value)
|
512
|
+
else
|
513
|
+
image_ttf_text(@picture,@font_size,angle,(xpos).floor+text_width+5,ypos,c_text_color,@font_name,value)
|
514
|
+
end
|
515
|
+
|
516
|
+
end
|
517
|
+
|
518
|
+
ymax = ypos if (ymax.nil? || ymax < ypos)
|
519
|
+
i=i+1
|
520
|
+
xpos = xpos + @division_width
|
521
|
+
end
|
522
|
+
#Write the Y Axis caption if set
|
523
|
+
if ((!data_description["axis"].nil? && !data_description["axis"]["y"].nil?) )
|
524
|
+
position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["y"])
|
525
|
+
text_height = (position[1]).abs+(position[3]).abs
|
526
|
+
text_top = ((@g_area_y2 - @g_area_y1) / 2) + @g_area_y1 + (text_width/2)
|
527
|
+
image_ttf_text(@picture,@font_size,90,xmin-@font_size,text_top,c_text_color,@font_name,data_description["axis"]["y"].to_s)
|
528
|
+
end
|
529
|
+
if ((!data_description["axis"].nil? && !data_description["axis"]["x"].nil?) )
|
530
|
+
position = image_ftb_box(@font_size,90,@font_name,data_description["axis"]["x"])
|
531
|
+
text_width = (position[2]).abs+(position[0]).abs
|
532
|
+
text_left = ((@g_area_x2 - @g_area_x1) / 2) + @g_area_x1 + (text_width/2)
|
533
|
+
image_ttf_text(@picture,@font_size,0,text_left,ymax+@font_size+5,c_text_color,@font_name,data_description["axis"]["x"].to_s)
|
534
|
+
end
|
535
|
+
|
536
|
+
end
|
537
|
+
|
538
|
+
end
|