Class: GraphImageDrawer

Inherits:
Object
  • Object
show all
Defined in:
lib/technical_graph/graph_image_drawer.rb

Overview

options parameters: :width - width of image :height - height of image :x_min, :x_max, :y_min, :y_max - default or fixed ranges :xy_behaviour:

  • :default - use them as default ranges

  • :fixed - ranges will not be changed during addition of layers

Constant Summary collapse

DEFAULT_WIDTH =

default sizes

1600
DEFAULT_HEIGHT =
1200
ONE_LAYER_LEGEND_HEIGHT =

height of 1 layer

15

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(technical_graph) ⇒ GraphImageDrawer

Returns a new instance of GraphImageDrawer.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/technical_graph/graph_image_drawer.rb', line 75

def initialize(technical_graph)
  @technical_graph = technical_graph

  t = Time.now

  # drawer type
  #options[:drawer_class] ||= :rmagick
  options[:drawer_class] ||= :rasem

  options[:width] ||= DEFAULT_WIDTH
  options[:height] ||= DEFAULT_HEIGHT

  options[:axis_value_and_param_labels] = true if options[:axis_value_and_param_labels].nil?
  options[:axis_zero_labels] = true if options[:axis_zero_labels].nil?

  # colors
  options[:background_color] ||= 'white'
  options[:background_hatch_color] ||= 'lightcyan2'
  options[:axis_color] ||= '#000000'

  # antialias
  options[:antialias] = false if options[:antialias].nil?

  # font sizes
  options[:axis_font_size] ||= 10
  options[:layers_font_size] ||= 10
  options[:axis_label_font_size] ||= 10

  # legend
  options[:legend] = false if options[:legend].nil?
  options[:legend_auto] = true if options[:legend_auto].nil?
  options[:legend_x] ||= 50
  options[:legend_y] ||= 50
  options[:legend_width] ||= 100
  options[:legend_margin] ||= 50

  # array of all points drawn on graph, used for auto positioning of legend
  @drawn_points = Array.new

  logger.debug "initializing #{self.class}"
  logger.debug " TIME COST #{Time.now - t}"
end

Instance Attribute Details

#drawerObject (readonly)

Returns the value of attribute drawer.



190
191
192
# File 'lib/technical_graph/graph_image_drawer.rb', line 190

def drawer
  @drawer
end

#technical_graphObject (readonly)

Returns the value of attribute technical_graph.



36
37
38
# File 'lib/technical_graph/graph_image_drawer.rb', line 36

def technical_graph
  @technical_graph
end

Instance Method Details

#antialiasObject



134
135
136
# File 'lib/technical_graph/graph_image_drawer.rb', line 134

def antialias
  options[:antialias] == true
end

#axis_font_sizeObject



66
67
68
# File 'lib/technical_graph/graph_image_drawer.rb', line 66

def axis_font_size
  options[:axis_font_size]
end

#best_output_formatObject

Best output image format, used for testing



32
33
34
# File 'lib/technical_graph/graph_image_drawer.rb', line 32

def best_output_format
  @technical_graph.best_output_format
end

#calc_bitmap_x(_x) ⇒ Object

Calculate image X position



163
164
165
166
167
# File 'lib/technical_graph/graph_image_drawer.rb', line 163

def calc_bitmap_x(_x)
  l = data_processor.x_max - data_processor.x_min
  offset = _x - data_processor.x_min
  return (offset.to_f * width.to_f) / l.to_f
end

#calc_bitmap_y(_y) ⇒ Object

Calculate image Y position



170
171
172
173
174
175
# File 'lib/technical_graph/graph_image_drawer.rb', line 170

def calc_bitmap_y(_y)
  l = data_processor.y_max - data_processor.y_min
  #offset = _y - data_processor.y_min
  offset = data_processor.y_max - _y
  return (offset.to_f * height.to_f) / l.to_f
end

#crate_blank_graph_imageObject

Create background image



184
185
186
187
188
# File 'lib/technical_graph/graph_image_drawer.rb', line 184

def crate_blank_graph_image
  pre_image_create_calculations
  # create drawing proxy
  @drawer = drawing_class.new(self)
end

#data_processorObject

Calculate everything



49
50
51
# File 'lib/technical_graph/graph_image_drawer.rb', line 49

