shank 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,767 +0,0 @@
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));