├── LICENSE
├── README.md
├── demo
├── disc.png
├── header.jpg
├── index.html
├── rStats.css
└── three.min.js
├── package.json
└── src
├── rStats.extras.js
└── rStats.js
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Jaume Sanchez Elias
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rStats
2 |
3 | rStats aims to provide a way of measuring and visualizing performance of your code, mainly in apps based on an update loop, like games or interactive experiences.
4 |
5 | You can read more here [Introduction and demos](http://spite.github.io/rstats)
6 |
7 | # Credits
8 |
9 | Jaume Sanchez Elias [@thespite](http://www.twitter.com/thespite)
10 | [www.clicktorelease.com](http://www.clicktorelease.com)
--------------------------------------------------------------------------------
/demo/disc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/rstats/7b10eba2c14e27b5dfa575614abbb49241427ac5/demo/disc.png
--------------------------------------------------------------------------------
/demo/header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/rstats/7b10eba2c14e27b5dfa575614abbb49241427ac5/demo/header.jpg
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | rStats test
6 |
7 |
8 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
395 |
396 |
397 |
398 |
--------------------------------------------------------------------------------
/demo/rStats.css:
--------------------------------------------------------------------------------
1 | .alarm{
2 | color: #b70000;
3 | text-shadow: 0 0 0 #b70000,
4 | 0 0 1px #fff,
5 | 0 0 1px #fff,
6 | 0 0 2px #fff,
7 | 0 0 2px #fff,
8 | 0 0 3px #fff,
9 | 0 0 3px #fff,
10 | 0 0 4px #fff,
11 | 0 0 4px #fff;
12 | }
13 |
14 | .rs-base{
15 | position: absolute;
16 | z-index: 10000;
17 | padding: 10px;
18 | background-color: #222;
19 | font-size: 10px;
20 | line-height: 1.2em;
21 | width: 350px;
22 | font-family: 'Roboto Condensed', tahoma, sans-serif;
23 | left: 0;
24 | top: 0;
25 | overflow: hidden;
26 | }
27 |
28 | .rs-base h1{
29 | margin: 0;
30 | padding: 0;
31 | font-size: 1.4em;
32 | color: #fff;
33 | margin-bottom: 5px;
34 | cursor: pointer;
35 | }
36 |
37 | .rs-base div.rs-group{
38 | margin-bottom: 10px;
39 | }
40 |
41 | .rs-base div.rs-group.hidden{
42 | display: none;
43 | }
44 |
45 | .rs-base div.rs-fraction{
46 | position: relative;
47 | margin-bottom: 5px;
48 | }
49 |
50 | .rs-base div.rs-fraction p{
51 | width: 120px;
52 | text-align: right;
53 | margin: 0;
54 | padding: 0;
55 | }
56 |
57 | .rs-base div.rs-legend{
58 | position: absolute;
59 | line-height: 1em;
60 | }
61 |
62 | .rs-base div.rs-counter-base{
63 | position: relative;
64 | margin: 2px 0;
65 | height: 1em;
66 | }
67 |
68 | .rs-base span.rs-counter-id{
69 | position: absolute;
70 | left: 0;
71 | top: 0;
72 | }
73 |
74 | .rs-base div.rs-counter-value{
75 | position: absolute;
76 | left: 90px;
77 | width: 30px;
78 | height: 1em;
79 | top: 0;
80 | text-align: right;
81 | }
82 |
83 | .rs-base canvas.rs-canvas{
84 | position: absolute;
85 | right: 0;
86 | }
87 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rstatsjs",
3 | "version": "1.0.1",
4 | "description": "JavaScript Performance Monitor",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/spite/rstats.git"
12 | },
13 | "keywords": [
14 | "stats"
15 | ],
16 | "author": "Jaume Sanchez (https://www.clicktorelease.com)",
17 | "license": "MIT",
18 | "bugs": {
19 | "url": "https://github.com/spite/rstats/issues"
20 | },
21 | "homepage": "https://github.com/spite/rstats#readme"
22 | }
23 |
--------------------------------------------------------------------------------
/src/rStats.extras.js:
--------------------------------------------------------------------------------
1 | window.glStats = function () {
2 |
3 | var _rS = null;
4 |
5 | var _totalDrawArraysCalls = 0,
6 | _totalDrawElementsCalls = 0,
7 | _totalUseProgramCalls = 0,
8 | _totalFaces = 0,
9 | _totalVertices = 0,
10 | _totalPoints = 0,
11 | _totalBindTexures = 0;
12 |
13 | function _h ( f, c ) {
14 | return function () {
15 | c.apply( this, arguments );
16 | f.apply( this, arguments );
17 | };
18 | }
19 |
20 | WebGLRenderingContext.prototype.drawArrays = _h( WebGLRenderingContext.prototype.drawArrays, function () {
21 | _totalDrawArraysCalls++;
22 | if ( arguments[ 0 ] == this.POINTS ) _totalPoints += arguments[ 2 ];
23 | else _totalVertices += arguments[ 2 ];
24 | } );
25 |
26 | WebGLRenderingContext.prototype.drawElements = _h( WebGLRenderingContext.prototype.drawElements, function () {
27 | _totalDrawElementsCalls++;
28 | _totalFaces += arguments[ 1 ] / 3;
29 | _totalVertices += arguments[ 1 ];
30 | } );
31 |
32 | WebGLRenderingContext.prototype.useProgram = _h( WebGLRenderingContext.prototype.useProgram, function () {
33 | _totalUseProgramCalls++;
34 | } );
35 |
36 | WebGLRenderingContext.prototype.bindTexture = _h( WebGLRenderingContext.prototype.bindTexture, function () {
37 | _totalBindTexures++;
38 | } );
39 |
40 | var _values = {
41 | allcalls: {
42 | over: 3000,
43 | caption: 'Calls (hook)'
44 | },
45 | drawelements: {
46 | caption: 'drawElements (hook)'
47 | },
48 | drawarrays: {
49 | caption: 'drawArrays (hook)'
50 | }
51 | };
52 |
53 | var _groups = [ {
54 | caption: 'WebGL',
55 | values: [ 'allcalls', 'drawelements', 'drawarrays', 'useprogram', 'bindtexture', 'glfaces', 'glvertices', 'glpoints' ]
56 | } ];
57 |
58 | var _fractions = [ {
59 | base: 'allcalls',
60 | steps: [ 'drawelements', 'drawarrays' ]
61 | } ];
62 |
63 | function _update () {
64 | _rS( 'allcalls' ).set( _totalDrawArraysCalls + _totalDrawElementsCalls );
65 | _rS( 'drawElements' ).set( _totalDrawElementsCalls );
66 | _rS( 'drawArrays' ).set( _totalDrawArraysCalls );
67 | _rS( 'bindTexture' ).set( _totalBindTexures );
68 | _rS( 'useProgram' ).set( _totalUseProgramCalls );
69 | _rS( 'glfaces' ).set( _totalFaces );
70 | _rS( 'glvertices' ).set( _totalVertices );
71 | _rS( 'glpoints' ).set( _totalPoints );
72 | }
73 |
74 | function _start () {
75 | _totalDrawArraysCalls = 0;
76 | _totalDrawElementsCalls = 0;
77 | _totalUseProgramCalls = 0;
78 | _totalFaces = 0;
79 | _totalVertices = 0;
80 | _totalPoints = 0;
81 | _totalBindTexures = 0;
82 | }
83 |
84 | function _end () {}
85 |
86 | function _attach ( r ) {
87 | _rS = r;
88 | }
89 |
90 | return {
91 | update: _update,
92 | start: _start,
93 | end: _end,
94 | attach: _attach,
95 | values: _values,
96 | groups: _groups,
97 | fractions: _fractions
98 | };
99 |
100 | };
101 |
102 | window.threeStats = function ( renderer ) {
103 |
104 | var _rS = null;
105 |
106 | var _values = {
107 | 'renderer.info.memory.geometries': {
108 | caption: 'Geometries'
109 | },
110 | 'renderer.info.memory.textures': {
111 | caption: 'Textures'
112 | },
113 | 'renderer.info.programs': {
114 | caption: 'Programs'
115 | },
116 | 'renderer.info.render.calls': {
117 | caption: 'Calls'
118 | },
119 | 'renderer.info.render.faces': {
120 | caption: 'Faces',
121 | over: 1000
122 | },
123 | 'renderer.info.render.points': {
124 | caption: 'Points'
125 | },
126 | 'renderer.info.render.vertices': {
127 | caption: 'Vertices'
128 | }
129 | };
130 |
131 | var _groups = [ {
132 | caption: 'Three.js - Memory',
133 | values: [ 'renderer.info.memory.geometries', 'renderer.info.programs', 'renderer.info.memory.textures' ]
134 | }, {
135 | caption: 'Three.js - Render',
136 | values: [ 'renderer.info.render.calls', 'renderer.info.render.faces', 'renderer.info.render.points', 'renderer.info.render.vertices' ]
137 | } ];
138 |
139 | var _fractions = [];
140 |
141 | function _update () {
142 |
143 | _rS( 'renderer.info.memory.geometries' ).set( renderer.info.memory.geometries );
144 | //_rS( 'renderer.info.programs' ).set( renderer.info.programs.length );
145 | _rS( 'renderer.info.memory.textures' ).set( renderer.info.memory.textures );
146 | _rS( 'renderer.info.render.calls' ).set( renderer.info.render.calls );
147 | _rS( 'renderer.info.render.faces' ).set( renderer.info.render.faces );
148 | _rS( 'renderer.info.render.points' ).set( renderer.info.render.points );
149 | _rS( 'renderer.info.render.vertices' ).set( renderer.info.render.vertices );
150 |
151 | }
152 |
153 | function _start () {}
154 |
155 | function _end () {}
156 |
157 | function _attach ( r ) {
158 | _rS = r;
159 | }
160 |
161 | return {
162 | update: _update,
163 | start: _start,
164 | end: _end,
165 | attach: _attach,
166 | values: _values,
167 | groups: _groups,
168 | fractions: _fractions
169 | };
170 |
171 | };
172 |
173 | /*
174 | * From https://github.com/paulirish/memory-stats.js
175 | */
176 |
177 | window.BrowserStats = function () {
178 |
179 | var _rS = null;
180 |
181 | var _usedJSHeapSize = 0,
182 | _totalJSHeapSize = 0;
183 |
184 | var memory = {
185 | usedJSHeapSize: 0,
186 | totalJSHeapSize: 0
187 | };
188 |
189 | if ( window.performance && performance.memory )
190 | memory = performance.memory;
191 |
192 | if ( memory.totalJSHeapSize === 0 ) {
193 | console.warn( 'totalJSHeapSize === 0... performance.memory is only available in Chrome .' );
194 | }
195 |
196 | var _values = {
197 | memory: {
198 | caption: 'Used Memory',
199 | average: true,
200 | avgMs: 1000,
201 | over: 22
202 | },
203 | total: {
204 | caption: 'Total Memory'
205 | }
206 | };
207 |
208 | var _groups = [ {
209 | caption: 'Browser',
210 | values: [ 'memory', 'total' ]
211 | } ];
212 |
213 | var _fractions = [ {
214 | base: 'total',
215 | steps: [ 'memory' ]
216 | } ];
217 |
218 | var log1024 = Math.log( 1024 );
219 |
220 | function _size ( v ) {
221 |
222 | var precision = 100; //Math.pow(10, 2);
223 | var i = Math.floor( Math.log( v ) / log1024 );
224 | if( v === 0 ) i = 1;
225 | return Math.round( v * precision / Math.pow( 1024, i ) ) / precision; // + ' ' + sizes[i];
226 |
227 | }
228 |
229 | function _update () {
230 | _usedJSHeapSize = _size( memory.usedJSHeapSize );
231 | _totalJSHeapSize = _size( memory.totalJSHeapSize );
232 |
233 | _rS( 'memory' ).set( _usedJSHeapSize );
234 | _rS( 'total' ).set( _totalJSHeapSize );
235 | }
236 |
237 | function _start () {
238 | _usedJSHeapSize = 0;
239 | }
240 |
241 | function _end () {}
242 |
243 | function _attach ( r ) {
244 | _rS = r;
245 | }
246 |
247 | return {
248 | update: _update,
249 | start: _start,
250 | end: _end,
251 | attach: _attach,
252 | values: _values,
253 | groups: _groups,
254 | fractions: _fractions
255 | };
256 |
257 | };
258 |
259 | if (typeof module === 'object') {
260 | module.exports = {
261 | glStats: window.glStats,
262 | threeStats: window.threeStats,
263 | BrowserStats: window.BrowserStats
264 | };
265 | }
266 |
--------------------------------------------------------------------------------
/src/rStats.js:
--------------------------------------------------------------------------------
1 | // performance.now() polyfill from https://gist.github.com/paulirish/5438650
2 | 'use strict';
3 |
4 | ( function () {
5 |
6 | // prepare base perf object
7 | if ( typeof window.performance === 'undefined' ) {
8 | window.performance = {};
9 | }
10 |
11 | if ( !window.performance.now ) {
12 |
13 | var nowOffset = Date.now();
14 |
15 | if ( performance.timing && performance.timing.navigationStart ) {
16 | nowOffset = performance.timing.navigationStart;
17 | }
18 |
19 | window.performance.now = function now () {
20 | return Date.now() - nowOffset;
21 | };
22 |
23 | }
24 |
25 | if( !window.performance.mark ) {
26 | window.performance.mark = function(){}
27 | }
28 |
29 | if( !window.performance.measure ) {
30 | window.performance.measure = function(){}
31 | }
32 |
33 | } )();
34 |
35 | /**
36 | * @class rStats
37 | * @param {rStats~Settings} [settings] Settings for the rStats instance.
38 | */
39 |
40 | /**
41 | * @typedef {Object} rStats~Settings
42 | * @property {Array.} [colours] An array of CSS colour values.
43 | * @property {String} [CSSPath=''] Base URL where rStats.css is located.
44 | * @property {Array.} [css] URLs of CSS or font files to import.
45 | * @property {Object.} [values] Properties to use for each counter.
46 | * @property {Array.} [groups] Define groups of counters.
47 | * @property {Array.} [fractions] Define stacked counters.
48 | * @property {Array.} [plugins] Additional plugins.
49 | */
50 |
51 | /**
52 | * @typedef {Object} rStats~CounterProperties
53 | * @property {String} [caption] Caption for this counter.
54 | * @property {Boolean} [average=false] Whether the values should be averaged.
55 | * @property {Number} [avgMs=1000] Duration for which the values should be averaged.
56 | * @property {Number} [below] Value below which the graph should be highlighted.
57 | * @property {Number} [over] Value over which the graph should be highlighted.
58 | * @property {Boolean} [interpolate=true] Whether framerate should be interpolated.
59 | */
60 |
61 | window.rStats = function rStats ( settings ) {
62 |
63 | function iterateKeys ( array, callback ) {
64 | var keys = Object.keys( array );
65 | for ( var j = 0, l = keys.length; j < l; j++ ) {
66 | callback( keys[ j ] );
67 | }
68 | }
69 |
70 | function importCSS ( url ) {
71 |
72 | var element = document.createElement( 'link' );
73 | element.href = url;
74 | element.rel = 'stylesheet';
75 | element.type = 'text/css';
76 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( element );
77 |
78 | }
79 |
80 | var _settings = settings || {};
81 | var _colours = _settings.colours || [ '#850700', '#c74900', '#fcb300', '#284280', '#4c7c0c' ];
82 |
83 | var _cssFont = 'https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700,300';
84 | var _cssRStats = ( _settings.CSSPath ? _settings.CSSPath : '' ) + 'rStats.css';
85 |
86 | var _css = _settings.css || [ _cssFont, _cssRStats ];
87 | _css.forEach(function (uri) {
88 | importCSS( uri );
89 | });
90 |
91 | if ( !_settings.values ) _settings.values = {};
92 |
93 | var _base, _div, _elHeight = 10, _elWidth = 200;
94 | var _perfCounters = {};
95 |
96 |
97 | function Graph ( _dom, _id, _defArg ) {
98 |
99 | var _def = _defArg || {};
100 | var _canvas = document.createElement( 'canvas' ),
101 | _ctx = _canvas.getContext( '2d' ),
102 | _max = 0,
103 | _current = 0;
104 |
105 | var c = _def.color ? _def.color : '#666666';
106 |
107 | var _dotCanvas = document.createElement( 'canvas' ),
108 | _dotCtx = _dotCanvas.getContext( '2d' );
109 | _dotCanvas.width = 1;
110 | _dotCanvas.height = 2 * _elHeight;
111 | _dotCtx.fillStyle = '#444444';
112 | _dotCtx.fillRect( 0, 0, 1, 2 * _elHeight );
113 | _dotCtx.fillStyle = c;
114 | _dotCtx.fillRect( 0, _elHeight, 1, _elHeight );
115 | _dotCtx.fillStyle = '#ffffff';
116 | _dotCtx.globalAlpha = 0.5;
117 | _dotCtx.fillRect( 0, _elHeight, 1, 1 );
118 | _dotCtx.globalAlpha = 1;
119 |
120 | var _alarmCanvas = document.createElement( 'canvas' ),
121 | _alarmCtx = _alarmCanvas.getContext( '2d' );
122 | _alarmCanvas.width = 1;
123 | _alarmCanvas.height = 2 * _elHeight;
124 | _alarmCtx.fillStyle = '#444444';
125 | _alarmCtx.fillRect( 0, 0, 1, 2 * _elHeight );
126 | _alarmCtx.fillStyle = '#b70000';
127 | _alarmCtx.fillRect( 0, _elHeight, 1, _elHeight );
128 | _alarmCtx.globalAlpha = 0.5;
129 | _alarmCtx.fillStyle = '#ffffff';
130 | _alarmCtx.fillRect( 0, _elHeight, 1, 1 );
131 | _alarmCtx.globalAlpha = 1;
132 |
133 | function _init () {
134 |
135 | _canvas.width = _elWidth;
136 | _canvas.height = _elHeight;
137 | _canvas.style.width = _canvas.width + 'px';
138 | _canvas.style.height = _canvas.height + 'px';
139 | _canvas.className = 'rs-canvas';
140 | _dom.appendChild( _canvas );
141 |
142 | _ctx.fillStyle = '#444444';
143 | _ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
144 |
145 | }
146 |
147 | function _draw ( v, alarm ) {
148 | _current += ( v - _current ) * 0.1;
149 | _max *= 0.99;
150 | if ( _current > _max ) _max = _current;
151 | _ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
152 | if ( alarm ) {
153 | _ctx.drawImage( _alarmCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
154 | } else {
155 | _ctx.drawImage( _dotCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
156 | }
157 | }
158 |
159 | _init();
160 |
161 | return {
162 | draw: _draw
163 | };
164 |
165 | }
166 |
167 | function StackGraph ( _dom, _num ) {
168 |
169 | var _canvas = document.createElement( 'canvas' ),
170 | _ctx = _canvas.getContext( '2d' );
171 |
172 | function _init () {
173 |
174 | _canvas.width = _elWidth;
175 | _canvas.height = _elHeight * _num;
176 | _canvas.style.width = _canvas.width + 'px';
177 | _canvas.style.height = _canvas.height + 'px';
178 | _canvas.className = 'rs-canvas';
179 | _dom.appendChild( _canvas );
180 |
181 | _ctx.fillStyle = '#444444';
182 | _ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
183 |
184 | }
185 |
186 | function _draw ( v ) {
187 | _ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
188 | var th = 0;
189 | iterateKeys( v, function ( j ) {
190 | var h = v[ j ] * _canvas.height;
191 | _ctx.fillStyle = _colours[ j ];
192 | _ctx.fillRect( _canvas.width - 1, th, 1, h );
193 | th += h;
194 | } );
195 | }
196 |
197 | _init();
198 |
199 | return {
200 | draw: _draw
201 | };
202 |
203 | }
204 |
205 | function PerfCounter ( id, group ) {
206 |
207 | var _id = id,
208 | _time,
209 | _value = 0,
210 | _total = 0,
211 | _averageValue = 0,
212 | _accumValue = 0,
213 | _accumStart = performance.now(),
214 | _accumSamples = 0,
215 | _dom = document.createElement( 'div' ),
216 | _spanId = document.createElement( 'span' ),
217 | _spanValue = document.createElement( 'div' ),
218 | _spanValueText = document.createTextNode( '' ),
219 | _def = _settings ? _settings.values[ _id.toLowerCase() ] : null,
220 | _graph = new Graph( _dom, _id, _def ),
221 | _started = false;
222 |
223 | _spanId.className = 'rs-counter-id';
224 | _spanId.textContent = ( _def && _def.caption ) ? _def.caption : _id;
225 |
226 | _spanValue.className = 'rs-counter-value';
227 | _spanValue.appendChild( _spanValueText );
228 |
229 | _dom.appendChild( _spanId );
230 | _dom.appendChild( _spanValue );
231 | if ( group ) group.div.appendChild( _dom );
232 | else _div.appendChild( _dom );
233 |
234 | _time = performance.now();
235 |
236 | function _average ( v ) {
237 | if ( _def && _def.average ) {
238 | _accumValue += v;
239 | _accumSamples++;
240 | var t = performance.now();
241 | if ( t - _accumStart >= ( _def.avgMs || 1000 ) ) {
242 | _averageValue = _accumValue / _accumSamples;
243 | _accumValue = 0;
244 | _accumStart = t;
245 | _accumSamples = 0;
246 | }
247 | }
248 | }
249 |
250 | function _start () {
251 | _time = performance.now();
252 | if( _settings.userTimingAPI ) performance.mark( _id + '-start' );
253 | _started = true;
254 | }
255 |
256 | function _end () {
257 | _value = performance.now() - _time;
258 | if( _settings.userTimingAPI ) {
259 | performance.mark( _id + '-end' );
260 | if( _started ) {
261 | performance.measure( _id, _id + '-start', _id + '-end' );
262 | }
263 | }
264 | _average( _value );
265 | }
266 |
267 | function _tick () {
268 | _end();
269 | _start();
270 | }
271 |
272 | function _draw () {
273 | var v = ( _def && _def.average ) ? _averageValue : _value;
274 | _spanValueText.nodeValue = Math.round( v * 100 ) / 100;
275 | var a = ( _def && ( ( _def.below && _value < _def.below ) || ( _def.over && _value > _def.over ) ) );
276 | _graph.draw( _value, a );
277 | _dom.className = a ? 'rs-counter-base alarm' : 'rs-counter-base';
278 |
279 | }
280 |
281 | function _frame () {
282 | var t = performance.now();
283 | var e = t - _time;
284 | _total++;
285 | if ( e > 1000 ) {
286 | if ( _def && _def.interpolate === false ) {
287 | _value = _total;
288 | } else {
289 | _value = _total * 1000 / e;
290 | }
291 | _total = 0;
292 | _time = t;
293 | _average( _value );
294 | }
295 | }
296 |
297 | function _set ( v ) {
298 | _value = v;
299 | _average( _value );
300 | }
301 |
302 | return {
303 | set: _set,
304 | start: _start,
305 | tick: _tick,
306 | end: _end,
307 | frame: _frame,
308 | value: function () {
309 | return _value;
310 | },
311 | draw: _draw
312 | };
313 |
314 | }
315 |
316 | function sample () {
317 |
318 | var _value = 0;
319 |
320 | function _set ( v ) {
321 | _value = v;
322 | }
323 |
324 | return {
325 | set: _set,
326 | value: function () {
327 | return _value;
328 | }
329 | };
330 |
331 | }
332 |
333 | function _perf ( idArg ) {
334 |
335 | var id = idArg.toLowerCase();
336 | if ( id === undefined ) id = 'default';
337 | if ( _perfCounters[ id ] ) return _perfCounters[ id ];
338 |
339 | var group = null;
340 | if ( _settings && _settings.groups ) {
341 | iterateKeys( _settings.groups, function ( j ) {
342 | var g = _settings.groups[ parseInt( j, 10 ) ];
343 | if ( !group && g.values.indexOf( id.toLowerCase() ) !== -1 ) {
344 | group = g;
345 | }
346 | } );
347 | }
348 |
349 | var p = new PerfCounter( id, group );
350 | _perfCounters[ id ] = p;
351 | return p;
352 |
353 | }
354 |
355 | function _init () {
356 |
357 | if ( _settings.plugins ) {
358 | if ( !_settings.values ) _settings.values = {};
359 | if ( !_settings.groups ) _settings.groups = [];
360 | if ( !_settings.fractions ) _settings.fractions = [];
361 | for ( var j = 0; j < _settings.plugins.length; j++ ) {
362 | _settings.plugins[ j ].attach( _perf );
363 | iterateKeys( _settings.plugins[ j ].values, function ( k ) {
364 | _settings.values[ k ] = _settings.plugins[ j ].values[ k ];
365 | } );
366 | _settings.groups = _settings.groups.concat( _settings.plugins[ j ].groups );
367 | _settings.fractions = _settings.fractions.concat( _settings.plugins[ j ].fractions );
368 | }
369 | } else {
370 | _settings.plugins = {};
371 | }
372 |
373 | _base = document.createElement( 'div' );
374 | _base.className = 'rs-base';
375 | _div = document.createElement( 'div' );
376 | _div.className = 'rs-container';
377 | _div.style.height = 'auto';
378 | _base.appendChild( _div );
379 | document.body.appendChild( _base );
380 |
381 | if ( !_settings ) return;
382 |
383 | if ( _settings.groups ) {
384 | iterateKeys( _settings.groups, function ( j ) {
385 | var g = _settings.groups[ parseInt( j, 10 ) ];
386 | var div = document.createElement( 'div' );
387 | div.className = 'rs-group';
388 | g.div = div;
389 | var h1 = document.createElement( 'h1' );
390 | h1.textContent = g.caption;
391 | h1.addEventListener( 'click', function ( e ) {
392 | this.classList.toggle( 'hidden' );
393 | e.preventDefault();
394 | }.bind( div ) );
395 | _div.appendChild( h1 );
396 | _div.appendChild( div );
397 | } );
398 | }
399 |
400 | if ( _settings.fractions ) {
401 | iterateKeys( _settings.fractions, function ( j ) {
402 | var f = _settings.fractions[ parseInt( j, 10 ) ];
403 | var div = document.createElement( 'div' );
404 | div.className = 'rs-fraction';
405 | var legend = document.createElement( 'div' );
406 | legend.className = 'rs-legend';
407 |
408 | var h = 0;
409 | iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
410 | var p = document.createElement( 'p' );
411 | p.textContent = _settings.fractions[ j ].steps[ k ];
412 | p.style.color = _colours[ h ];
413 | legend.appendChild( p );
414 | h++;
415 | } );
416 | div.appendChild( legend );
417 | div.style.height = h * _elHeight + 'px';
418 | f.div = div;
419 | var graph = new StackGraph( div, h );
420 | f.graph = graph;
421 | _div.appendChild( div );
422 | } );
423 | }
424 |
425 | }
426 |
427 | function _update () {
428 |
429 | iterateKeys( _settings.plugins, function ( j ) {
430 | _settings.plugins[ j ].update();
431 | } );
432 |
433 | iterateKeys( _perfCounters, function ( j ) {
434 | _perfCounters[ j ].draw();
435 | } );
436 |
437 | if ( _settings && _settings.fractions ) {
438 | iterateKeys( _settings.fractions, function ( j ) {
439 | var f = _settings.fractions[ parseInt( j, 10 ) ];
440 | var v = [];
441 | var base = _perfCounters[ f.base.toLowerCase() ];
442 | if ( base ) {
443 | base = base.value();
444 | iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
445 | var s = _settings.fractions[ j ].steps[ parseInt( k, 10 ) ].toLowerCase();
446 | var val = _perfCounters[ s ];
447 | if ( val ) {
448 | v.push( val.value() / base );
449 | }
450 | } );
451 | }
452 | f.graph.draw( v );
453 | } );
454 | }
455 |
456 | /*if( _height != _div.clientHeight ) {
457 | _height = _div.clientHeight;
458 | _base.style.height = _height + 2 * _elHeight + 'px';
459 | console.log( _base.clientHeight );
460 | }*/
461 |
462 | }
463 |
464 | _init();
465 |
466 | return function ( id ) {
467 | if ( id ) return _perf( id );
468 | return {
469 | element: _base,
470 | update: _update
471 | };
472 | };
473 |
474 | }
475 |
476 | if (typeof module === 'object') {
477 | module.exports = window.rStats;
478 | }
479 |
--------------------------------------------------------------------------------