def data_processor
  @technical_graph.data_processor
end

#draw_legend?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/technical_graph/graph_image_drawer.rb', line 138

def draw_legend?
  options[:legend]
end

#drawing_classObject

Which type of drawing class use?



19
20
21
22
23
24
25
26
27
28
29
# File 'lib/technical_graph/graph_image_drawer.rb', line 19

def drawing_class
  if options[:drawer_class] == :rasem
    require 'technical_graph/graph_image_drawer_rasem'
    return GraphImageDrawerRasem
  end

  if options[:drawer_class] == :rmagick
    require 'technical_graph/graph_image_drawer_rmagick'
    return GraphImageDrawerRmagick
  end
end

#graph_axisObject

Axis processing



54
55
56
# File 'lib/technical_graph/graph_image_drawer.rb', line 54

def graph_axis
  @technical_graph.axis
end

#heightObject



122
123
124
# File 'lib/technical_graph/graph_image_drawer.rb', line 122

def height
  options[:height].to_i
end

#height=(h) ⇒ Object



130
131
132
# File 'lib/technical_graph/graph_image_drawer.rb', line 130

def height=(h)
  options[:height] = h.to_i if h.to_i > 0
end

#layersObject

Accessor for DataLayer Array



44
45
46
# File 'lib/technical_graph/graph_image_drawer.rb', line 44

def layers
  @technical_graph.layers
end

#legend_auto_positionObject



150
151
152
# File 'lib/technical_graph/graph_image_drawer.rb', line 150

def legend_auto_position
  options[:legend_auto]
end

#legend_marginObject



158
159
160
# File 'lib/technical_graph/graph_image_drawer.rb', line 158

def legend_margin
  options[:legend_margin]
end

#legend_widthObject



154
155
156
# File 'lib/technical_graph/graph_image_drawer.rb', line 154

def legend_width
  options[:legend_width]
end

#legend_xObject



142
143
144
# File 'lib/technical_graph/graph_image_drawer.rb', line 142

def legend_x
  options[:legend_x]
end

#legend_yObject



146
147
148
# File 'lib/technical_graph/graph_image_drawer.rb', line 146

def legend_y
  options[:legend_y]
end

#loggerObject



58
59
60
# File 'lib/technical_graph/graph_image_drawer.rb', line 58

def logger
  @technical_graph.logger
end

#optionsObject

Accessor for options Hash



39
40
41
# File 'lib/technical_graph/graph_image_drawer.rb', line 39

def options
  @technical_graph.options
end

#post_dot_drawn(bx, by) ⇒ Object

Used for auto position for legend



228
229
230
231
232
# File 'lib/technical_graph/graph_image_drawer.rb', line 228

def post_dot_drawn(bx, by)
  if legend_auto_position
    @drawn_points << { :x => bx, :y => by }
  end
end

#pre_image_create_calculationsObject

Everything that must be done before creating image



178
179
180
181
# File 'lib/technical_graph/graph_image_drawer.rb', line 178

def pre_image_create_calculations
  # check axis density and enlarge if this option is on
  graph_axis.axis_distance_image_enlarge
end

#recalculate_legend_positionObject

Choose best location



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/technical_graph/graph_image_drawer.rb', line 238

def recalculate_legend_position
  return unless legend_auto_position
  logger.debug "Auto position calculation, drawn points #{@drawn_points.size}"

  legend_height = layers.size * ONE_LAYER_LEGEND_HEIGHT

  # check 8 places:
  positions = [
    { :x => legend_margin, :y => 0 + legend_margin }, # top-left
    { :x => width/2, :y => 0 + legend_margin }, # top-center
    { :x => width - legend_margin - legend_width, :y => 0 + legend_margin }, # top-right
    { :x => legend_margin, :y => height/2 }, # middle-left
    { :x => width - legend_margin - legend_width, :y => height/2 }, # middle-right
    { :x => legend_margin, :y => height - legend_margin - legend_height }, # bottom-left
    { :x => width/2, :y => height - legend_margin - legend_height }, # bottom-center
    { :x => width - legend_margin - legend_width, :y => height - legend_margin - legend_height }, # bottom-right
  ]

  t = Time.now

  # calculate nearest distance of all drawn points
  positions.each do |p|
    p[:distance] = (width ** 2 + height ** 2) ** 0.5 # max distance, diagonal of graph
    @drawn_points.each do |dp|
      # calculate drawn point distance to being checked now legend position
      two_points_distance = ((p[:x] - dp[:x]) ** 2 + (p[:y] - dp[:y]) ** 2) ** 0.5
      # modify only if distance is closer
      if p[:distance] > two_points_distance
        p[:distance] = two_points_distance
      end
    end
  end

  logger.debug "auto legend best position distance calc."
  logger.debug " TIME COST #{Time.now - t}"
  t = Time.now

  # chose position with highest distance
  positions.sort! { |a, b| a[:distance] <=> b[:distance] }
  best_position = positions.last
  options[:legend_x] = best_position[:x]
  options[:legend_y] = best_position[:y]

  logger.debug "Best position x #{options[:legend_x]}, y #{options[:legend_y]}, distance #{best_position[:distance]}"
  logger.debug " TIME COST #{Time.now - t}"
