shank 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +22 -0
  4. data/README.md +0 -0
  5. data/Rakefile +2 -0
  6. data/lib/assets/javascripts/engine.gamepads.coffee +46 -0
  7. data/lib/assets/javascripts/engine_stats.coffee +10 -0
  8. data/lib/assets/javascripts/error_handler.coffee +11 -0
  9. data/lib/assets/javascripts/game_keys.coffee +6 -0
  10. data/lib/assets/javascripts/gamepads.coffee +21 -0
  11. data/lib/assets/javascripts/gamepads.controller.coffee +138 -0
  12. data/lib/assets/javascripts/init.coffee +6 -0
  13. data/lib/assets/javascripts/joysticks.coffee +238 -0
  14. data/lib/assets/javascripts/jquery.hotkeys.coffee +161 -0
  15. data/lib/assets/javascripts/jquery.reverse_merge.coffee +21 -0
  16. data/lib/assets/javascripts/keydown.coffee +73 -0
  17. data/lib/assets/javascripts/mouse.coffee +66 -0
  18. data/lib/assets/javascripts/music.coffee +78 -0
  19. data/lib/assets/javascripts/pixie_canvas.coffee +739 -0
  20. data/lib/assets/javascripts/request_animation_frame.coffee +22 -0
  21. data/lib/assets/javascripts/shank.coffee +18 -0
  22. data/lib/assets/javascripts/sound.coffee +131 -0
  23. data/lib/assets/javascripts/storage.coffee +88 -0
  24. data/lib/shank/version.rb +3 -0
  25. data/lib/shank.rb +10 -0
  26. data/shank.gemspec +17 -0
  27. data/test/jquery.reverse_merge.coffee +43 -0
  28. data/test/keydown.coffee +19 -0
  29. data/test/pixie_canvas.coffee +18 -0
  30. data/test/request_animation_frame.coffee +7 -0
  31. data/test/sound.coffee +7 -0
  32. data/test/storage.coffee +47 -0
  33. data/test/xstats.coffee +7 -0
  34. data/vendor/assets/javascripts/xstats.js +767 -0
  35. metadata +113 -0
