graphit 0.0.6 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cff85df062116029645654037094f8c056299c7c
4
- data.tar.gz: bca19ead37b0ba0690cd87601a5571558e35e773
3
+ metadata.gz: 1941e4e3ce7e786d8ea2396895269e98c0a9c5f0
4
+ data.tar.gz: 20bfe9f272774fc841b4d891cbb61c2f310ac63d
5
5
  SHA512:
6
- metadata.gz: 9d0ff1e0b05124e6f7d2c69e69268b3ea46e91a1fa1132b758c932718964b6ace2176f910198057a24c1879825c848100d5a9166ded6f3a72de7f268cf160ead
7
- data.tar.gz: 5c53f8bc1790c42969733bf28486e8f6639daf09468af0ad50262ff409e0a87098e855a3eab64f115628b2176d325f1b1d0cf7cad8ee9b1c9e1bcc53a240bef2
6
+ metadata.gz: 320d9bd9482287b375e82cd0d45027b9476e574fefe202f0866c9bbd6130d626a62ab382e619516c74d3076943a20c4594c0e2bd15f195ef1d8873a6af712ace
7
+ data.tar.gz: 79a6028ffe3c3fd14d098b367c57ac4505a1b8521886e9d47ee73d895b86919f4711c2e256c9da537fc0cf9370a90075d3e6dfff6fb348d8af1f2ac6c0a8c27b
@@ -6,21 +6,39 @@ require 'bin_utils' # For Speed
6
6
  require 'optparse'
7
7
 
8
8
  options = {}
9
+ options[:debug] = false
10
+ options[:verbose] = false
9
11
  OptionParser.new do |opts|
10
12
  opts.banner = "Usage: graphit [options] data"
11
13
 
14
+ opts.on("-d", "--[no-]debug", "Debug output") do |d|
15
+ options[:debug] = d
16
+ end
17
+
12
18
  opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
13
19
  options[:verbose] = v
14
20
  end
15
21
 
16
- opts.on("--ymin [ymin]", Float) do |ymin|
22
+ opts.on("-p", "--png", "Convert BMP to PNG. (Requires ImageMagick)") do |png|
23
+ options[:png] = png
24
+ end
25
+
26
+ opts.on("--ymin [ymin]", String) do |ymin|
17
27
  options[:ymin] = ymin
18
28
  end
19
29
 
20
- opts.on("--ymax [ymax]", Float) do |ymax|
30
+ opts.on("--ymax [ymax]", String) do |ymax|
21
31
  options[:ymax] = ymax
22
32
  end
23
33
 
34
+ opts.on("--xmin [xmin]", String) do |xmin|
35
+ options[:xmin] = xmin
36
+ end
37
+
38
+ opts.on("--xmax [xmax]", String) do |xmax|
39
+ options[:xmax] = xmax
40
+ end
41
+
24
42
  opts.on("--height [h]", Integer) do |h|
25
43
  options[:height] = h
26
44
  end
@@ -43,352 +61,63 @@ OptionParser.new do |opts|
43
61
 
44
62
  end.parse!
45
63
 
46
- options[:outputfile] = "graph.bmp" if options[:outputfile].nil?
47
-
48
- @characters = Graphit.pixel_font
49
-
50
- @h = options[:height] || 300
51
- @w = options[:width] || 1050
64
+ options[:outputfile] ||= "graph.bmp"
52
65
 
53
- @ymin = options[:ymin] || 40
54
- @ymax = options[:ymax] || 95
66
+ options[:height] ||= 300
67
+ options[:width] ||= 1050
55
68
 
56
- puts "h: #{@h}, w: #{@w}"
57
- puts "ymin: #{@ymin}, ymax: #{@ymax}"
69
+ options[:ymin] ||= "auto"
70
+ options[:ymax] ||= "auto"
58
71
 
59
- @xmin = 1458621300
60
- @xmax = 1458770444
72
+ options[:xmin] ||= "auto"
73
+ options[:xmax] ||= "auto"
61
74
 
62
- @bottom_padding = 25
63
- @top_padding = 10
64
- @left_padding = 100
65
- @right_padding = 10
66
-
67
- @y_tics_mod = options[:yticsmod] || 10
68
- @x_tics_mod = options[:xticsmod] || 3600
69
-
70
- @graph_width = @w - @left_padding - @right_padding
71
- @graph_height = @h - @bottom_padding - @top_padding
72
-
73
- def recalculate_pixels_per_unit
74
- @x_pixels_per_unit = @graph_width.to_f / (@xmax.to_f - @xmin.to_f)
75
- @y_pixels_per_unit = @graph_height.to_f / (@ymax.to_f - @ymin.to_f)
76
-
77
- if @xmax - @xmin < (86400 * 3.5)
78
- @x_tics_mod = 3600
79
- elsif @xmax - @xmin < (86400 * 7.5)
80
- @x_tics_mod = (86400 * 24)
81
- elsif @xmax - @xmin < (86400 * 50)
82
- @x_tics_mod = (86400 * 24 * 7)
83
- elsif @xmax - @xmin < (86400 * 800)
84
- @x_tics_mod = (86400 * 24 * 30)
85
- else
86
- @x_tics_mod = 3600
87
- end
88
-
89
- puts "@x_pixels_per_unit: #{@x_pixels_per_unit}"
90
- puts "@y_pixels_per_unit: #{@y_pixels_per_unit}"
75
+ if options[:debug]
76
+ puts "h: #{@h}, w: #{@w}"
77
+ puts "ymin: #{@ymin}, ymax: #{@ymax}"
91
78
  end