end

#render_data_layer(l) ⇒ Object

Render data layer, calculate coords and execute proxy



193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/technical_graph/graph_image_drawer.rb', line 193

def render_data_layer(l)
  layer_data = l.processed_data

  t = Time.now

  # calculate coords, draw text, and then lines and circles
  coords = Array.new

  (0...(layer_data.size - 1)).each do |i|
    ax = layer_data[i].x
    ax = calc_bitmap_x(ax).round
    ay = layer_data[i].y
    ay = calc_bitmap_y(ay).round

    bx = layer_data[i+1].x
    bx = calc_bitmap_x(bx).round
    by = layer_data[i+1].y
    by = calc_bitmap_y(by).round

    coords << {
      :ax => ax, :ay => ay,
      :bx => bx, :by => by,
      :dy => layer_data[i].y
    }
  end

  logger.debug "rendering layer of size #{layer_data.size}, bitmap position calculation"
  logger.debug " TIME COST #{Time.now - t}"
  t = Time.now

  # draw using proxy
  drawer.render_data_layer(l, coords)
end

#render_data_legendObject

Render legend on graph



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/technical_graph/graph_image_drawer.rb', line 286

def render_data_legend
  return unless draw_legend?
  recalculate_legend_position

  x = legend_x
  y = legend_y

  legend_data = Array.new

  layers.each do |l|
    h = Hash.new
    h[:color] = l.color
    h[:label] = l.label
    h[:x] = x
    h[:y] = y

    legend_data << h
    y += ONE_LAYER_LEGEND_HEIGHT
  end

  drawer.legend(legend_data)
end

#save_to_file(file) ⇒ Object

Save output to file



310
311
312
313
314
315
316
317
# File 'lib/technical_graph/graph_image_drawer.rb', line 310

def save_to_file(file)
  t = Time.now

  drawer.save(file)

  logger.debug "saving image"
  logger.debug " TIME COST #{Time.now - t}"
end

#to_format(format) ⇒ Object

Export image



320
321
322
323
324
325
326
327
328
329
# File 'lib/technical_graph/graph_image_drawer.rb', line 320

def to_format(format)
  t = Time.now

  blob = drawer.to_format(format)

  logger.debug "exporting image as string"
  logger.debug " TIME COST #{Time.now - t}"

  return blob
end

#to_pngObject

Return binary PNG



332
333
334
# File 'lib/technical_graph/graph_image_drawer.rb', line 332

def to_png
  drawer.to_png
end

#to_svgObject



336
337
338
# File 'lib/technical_graph/graph_image_drawer.rb', line 336

def to_svg
  drawer.to_svg
end

#to_svgzObject



340
341
342
# File 'lib/technical_graph/graph_image_drawer.rb', line 340

def to_svgz
  drawer.to_svgz
end

#truncate_stringObject



62
63
64
# File 'lib/technical_graph/graph_image_drawer.rb', line 62

def truncate_string
  options[:truncate_string]
end

#widthObject



118
119
120
# File 'lib/technical_graph/graph_image_drawer.rb', line 118

def width
  options[:width].to_i
end

#width=(w) ⇒ Object



126
127
128
# File 'lib/technical_graph/graph_image_drawer.rb', line 126

def width=(w)
  options[:width] = w.to_i if w.to_i > 0
end