shank 0.0.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.
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));