@@ -0,0 +1,767 @@
1
+ /*!
2
+ * xStats.js v1.0.0-pre
3
+ * Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/>
4
+ * Based on Stats.js, copyright Ricardo Cabello <http://mrdoob.com/>
5
+ * Available under MIT license <https://github.com/jdalton/xstats.js/raw/master/LICENSE.txt>
6
+ */
7
+ ;(function(window, document) {
8
+ 'use strict';
9
+
10
+ /** Detect memory object */
11
+ var memoryNS = (memoryNS = window.performance || window.webkitPerformance || window.console) &&
12
+ memoryNS.memory && memoryNS;
13
+
14
+ /** Shortcut used to convert array-like objects to arrays */
15
+ var slice = [].slice;
16
+
17
+ /** Internal cached used by various methods */
18
+ var cache = {
19
+ 'counter': 1,
20
+ 'frameTimes': [],
21
+ 'lastSecond': null,
22
+ 'lastTime': null,
23
+ 'data': { 'fps': new Data, 'ms': new Data, 'mem': new Data }
24
+ };
25
+
26
+ /** Math shortcuts */
27
+ var floor = Math.floor,
28
+ max = Math.max,
29
+ min = Math.min,
30
+ round = Math.round;
31
+
32
+ /*--------------------------------------------------------------------------*/
33
+
34
+ /**
35
+ * The Data object constructor.
36
+ *
37
+ * @private
38
+ * @constructor
39
+ */
40
+ function Data() {
41
+ // add own properties to avoid lookups on the Array.prototype
42
+ return extend([], { 'max': null, 'min': null });
43
+ }
44
+
45
+ /**
46
+ * The Event constructor.
47
+ *
48
+ * @constructor
49
+ * @memberOf xStats
50
+ * @param {String|Object} type The event type.
51
+ */
52
+ function Event(type) {
53
+ var me = this;
54
+ return (!me || me.constructor != Event)
55
+ ? new Event(type)
56
+ : (type instanceof Event)
57
+ ? type
58
+ : extend(me, typeof type == 'string' ? { 'type': type } : type);
59
+ }
60
+
61
+ /**
62
+ * The xStats constructor.
63
+ *
64
+ * @constructor
65
+ * @param {Object} [options={}] Options object.
66
+ * @example
67
+ *
68
+ * // basic usage (the `new` operator is optional)
69
+ * var stats = new xStats;
70
+ *
71
+ * // or using options
72
+ * var stats = new xStats({
73
+ * 'mode': 'ms',
74
+ * 'height': 130,
75
+ * 'width':200,
76
+ * 'padding':10,
77
+ * 'locked': false,
78
+ * 'fps': {
79
+ * 'bg': '#330000',
80
+ * 'fg': '#cc6600'
81
+ * },
82
+ * 'ms': {
83
+ * 'bg': '#000033',
84
+ * 'fg': '#3366ff'
85
+ * },
86
+ * 'mem': {
87
+ * 'bg': '#000033',
88
+ * 'fg': '#660099'
89
+ * }
90
+ * });
91
+ *
92
+ * // insert into document
93
+ * document.body.appendChild(stats.element);
94
+ */
95
+ function xStats(options) {
96
+ var clipped,
97
+ element,
98
+ fps,
99
+ height,
100
+ mem,
101
+ ms,
102
+ padding,
103
+ uid,
104
+ width,
105
+ data = cache.data,
106
+ me = this,
107
+ tmp = {};
108
+
109
+ // allow instance creation without the `new` operator
110
+ if (!me || me.constructor != xStats) {
111
+ return new xStats(options);
112
+ }
113
+
114
+ element = document.createElement('div');
115
+ uid = 'xstats' + cache.counter++;
116
+
117
+ // apply options
118
+ extend(me, options || (options = {}));
119
+ me.uid = uid;
120
+ extend(tmp, me);
121
+
122
+ fps = me.fps = extend(extend({}, me.fps), options.fps);
123
+ ms = me.ms = extend(extend({}, me.ms), options.ms);
124
+ mem = me.mem = extend(extend({}, me.mem), options.mem);
125
+
126
+ // compute dimensions
127
+ padding = me.padding * 2;
128
+ height = me.height - padding;
129
+ width = me.width - padding;
130
+ clipped = max(1, round(width * 0.02));
131
+ width = floor(width / clipped);
132
+
133
+ // sweet spot for font-size, height, and width
134
+ tmp.titleHeight = round(height * 0.28);
135
+ tmp.barWidth = clipped + 4;
136
+ tmp.fontSize = (tmp.titleHeight / 22.2).toFixed(2);
137
+ tmp.innerWidth = clipped * width;
138
+ tmp.innerHeight = height - tmp.titleHeight;
139
+ tmp.padding = round((me.width - tmp.innerWidth) / 2);
140
+
141
+ // increase shared data if needed
142
+ if (data.ms.length < width) {
143
+ data.fps.length =
144
+ data.ms.length =
145
+ data.mem.length = width;
146
+ }
147
+ // append customized css
148
+ appendCSS(
149
+ interpolate(
150
+ '.#{uid},.#{uid} .bg,.#{uid} .fg{width:#{width}px;height:#{height}px}' +
151
+ '.#{uid} .mi{margin:#{padding}px;width:#{innerWidth}px}' +
152
+ '.#{uid} p{font-size:#{fontSize}em;height:#{titleHeight}px;width:#{innerWidth}px}' +
153
+ '.#{uid} ul{height:#{innerHeight}px;width:#{innerWidth}px}' +
154
+ '.#{uid} li{width:#{barWidth}px}', tmp) +
155
+ interpolate(
156
+ '.#{uid}.fps{color:#{fg}}' +
157
+ '.#{uid}.fps ul{background:#{fg}}' +
158
+ '.#{uid}.fps .bg,.#{uid}.fps li{background:#{bg}}', extend(tmp, fps)) +
159
+ interpolate(
160
+ '.#{uid}.ms{color:#{fg}}' +
161
+ '.#{uid}.ms ul{background:#{fg}}' +
162
+ '.#{uid}.ms .bg,.#{uid}.ms li{background:#{bg}}', extend(tmp, ms)) +
163
+ interpolate(
164
+ '.#{uid}.mem{color:#{fg}}' +
165
+ '.#{uid}.mem ul{background:#{fg}}' +
166
+ '.#{uid}.mem .bg,.#{uid}.mem li{background:#{bg}}', extend(tmp, mem)));
167
+
168
+ // build interface
169
+ element.className = 'xstats ' + uid + ' ' + me.mode;
170
+ element.innerHTML = '<div class=bg></div><div class=mi><p>&nbsp;</p><ul>' + repeat('<li></li>', width) + '</ul></div><div class=fg></div>';
171
+
172
+ // add element event listeners
173
+ if (typeof element.addEventListener != 'undefined') {
174
+ element.addEventListener('click', createSwapMode(me), false);
175
+ } else if (element.attachEvent != 'undefined') {
176
+ element.attachEvent('onclick', createSwapMode(me));
177
+ }
178
+
179
+ // grab elements
180
+ me.element = element;
181
+ me.canvas = element.getElementsByTagName('ul')[0];
182
+ me.title = element.getElementsByTagName('p')[0].firstChild;
183
+
184
+ // keep track of instances to animate
185
+ xStats.subclasses.push(me);
186
+ }
187
+
188
+ /*--------------------------------------------------------------------------*/
189
+
190
+ /**
191
+ * Adds a css class name to an element's className property.
192
+ *
193
+ * @private
194
+ * @param {Object} element The element.
195
+ * @param {String} className The class name.
196
+ */
197
+ function addClass(element, className) {
198
+ element.className += (element.className ? ' ' : '') + className;
199
+ }
200
+
201
+ /**
202
+ * Appends CSS text to a planted style sheet.
203
+ *
204
+ * @private
205
+ * @param {String} cssText The CSS text.
206
+ */
207
+ function appendCSS(cssText) {
208
+ var node,
209
+ prop = 'cssText',
210
+ sheet = cache.sheet;
211
+
212
+ if (!sheet) {
213
+ node = document.getElementsByTagName('head')[0];
214
+ sheet = cache.sheet = document.createElement('style');
215
+ sheet.type = 'text/css';
216
+ node.insertBefore(sheet, node.firstChild);
217
+ }
218
+ if (!(node = 'styleSheet' in sheet && sheet.styleSheet)) {
219
+ prop = 'nodeValue';
220
+ node = sheet.firstChild || sheet.appendChild(document.createTextNode(''));
221
+ }
222
+ node[prop] += cssText;
223
+ }
224
+
225
+ /**
226
+ * An iteration utility for arrays.
227
+ * Callbacks may terminate the loop by explicitly returning `false`.
228
+ *
229
+ * @private
230
+ * @param {Array} array The array to iterate over.
231
+ * @param {Function} callback The function called per iteration.
232
+ * @returns {Array} Returns the array iterated over.
233
+ */
234
+ function each(array, callback) {
235
+ var index = -1,
236
+ length = array.length;
237
+
238
+ while (++index < length) {
239
+ if (callback(array[index], index, array) === false) {
240
+ break;
241
+ }
242
+ }
243
+ return array;
244
+ }
245
+
246
+ /**
247
+ * Copies enumerable properties from the source object to the destination object.
248
+ *
249
+ * @private
250
+ * @param {Object} destination The destination object.
251
+ * @param {Object} [source={}] The source object.
252
+ * @returns {Object} The destination object.
253
+ */
254
+ function extend(destination, source) {
255
+ source || (source = {});
256
+ for (var key in source) {
257
+ destination[key] = source[key];
258
+ }
259
+ return destination;
260
+ }
261
+
262
+ /**
263
+ * Modify a string by replacing named tokens with matching object property values.
264
+ *
265
+ * @private
266
+ * @param {String} string The string to modify.
267
+ * @param {Object} object The template object.
268
+ * @returns {String} The modified string.
269
+ */
270
+ function interpolate(string, object) {
271
+ for (var key in object) {
272
+ string = string.replace(RegExp('#\\{' + key + '\\}', 'g'), object[key]);
273
+ }
274
+ return string;
275
+ }
276
+
277
+ /**
278
+ * Removes a css class name from an element's className property.
279
+ *
280
+ * @private
281
+ * @param {Object} element The element.
282
+ * @param {String} className The class name.
283
+ */
284
+ function removeClass(element, className) {
285
+ var cn,
286
+ classNames = element.className.split(' '),
287
+ filtered = [];
288
+
289
+ while ((cn = classNames.pop())) {
290
+ if (className != cn) {
291
+ filtered.push(cn);
292
+ }
293
+ }
294
+ element.className = filtered.join(' ');
295
+ }
296
+
297
+ /**
298
+ * Repeat a string a given number of times using the `Exponentiation by squaring` algorithm.
299
+ *
300
+ * @private
301
+ * @param {String} string The string to repeat.
302
+ * @param {Number} count The number of times to repeat the string.
303
+ * @returns {String} The repeated string.
304
+ * @see http://www.merlyn.demon.co.uk/js-misc0.htm#MLS
305
+ */
306
+ function repeat(string, count) {
307
+ if (count < 1) return '';
308
+ if (count % 2) return repeat(string, count - 1) + string;
309
+ var half = repeat(string, count / 2);
310
+ return half + half;
311
+ }
312
+
313
+ /*--------------------------------------------------------------------------*/
314
+
315
+ /**
316
+ * Registers a single listener for the specified event type(s).
317
+ *
318
+ * @memberOf xStats
319
+ * @param {String} type The event type.
320
+ * @param {Function} listener The function called when the event occurs.
321
+ * @returns {Object} The xStats instance.
322
+ * @example
323
+ *
324
+ * // register a listener for an event type
325
+ * xs.addListener('sample', listener);
326
+ *
327
+ * // register a listener for multiple event types
328
+ * xs.addListener('start sample', listener);
329
+ */
330
+ function addListener(type, listener) {
331
+ var me = this,
332
+ events = me.events || (me.events = {});
333
+
334
+ each(type.split(' '), function(type) {
335
+ (events[type] || (events[type] = [])).push(listener);
336
+ });
337
+ return me;
338
+ }
339
+
340
+ /**
341
+ * Executes all registered listeners of the specified event type.
342
+ *
343
+ * @memberOf xStats
344
+ * @param {String|Object} type The event type or object.
345
+ * @returns {Boolean} Returns `true` if all listeners were executed, else `false`.
346
+ */
347
+ function emit(type) {
348
+ var me = this,
349
+ event = Event(type),
350
+ args = (arguments[0] = event, slice.call(arguments)),
351
+ events = me.events,
352
+ listeners = events && events[event.type] || [],
353
+ result = true;
354
+
355
+ each(listeners.slice(), function(listener) {
356
+ if (!(result = listener.apply(me, args) !== false)) {
357
+ return result;
358
+ }
359
+ });
360
+ return result;
361
+ }
362
+
363
+ /**
364
+ * Unregisters a single listener for the specified event type(s).
365
+ *
366
+ * @memberOf xStats
367
+ * @param {String} type The event type.
368
+ * @param {Function} listener The function to unregister.
369
+ * @returns {Object} The xStats instance.
370
+ * @example
371
+ *
372
+ * // unregister a listener for an event type
373
+ * xs.removeListener('sample', listener);
374
+ *
375
+ * // unregister a listener for multiple event types
376
+ * xs.removeListener('start sample', listener);
377
+ */
378
+ function removeListener(type, listener) {
379
+ var me = this,
380
+ events = me.events;
381
+
382
+ each(type.split(' '), function(type) {
383
+ var listeners = events && events[type] || [],
384
+ index = indexOf(listeners, listener);
385
+ if (index > -1) {
386
+ listeners.splice(index, 1);
387
+ }
388
+ });
389
+ return me;
390
+ }
391
+
392
+ /**
393
+ * Unregisters all listeners or those for the specified event type(s).
394
+ *
395
+ * @memberOf xStats
396
+ * @param {String} type The event type.
397
+ * @returns {Object} The xStats instance.
398
+ * @example
399
+ *
400
+ * // unregister all listeners
401
+ * xs.removeAllListeners();
402
+ *
403
+ * // unregister all listeners for an event type
404
+ * xs.removeAllListeners('sample');
405
+ *
406
+ * // unregister all listeners for multiple event types
407
+ * xs.removeAllListeners('start sample complete');
408
+ */
409
+ function removeAllListeners(type) {
410
+ var me = this,
411
+ events = me.events;
412
+
413
+ each(type ? type.split(' ') : events, function(type) {
414
+ (events && events[type] || []).length = 0;
415
+ });
416
+ return me;
417
+ }
418
+
419
+ /*--------------------------------------------------------------------------*/
420
+
421
+ /**
422
+ * Creates the click event handler that controls swaping modes and redrawing
423
+ * the display.
424
+ *
425
+ * @private
426
+ * @param {Object} me The xStats instance.
427
+ * @returns {Function} The event handler.
428
+ */
429
+ function createSwapMode(me) {
430
+ return function() {
431
+ if (!me.locked) {
432
+ var mode = me.mode == 'fps' ? 'ms' : me.mode == 'ms' ? (memoryNS ? 'mem' : 'fps') : 'fps',
433
+ element = me.element,
434
+ nodes = me.canvas.childNodes,
435
+ data = cache.data[mode],
436
+ entry = data[0],
437
+ length = nodes.length;
438
+
439
+ me.mode = mode;
440
+ setTitle(me, entry && entry.value);
441
+ while (length--) {
442
+ entry = data[length];
443
+ setBar(me, nodes[length], entry && entry.percent);
444
+ }
445
+ removeClass(element, 'fps');
446
+ removeClass(element, 'ms');
447
+ removeClass(element, 'mem');
448
+ addClass(element, mode);
449
+ }
450
+ };
451
+ }
452
+
453
+ /**
454
+ * Records a value for the given mode.
455
+ *
456
+ * @private
457
+ * @param {String} mode The mode to record.
458
+ * @param {Mixed} value The value recorded.
459
+ */
460
+ function record(mode, value) {
461
+ var data = cache.data[mode],
462
+ percent = min(100, 100 * (value / (mode == 'fps' ? 80 : mode == 'ms' ? 1e3 : 128)));
463
+
464
+ value = mode == 'mem' ? value.toFixed(2) : round(value);
465
+ data.length = [data.length, data.unshift({ 'value': value, 'percent': percent })][0];
466
+
467
+ value = floor(value);
468
+ data.min = min(data.min != null ? data.min : value, value);
469
+ data.max = max(data.max != null ? data.max : value, value);
470
+ }
471
+
472
+ /**
473
+ * Sets the LI element's height based on the given value.
474
+ *
475
+ * @private
476
+ * @param {Object} me The xStats instance.
477
+ * @param {Object} node The LI element.
478
+ * @param {Number} percent The bar height as a percentage.
479
+ */
480
+ function setBar(me, node, percent) {
481
+ var height = 100,
482
+ base = (height / 16) * 15,
483
+ portion = (base / 100) * percent,
484
+ value = percent != null ? (base - portion).toFixed(2) : height;
485
+
486
+ node.style.height = value + '%';
487
+ }
488
+
489
+ /**
490
+ * Sets a chart's title based on the given value.
491
+ *
492
+ * @private
493
+ * @param {Object} me The xStats instance.
494
+ * @param {Number} value The value.
495
+ */
496
+ function setTitle(me, value) {
497
+ var mode = me.mode,
498
+ unit = mode == 'mem' ? 'MB' : mode.toUpperCase(),
499
+ data = cache.data[mode];
500
+
501
+ me.title.nodeValue = value == null ? ' ' :
502
+ value + unit + ' (' + data.min + '-' + data.max + ')';
503
+ }
504
+
505
+ /**
506
+ * Updates chart data and display of all xStats instances.
507
+ *
508
+ * @private
509
+ */
510
+ function update() {
511
+ var length,
512
+ data = cache.data,
513
+ frameTimes = cache.frameTimes,
514
+ fps = 0,
515
+ now = new Date,
516
+ secValue = now - cache.lastSecond,
517
+ lastSec = new Date - 1000;
518
+
519
+ // skip first call
520
+ if (cache.lastTime != null) {
521
+ // record data
522
+ frameTimes.push(new Date);
523
+ record('ms', now - cache.lastTime);
524
+ if (secValue > 999) {
525
+ length = frameTimes.length;
526
+ //console.log('length', length);
527
+ while (length--) {
528
+ if (frameTimes[length] < lastSec) {
529
+ break;
530
+ }
531
+ fps++;
532
+ }
533
+ //console.log('fps', fps);
534
+ record('fps', fps);
535
+ memoryNS && record('mem', memoryNS.memory.usedJSHeapSize / 1048576);
536
+ cache.frameTimes = frameTimes.slice(length);
537
+ cache.lastSecond = now;
538
+ }
539
+ // render instances
540
+ each(xStats.subclasses, function(subclass) {
541
+ var canvas = subclass.canvas,
542
+ mode = subclass.mode,
543
+ entry = data[mode][0];
544
+
545
+ if (entry && (mode == 'ms' || cache.lastSecond == now)) {
546
+ setTitle(subclass, entry.value);
547
+ setBar(subclass, canvas.insertBefore(canvas.lastChild, canvas.firstChild), entry.percent);
548
+ }
549
+ });
550
+ }
551
+ else {
552
+ cache.lastSecond = now;
553
+ }
554
+ cache.lastTime = now;
555
+ }
556
+
557
+ /*--------------------------------------------------------------------------*/
558
+
559
+ /**
560
+ * An array of xStat instances.
561
+ *
562
+ * @static
563
+ * @memberOf xStats
564
+ * @type Array
565
+ */
566
+ xStats.subclasses = [];
567
+
568
+ /*--------------------------------------------------------------------------*/
569
+
570
+ extend(xStats.prototype, {
571
+
572
+ /**
573
+ * The height of the chart (px).
574
+ *
575
+ * @memberOf xStats
576
+ * @type Number
577
+ */
578
+ 'height': 48,
579
+
580
+ /**
581
+ * The width of the chart (px).
582
+ *
583
+ * @memberOf xStats
584
+ * @type Number
585
+ */
586
+ 'width': 94,
587
+
588
+ /**
589
+ * The inner padding of the chart that doesn't affect dimensions (px).
590
+ *
591
+ * @memberOf xStats
592
+ * @type Number
593
+ */
594
+ 'padding': 3,
595
+
596
+ /**
597
+ * A flag to indicate if the chart is locked at its current display mode.
598
+ *
599
+ * @memberOf xStats
600
+ * @type Boolean
601
+ */
602
+ 'locked': false,
603
+
604
+ /**
605
+ * The charts current display mode (fps, ms, mem).
606
+ *
607
+ * @memberOf xStats
608
+ * @type String
609
+ */
610
+ 'mode': 'fps',
611
+
612
+ /**
613
+ * The rate at which the "sample" event is emitted (secs).
614
+ *
615
+ * @memberOf xStats
616
+ * @type Number
617
+ */
618
+ 'sampleRate': 0,
619
+
620
+ /**
621
+ * Alias of [`xStats#addListener`](#xStats:addListener).
622
+ *
623
+ * @memberOf xStats
624
+ * @type Function
625
+ */
626
+ 'on': addListener,
627
+
628
+ /**
629
+ * The "frames per second" display mode options object.
630
+ *
631
+ * @memberOf xStats
632
+ * @type Object
633
+ */
634
+ 'fps': {
635
+
636
+ /**
637
+ * The background color of the chart for the display mode.
638
+ *
639
+ * @memberOf xStats#fps
640
+ * @type String
641
+ */
642
+ 'bg': '#282845',
643
+
644
+ /**
645
+ * The foreground color of the chart for the display mode.
646
+ *
647
+ * @memberOf xStats#fps
648
+ * @type String
649
+ */
650
+ 'fg': '#1affff'
651
+ },
652
+
653
+ /**
654
+ * The "millisecond" display mode options object.
655
+ *
656
+ * @memberOf xStats
657
+ * @type Object
658
+ */
659
+ 'ms': {
660
+
661
+ /**
662
+ * The background color of the chart for the display mode.
663
+ *
664
+ * @memberOf xStats#ms
665
+ * @type String
666
+ */
667
+ 'bg': '#284528',
668
+
669
+ /**
670
+ * The foreground color of the chart for the display mode.
671
+ *
672
+ * @memberOf xStats#ms
673
+ * @type String
674
+ */
675
+ 'fg': '#1aff1a'
676
+ },
677
+
678
+ /**
679
+ * The "memory" display mode options object.
680
+ *
681
+ * @memberOf xStats
682
+ * @type Object
683
+ */
684
+ 'mem': {
685
+
686
+ /**
687
+ * The background color of the chart for the display mode.
688
+ *
689
+ * @memberOf xStats#mem
690
+ * @type String
691
+ */
692
+ 'bg': '#452831',
693
+
694
+ /**
695
+ * The foreground color of the chart for the display mode.
696
+ *
697
+ * @memberOf xStats#mem
698
+ * @type String
699
+ */
700
+ 'fg': '#ff1a8d'
701
+ },
702
+
703
+ // registers a single listener
704
+ 'addListener': addListener,
705
+
706
+ // executes listeners of a specified type
707
+ 'emit': emit,
708
+
709
+ // removes all listeners of a specified type
710
+ 'removeAllListeners': removeAllListeners,
711
+
712
+ // removes a single listener
713
+ 'removeListener': removeListener
714
+ });
715
+
716
+ /*--------------------------------------------------------------------------*/
717
+
718
+ /**
719
+ * The event type.
720
+ *
721
+ * @memberOf xStats.Event
722
+ * @type String
723
+ */
724
+ Event.prototype.type = '';
725
+
726
+ /*--------------------------------------------------------------------------*/
727
+
728
+ // expose Event
729
+ xStats.Event = Event;
730
+
731
+ // expose xStats
732
+ // use square bracket notation so Closure Compiler won't munge `xStats`
733
+ // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export
734
+ window['xStats'] = xStats;
735
+
736
+ // ensure we can read memory info
737
+ memoryNS = memoryNS && !!memoryNS.memory.usedJSHeapSize && memoryNS;
738
+
739
+ // start recording
740
+ setInterval(update, 1e3 / 60);
741
+
742
+ // start sampling (once every two seconds)
743
+ setInterval(function() {
744
+ var data = cache.data,
745
+ fps = data.fps[0],
746
+ mem = data.mem[0],
747
+ ms = data.ms[0];
748
+
749
+ each(xStats.subclasses, function(subclass) {
750
+ subclass.emit('sample', {
751
+ 'fps': fps && fps.value,
752
+ 'mem': mem && mem.value,
753
+ 'ms': ms && ms.value
754
+ });
755
+ });
756
+ }, 2e3);
757
+
758
+ // shared CSS
759
+ appendCSS(
760
+ '.xstats div{position:absolute;overflow:hidden}' +
761
+ '.xstats p{margin:0;overflow:hidden;font-family:sans-serif;-webkit-text-size-adjust:100%}' +
762
+ '.xstats ul{margin:0;padding:0;list-style:none;overflow:hidden}' +
763
+ '.xstats li{float:right;height:100%;margin-left:-4px}' +
764
+ '.xstats .bg{opacity:.5;filter:alpha(opacity=50)}' +
765
+ '.xstats{cursor:pointer;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-o-user-select:none;user-select:none}');
766
+
767
+ }(this, this.document));