92
79
 
93
- def translate_data_point_to_graph_point( point )
94
- #puts "In x: #{point[:x]}, y: #{point[:y]}"
95
-
96
- if point[:x] < @xmin
97
- point[:x] = @xmin
98
- elsif point[:x] > @xmax
99
- point[:x] = @xmax
100
- end
101
-
102
- if point[:y] < @ymin
103
- point[:y] = @ymin
104
- elsif point[:y] > @ymax
105
- point[:y] = @ymax
106
- end
107
-
108
- #puts "Mid x: #{point[:x]}, y: #{point[:y]}"
109
-
110
- x = @left_padding + (point[:x] - @xmin) * @x_pixels_per_unit
111
- y = @h - @bottom_padding - ((point[:y] - @ymin) * @y_pixels_per_unit)
112
-
113
- #puts "Out x: #{x}, y: #{y}"
114
-
115
- return { x: x, y: y }
116
- end
80
+ options[:bottom_padding] ||= 25
81
+ options[:top_padding] ||= 10
82
+ options[:left_padding] ||= 100
83
+ options[:right_padding] ||= 10
117
84
 
118
- def draw_text( text, px, py, pixels, color )
119
- text.each_char do |c|
120
- if @characters[c].nil?
121
- # skip
122
- else
123
- @characters[c].each_with_index do |row, y|
124
- row.each_with_index do |col, x|
125
- if col == 0
126
- # Do nothing
127
- else
128
- thisY = px + x
129
- thisX = py + y
130
-
131
- pixels[thisX][thisY] = color unless pixels[thisX][thisY].nil?
132
- end
133
- end
134
- end
135
-
136
- px += @characters[c].size + 1
137
- end
138
- end
139
-
140
- return pixels
141
- end
85
+ options[:yticsmod] ||= 10
86
+ options[:xticsmod] ||= 3600
142
87
 
143
- def draw_line( x1, y1, x2, y2, pixels, color )
144
- len = Math.sqrt( (x2-x1)**2 + (y2 - y1)**2 )
145
-
146
- d = 0.0
147
-
148
- while d < 1
149
- if x2 == x1
150
- x = x1
151
- else
152
- x = x1 + (x2.to_f-x1.to_f) * d
153
- end
154
-
155
- y = y1 + (y2.to_f-y1.to_f) * d
156
-
157
- pixels[y.to_i][x.to_i] = color unless pixels[y.to_i][x.to_i].nil?
158
-
159
- d += 1.0 / ( len.to_f * 2.0 )
160
- end
161
-
162
- return pixels
163
- end
88
+ options[:data_color] ||= Graphit::Color.blue_color
89
+ options[:background_color] ||= Graphit::Color.light_light_gray_color
164
90
 
