summaryrefslogtreecommitdiff
path: root/js/lib/wavegrid.js
blob: 532bbfcf1499b98f1b0ccb3a0e61546af29207e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
var WaveGrid = (function(){

  function WaveGrid (opt){
    this.opt = defaults(opt, {
      stroke_width: 2,
      stroke: "#ffffff",
      fill: "#000000",
      wave_spacing: 20,
      wave_height: 6,
      wave_height_scale: 4,
      speed: 15,
      wave_stagger: 8,
      smooth_stagger: true,
      face: null,
      waves: true,
    })
    if (! this.opt.face) {
      console.error("WaveGrid: please supply a SnapMX face object")
    }
    this.loaded = false
  }
  WaveGrid.prototype.load = function(data, w, h){
    this.waves = []
    this.data = data

    var dx = this.opt.wave_spacing
    var dy = this.opt.wave_height
    var top_padding = dy * this.opt.wave_height_scale + this.opt.stroke_width
    var wave
    var x, y
    
    this.w = w
    this.h = h
    
    this.opt.face.resize(w + dx*2, h + top_padding + dy*2)
    this.group = this.opt.face.snap.g()
    this.group.attr({ transform: "T" + (2.5*dx) + ","+ -top_padding/2 })

    for (y = 0; y < h; y += dy) {
      wave = this.group.path().attr({
        strokeWidth: this.opt.stroke_width,
        stroke: this.opt.stroke,
        fill: this.opt.fill,
      })
      this.waves.push(wave)
    }
    this.loaded = true
    this.update(0)
  }
  WaveGrid.prototype.update = function(t){
    if (! this.loaded) return
    
    t *= this.opt.speed / 1000
    
    var wave_height_scale = this.opt.wave_height_scale
    var dx = this.opt.wave_spacing
    var dy = this.opt.wave_height
    var dt = t % dx
    var dtr = dt/dx

    var pixels = this.data.data
    var pw = this.data.width
    var ph = this.data.height

    var w = this.w
    var xmin = (dx-dt) - dx
    var xmax = w + (dx*2)

    var wave, path, x, xx, y, yy
    var at, bt, ay, by, zt, zy
    var pi, i, j = this.waves.length-1
    var xstart = 0
    
    var smooth_stagger = this.opt.smooth_stagger
    var stagger = this.opt.wave_stagger
    var stagger_dtr
    
    var use_waves = this.opt.waves

    for (y = 0; y < this.h; y += dy, j--) {
      pi = ((y/this.h) * ph)|0
      wave = this.waves[j]
      path = "M" + (-dx) + "," + y
      
      if (smooth_stagger) {
        dt = (t/stagger + ((j % stagger)/stagger * dx)) % dx
        dtr = dt/dx
        xmin = (dx-dt) - dx
      }
      else {
        xstart = stagger == 1 ? 0 : ((j % stagger)/stagger) * dx
      }
      
      for (x = xstart; x <= xmax; x += dx) {
        xx = x + xmin
        
        jj = clamp( x / w, 0, 1 ) * (pw)
        jjj = clamp( (x+dx) / w, 0, 1 ) * (pw)

        if (jjj >= pw) {
          at = ((pi * pw) + pw-2)|0
        }
        else {
          at = ((pi * pw) + jj)|0
        }
        
        if (jjj >= pw) {
          bt = ((pi * pw) + pw - 1)|0
        }
        else {
          bt = ((pi * pw) + jjj)|0
        }
        
        ay = (pixels[at]/255 * dy) * (dtr) * wave_height_scale
        by = (pixels[bt]/255 * dy) * (1-dtr) * wave_height_scale
        yy = y + (ay + by)
        
        if (use_waves) {
          path += "C"
          path += (xx).toFixed(3) + "," + (y).toFixed(3) + " "
          path += (xx).toFixed(3) + "," + (yy + (ay+by)).toFixed(3) + " "
          path += (xx).toFixed(3) + "," + (yy).toFixed(3) + " "
        }
        else {
          path += "M" + (xx - 0.01).toFixed(3) + "," + (y).toFixed(3)
          path += "L" + (xx).toFixed(3) + "," + (yy).toFixed(3)
          path += "L" + (xx + 0.01).toFixed(3) + "," + (y).toFixed(3)
        }
      }
      wave.attr({ d: path })
    }
  }
  
  return WaveGrid

})()