graphit 0.0.6 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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