165
- def graph_data( data, pixels, color )
166
-
167
- # Horizontal Grid lines
168
- (@ymin.to_i..@ymax.to_i).each do |y|
169
- if y % @y_tics_mod == 0
170
- p1 = translate_data_point_to_graph_point( { y: y, x: @xmin } )
171
- p2 = translate_data_point_to_graph_point( { y: y, x: @xmax } )
172
-
173
- pixels = draw_line( p1[:x], p1[:y], p2[:x], p2[:y], pixels, [0xAA,0xAA,0xAA] )
174
-
175
- # Dunno why 60. Can't figure it out. I'm sure it's because I'm dumb.
176
- pixels = draw_text( "#{y}", p1[:x] - (10 * y.to_s.size), p1[:y], pixels, [0x00,0x00,0x00] )
177
- end
178
- end
179
-
180
- #Vertical Grid Lines
181
- (@xmin..@xmax).each do |x|
182
- if x % @x_tics_mod == 0
183
- p1 = translate_data_point_to_graph_point( { x: x, y: @ymin } )
184
- p2 = translate_data_point_to_graph_point( { x: x, y: @ymax } )
185
-
186
- #Manual offset for GMT-7
187
- if (x + (3600*-7)) % 86400 == 0
188
- lcolor = [0x00,0x00,0xFF]
189
- else
190
- lcolor = [0xAA,0xAA,0xAA]
191
- end
192
-
193
-
194
- pixels = draw_line( p1[:x], p1[:y], p2[:x], p2[:y], pixels, lcolor )
195
- end
196
- end
197
-
198
- # Graph Outline
199
- p1 = translate_data_point_to_graph_point( { x: @xmin, y: @ymin } )
200
- p2 = translate_data_point_to_graph_point( { x: @xmax, y: @ymin } )
201
- pixels = draw_line( p1[:x], p1[:y], p2[:x], p2[:y], pixels, [0x22,0x22,0x22] )
202
- p1 = translate_data_point_to_graph_point( { x: @xmax, y: @ymin } )
203
- p2 = translate_data_point_to_graph_point( { x: @xmax, y: @ymax } )
204
- pixels = draw_line( p1[:x], p1[:y], p2[:x], p2[:y], pixels, [0x22,0x22,0x22] )
205
- p1 = translate_data_point_to_graph_point( { x: @xmax, y: @ymax } )
206
- p2 = translate_data_point_to_graph_point( { x: @xmin, y: @ymax } )
207
- pixels = draw_line( p1[:x], p1[:y], p2[:x], p2[:y], pixels, [0x22,0x22,0x22] )
208
- p1 = translate_data_point_to_graph_point( { x: @xmin, y: @ymax } )
209
- p2 = translate_data_point_to_graph_point( { x: @xmin, y: @ymin } )
210
- pixels = draw_line( p1[:x], p1[:y], p2[:x], p2[:y], pixels, [0x22,0x22,0x22] )
211
-
212
-
213
- data.each_with_index do |p, i|
214
- data[i] = translate_data_point_to_graph_point( p )
215
- end
216
-
217
- data.each_with_index do |point, i|
218
- if i < data.size - 1
219
- x1 = point[:x]
220
- y1 = point[:y]
221
-
222
- x2 = data[i+1][:x]
223
- y2 = data[i+1][:y]
224
-
225
- pixels = draw_line( x1, y1, x2, y2, pixels, color )
226
- end
227
- end
91
+ data_to_graph = []
228
92
 
229
- pixels
230
- end
93
+ xmin = 9999999999
94
+ xmax = 0
231
95
 
232
- File.open( options[:outputfile], 'w') do |f|
233
-
234
- start = Time.now.to_f
235
-
236
- h = @h
237
- w = @w
238
-
239
- pixels = []
240
- (1..h).each do |y|
241
- row = []
242
- (1..w).each do |x|
243
- row.push( [0xEE,0xEE,0xEE] )
244
- end
245
- pixels.push(row)
246
- end
247
-
248
- puts "Generating pixels: #{Time.now.to_f - start}"
249
-
250
- # (0..499).each do |n|
251
- #
252
- # i = (n/100.0) * (2 * Math::PI)
253
- #
254
- # y = 50 + (40 * Math.sin(i))
255
- #
256
- # pixels[y][n] = [0x00,0x00,0xFF]
257
- # end
258
- #
259
- # (0..499).each do |n|
260
- #
261
- # i = (n/100.0) * (2 * Math::PI)
262
- #
263
- # y = 50 + (40 * Math.cos(i))
264
- #
265
- # pixels[y][n] = [0xFF,0x00,0x00]
266
- # end
96
+ # Expected Input:
97
+ # x y
98
+ ARGF.each_line do |line|
99
+ # puts line
100
+ l = line.strip.split(" ")
267
101
 
268
- # pixels = draw_line( 50, 75, 900, 250, pixels, [0x00,0x00,0xFF] )
269
- # pixels = draw_line( 40, 65, 900, 250, pixels, [0x00,0xFF,0xFF] )
270
- #
271
- # pixels = draw_line( 50, 50, w, 50, pixels, [0xAA,0xAA,0xAA] )
272
- # pixels = draw_line( 50, 100, w, 100, pixels, [0xAA,0xAA,0xAA] )
273
- # pixels = draw_line( 50, 150, w, 150, pixels, [0xAA,0xAA,0xAA] )
102
+ next unless l.size == 2
274
103
 
275
- data_to_graph = []
104
+ x = l[0].to_i
105
+ y = l[1].to_f
276
106
 
277
- @xmin = 9999999999
278
- @xmax = 0
279
-
280
- ARGF.each_line do |line|
281
- # puts line
282
- l = line.strip.split(":")
283
-
284
- next unless l.size == 2
285
-
286
- x = l[0].to_i
287
- y = l[1].to_f
288
-
289
- @xmin = x if x < @xmin
290
- @xmax = x if x > @xmax
291
-
292
- data_to_graph.push( { x: x, y: y } )
293
- end
107
+ xmin = x if x < xmin
108
+ xmax = x if x > xmax
294
109
 
