Class: SparkCanvas

Inherits:
Object
  • Object
show all
Defined in:
lib/city_watch/util/spark_pr.rb

Overview

pure ruby sparklines module, generates PNG or ASCII contact [email protected] for questions

strives to be somewhat compatible with sparklines lib by Dan Nugent and Geoffrey Grosenbach

png creation based on www.whytheluckystiff.net/bumpspark/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(width, height) ⇒ SparkCanvas

Returns a new instance of SparkCanvas.



15
16
17
18
19
20
21
# File 'lib/city_watch/util/spark_pr.rb', line 15

def initialize(width,height)
  @canvas = []
  @height = height
  @width = width
  height.times{ @canvas << [[0xFF,0xFF,0xFF]]*width }
  @color = [0,0,0,0xFF] #RGBA
end

Instance Attribute Details

#colorObject

Returns the value of attribute color.



12
13
14
# File 'lib/city_watch/util/spark_pr.rb', line 12

def color
  @color
end

#heightObject (readonly)

Returns the value of attribute height.



13
14
15
# File 'lib/city_watch/util/spark_pr.rb', line 13

def height
  @height
end

#widthObject (readonly)

Returns the value of attribute width.



13
14
15
# File 'lib/city_watch/util/spark_pr.rb', line 13

def width
  @width
end

Instance Method Details

#blend(c1, c2) ⇒ Object

alpha blends two colors, using the alpha given by c2



24
25
26
# File 'lib/city_watch/util/spark_pr.rb', line 24

def blend(c1, c2)
  (0..2).map{ |i| (c1[i]*(0xFF-c2[3]) + c2[i]*c2[3]) >> 8 }
end

#build_png_chunk(type, data) ⇒ Object



105
106
107
108
# File 'lib/city_watch/util/spark_pr.rb', line 105

def build_png_chunk(type,data)
  to_check = type + data
  [data.length].pack("N") + to_check + [Zlib.crc32(to_check)].pack("N")
end

#grayscale(c) ⇒ Object

calculate perceptive grayscale value



34
35
36
# File 'lib/city_watch/util/spark_pr.rb', line 34

def grayscale(c)
  (c[0]*0.3 + c[1]*0.59 + c[2]*0.11).to_i
end

#intensity(c, i) ⇒ Object

calculate a new alpha given a 0-0xFF intensity



29
30
31
# File 'lib/city_watch/util/spark_pr.rb', line 29

def intensity(c,i)
  [c[0],c[1],c[2],(c[3]*i) >> 8]
end

#line(x0, y0, x1, y1) ⇒ Object

draw an antialiased line google for “wu antialiasing”



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/city_watch/util/spark_pr.rb', line 52

def line(x0, y0, x1, y1)
  # clean params
  x0, y0, x1, y1 = x0.to_i, y0.to_i, x1.to_i, y1.to_i
  y0, y1, x0, x1 = y1, y0, x1, x0 if y0>y1 
  sx = (dx = x1-x0) < 0 ? -1 : 1 ; dx *= sx ; dy = y1-y0
  
  # special cases
  x0.step(x1,sx) { |x| point x, y0 } and return if dy.zero?
  y0.upto(y1)    { |y| point x0, y } and return if dx.zero?
  x0.step(x1,sx) { |x| point x, y0; y0 += 1 } and return if dx==dy
  
  # main loops
  point x0, y0
  
  e_acc = 0
  if dy > dx
    e = (dx << 16) / dy
    y0.upto(y1-1) do
      e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
      x0 += sx if (e_acc <= e_acc_temp)
      point x0, (y0 += 1), intensity(@color,(w=0xFF-(e_acc >> 8)))
      point x0+sx, y0, intensity(@color,(0xFF-w))
    end
    point x1, y1
    return
  end
  
  e = (dy << 16) / dx
  x0.step(x1-sx,sx) do
    e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xFFFF
    y0 += 1 if (e_acc <= e_acc_temp)
    point (x0 += sx), y0, intensity(@color,(w=0xFF-(e_acc >> 8)))
    point x0, y0+1, intensity(@color,(0xFF-w))
  end
  point x1, y1
end

#point(x, y, color = nil) ⇒ Object



38
39
40
41
# File 'lib/city_watch/util/spark_pr.rb', line 38

def point(x,y,color = nil)
  return if x<0 or y<0 or x>@width-1 or y>@height-1
  @canvas[y][x] = blend(@canvas[y][x], color || @color)
end

#polyline(arr) ⇒ Object



89
90
91
# File 'lib/city_watch/util/spark_pr.rb', line 89

def polyline(arr)
  (0...arr.size-1).each{ |i| line(arr[i][0], arr[i][1], arr[i+1][0], arr[i+1][1]) }
end

#rectangle(x0, y0, x1, y1) ⇒ Object



43
44
45
46
47
48
# File 'lib/city_watch/util/spark_pr.rb', line 43

def rectangle(x0, y0, x1, y1)
  x0, y0, x1, y1 = x0.to_i, y0.to_i, x1.to_i, y1.to_i
  x0, x1 = x1, x0 if x0 > x1
  y0, y1 = y1, y0 if y0 > y1
  x0.upto(x1) { |x| y0.upto(y1) { |y| point x, y } }
end

#to_asciiObject



110
111
112
113
# File 'lib/city_watch/util/spark_pr.rb', line 110

def to_ascii
  chr = %w(M O # + ; - .) << ' '
  @canvas.map{ |r| r.map { |pt| chr[grayscale(pt) >> 5] }.to_s << "\n" }.to_s
end

#to_pngObject



93
94
95
96
97
98
99
100
101
102
103
# File 'lib/city_watch/util/spark_pr.rb', line 93

def to_png
  header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
  raw_data = @canvas.map { |row| [0] + row }.flatten.pack("C*")
  ihdr_data = [@canvas.first.length,@canvas.length,8,2,0,0,0].pack("NNCCCCC")
  
  header +
  build_png_chunk("IHDR", ihdr_data) +
  build_png_chunk("tRNS", ([ 0xFF ]*6).pack("C6")) +
  build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data)) +
  build_png_chunk("IEND", "")
end