source: main/trunk/model-sites-dev/respooled/collect/popup-video-respooled/js/jam-guitar.js@ 29878

Last change on this file since 29878 was 29878, checked in by davidb, 9 years ago

Work developing a guitar to play, and recording notes on piano when played (with the radio button set to record)

  • Property svn:executable set to *
File size: 8.4 KB
Line 
1// Script derived from Chrome Jam
2
3// Shim by Paul Irish
4// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
5window.requestAnimFrame = (function() {
6 return window.requestAnimationFrame ||
7 window.webkitRequestAnimationFrame ||
8 window.mozRequestAnimationFrame ||
9 window.oRequestAnimationFrame ||
10 window.msRequestAnimationFrame ||
11 function(callback) {
12 window.setTimeout(callback, 1000 / 60);
13 };
14})();
15
16function Stage(id) {
17 this.el = document.getElementById(id);
18
19 this.position();
20 this.listeners();
21 this.hitZones = [];
22 return this;
23}
24
25Stage.prototype.position = function() {
26 var offset = this.offset();
27 this.positionTop = Math.floor(offset.left);
28 this.positionLeft = Math.floor(offset.top);
29};
30
31Stage.prototype.offset = function() {
32 var _x, _y,
33 el = this.el;
34
35 if (typeof el.getBoundingClientRect !== "undefined") {
36 return el.getBoundingClientRect();
37 } else {
38 _x = 0;
39 _y = 0;
40 while(el && !isNaN( el.offsetLeft ) && !isNaN( el.offsetTop ) ) {
41 _x += el.offsetLeft;
42 _y += el.offsetTop;
43 el = el.offsetParent;
44 }
45 return { top: _y - window.scrollY, left: _x - window.scrollX };
46 }
47};
48
49Stage.prototype.listeners = function() {
50 var _self = this;
51
52 _self.dragging = false;
53 _self.limit = false;
54
55 window.addEventListener('resize', function() {
56 _self.position();
57 }, false);
58
59 window.addEventListener('scroll', function() {
60 _self.position();
61 }, false);
62
63 this.el.addEventListener('mousedown', function(e) {
64 var x = e.clientX - _self.positionTop,
65 y = e.clientY - _self.positionLeft;
66
67 _self.hitZones.forEach(function(zone) {
68 _self.checkPoint(x, y, zone);
69 });
70
71 _self.dragging = true;
72 _self.prev = [x, y];
73 }, false);
74
75
76 document.addEventListener('mousemove', function(e) {
77 var x, y;
78
79 if (!_self.dragging || _self.limit) return;
80 _self.limit = true;
81
82 x = e.clientX - _self.positionTop,
83 y = e.clientY - _self.positionLeft;
84
85
86 _self.hitZones.forEach(function(zone) {
87 _self.checkIntercept(_self.prev[0],
88 _self.prev[1],
89 x,
90 y,
91 zone);
92 });
93
94 _self.prev = [x, y];
95
96 setInterval(function() {
97 _self.limit = false;
98 }, 50);
99 }, false);
100
101 document.addEventListener('mouseup', function(e) {
102 var x, y;
103
104 if (!_self.dragging) return;
105 _self.dragging = false;
106
107 x = e.clientX - _self.positionTop,
108 y = e.clientY - _self.positionLeft;
109
110 _self.hitZones.forEach(function(zone) {
111 _self.checkIntercept(_self.prev[0],
112 _self.prev[1],
113 x,
114 y,
115 zone);
116 });
117 }, false);
118};
119
120Stage.prototype.check = function(x, y, zone) {
121 if(!zone.el) return;
122
123 if(zone.inside(x, y)){
124 zone.el.classList.add('hit');
125 this.el.classList.add('active');
126 }else{
127 zone.el.classList.remove('hit');
128 this.el.classList.remove('active');
129 }
130};
131
132Stage.prototype.addRect = function(id) {
133 var el = document.getElementById(id),
134 rect = new Rect(el.offsetLeft,
135 el.offsetTop,
136 el.offsetWidth,
137 el.offsetHeight
138 );
139 rect.el = el;
140
141 this.hitZones.push(rect);
142 return rect;
143};
144
145Stage.prototype.addString = function(rect, string) {
146 rect.string = string;
147
148 this.hitZones.push(rect);
149 return rect;
150};
151
152Stage.prototype.checkPoint = function(x, y, zone) {
153 if(zone.inside(x, y)) {
154 zone.string.strum();
155 }
156};
157
158Stage.prototype.checkIntercept = function(x1, y1, x2, y2, zone) {
159 if(zone.intercept(x1, y1, x2, y2)) {
160 zone.string.strum();
161 }
162};
163
164
165function Rect(x, y, width, height) {
166 this.x = x;
167 this.y = y;
168 this.width = width;
169 this.height = height;
170
171 return this;
172}
173
174Rect.prototype.inside = function(x,y) {
175 return x >= this.x && y >= this.y
176 && x <= this.x + this.width
177 && y <= this.y + this.height;
178};
179
180Rect.prototype.midLine = function() {
181 if (this.middle) return this.middle;
182
183 this.middle = [
184 {x: this.x, y: this.y + this.height / 2},
185 {x: this.x + this.width, y: this.y + this.height / 2}
186 ]
187 return this.middle;
188};
189
190Rect.prototype.intercept = function(x1, y1, x2, y2) {
191 var result = false,
192 segment = this.midLine(),
193 start = {x: x1, y: y1},
194 end = {x: x2, y: y2};
195
196 return this.intersectLine(segment[0], segment[1], start, end);
197};
198
199Rect.prototype.intersectLine = function(a1, a2, b1, b2) {
200 //-- http://www.kevlindev.com/gui/math/intersection/Intersection.js
201 var result,
202 ua_t = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),
203 ub_t = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),
204 u_b = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
205
206 if (u_b != 0) {
207 var ua = ua_t / u_b;
208 var ub = ub_t / u_b;
209
210 if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {
211 result = true;
212 } else {
213 result = false; //--"No Intersection"
214 }
215 } else {
216 if (ua_t == 0 || ub_t == 0) {
217 result = false; //-- Coincident"
218 } else {
219 result = false; //-- Parallel
220 }
221 }
222
223 return result;
224};
225
226
227function GuitarString(rect) {
228 this.x = rect.x;
229 this.y = rect.y + rect.height / 2;
230 this.width = rect.width;
231 this._strumForce = 0;
232 this.a = 0;
233}
234
235GuitarString.prototype.strum = function() {
236 this._strumForce = 5;
237 this._strumDuration = 100;
238 MIDI.noteOn(0, this._midiPitch, 40);
239 console.log("*** Setting Jam guitar strumForce = 5");
240
241};
242
243GuitarString.prototype.render = function(ctx, canvas) {
244 ctx.strokeStyle = "#000000";
245 ctx.lineWidth = 1;
246 ctx.beginPath();
247 ctx.moveTo(this.x, this.y);
248 ctx.bezierCurveTo(
249 this.x, this.y + Math.sin(this.a) * this._strumForce,
250 this.x + this.width, this.y + Math.sin(this.a) * this._strumForce,
251 this.x + this.width, this.y);
252 ctx.stroke();
253
254 this._strumForce *= 0.99;
255 this.a += 0.5;
256
257 if (this._strumDuration>0) {
258 this._strumDuration--;
259 }
260 else if (this._strumDuration == 0) {
261 this._strumDuration = -1;
262 console.log("*** setting strumDuration = 0");
263 MIDI.noteOff(0, this._midiPitch, 0);
264 }
265};
266
267
268function StringInstrument(stageID, canvasID, stringNum){
269 this.strings = [];
270 this.canvas = document.getElementById(canvasID);
271 this.stage = new Stage(stageID);
272 this.ctx = this.canvas.getContext('2d');
273 this.stringNum = stringNum;
274
275 this.create();
276 this.render();
277
278 return this;
279}
280
281var jamStringLength = 680; // used to be 380
282var jamStringThickness = 5;
283
284//var jamMidiStringPitches = [ 60, 64, 67, 72, 76, 79 ];
285var jamMidiStringPitches = [ 48, 52, 55, 60, 64, 67 ];
286
287StringInstrument.prototype.create = function() {
288 for (var i = 0; i < this.stringNum; i++) {
289 var srect = new Rect(10, 90 + i * (jamStringThickness * 1.6), jamStringLength, jamStringThickness);
290 var s = new GuitarString(srect);
291 s._midiPitch = jamMidiStringPitches[i];
292 this.stage.addString(srect, s);
293 this.strings.push(s);
294 }
295};
296
297var lastTime = 0;
298
299StringInstrument.prototype.render = function() {
300 var _self = this;
301
302 requestAnimFrame(function(){
303 _self.render();
304 });
305
306
307 var currTime = new Date().getTime();
308 var dt = currTime - lastTime;
309
310 if (dt>0) {
311 lastTime = currTime;
312 this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
313
314 for (var i = 0; i < this.stringNum; i++) {
315 this.strings[i].render(this.ctx);
316 }
317 }
318};
319
320$(document).ready(function() {
321 var guitar = new StringInstrument("jamStage", "jamStrings", 6);
322});
Note: See TracBrowser for help on using the repository browser.