295
- puts data_to_graph.size
296
- puts "Data points ^"
110
+ data_to_graph.push( Graphit::Point.new( x, y ) )
111
+ end
297
112
 
298
- puts "Max: #{@xmax}, Min: #{@xmin}"
299
-
300
- recalculate_pixels_per_unit
301
-
302
- # (0..140).each do |n|
303
- # point = { x: n * 10, y: @ymax - rand( @ymax ).to_i }
304
- # data_to_graph.push( translate_data_point_to_graph_point( point ) )
305
- # end
306
-
307
- graph_data( data_to_graph, pixels, [0xEE,0x00,0x00] )
308
-
309
- @xmin = @xmax if @xmin > @xmax
310
-
311
- (@xmin..@xmax).each do |x|
312
-
313
- if x % 3600 == 0
314
- x_offset = translate_data_point_to_graph_point( { x: x, y: 10 } )[:x].to_i
315
-
316
- h = Time.at(x).hour
317
-
318
- if h % 2 == 0
319
- puts "h: #{h.to_s}, x: #{x_offset}"
320
- pixels = draw_text( h.to_s, x_offset, @h - 15, pixels, [0x00,0x00,0x00] )
321
- end
322
- end
323
- end
324
-
325
-
326
- pixel_data = ""
113
+ @graph = Graphit::Graph.new( options, data_to_graph )
327
114
 
328
- #pixels = [["0000FF", "FFFFFF", "0000FF", "FFFFFF"],
329
- # ["FF0000", "00FF00", "FF0000", "00FF00"] ]
330
-
331
- height = pixels.size
332
- width = pixels[0].size
333
-
334
- start = Time.now.to_f
335
-
336
- pixels.reverse.each_with_index do |row, i|
337
- row_bytes = 0
338
- row.each do |pixel|
339
-
340
- BinUtils.append_int8!(pixel_data, pixel[0])
341
- BinUtils.append_int8!(pixel_data, pixel[1])
342
- BinUtils.append_int8!(pixel_data, pixel[2])
343
-
344
- #pixel_data += [pixel[0,2].hex].pack( "C" )
345
- #pixel_data += [pixel[2,2].hex].pack( "C" )
346
- #pixel_data += [pixel[4,2].hex].pack( "C" )
347
-
348
- row_bytes += 3
349
- end
350
-
351
- # Padding
352
- bytes_to_pad = row_bytes % 4
353
-
354
- # puts "Row: #{i}, bytes: #{row_bytes}, padding: #{bytes_to_pad}"
355
-
356
- bytes_to_pad.times do
357
- BinUtils.append_int8!(pixel_data, 0x00)
358
- end
359
- end
360
-
361
- puts "Generating pixel data string: #{Time.now.to_f - start}"
362
-
363
-
364
- file_size = 54 + pixel_data.size
115
+ puts @graph
365
116
 
366
- f.print [0x42].pack ("C")
367
- f.print [0x4D].pack( "C" )
368
- f.print [file_size].pack( "L" )
369
-
370
- f.print [0x00].pack( "C" ) # Unused
371
- f.print [0x00].pack( "C" )
372
- f.print [0x00].pack( "C" )
373
- f.print [0x00].pack( "C" )
374
-
375
- f.print [54].pack( "L" ) # Pixel Array Offset
376
-
377
- f.print [0x28, 0x00, 0x00, 0x00].pack( "L" ) #Number of bytes in the DIB header (from this point)
117
+ @bmp = Graphit::BmpFile.new( @graph.bitmap_drawing )
378
118
 
379
- f.print [width].pack( "L" ) #Width of the bitmap in pixels
380
- f.print [height].pack( "L" ) #Height
381
-
382
- f.print [0x01, 0x00].pack( "S" ) # Number of color planes being used
383
- f.print [0x18, 0x00].pack( "S" ) # Number of bits per pixel
384
- f.print [0x00].pack( "L" ) # BI_RGB, no pixel array compression used
385
- f.print [pixel_data.size].pack( "L" ) # Size of the raw bitmap data (including padding)
386
- f.print [0x130B].pack( "L" ) #2835 pixels/meter horizontal
387
- f.print [0x130B].pack( "L" ) #2835 pixels/meter vertical
388
- f.print [0x00].pack( "L" ) # Number of colors in the palette
389
- f.print [0x00].pack( "L" ) #0 means all colors are important
390
-
391
- f.print pixel_data
392
- end
119
+ @bmp.save_to_file( options[:outputfile] )
393
120
 
394
- `convert #{options[:outputfile]} #{options[:outputfile].gsub('bmp', 'png')}`
121
+ if options[:png]
122
+ `convert #{options[:outputfile]} #{options[:outputfile].gsub('bmp', 'png')}`
123
+ end
@@ -1 +1,6 @@
1
1
  require 'graphit/pixel_font.rb'
2
+ require 'graphit/bmp_file.rb'
3
+ require 'graphit/color.rb'
4
+ require 'graphit/bitmap_drawing.rb'
5
+ require 'graphit/point.rb'
6
+ require 'graphit/graph.rb'
@@ -0,0 +1,82 @@
1
+ module Graphit
2
+ class BitmapDrawing
3
+
4
+ attr_accessor :pixels
5
+
6
+ def initialize( height, width, background_color = [0x00,0x00,0x00] )
7
+ background_color = background_color.to_hex_array if background_color.class == Color
8
+
9
+ self.pixels = []
10
+ (1..height).each do |y|
11
+ row = []
12
+ (1..width).each do |x|
13
+ row.push( background_color )
14
+ end
15
+ self.pixels.push(row)
16
+ end
17
+ end
18
+
19
+ def height
20
+ self.pixels.size rescue 0
21
+ end
22
+
23
+ def width
24
+ self.pixels[0].size rescue 0
25
+ end
26
+
27
+ def draw_text( text, point, color = [0x00,0x00,0x00] )
28
+ @characters = Graphit.pixel_font
29
+ color = color.to_hex_array if color.class == Color
30
+
31
+ px = point.x
32
+
33
+ text.each_char do |c|
34
+ if @characters[c].nil?
35
+ # skip
36
+ else
37
+ @characters[c].each_with_index do |row, y|
38
+ row.each_with_index do |col, x|
39
+ if col == 0
40
+ # Do nothing
41
+ else
42
+ thisY = px + x
43
+ thisX = point.y + y
44
+
45
+ self.pixels[thisX][thisY] = color unless pixels[thisX][thisY].nil?
46
+ end
47
+ end
48
+ end
49
+
50
+ px += @characters[c].size + 1
51
+ end
52
+ end
53
+
54
+ return self.pixels
55
+ end
56
+
57
+ def draw_line( start_point, end_point, color )
58
+ color = color.to_hex_array if color.class == Color
59
+
60
+ len = Math.sqrt( (end_point.x-start_point.x)**2 + (end_point.y - start_point.y)**2 )
61
+
62
+ d = 0.0
63
+
64
+ while d < 1
65
+ if end_point.x == start_point.x
66
+ x = start_point.x
67
+ else
68
+ x = start_point.x + (end_point.x-start_point.x) * d
69
+ end
70
+
71
+ y = start_point.y + (end_point.y-start_point.y) * d
72
+
73
+ self.pixels[y.to_i][x.to_i] = color unless self.pixels[y.to_i][x.to_i].nil?
74
+
75
+ d += 1.0 / ( len * 2.0 )
76
+ end
77
+
78
+ return self.pixels
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,92 @@
1
+ module Graphit
2
+ class BmpFile
3
+
4
+ attr_accessor :bitmap_drawing
5
+
6
+ def initialize( bitmap_drawing )
7
+ self.bitmap_drawing = bitmap_drawing
8
+ end
9
+
10
+ def save_to_file( filename )
11
+ File.open( filename, 'w') do |f|
12
+
13
+ start = Time.now.to_f
14
+
15
+ # if options[:debug]
16
+ # puts "Generating pixels: #{Time.now.to_f - start}"
17
+ # end
18
+
19
+ # if options[:debug]
20
+ # puts data_to_graph.size
21
+ # puts "Data points ^"
22
+ # puts "Max: #{@xmax}, Min: #{@xmin}"
23
+ # end
24
+
25
+
26
+ height = self.bitmap_drawing.height
27
+ width = self.bitmap_drawing.width
28
+
29
+ start = Time.now.to_f
30
+
31
+ pixel_data = ""
32
+ self.bitmap_drawing.pixels.reverse.each_with_index do |row, i|
33
+ row_bytes = 0
34
+ row.each do |pixel|
35
+ BinUtils.append_int8!(pixel_data, pixel[0])
36
+ BinUtils.append_int8!(pixel_data, pixel[1])
37
+ BinUtils.append_int8!(pixel_data, pixel[2])
38
+
39
+ #pixel_data += [pixel[0,2].hex].pack( "C" )
40
+ #pixel_data += [pixel[2,2].hex].pack( "C" )
41
+ #pixel_data += [pixel[4,2].hex].pack( "C" )
42
+
43
+ row_bytes += 3
44
+ end
45
+
46
+ # Padding
47
+ bytes_to_pad = row_bytes % 4
48
+
49
+ # puts "Row: #{i}, bytes: #{row_bytes}, padding: #{bytes_to_pad}"
50
+
51
+ bytes_to_pad.times do
52
+ BinUtils.append_int8!(pixel_data, 0x00)
53
+ end
54
+ end
55
+
56
+ # if options[:debug]
57
+ # puts "Generating pixel data string: #{Time.now.to_f - start}"
58
+ # end
59
+
60
+ file_size = 54 + pixel_data.size
61
+
62
+ f.print [0x42].pack ("C")
63
+ f.print [0x4D].pack( "C" )
64
+ f.print [file_size].pack( "L" )
65
+
66
+ f.print [0x00].pack( "C" ) # Unused
67
+ f.print [0x00].pack( "C" )
68
+ f.print [0x00].pack( "C" )
69
+ f.print [0x00].pack( "C" )
70
+
71
+ f.print [54].pack( "L" ) # Pixel Array Offset
72
+
73
+ f.print [0x28, 0x00, 0x00, 0x00].pack( "L" ) #Number of bytes in the DIB header (from this point)
74
+
75
+ f.print [width].pack( "L" ) #Width of the bitmap in pixels
76
+ f.print [height].pack( "L" ) #Height
77
+
78
+ f.print [0x01, 0x00].pack( "S" ) # Number of color planes being used
79
+ f.print [0x18, 0x00].pack( "S" ) # Number of bits per pixel
80
+ f.print [0x00].pack( "L" ) # BI_RGB, no pixel array compression used
81
+ f.print [pixel_data.size].pack( "L" ) # Size of the raw bitmap data (including padding)
82
+ f.print [0x130B].pack( "L" ) #2835 pixels/meter horizontal
83
+ f.print [0x130B].pack( "L" ) #2835 pixels/meter vertical
84
+ f.print [0x00].pack( "L" ) # Number of colors in the palette
85
+ f.print [0x00].pack( "L" ) #0 means all colors are important
86
+
87
+ f.print pixel_data
88
+ end
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,52 @@
1
+ module Graphit
2
+ class Color
3
+
4
+ # 0 - 255
5
+ attr_accessor :red
6
+ attr_accessor :green
7
+ attr_accessor :blue
8
+
9
+ def initialize( red, green, blue )
10
+ self.red = red
11
+ self.green = green
12
+ self.blue = blue
13
+ end
14
+
15
+ def to_hex_array
16
+ [blue,green,red]
17
+ end
18
+
19
+ def self.light_light_gray_color
20
+ Graphit::Color.new( 225, 225, 225 )
21
+ end
22
+
23
+ def self.light_gray_color
24
+ Graphit::Color.new( 204, 204, 204 )
25
+ end
26
+
27
+ def self.medium_gray_color
28
+ Graphit::Color.new( 170, 170, 170 )
29
+ end
30
+
31
+ def self.white_color
32
+ Graphit::Color.new( 255, 255, 255 )
33
+ end
34
+
35
+ def self.black_color
36
+ Graphit::Color.new( 0, 0, 0 )
37
+ end
38
+
39
+ def self.red_color
40
+ Graphit::Color.new( 255, 0, 0 )
41
+ end
42
+
43
+ def self.blue_color
44
+ Graphit::Color.new( 0, 0, 255 )
45
+ end
46
+
47
+ def self.green_color
48
+ Graphit::Color.new( 0, 255, 0 )
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,243 @@
1
+ module Graphit
2
+ class Graph
3
+
4
+ attr_accessor :bitmap_drawing
5
+
6
+ attr_accessor :graph_data
7
+
8
+ attr_accessor :height, :width
9
+ attr_accessor :xmin, :xmax, :xticsmod
10
+ attr_accessor :ymin, :ymax, :yticsmod
11
+ attr_accessor :background_color
12
+ attr_accessor :verbose
13
+ attr_accessor :debug
14
+ attr_accessor :left_padding, :right_padding, :top_padding, :bottom_padding
15
+ attr_accessor :x_pixels_per_unit, :y_pixels_per_unit
16
+ attr_accessor :data_color
17
+
18
+ def initialize( options, data )
19
+
20
+ options.each do |k,v|
21
+ if self.respond_to?("#{k}=".to_sym)
22
+ self.send( "#{k}=".to_sym, v )
23
+ end
24
+ end
25
+
26
+ self.graph_data = data
27
+
28
+ recalculate_xmin if xmin.to_s == "auto"
29
+ recalculate_xmax if xmax.to_s == "auto"
30
+ recalculate_ymin if ymin.to_s == "auto"
31
+ recalculate_ymax if ymax.to_s == "auto"
32
+
33
+ # Ensure floats
34
+ self.xmin = self.xmin.to_f
35
+ self.xmax = self.xmax.to_f
36
+ self.ymin = self.ymin.to_f
37
+ self.ymax = self.ymax.to_f
38
+
39
+ recalculate_pixels_per_unit
40
+
41
+ puts "BGColor: #{options[:background_color]}"
42
+
43
+ self.bitmap_drawing = BitmapDrawing.new( options[:height], options[:width], options[:background_color] )
44
+
45
+ draw_horizontal_gridlines
46
+ draw_vertical_gridlines
47
+ draw_graph_outline
48
+ draw_xaxis_labels
49
+
50
+ draw_graph( data )
51
+ end
52
+
53
+ def to_s
54
+ s = super
55
+ s += "\n"
56
+ s += " Height: #{height}, Width: #{width}\n"
57
+ s += " Xmin: #{xmin}, Xmax: #{xmax}, Xticsmod: #{xticsmod}\n"
58
+ s += " Ymin: #{ymin}, Ymax: #{ymax}, Yticsmod: #{yticsmod}\n"
59
+ s
60
+ end
61
+
62
+ def recalculate_xmin
63
+ puts "recalculate_xmin" if self.debug
64
+
65
+ self.xmin = self.graph_data.min_by{ |p| p.x.to_f }.x
66
+
67
+ puts " xmin: #{self.xmin}" if self.debug
68
+
69
+ self.xmin
70
+ end
71
+
72
+ def recalculate_xmax
73
+ puts "recalculate_xmax" if self.debug
74
+
75
+ self.xmax = self.graph_data.max_by{ |p| p.x.to_f }.x
76
+
77
+ puts " xmax: #{self.xmax}" if self.debug
78
+
79
+ self.xmax
80
+ end
81
+
82
+ def recalculate_ymin
83
+ puts "recalculate_ymin" if self.debug
84
+
85
+ self.ymin = self.graph_data.min_by{ |p| p.y.to_f }.y
86
+ end
87
+
88
+ def recalculate_ymax
89
+ puts "recalculate_ymax" if self.debug
90
+
91
+ self.ymax = self.graph_data.max_by{ |p| p.y.to_f }.y
92
+ end
93
+
94
+ def graph_width
95
+ width - left_padding - right_padding
96
+ end
97
+
98
+ def graph_height
99
+ height - bottom_padding - top_padding
100
+ end
101
+
102
+ def recalculate_pixels_per_unit
103
+ self.x_pixels_per_unit = graph_width / (xmax.to_f - xmin.to_f)
104
+ self.y_pixels_per_unit = graph_height / (ymax.to_f - ymin.to_f)
105
+
106
+ if xmax - xmin < (86400 * 3.5)
107
+ self.xticsmod = 3600
108
+ elsif xmax - xmin < (86400 * 7.5)
109
+ self.xticsmod = (86400 * 24)
110
+ elsif xmax - xmin < (86400 * 50)
111
+ self.xticsmod = (86400 * 24 * 7)
112
+ elsif xmax - xmin < (86400 * 800)
113
+ self.xticsmod = (86400 * 24 * 30)
114
+ else
115
+ self.xticsmod = 3600
116
+ end
117
+
118
+ # if options[:debug]
119
+ # puts "@x_pixels_per_unit: #{@x_pixels_per_unit}"
120
+ # puts "@y_pixels_per_unit: #{@y_pixels_per_unit}"
121
+ # end
122
+ end
123
+
124
+ def draw_graph( data )
125
+ self.graph_data = data
126
+
127
+ recalculate_pixels_per_unit
128
+
129
+ data.each_with_index do |p, i|
130
+ data[i] = translate_data_point_to_graph_point( p )
131
+ end
132
+
133
+ data.each_with_index do |point, i|
134
+ if i < data.size - 1
135
+ x1 = point.x
136
+ y1 = point.y
137
+
138
+ x2 = data[i+1].x
139
+ y2 = data[i+1].y
140
+
141
+ self.bitmap_drawing.draw_line( Point.new( x1, y1 ), Point.new( x2, y2), self.data_color )
142
+ end
143
+ end
144
+ end
145
+
146
+ def draw_horizontal_gridlines
147
+ (self.ymin.to_i..self.ymax.to_i).each do |y|
148
+ if y % self.yticsmod == 0
149
+ p1 = translate_data_point_to_graph_point( Point.new( self.xmin, y ) )
150
+ p2 = translate_data_point_to_graph_point( Point.new( self.xmax, y ) )
151
+
152
+ self.bitmap_drawing.draw_line( Point.new( p1.x, p1.y ), Point.new( p2.x, p2.y ), [0xAA,0xAA,0xAA] )
153
+
154
+ self.bitmap_drawing.draw_text( "#{y}", Point.new( p1.x - (10 * y.to_s.size), p1.y ), [0x00,0x00,0x00] )
155
+ end
156
+ end
157
+ end
158
+
159
+ def draw_vertical_gridlines
160
+ (self.xmin.to_i..self.xmax.to_i).each do |x|
161
+ if x % self.xticsmod == 0
162
+ p1 = translate_data_point_to_graph_point( Point.new( x, self.ymin ) )
163
+ p2 = translate_data_point_to_graph_point( Point.new( x, self.ymax ) )
164
+
165
+ #Manual offset for GMT-7
166
+ if (x + (3600*-7)) % 86400 == 0
167
+ lcolor = [0x00,0x00,0xFF]
168
+ else
169
+ lcolor = [0xAA,0xAA,0xAA]
170
+ end
171
+
172
+
173
+ self.bitmap_drawing.draw_line( Point.new( p1.x, p1.y ), Point.new( p2.x, p2.y ), lcolor )
174
+ end
175
+ end
176
+ end
177
+
178
+ def draw_graph_outline
179
+ p1 = translate_data_point_to_graph_point( Point.new( self.xmin, self.ymin ) )
180
+ p2 = translate_data_point_to_graph_point( Point.new( self.xmax, self.ymin ) )
181
+ self.bitmap_drawing.draw_line( Point.new( p1.x, p1.y ), Point.new( p2.x, p2.y ), [0x22,0x22,0x22] )
182
+
183
+ p1 = translate_data_point_to_graph_point( Point.new( self.xmax, self.ymin ) )
184
+ p2 = translate_data_point_to_graph_point( Point.new( self.xmax, self.ymax ) )
185
+ self.bitmap_drawing.draw_line( Point.new( p1.x, p1.y ), Point.new( p2.x, p2.y ), [0x22,0x22,0x22] )
186
+
187
+ p1 = translate_data_point_to_graph_point( Point.new( self.xmax, self.ymax ) )
188
+ p2 = translate_data_point_to_graph_point( Point.new( self.xmin, self.ymax ) )
189
+ self.bitmap_drawing.draw_line( Point.new( p1.x, p1.y ), Point.new( p2.x, p2.y ), [0x22,0x22,0x22] )
190
+
191
+ p1 = translate_data_point_to_graph_point( Point.new( self.xmin, self.ymax ) )
192
+ p2 = translate_data_point_to_graph_point( Point.new( self.xmin, self.ymin ) )
193
+ self.bitmap_drawing.draw_line( Point.new( p1.x, p1.y ), Point.new( p2.x, p2.y ), [0x22,0x22,0x22] )
194
+ end
195
+
196
+ def draw_xaxis_labels
197
+ (self.xmin.to_i..self.xmax.to_i).each do |x|
198
+
199
+ if x % 3600 == 0
200
+ x_offset = translate_data_point_to_graph_point( Point.new( x, 10 ) ).x.to_i
201
+
202
+ h = Time.at(x).hour
203
+
204
+ if h % 2 == 0
205
+ if self.debug
206
+ puts "h: #{h.to_s}, x: #{x_offset}"
207
+ end
208
+ self.bitmap_drawing.draw_text( h.to_s, Point.new( x_offset, self.height - 15 ), [0x00,0x00,0x00] )
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ def draw_yaxis_labels
215
+ # Currently happening in the y gridlines method
216
+ end
217
+
218
+ def translate_data_point_to_graph_point( point )
219
+
220
+ if point.x < self.xmin
221
+ point.x = self.xmin
222
+ elsif point.x > self.xmax
223
+ point.x = self.xmax
224
+ end
225
+
226
+ if point.y < self.ymin
227
+ point.y = self.ymin
228
+ elsif point.y > self.ymax
229
+ point.y = self.ymax
230
+ end
231
+
232
+ #puts "Mid x: #{point.x}, y: #{point.y}"
233
+
234
+ x = self.left_padding + (point.x - self.xmin) * self.x_pixels_per_unit
235
+ y = self.height - self.bottom_padding - ((point.y - self.ymin) * self.y_pixels_per_unit)
236
+
237
+ #puts "Out x: #{x}, y: #{y}"
238
+
239
+ return Point.new( x, y )
240
+ end
241
+
242
+ end
243
+ end
@@ -0,0 +1,11 @@
1
+ module Graphit
2
+ class Point
3
+ attr_accessor :x
4
+ attr_accessor :y
5
+
6
+ def initialize( x, y )
7
+ self.x = x.to_f
8
+ self.y = y.to_f
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module Graphit
2
- VERSION = "0.0.6"
2
+ VERSION = "0.1.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphit
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - jeffmcfadden
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-03-28 00:00:00.000000000 Z
11
+ date: 2016-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bin_utils
@@ -72,7 +72,12 @@ files:
72
72
  - graphit.gemspec
73
73
  - graphit/version.rb
74
74
  - lib/graphit.rb
75
+ - lib/graphit/bitmap_drawing.rb
76
+ - lib/graphit/bmp_file.rb
77
+ - lib/graphit/color.rb
78
+ - lib/graphit/graph.rb
75
79
  - lib/graphit/pixel_font.rb
80
+ - lib/graphit/point.rb
76
81
  - lib/graphit/version.rb
77
82
  - test-01.bmp
78
83
  - test-01.png