├── src ├── styles │ ├── main.less │ ├── forms.less │ └── panel.less ├── hbs │ └── scene │ │ ├── panel.hbs │ │ ├── tree.hbs │ │ └── details.hbs ├── panels │ ├── Panel.js │ ├── Performance.js │ └── Scene.js ├── util │ ├── ui.js │ └── Graph.js └── index.js ├── .gitignore ├── .editorconfig ├── LICENSE ├── package.json ├── README.md ├── gulpfile.js ├── CONTRIBUTING.md ├── .jshintrc └── dist └── phaser-debug.js /src/styles/main.less: -------------------------------------------------------------------------------- 1 | @import "panel.less"; 2 | @import "forms.less"; 3 | -------------------------------------------------------------------------------- /src/hbs/scene/panel.hbs: -------------------------------------------------------------------------------- 1 | 3 | 4 | refresh 5 |
6 |
7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # sublime text 2 files 2 | *.sublime* 3 | *.*~*.TMP 4 | 5 | # temp files 6 | .DS_Store 7 | Thumbs.db 8 | Desktop.ini 9 | npm-debug.log 10 | 11 | # vim swap files 12 | *.sw* 13 | 14 | # emacs temp files 15 | *~ 16 | \#*# 17 | 18 | # project ignores 19 | !.gitkeep 20 | *__temp 21 | node_modules/* 22 | build/* 23 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Unix-style newlines with a newline ending every file 2 | [*] 3 | end_of_line = lf 4 | insert_final_newline = true 5 | trim_trailing_whitespace = true 6 | indent_style = space 7 | indent_size = 4 8 | 9 | [*.md] 10 | trim_trailing_whitespace = false 11 | 12 | [{package.json,bower.json,.travis.yml}] 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /src/hbs/scene/tree.hbs: -------------------------------------------------------------------------------- 1 | {{listItemOpen}} 2 | {{typeString}} 3 | 4 | {{#if name}} 5 | ({{name}}) 6 | {{/if}} 7 | 8 | {{#if children}} 9 | 14 | {{/if}} 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014 Chad Engler 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. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phaser-debug", 3 | "version": "1.1.9", 4 | "description": "Simple debug module for phaser", 5 | "author": "Chad Engler ", 6 | "license": "MIT", 7 | "homepage": "https://github.com/englercj/phaser-debug", 8 | "repository": { 9 | "type": "git", 10 | "url": "https://github.com/englercj/phaser-debug.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/englercj/phaser-debug/issues" 14 | }, 15 | "keywords": [ 16 | "phaser", 17 | "debug", 18 | "html5", 19 | "game", 20 | "engine" 21 | ], 22 | "dependencies": { 23 | "handlebars": "^2.0.0", 24 | "node-lessify": "^0.0.5", 25 | "hbsfy": "^2.1.0" 26 | }, 27 | "devDependencies": { 28 | "browserify": "^5.11.1", 29 | "event-stream": "^3.1.7", 30 | "gulp": "^3.8.8", 31 | "gulp-bump": "^0.1.11", 32 | "gulp-git": "^0.5.3", 33 | "gulp-jshint": "^1.8.4", 34 | "gulp-util": "^3.0.1", 35 | "jshint-summary": "^0.4.0", 36 | "vinyl-source-stream": "^0.1.1", 37 | "watchify": "^1.0.2" 38 | }, 39 | "main": "./dist/phaser-debug.js", 40 | "browser": "./src/index.js", 41 | "browserify": { 42 | "transform": [ 43 | "hbsfy", 44 | "node-lessify" 45 | ], 46 | "transform-options": { 47 | "node-lessify": "textMode" 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Phaser Debug 2 | 3 | Simple debug module for the [Phaser][0] game framework. 4 | 5 | ![Screenshot][1] 6 | 7 | [0]: https://github.com/photonstorm/phaser 8 | [1]: https://dl.dropboxusercontent.com/u/1810371/pics/phaser-debug.png 9 | 10 | ## Usage 11 | 12 | Simply download the `phaser-debug.js` script from the [latest release][10] and include it on your page 13 | after including Phaser: 14 | 15 | ```html 16 | 17 | 18 | ``` 19 | 20 | After adding the script to the page you can activate it by enabling the plugin: 21 | 22 | ```js 23 | game.add.plugin(Phaser.Plugin.Debug); 24 | ``` 25 | 26 | [10]: https://github.com/englercj/phaser-debug/releases 27 | 28 | ## TypeScript Usage 29 | Add the `phaser-debug.js` script to the page (see the first part of the usage section above). 30 | 31 | In your `phaser.d.ts` file, inside `module Plugin` add: 32 | ```typescript 33 | class Debug extends Phaser.Plugin { 34 | 35 | constructor(game: Phaser.Game, parent: Phaser.PluginManager); 36 | } 37 | ``` 38 | Activate the plugin: 39 | 40 | ```typescript 41 | this.game.add.plugin(new Phaser.Plugin.Debug(this.game, this.game.plugins)); 42 | ``` 43 | 44 | ## Browser Support 45 | 46 | Currently this module supports the following browsers: 47 | 48 | - Desktop 49 | * Firefox 30+ 50 | * Chrome 27+ 51 | * Safari 5.1+ 52 | * Opera 23+ 53 | -------------------------------------------------------------------------------- /src/panels/Panel.js: -------------------------------------------------------------------------------- 1 | var ui = require('../util/ui'); 2 | 3 | function Panel(game, parent) { 4 | this.game = game; 5 | this.parent = parent; 6 | 7 | this.name = ''; 8 | this.title = ''; 9 | this.active = false; 10 | 11 | this._panel = null; 12 | } 13 | 14 | Panel.prototype.constructor = Panel; 15 | 16 | module.exports = Panel; 17 | 18 | //builds the html for a panel 19 | Panel.prototype.createPanelElement = function () { 20 | var elm = this._panel = document.createElement('div'); 21 | ui.addClass(elm, 'pdebug-panel ' + this.name); 22 | 23 | return elm; 24 | }; 25 | 26 | //builds the html for this panels menu item 27 | Panel.prototype.createMenuElement = function () { 28 | var elm = this._menuItem = document.createElement('a'); 29 | 30 | elm.href = '#' + this.name; 31 | 32 | ui.addClass(elm, 'pdebug-menu-item ' + this.name); 33 | ui.setText(elm, this.title); 34 | 35 | return elm; 36 | }; 37 | 38 | Panel.prototype.toggle = function () { 39 | if (this.active) { 40 | this.hide(); 41 | } else { 42 | this.show(); 43 | } 44 | }; 45 | 46 | Panel.prototype.show = function () { 47 | this.active = true; 48 | ui.setStyle(this._panel, 'display', 'block'); 49 | }; 50 | 51 | Panel.prototype.hide = function () { 52 | this.active = false; 53 | ui.setStyle(this._panel, 'display', 'none'); 54 | }; 55 | 56 | Panel.prototype.destroy = function () { 57 | this.game = null; 58 | this.parent = null; 59 | 60 | this.name = null; 61 | this.title = null; 62 | this.active = null; 63 | 64 | this._panel = null; 65 | }; 66 | -------------------------------------------------------------------------------- /src/hbs/scene/details.hbs: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | {{name}} 5 |
6 | 7 | 8 | {{typeString}} 9 |
10 | 11 | 12 | {{visible}} 13 |
14 | 15 | 16 | {{rotation}} 17 |
18 | 19 | 20 | {{position.x}} x {{position.y}} 21 |
22 | 23 | 24 | {{scale.x}} x {{scale.y}} 25 |
26 | 27 | 28 | {{alpha}} 29 |
30 | 31 |
32 | 33 | 34 | {{worldVisible}} 35 |
36 | 37 | 38 | {{worldRotation}} 39 |
40 | 41 | 42 | {{worldPosition.x}} x {{worldPosition.y}} 43 |
44 | 45 | 46 | {{worldScale.x}} x {{worldScale.y}} 47 |
48 | 49 | 50 | {{worldAlpha}} 51 |
52 | 53 |
54 | 55 | {{#if children}} 56 | 57 | {{children.length}} 58 |
59 | {{/if}} 60 | 61 | {{#if texture}} 62 | 63 | {{#if texture.baseTexture.source.src}} 64 | {{texture.baseTexture.source.src}} 65 | {{else}} 66 | {{texture.baseTexture.source}} 67 | {{/if}} 68 |
69 | {{/if}} 70 | -------------------------------------------------------------------------------- /src/panels/Performance.js: -------------------------------------------------------------------------------- 1 | // TODO: Not measuring render time!! 2 | 3 | var Panel = require('./Panel'), 4 | Graph = require('../util/Graph'); 5 | 6 | function Performance(game, parent) { 7 | Panel.call(this, game, parent); 8 | 9 | this.name = 'performance'; 10 | this.title = 'Performance'; 11 | this.eventQueue = []; 12 | 13 | this.graph = null; 14 | 15 | this.colorPalettes = { 16 | _default: [ 17 | // Colors from: https://github.com/highslide-software/highcharts.com/blob/master/js/themes/grid.js 18 | '#058DC7', '#50B432', '#ED561B', '#DDDF00', 19 | '#24CBE5', '#64E572', '#FF9655', '#FFF263', 20 | '#6AF9C4', 21 | // Colors from: https://github.com/highslide-software/highcharts.com/blob/master/js/themes/dark-unica.js 22 | '#2b908f', '#90ee7e', '#f45b5b', '#7798BF', 23 | '#aaeeee', '#ff0066', '#eeaaee', 24 | '#55BF3B', '#DF5353', '#7798BF', '#aaeeee' 25 | ] 26 | }; 27 | } 28 | 29 | Performance.prototype = Object.create(Panel.prototype); 30 | Performance.prototype.constructor = Performance; 31 | 32 | module.exports = Performance; 33 | 34 | Performance.prototype.createPanelElement = function () { 35 | var elm = Panel.prototype.createPanelElement.call(this); 36 | 37 | this.graph = new Graph(elm, window.innerWidth - 20, 256, this.colorPalettes._default); 38 | 39 | return elm; 40 | }; 41 | 42 | Performance.prototype.update = function () { 43 | this.graph.addData(this.parent.timings, this.eventQueue.shift()); 44 | }; 45 | 46 | Performance.prototype.mark = function (label) { 47 | this.eventQueue.push(label); 48 | }; 49 | 50 | Performance.prototype.destroy = function () { 51 | Panel.prototype.destroy.call(this); 52 | 53 | this.graph.destroy(); 54 | 55 | this.eventQueue = null; 56 | this.graph = null; 57 | this.colorPalettes = null; 58 | }; 59 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'), 2 | path = require('path'), 3 | git = require('gulp-git'), 4 | bump = require('gulp-bump'), 5 | gutil = require('gulp-util'), 6 | jshint = require('gulp-jshint'), 7 | 8 | es = require('event-stream'), 9 | source = require('vinyl-source-stream'), 10 | watchify = require('watchify'), 11 | browserify = require('browserify'), 12 | 13 | index = './src/index.js', 14 | outdir = './build', 15 | bundle = 'Phaser.Plugin.Debug', 16 | outfile = 'phaser-debug.js', 17 | ver = { 18 | major: 0, 19 | minor: 1, 20 | patch: 2 21 | }, 22 | pkg = require('./package.json'), 23 | version = pkg.version.split('.'); 24 | 25 | function rebundle(file) { 26 | if (file) { 27 | gutil.log('Rebundling,', path.basename(file[0]), 'has changes.'); 28 | } 29 | 30 | return this.bundle() 31 | // log errors if they happen 32 | .on('error', gutil.log.bind(gutil, 'Browserify Error')) 33 | .pipe(source(outfile)) 34 | .pipe(gulp.dest(outdir)); 35 | } 36 | 37 | function createBundler(args) { 38 | args = args || {}; 39 | args.standalone = bundle; 40 | 41 | return browserify(index, args); 42 | } 43 | 44 | /***** 45 | * Dev task, incrementally rebuilds the output bundle as the the sources change 46 | *****/ 47 | gulp.task('dev', function() { 48 | watchify.args.standalone = bundle; 49 | var bundler = watchify(createBundler(watchify.args)); 50 | 51 | bundler.on('update', rebundle); 52 | 53 | return rebundle.call(bundler); 54 | }); 55 | 56 | /***** 57 | * Build task, builds the output bundle 58 | *****/ 59 | gulp.task('build', function () { 60 | return rebundle.call(createBundler()); 61 | }); 62 | 63 | /***** 64 | * JSHint task, lints the lib and test *.js files. 65 | *****/ 66 | gulp.task('jshint', function () { 67 | return gulp.src([ 68 | './src/**/*.js', 69 | 'gulpfile.js' 70 | ]) 71 | .pipe(jshint()) 72 | .pipe(jshint.reporter('jshint-summary')); 73 | }); 74 | 75 | /***** 76 | * Base task 77 | *****/ 78 | gulp.task('default', ['jshint', 'build']); 79 | 80 | /***** 81 | * Release task 82 | *****/ 83 | gulp.task('release', ['jshint', 'build'], function (cb) { 84 | var up = process.argv[3] || 'patch'; 85 | 86 | up = up.replace('--', ''); 87 | 88 | if (Object.keys(ver).indexOf(up) === -1) { 89 | return cb(new Error('Please specify major, minor, or patch release.')); 90 | } 91 | 92 | version[ver[up]]++; 93 | for (var i = 0; i < 3; ++i) { 94 | if (i > ver[up]) { 95 | version[i] = 0; 96 | } 97 | } 98 | 99 | version = 'v' + version.join('.'); 100 | 101 | return es.merge( 102 | gulp.src('./package.json') 103 | .pipe(bump({ type: up })) 104 | .pipe(gulp.dest('./')), 105 | gulp.src(outdir + '/' + outfile) 106 | .pipe(gulp.dest('./dist')) 107 | ) 108 | .pipe(git.commit('release ' + version)) 109 | .pipe(git.tag(version, version, function () {})); 110 | }); 111 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # How to contribute 2 | 3 | Please read this short guide to contributing before performing pull requests or reporting issues. The purpose 4 | of this guide is to ensure the best experience for all involved and make development as smooth as possible. 5 | 6 | 7 | ## Reporting issues 8 | 9 | To report a bug, request a feature, or even ask a question, make use of the [GitHub Issues][10] in this repo. 10 | When submitting an issue please take the following steps: 11 | 12 | **1. Search for existing issues.** Your bug may have already been fixed or addressed in an unreleased version, so 13 | be sure to search the issues first before putting in a duplicate issue. 14 | 15 | **2. Create an isolated and reproducible test case.** If you are reporting a bug, make sure you also have a minimal, 16 | runnable, code example that reproduces the problem you have. 17 | 18 | **3. Include a live example.** After narrowing your code down to only the problem areas, make use of [jsFiddle][11], 19 | [jsBin][12], or a link to your live site so that we can view a live example of the problem. 20 | 21 | **4. Share as much information as possible.** Include browser version affected, your OS, version of the library, 22 | steps to reproduce, etc. "X isn't working!!!1!" will probably just be closed. 23 | 24 | [10]: https://github.com/englercj/phaser-debug/issues 25 | [11]: http://jsfiddle.net 26 | [12]: http://jsbin.com/ 27 | 28 | 29 | ## Making Changes 30 | 31 | To build the library you will need to download node.js from [nodejs.org][20]. After it has been installed open a 32 | console and run `npm install -g gulp` to install the global `gulp` executable. 33 | 34 | After that you can clone the repository and run `npm install` inside the cloned folder. This will install 35 | dependencies necessary for building the project. You can rebuild the project by running `gulp` in the cloned 36 | folder. 37 | 38 | Once that is ready, you can make your changes and submit a Pull Request: 39 | 40 | - **Send Pull Requests to the `master` branch.** All Pull Requests must be sent to the `master` branch. 41 | 42 | - **Ensure changes are jshint validated.** Our JSHint configuration file is provided in the repository and you 43 | should check against it before submitting. This should happen automatically when running `gulp` in the repo directory. 44 | 45 | - **Never commit new builds.** When making a code change you should always run `gulp` which will rebuild the project 46 | so you can test, *however* please do not commit the new builds placed in `dist/` or your PR will be closed. By default 47 | the build process will output to an ignored folder (`build/`) you should be fine. 48 | 49 | - **Only commit relevant changes.** Don't include changes that are not directly relevant to the fix you are making. 50 | The more focused a PR is, the faster it will get attention and be merged. Extra files changing only whitespace or 51 | trash files will likely get your PR closed. 52 | 53 | [20]: http://nodejs.org 54 | 55 | 56 | ## Quickie Code Style Guide 57 | 58 | Use EditorConfig and JSHint! Both tools will ensure your code is in the required styles! Either way, here are some tips: 59 | 60 | - Use 4 spaces for tabs, never tab characters. 61 | 62 | - No trailing whitespace, blank lines should have no whitespace. 63 | 64 | - Always favor strict equals `===` unless you *need* to use type coercion. 65 | 66 | - Follow conventions already in the code, and listen to jshint. Our config is set-up for a reason. 67 | -------------------------------------------------------------------------------- /src/styles/forms.less: -------------------------------------------------------------------------------- 1 | /** 2 | * Based on: http://cssdeck.com/labs/css-checkbox-styles 3 | */ 4 | 5 | .pdebug { 6 | input[type=checkbox] { 7 | visibility: hidden; 8 | } 9 | 10 | .rounded(@radius: 2px) { 11 | -webkit-border-radius: @radius; 12 | -moz-border-radius: @radius; 13 | border-radius: @radius; 14 | } 15 | 16 | .boxit(@color1, @color2) { 17 | -webkit-box-shadow: inset 0px 1px 1px @color1, 0px 1px 0px @color2; 18 | -moz-box-shadow: inset 0px 1px 1px @color1, 0px 1px 0px @color2; 19 | -o-box-shadow: inset 0px 1px 1px @color1, 0px 1px 0px @color2; 20 | -ms-box-shadow: inset 0px 1px 1px @color1, 0px 1px 0px @color2; 21 | box-shadow: inset 0px 1px 1px @color1, 0px 1px 0px @color2; 22 | } 23 | 24 | .gradit(@one, @two, @three) { 25 | background: -webkit-linear-gradient(top, @one 0%, @two 40%, @three 100%); 26 | background: -moz-linear-gradient(top, @one 0%, @two 40%, @three 100%); 27 | background: -o-linear-gradient(top, @one 0%, @two 40%, @three 100%); 28 | background: -ms-linear-gradient(top, @one 0%, @two 40%, @three 100%); 29 | background: linear-gradient(top, @one 0%, @two 40%, @three 100%); 30 | } 31 | 32 | .checkbox { 33 | width: 75px; 34 | height: 26px; 35 | background: #333; 36 | position: relative; 37 | line-height: normal; 38 | //margin: 20px auto; 39 | 40 | .rounded(50px); 41 | .boxit(rgba(0,0,0,0.5), rgba(255,255,255,0.2)); 42 | 43 | &:after { 44 | content: 'OFF'; 45 | font: 12px/26px Arial, sans-serif; 46 | color: #000; 47 | position: absolute; 48 | right: 10px; 49 | z-index: 0; 50 | font-weight: bold; 51 | text-shadow: 1px 1px 0px rgba(255,255,255,.15); 52 | } 53 | 54 | &:before { 55 | content: 'ON'; 56 | font: 12px/26px Arial, sans-serif; 57 | color: #00bf00; 58 | position: absolute; 59 | left: 10px; 60 | z-index: 0; 61 | font-weight: bold; 62 | } 63 | 64 | & + span { 65 | position: relative; 66 | display: block; 67 | top: -25px; 68 | left: 90px; 69 | width: 200px; 70 | color: #fcfff4; 71 | font-size: 1.1em; 72 | } 73 | 74 | input[type=checkbox]:checked + label { 75 | left: 38px; 76 | } 77 | 78 | 79 | label { 80 | display: block; 81 | width: 34px; 82 | height: 20px; 83 | 84 | -webkit-border-radius: 50px; 85 | -moz-border-radius: 50px; 86 | border-radius: 50px; 87 | 88 | -webkit-transition: all .4s ease; 89 | -moz-transition: all .4s ease; 90 | -o-transition: all .4s ease; 91 | -ms-transition: all .4s ease; 92 | transition: all .4s ease; 93 | cursor: pointer; 94 | position: absolute; 95 | top: 3px; 96 | left: 3px; 97 | z-index: 1; 98 | 99 | background: #fcfff4; 100 | .gradit(#fcfff4, #dfe5d7, #b3bead); 101 | //.rounded(@cb_radius); 102 | //.boxit(@cb_accent_start, @cb_accent_stop); 103 | 104 | -webkit-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.3); 105 | -moz-box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.3); 106 | box-shadow: 0px 2px 5px 0px rgba(0,0,0,0.3); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/util/ui.js: -------------------------------------------------------------------------------- 1 | //Some general dom helpers 2 | var ui = { 3 | delegate: function (dom, evt, selector, fn) { 4 | dom.addEventListener(evt, function(e) { 5 | window.target = e.target; 6 | if (e.target && e.target.matches(selector)) { 7 | e.delegateTarget = e.target; 8 | 9 | if (fn) { 10 | fn(e); 11 | } 12 | } 13 | else if (e.target.parentElement && e.target.parentElement.matches(selector)) { 14 | e.delegateTarget = e.target.parentElement; 15 | 16 | if (fn) { 17 | fn(e); 18 | } 19 | } 20 | }); 21 | }, 22 | 23 | on: function (dom, evt, delegate, fn) { 24 | if (typeof delegate === 'function') { 25 | fn = delegate; 26 | delegate = null; 27 | } 28 | 29 | if (delegate) { 30 | return ui.delegate(dom, evt, delegate, fn); 31 | } 32 | 33 | dom.addEventListener(evt, fn); 34 | }, 35 | 36 | removeClass: function (dom, cls) { 37 | var classes = dom.className.split(' '), 38 | i = classes.indexOf(cls); 39 | 40 | if(i !== -1) { 41 | classes.splice(i, 1); 42 | dom.className = classes.join(' ').trim(); 43 | } 44 | }, 45 | 46 | addClass: function (dom, cls) { 47 | var classes = dom.className.split(' '); 48 | 49 | classes.push(cls); 50 | dom.className = classes.join(' ').trim(); 51 | }, 52 | 53 | hasClass: function (dom, cls) { 54 | return dom.className.split(' ').indexOf(cls) !== -1; 55 | }, 56 | 57 | toggleClass: function (dom, cls) { 58 | if (ui.hasClass(dom, cls)) { 59 | ui.removeClass(dom, cls); 60 | } else { 61 | ui.addClass(dom, cls); 62 | } 63 | }, 64 | 65 | setText: function (dom, txt) { 66 | dom.textContent = txt; 67 | }, 68 | 69 | setHtml: function (dom, html) { 70 | dom.innerHTML = html; 71 | }, 72 | 73 | setStyle: function (dom, style, value) { 74 | if(typeof style === 'string') { 75 | dom.style[style] = value; 76 | } else { 77 | for(var key in style) { 78 | dom.style[key] = style[key]; 79 | } 80 | } 81 | }, 82 | 83 | empty: function (dom) { 84 | while(dom.firstChild) { 85 | dom.removeChild(dom.firstChild); 86 | } 87 | }, 88 | 89 | show: function (dom) { 90 | ui.setStyle(dom, 'display', 'block'); 91 | }, 92 | 93 | hide: function (dom) { 94 | ui.setStyle(dom, 'display', 'none'); 95 | }, 96 | 97 | clear: function () { 98 | var br = document.createElement('br'); 99 | ui.setStyle(br, 'clear', 'both'); 100 | 101 | return br; 102 | }, 103 | 104 | addCss: function (css) { 105 | var style = document.createElement('style'); 106 | 107 | style.type = 'text/css'; 108 | 109 | if (style.styleSheet){ 110 | style.styleSheet.cssText = css; 111 | } else { 112 | style.appendChild(document.createTextNode(css)); 113 | } 114 | 115 | document.head.appendChild(style); 116 | } 117 | }; 118 | 119 | module.exports = ui; 120 | 121 | // polyfill for matchesSelector 122 | if (!HTMLElement.prototype.matches) { 123 | var htmlprot = HTMLElement.prototype; 124 | 125 | htmlprot.matches = 126 | htmlprot.matches || 127 | htmlprot.webkitMatchesSelector || 128 | htmlprot.mozMatchesSelector || 129 | htmlprot.msMatchesSelector || 130 | htmlprot.oMatchesSelector || 131 | function (selector) { 132 | // poorman's polyfill for matchesSelector 133 | var elements = this.parentElement.querySelectorAll(selector), 134 | element, 135 | i = 0; 136 | 137 | while (element = elements[i++]) { 138 | if (element === this) { 139 | return true; 140 | } 141 | } 142 | 143 | return false; 144 | }; 145 | } 146 | -------------------------------------------------------------------------------- /src/styles/panel.less: -------------------------------------------------------------------------------- 1 | @background: #333; 2 | @foreground: #aaa; 3 | @accent: #00bf00; 4 | @strong: #fff; 5 | 6 | @activeTabForeground: @accent; 7 | @activeTabBackground: #111; 8 | 9 | @seperatorWidth: 1px; 10 | @separatorColor: lighten(@background, 20%); 11 | 12 | @accentHeight: 3px; 13 | 14 | @bar_height: 32px; 15 | @panel_height: 265px; 16 | 17 | @padding: 10px; 18 | 19 | //container 20 | .pdebug { 21 | font-size: 14px; 22 | position: fixed; 23 | bottom: 0; 24 | width: 100%; 25 | 26 | color: @foreground; 27 | background: @background; 28 | border-top: @accentHeight solid @accent; 29 | 30 | z-index: 999999; 31 | 32 | a { 33 | color: @accent; 34 | } 35 | 36 | label { 37 | display: inline-block; 38 | width: 100px; 39 | } 40 | 41 | strong { 42 | font-weight: normal; 43 | color: @strong; 44 | } 45 | 46 | .weak { 47 | color: @foreground; 48 | } 49 | 50 | //menu bar 51 | .pdebug-menu { 52 | height: @bar_height; 53 | padding: 0 15px; 54 | 55 | text-shadow: 1px 1px 0 #111; 56 | 57 | background: @background; 58 | 59 | span { 60 | display: inline-block; 61 | height: @bar_height; 62 | line-height: @bar_height; 63 | } 64 | 65 | //head of the menu bar 66 | .pdebug-head { 67 | padding-right: 25px; 68 | border-right: @seperatorWidth solid @separatorColor; 69 | } 70 | 71 | //main bar stats 72 | .pdebug-stats { 73 | float:right; 74 | padding: 0 0 0 @padding; 75 | 76 | //an item on the stats bar 77 | .pdebug-stats-item { 78 | display: inline-block; 79 | width: 100px; 80 | 81 | text-align: right; 82 | 83 | & > span { 84 | color: @strong; 85 | } 86 | 87 | //fps stat item 88 | &.fps {} 89 | 90 | //ms stat item 91 | &.ms {} 92 | 93 | //sprites stat item 94 | &.obj { 95 | width: 100px; 96 | border: none; 97 | } 98 | } 99 | } 100 | 101 | //menu items (to switch between panels) 102 | .pdebug-menu-item { 103 | color: @strong; 104 | 105 | display: inline-block; 106 | 107 | text-decoration: none; 108 | 109 | padding: 0 @padding; 110 | height: @bar_height; 111 | line-height: @bar_height; 112 | border-right: @seperatorWidth solid @separatorColor; 113 | 114 | &.active { 115 | color: @activeTabForeground; 116 | background: @activeTabBackground; 117 | } 118 | } 119 | } 120 | 121 | //panels 122 | .pdebug-panel { 123 | display: none; 124 | height: @panel_height; 125 | overflow: auto; 126 | 127 | font-size: 12px; 128 | 129 | background: @activeTabBackground; 130 | 131 | //the performance panel 132 | &.performance {} 133 | 134 | //the scene tree panel 135 | &.scene { 136 | .sidebar { 137 | float: left; 138 | height: 100%; 139 | 140 | min-width: 175px; 141 | max-width: 500px; 142 | 143 | resize: horizontal; 144 | overflow: auto; 145 | } 146 | 147 | .details { 148 | float: left; 149 | height: 100%; 150 | } 151 | 152 | .refresh { 153 | position: absolute; 154 | } 155 | 156 | > ul { 157 | padding: 0; 158 | margin: 0; 159 | 160 | border-right: solid 1px @foreground; 161 | margin-right: 10px; 162 | 163 | li { 164 | color: @strong; 165 | 166 | list-style: none; 167 | cursor: pointer; 168 | 169 | &.expanded > ul { 170 | display: block; 171 | } 172 | 173 | &.selected { 174 | color: @accent; 175 | } 176 | 177 | &::before { 178 | content: '-'; 179 | 180 | display: inline-block; 181 | 182 | width: 12px; 183 | height: 1px; 184 | 185 | color: @foreground; 186 | } 187 | 188 | &.has-children { 189 | &::before { 190 | content: ''; 191 | 192 | display: inline-block; 193 | 194 | width: 0; 195 | height: 0; 196 | 197 | margin: 0 6px 0 0; 198 | 199 | border-top: 6px solid transparent; 200 | border-bottom: 6px solid transparent; 201 | border-right: none; 202 | border-left: 6px solid rgba(255, 255, 255, 0.3); 203 | } 204 | 205 | &.expanded::before { 206 | margin: 0 4px 0 -4px; 207 | 208 | border-top: 6px solid rgba(255, 255, 255, 0.3); 209 | border-left: 6px solid transparent; 210 | border-right: 6px solid transparent; 211 | border-bottom: none; 212 | } 213 | } 214 | 215 | > ul { 216 | display: none; 217 | padding: 0 0 0 10px; 218 | } 219 | } 220 | } 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/panels/Scene.js: -------------------------------------------------------------------------------- 1 | var Panel = require('./Panel'), 2 | ui = require('../util/ui'), 3 | Handlebars = require('hbsfy/runtime'); 4 | 5 | //require templates 6 | var panelHtml = require('../hbs/scene/panel.hbs'), 7 | detailsHtml = require('../hbs/scene/details.hbs'), 8 | treeHtml = require('../hbs/scene/tree.hbs'), 9 | _cache = {}, 10 | _id = 0; 11 | 12 | Handlebars.registerPartial('sceneDetails', detailsHtml); 13 | Handlebars.registerPartial('sceneTree', treeHtml); 14 | Handlebars.registerHelper('typeString', typeToString); 15 | Handlebars.registerHelper('listItemOpen', listItemOpen); 16 | 17 | function Scene(game, parent) { 18 | Panel.call(this, game, parent); 19 | 20 | this.name = 'scene'; 21 | this.title = 'Scene Tree'; 22 | 23 | this._tree = null; 24 | 25 | this.tree = null; 26 | this.details = null; 27 | this.refresh = null; 28 | 29 | this.selected = null; 30 | } 31 | 32 | Scene.prototype = Object.create(Panel.prototype); 33 | Scene.prototype.constructor = Scene; 34 | 35 | module.exports = Scene; 36 | 37 | Scene.prototype.createPanelElement = function () { 38 | Panel.prototype.createPanelElement.call(this); 39 | 40 | this._panel.innerHTML = panelHtml(this.game.stage); 41 | 42 | this.tree = this._panel.querySelector('.sidebar'); 43 | this.details = this._panel.querySelector('.details'); 44 | this.refresh = this._panel.querySelector('.refresh'); 45 | 46 | ui.on(this.tree, 'click', 'li', this._onLiClick.bind(this)); 47 | ui.on(this.refresh, 'click', this._onRefreshClick.bind(this)); 48 | 49 | this.bmd = this.game.add.bitmapData(512, 256); 50 | 51 | return this._panel; 52 | }; 53 | 54 | Scene.prototype.rebuildTree = function () { 55 | ui.empty(this.tree); 56 | 57 | _cache = {}; 58 | 59 | this.tree.innerHTML = treeHtml(this.game.stage); 60 | 61 | this.select(this.tree.querySelector('li:first-child')); 62 | ui.addClass(this.selected, 'expanded'); 63 | 64 | this.reloadDetails(); 65 | }; 66 | 67 | Scene.prototype.reloadDetails = function () { 68 | var id = this.selected.dataset.id; 69 | var obj = _cache[id]; 70 | 71 | this.details.innerHTML = detailsHtml(obj); 72 | 73 | if (obj.texture) { 74 | this.details.appendChild(this.bmd.canvas); 75 | 76 | var w = Math.min(512, obj.width); 77 | var h = Math.min(256, obj.height); 78 | 79 | this.bmd.clear(); 80 | this.bmd.resize(w, h); 81 | 82 | try { 83 | this.bmd.draw(obj, 0, 0, w, h); 84 | } catch (e) {}; 85 | } 86 | }; 87 | 88 | Scene.prototype.select = function (li) { 89 | if (this.selected) { 90 | ui.removeClass(this.selected, 'selected'); 91 | } 92 | 93 | this.selected = li; 94 | ui.addClass(this.selected, 'selected'); 95 | }; 96 | 97 | Scene.prototype.show = function () { 98 | this.rebuildTree(); 99 | 100 | Panel.prototype.show.call(this); 101 | }; 102 | 103 | Scene.prototype.destroy = function () { 104 | Panel.prototype.destroy.call(this); 105 | 106 | this.tree = null; 107 | this.details = null; 108 | this.refresh = null; 109 | }; 110 | 111 | Scene.prototype._onLiClick = function (e) { 112 | e.stopPropagation(); 113 | 114 | this.select(e.delegateTarget); 115 | 116 | ui.toggleClass(e.delegateTarget, 'expanded'); 117 | 118 | this.reloadDetails(); 119 | }; 120 | 121 | Scene.prototype._onRefreshClick = function (e) { 122 | e.preventDefault(); 123 | e.stopPropagation(); 124 | 125 | this.rebuildTree(); 126 | }; 127 | 128 | function listItemOpen () { 129 | _cache[++_id] = this; 130 | 131 | return new Handlebars.SafeString( 132 | '
  • ' 133 | ); 134 | } 135 | 136 | function typeToString () { 137 | var node = this; 138 | 139 | // If no phaser type defined, try to guess 140 | if (node.type === undefined) { 141 | // Phaser.Stage does not have its 'type' property defined, so check here. 142 | if (node instanceof Phaser.Stage) { 143 | return 'Stage'; 144 | } 145 | // PIXI.Stage was removed in Phaser 2.4.4, so make sure it's defined first. 146 | else if (typeof PIXI.Stage !== 'undefined' && 147 | node instanceof PIXI.Stage) { 148 | return 'PIXI Stage'; 149 | } 150 | else if (node instanceof PIXI.Sprite) { 151 | return 'PIXI Sprite'; 152 | } 153 | else if (node instanceof PIXI.DisplayObjectContainer) { 154 | return 'PIXI DisplayObjectContainer'; 155 | } 156 | else if (node instanceof PIXI.DisplayObject) { 157 | return 'PIXI DisplayObject'; 158 | } 159 | else { 160 | return 'Unknown'; 161 | } 162 | } 163 | // return a string for the phaser type 164 | else { 165 | switch(node.type) { 166 | case Phaser.SPRITE: 167 | return 'Sprite'; 168 | 169 | case Phaser.BUTTON: 170 | return 'Button'; 171 | 172 | case Phaser.IMAGE: 173 | return 'Image'; 174 | 175 | case Phaser.GRAPHICS: 176 | return 'Graphics'; 177 | 178 | case Phaser.TEXT: 179 | return 'Text'; 180 | 181 | case Phaser.TILESPRITE: 182 | return 'Tile Sprite'; 183 | 184 | case Phaser.BITMAPTEXT: 185 | return 'Bitmap Text'; 186 | 187 | case Phaser.GROUP: 188 | return 'Group'; 189 | 190 | case Phaser.RENDERTEXTURE: 191 | return 'Render Texture'; 192 | 193 | case Phaser.TILEMAP: 194 | return 'Tilemap'; 195 | 196 | case Phaser.TILEMAPLAYER: 197 | return 'Tilemap Layer'; 198 | 199 | case Phaser.EMITTER: 200 | return 'Emitter'; 201 | 202 | case Phaser.POLYGON: 203 | return 'Polygon'; 204 | 205 | case Phaser.BITMAPDATA: 206 | return 'Bitmap Data'; 207 | 208 | case Phaser.CANVAS_FILTER: 209 | return 'Canvas Filter'; 210 | 211 | case Phaser.WEBGL_FILTER: 212 | return 'WebGL Filter'; 213 | 214 | case Phaser.ELLIPSE: 215 | return 'Ellipse'; 216 | 217 | case Phaser.SPRITEBATCH: 218 | return 'Sprite Batch'; 219 | 220 | case Phaser.RETROFONT: 221 | return 'Retro Font'; 222 | 223 | case Phaser.POINTER: 224 | return 'Pointer'; 225 | 226 | case Phaser.ROPE: 227 | return 'Rope'; 228 | 229 | default: 230 | return 'Unknown'; 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/util/Graph.js: -------------------------------------------------------------------------------- 1 | // TODO: Move the legend into DOM? 2 | 3 | function Graph(container, width, height, colors, options) { 4 | options = options || {}; 5 | 6 | this.canvas = document.createElement('canvas'); 7 | this.canvas.width = width; 8 | this.canvas.height = height; 9 | container.appendChild(this.canvas); 10 | 11 | this.ctx = this.canvas.getContext('2d'); 12 | 13 | this.labelStyle = 'rgba(200, 200, 200, 0.6)'; 14 | 15 | this.maxValue = options.maxValue || 50; 16 | this.padding = options.labelPadding || 5; 17 | 18 | this.dataLineWidth = options.lineWidth || 1; 19 | this.legendWidth = 230; 20 | this.legendBoxSize = 10; 21 | this.legendIndent = 5; 22 | 23 | this.eventY = this.padding * 2; 24 | 25 | this.colors = colors; 26 | 27 | this.dataCanvas = document.createElement('canvas'); 28 | this.dataCanvas.width = width - this.legendWidth; 29 | this.dataCanvas.height = height; 30 | this.dctx = this.dataCanvas.getContext('2d'); 31 | 32 | this.dataCanvasBuffer = document.createElement('canvas'); 33 | this.dataCanvasBuffer.width = this.dataCanvas.width - this.dataLineWidth; 34 | this.dataCanvasBuffer.height = this.dataCanvas.height; 35 | this.bctx = this.dataCanvasBuffer.getContext('2d'); 36 | } 37 | 38 | Graph.prototype.constructor = Graph; 39 | 40 | module.exports = Graph; 41 | 42 | // render the graph with the new data point 43 | Graph.prototype.addData = function (values, event) { 44 | // clear the main canvas 45 | this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); 46 | 47 | this.drawBg(); 48 | this.drawLegend(values); 49 | this.drawData(values, event); 50 | }; 51 | 52 | Graph.prototype.drawBg = function () { 53 | var fps60 = Math.floor(this.canvas.height - (this.canvas.height * (16 / this.maxValue))) + 0.5, 54 | fps30 = Math.floor(this.canvas.height - (this.canvas.height * (33 / this.maxValue))) + 0.5; 55 | 56 | this.ctx.strokeStyle = this.ctx.fillStyle = this.labelStyle; 57 | this.ctx.lineWidth = 1; 58 | 59 | //draw top marker line 60 | this.ctx.beginPath(); 61 | this.ctx.moveTo(this.legendWidth, fps60); 62 | this.ctx.lineTo(this.canvas.width, fps60); 63 | this.ctx.stroke(); 64 | 65 | this.ctx.fillText('16ms (60 fps)', this.legendWidth + this.padding, fps60 - this.padding); 66 | 67 | //draw the second marker line 68 | this.ctx.beginPath(); 69 | this.ctx.moveTo(this.legendWidth, fps30); 70 | this.ctx.lineTo(this.canvas.width, fps30); 71 | this.ctx.stroke(); 72 | 73 | this.ctx.fillText('33ms (30 fps)', this.legendWidth + this.padding, fps30 - this.padding); 74 | 75 | //draw baseline marker 76 | this.ctx.beginPath(); 77 | this.ctx.moveTo(this.legendWidth, this.canvas.height - 0.5); 78 | this.ctx.lineTo(this.canvas.width, this.canvas.height - 0.5); 79 | this.ctx.stroke(); 80 | }; 81 | 82 | Graph.prototype.drawLegend = function (values) { 83 | var colorIndex = 0, 84 | yIndex = 0, 85 | x = this.padding, 86 | y = 0; 87 | 88 | for (var k in values) { 89 | y = (yIndex * this.legendBoxSize) + (this.padding * (yIndex + 1)) + this.padding; 90 | 91 | // Draw parent label 92 | this.ctx.fillStyle = this.labelStyle; 93 | this.ctx.fillText(k, x, y); 94 | 95 | ++yIndex; 96 | 97 | // Draw children 98 | for (var c in values[k]) { 99 | y = (yIndex * this.legendBoxSize) + (this.padding * yIndex); 100 | 101 | this.ctx.fillStyle = this.colors[colorIndex++ % this.colors.length]; 102 | this.ctx.fillRect(x + this.legendIndent, y, this.legendBoxSize, this.legendBoxSize); 103 | 104 | this.ctx.fillStyle = this.labelStyle; 105 | this.ctx.fillText( 106 | Math.round(values[k][c]) + 'ms - ' + c, 107 | x + this.legendIndent + this.legendBoxSize + this.padding, 108 | y + this.legendBoxSize 109 | ); 110 | 111 | ++yIndex; 112 | 113 | if (yIndex > 16) { 114 | x += this.legendWidth / 2; 115 | yIndex = 0; 116 | } 117 | } 118 | } 119 | }; 120 | 121 | Graph.prototype.drawData = function (values, event) { 122 | var x = this.dataCanvas.width - this.dataLineWidth + 0.5, 123 | y = this.dataCanvas.height - 0.5; 124 | 125 | // clear the buffer 126 | this.bctx.clearRect(0, 0, this.dataCanvasBuffer.width, this.dataCanvasBuffer.height); 127 | 128 | // draw the data canvas to the buffer, skipping the first line 129 | this.bctx.drawImage( 130 | this.dataCanvas, 131 | this.dataLineWidth, 0, x, y, 132 | 0, 0, x, y 133 | ); 134 | 135 | // clear the data canvas 136 | this.dctx.clearRect(0, 0, this.dataCanvas.width, this.dataCanvas.height); 137 | 138 | // draw the buffer back to the data canvas 139 | this.dctx.drawImage(this.dataCanvasBuffer, 0, 0); 140 | 141 | // draw event to the new line of the data canvas if there was one 142 | if (event) { 143 | this.dctx.beginPath(); 144 | this.dctx.strokeStyle = this.dctx.fillStyle = '#ff0000'; 145 | this.dctx.lineWidth = this.dataLineWidth; 146 | 147 | this.dctx.moveTo(x, y); 148 | this.dctx.lineTo(x, 0); 149 | 150 | this.dctx.stroke(); 151 | 152 | this.dctx.textAlign = 'right'; 153 | this.dctx.fillText(event, x - this.padding, this.eventY); 154 | 155 | this.eventY += (this.padding * 2); 156 | 157 | if (this.eventY > (this.dataCanvas.height / 2)) { 158 | this.eventY = (this.padding * 2); 159 | } 160 | } 161 | 162 | // draws the data values to the new line of the data canvas 163 | 164 | // draw the new data points 165 | var colorIndex = 0, 166 | step = 0; 167 | 168 | for (var k in values) { 169 | for (var c in values[k]) { 170 | this.dctx.beginPath(); 171 | this.dctx.strokeStyle = this.dctx.fillStyle = this.colors[colorIndex++ % this.colors.length]; 172 | this.dctx.lineWidth = this.dataLineWidth; 173 | 174 | step = ((values[k][c] / this.maxValue) * this.dataCanvas.height); 175 | step = step < 0 ? 0 : step; 176 | 177 | this.dctx.moveTo(x, y); 178 | this.dctx.lineTo(x, y-=step); 179 | 180 | this.dctx.stroke(); 181 | } 182 | } 183 | 184 | // draw the data canvas to the main rendered canvas 185 | this.ctx.drawImage(this.dataCanvas, this.legendWidth, 0); 186 | }; 187 | 188 | Graph.prototype.destroy = function () { 189 | this.canvas = null; 190 | this.ctx = null; 191 | 192 | this.labelStyle = null; 193 | 194 | this.maxValue = null; 195 | this.padding = null; 196 | 197 | this.dataLineWidth = null; 198 | this.legendWidth = null; 199 | this.legendBoxSize = null; 200 | this.legendIndent = null; 201 | 202 | this.colors = null; 203 | 204 | this.dataCanvas = null; 205 | this.dctx = null; 206 | 207 | this.dataCanvasBuffer = null; 208 | this.bctx = null; 209 | }; 210 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | // -------------------------------------------------------------------- 3 | // JSHint Configuration 4 | // -------------------------------------------------------------------- 5 | // 6 | // @author Chad Engler 7 | 8 | // == Enforcing Options =============================================== 9 | // 10 | // These options tell JSHint to be more strict towards your code. Use 11 | // them if you want to allow only a safe subset of JavaScript, very 12 | // useful when your codebase is shared with a big number of developers 13 | // with different skill levels. 14 | 15 | "bitwise" : false, // Disallow bitwise operators (&, |, ^, etc.). 16 | "camelcase" : true, // Force all variable names to use either camelCase or UPPER_CASE. 17 | "curly" : true, // Require {} for every new block or scope. 18 | "eqeqeq" : true, // Require triple equals i.e. `===`. 19 | "es3" : false, // Enforce conforming to ECMAScript 3. 20 | "forin" : false, // Disallow `for in` loops without `hasOwnPrototype`. 21 | "immed" : true, // Require immediate invocations to be wrapped in parens e.g. `( function(){}() );` 22 | "indent" : 4, // Require that 4 spaces are used for indentation. 23 | "latedef" : "nofunc", // Prohibit variable use before definition. 24 | "newcap" : true, // Require capitalization of all constructor functions e.g. `new F()`. 25 | "noarg" : true, // Prohibit use of `arguments.caller` and `arguments.callee`. 26 | "noempty" : true, // Prohibit use of empty blocks. 27 | "nonew" : true, // Prohibit use of constructors for side-effects. 28 | "plusplus" : false, // Disallow use of `++` & `--`. 29 | "quotmark" : true, // Force consistency when using quote marks. 30 | "undef" : true, // Require all non-global variables be declared before they are used. 31 | "unused" : true, // Warn when varaibles are created but not used. 32 | "strict" : false, // Require `use strict` pragma in every file. 33 | "trailing" : true, // Prohibit trailing whitespaces. 34 | "maxparams" : 6, // Prohibit having more than X number of params in a function. 35 | "maxdepth" : 6, // Prohibit nested blocks from going more than X levels deep. 36 | "maxstatements" : false, // Restrict the number of statements in a function. 37 | "maxcomplexity" : false, // Restrict the cyclomatic complexity of the code. 38 | "maxlen" : 120, // Require that all lines are n characters or less. 39 | "globals" : { // Register globals that are used in the code. 40 | "PIXI": false, 41 | "Phaser": false 42 | }, 43 | 44 | // == Relaxing Options ================================================ 45 | // 46 | // These options allow you to suppress certain types of warnings. Use 47 | // them only if you are absolutely positive that you know what you are 48 | // doing. 49 | 50 | "asi" : false, // Tolerate Automatic Semicolon Insertion (no semicolons). 51 | "boss" : true, // Tolerate assignments inside if, for & while. Usually conditions & loops are for comparison, not assignments. 52 | "debug" : false, // Allow debugger statements e.g. browser breakpoints. 53 | "eqnull" : false, // Tolerate use of `== null`. 54 | "esnext" : false, // Allow ES.next specific features such as `const` and `let`. 55 | "evil" : false, // Tolerate use of `eval`. 56 | "expr" : false, // Tolerate `ExpressionStatement` as Programs. 57 | "funcscope" : false, // Tolerate declarations of variables inside of control structures while accessing them later from the outside. 58 | "globalstrict" : false, // Allow global "use strict" (also enables 'strict'). 59 | "iterator" : false, // Allow usage of __iterator__ property. 60 | "lastsemic" : false, // Tolerate missing semicolons when the it is omitted for the last statement in a one-line block. 61 | "laxbreak" : false, // Tolerate unsafe line breaks e.g. `return [\n] x` without semicolons. 62 | "laxcomma" : false, // Suppress warnings about comma-first coding style. 63 | "loopfunc" : false, // Allow functions to be defined within loops. 64 | "moz" : false, // Code that uses Mozilla JS extensions will set this to true 65 | "multistr" : false, // Tolerate multi-line strings. 66 | "proto" : false, // Tolerate __proto__ property. This property is deprecated. 67 | "scripturl" : false, // Tolerate script-targeted URLs. 68 | "smarttabs" : false, // Tolerate mixed tabs and spaces when the latter are used for alignmnent only. 69 | "shadow" : false, // Allows re-define variables later in code e.g. `var x=1; x=2;`. 70 | "sub" : false, // Tolerate all forms of subscript notation besides dot notation e.g. `dict['key']` instead of `dict.key`. 71 | "supernew" : false, // Tolerate `new function () { ... };` and `new Object;`. 72 | "validthis" : false, // Tolerate strict violations when the code is running in strict mode and you use this in a non-constructor function. 73 | 74 | // == Environments ==================================================== 75 | // 76 | // These options pre-define global variables that are exposed by 77 | // popular JavaScript libraries and runtime environments—such as 78 | // browser or node.js. 79 | 80 | "browser" : true, // Standard browser globals e.g. `window`, `document`. 81 | "couch" : false, // Enable globals exposed by CouchDB. 82 | "devel" : false, // Allow development statements e.g. `console.log();`. 83 | "dojo" : false, // Enable globals exposed by Dojo Toolkit. 84 | "jquery" : false, // Enable globals exposed by jQuery JavaScript library. 85 | "mootools" : false, // Enable globals exposed by MooTools JavaScript framework. 86 | "node" : true, // Enable globals available when code is running inside of the NodeJS runtime environment. (for Gruntfile) 87 | "nonstandard" : false, // Define non-standard but widely adopted globals such as escape and unescape. 88 | "prototypejs" : false, // Enable globals exposed by Prototype JavaScript framework. 89 | "rhino" : false, // Enable globals available when your code is running inside of the Rhino runtime environment. 90 | "worker" : false, // Enable globals available when your code is running as a WebWorker. 91 | "wsh" : false, // Enable globals available when your code is running as a script for the Windows Script Host. 92 | "yui" : false, // Enable globals exposed by YUI library. 93 | 94 | // == JSLint Legacy =================================================== 95 | // 96 | // These options are legacy from JSLint. Aside from bug fixes they will 97 | // not be improved in any way and might be removed at any point. 98 | 99 | "nomen" : false, // Prohibit use of initial or trailing underbars in names. 100 | "onevar" : false, // Allow only one `var` statement per function. 101 | "passfail" : false, // Stop on first error. 102 | "white" : false, // Check against strict whitespace and indentation rules. 103 | 104 | // == Undocumented Options ============================================ 105 | // 106 | // While I've found these options in [example1][2] and [example2][3] 107 | // they are not described in the [JSHint Options documentation][4]. 108 | // 109 | // [4]: http://www.jshint.com/options/ 110 | 111 | "maxerr" : 100 // Maximum errors before stopping. 112 | } 113 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | var ui = require('./util/ui'), 2 | css = require('./styles/main.less'), 3 | PerformancePanel = require('./panels/Performance'), 4 | ScenePanel = require('./panels/Scene'); 5 | 6 | /** 7 | * @class Phaser.Plugin.Debug 8 | * @classdesc Phaser - Debug Plugin 9 | * 10 | * @constructor 11 | * @extends Phaser.Plugin 12 | * 13 | * @param {Phaser.Game} game - A reference to the currently running game. 14 | * @param {Any} parent - The object that owns this plugin, usually Phaser.PluginManager. 15 | */ 16 | function Debug(game, parent) { 17 | Phaser.Plugin.call(this, game, parent); 18 | 19 | this.panels = { 20 | performance: null, 21 | scene: null 22 | }; 23 | 24 | this.tickTimings = { 25 | lastStart: 0, 26 | start: 0, 27 | ms: 0 28 | }; 29 | 30 | this.timings = { 31 | preUpdate: { 32 | physics : 0, 33 | state : 0, 34 | plugins : 0, 35 | stage : 0 36 | }, 37 | update: { 38 | state : 0, 39 | stage : 0, 40 | tweens : 0, 41 | sound : 0, 42 | input : 0, 43 | physics : 0, 44 | particles: 0, 45 | plugins : 0 46 | }, 47 | postUpdate: { 48 | stage : 0, 49 | plugins : 0 50 | }, 51 | preRender: { 52 | state : 0 53 | }, 54 | render: { 55 | renderer : 0, 56 | plugins : 0, 57 | state : 0 58 | }, 59 | postRender: { 60 | plugins : 0 61 | } 62 | }; 63 | 64 | this._container = null; 65 | this._bar = null; 66 | 67 | this._stats = { 68 | ms: null, 69 | fps: null, 70 | dpf: null, 71 | ent: null 72 | }; 73 | 74 | this.timer = (window.performance ? window.performance : Date); 75 | } 76 | 77 | // Extends the Phaser.Plugin template, setting up values we need 78 | Debug.prototype = Object.create(Phaser.Plugin.prototype); 79 | Debug.prototype.constructor = Debug; 80 | 81 | Debug.PKG = require('../package.json'); 82 | Debug.VERSION = Debug.PKG.version; 83 | 84 | module.exports = Debug; 85 | 86 | Debug.prototype.init = function () { 87 | // create the panels 88 | this.panels.performance = new PerformancePanel(this.game, this); 89 | this.panels.scene = new ScenePanel(this.game, this); 90 | 91 | // add elements to the page 92 | ui.addCss(css); 93 | document.body.appendChild(this._createElement()); 94 | 95 | this._bindEvents(); 96 | 97 | // wrap each component's update methods so we can time them 98 | for (var method in this.timings) { 99 | for (var comp in this.timings[method]) { 100 | this._wrap(this.game, comp, method, comp); 101 | } 102 | } 103 | 104 | // wrap the game update method 105 | this._wrap(this, 'game', 'update'); 106 | 107 | // initialize each panel 108 | for (var p in this.panels) { 109 | if (this.panels[p].init) { 110 | this.panels[p].init.apply(this.panels[p], arguments); 111 | } 112 | } 113 | }; 114 | 115 | /** 116 | * Post-Update is called after all the update methods have already been called, but before the render calls. 117 | * It is only called if active is set to true. 118 | * 119 | * @method Phaser.Plugin.Debug#postUpdate 120 | */ 121 | Debug.prototype.postUpdate = function () { 122 | for (var p in this.panels) { 123 | if (this.panels[p].update && this.panels[p].active) { 124 | this.panels[p].update(); 125 | } 126 | } 127 | 128 | var fps = Math.round(1000 / (this.tickTimings.start - this.tickTimings.lastStart)), 129 | dpf = this.game.renderer.renderSession.drawCount; 130 | 131 | fps = fps > 60 ? 60 : fps; 132 | 133 | // update stats indicators 134 | ui.setText(this._stats.dpf.firstElementChild, dpf === undefined ? '(N/A)' : dpf, 3); 135 | ui.setText(this._stats.ms.firstElementChild, Math.round(this.tickTimings.ms), 4); 136 | ui.setText(this._stats.fps.firstElementChild, Math.round(fps), 2); 137 | }; 138 | 139 | /** 140 | * Marks a point on the performance graph with a label to help you corrolate events and timing on the graph 141 | * 142 | * @method Phaser.Plugin.Debug#mark 143 | */ 144 | Debug.prototype.mark = function (label) { 145 | if (this.panels.performance) { 146 | this.panels.performance.mark(label); 147 | } 148 | }; 149 | 150 | Debug.prototype.destroy = function () { 151 | Phaser.Plugin.prototype.destroy.call(this); 152 | 153 | for (var p in this.panels) { 154 | this.panels[p].destroy(); 155 | } 156 | 157 | this.panels = null; 158 | this.tickTimings = null; 159 | this.timings = null; 160 | 161 | this._container = null; 162 | this._bar = null; 163 | this._stats = null; 164 | 165 | this.timer = null; 166 | }; 167 | 168 | Debug.prototype._wrap = function (obj, component, method, timingStat) { 169 | if (!obj[component] || !obj[component][method]) { 170 | return; 171 | } 172 | 173 | obj[component][method] = (function(self, name, method, stat, fn) { 174 | var start = 0, 175 | end = 0; 176 | 177 | // special tick capture for game update 178 | if (name === 'game' && method === 'update' && !stat) { 179 | return function () { 180 | start = self.timer.now(); 181 | 182 | self.tickTimings.lastStart = self.tickTimings.start; 183 | self.tickTimings.start = start; 184 | 185 | fn.apply(this, arguments); 186 | 187 | end = self.timer.now(); 188 | 189 | self.tickTimings.ms = end - start; 190 | }; 191 | } 192 | else { 193 | return function () { 194 | start = self.timer.now(); 195 | 196 | fn.apply(this, arguments); 197 | 198 | end = self.timer.now(); 199 | 200 | self.timings[method][stat] = end - start; 201 | }; 202 | } 203 | })(this, component, method, timingStat, obj[component][method]); 204 | }; 205 | 206 | Debug.prototype._bindEvents = function () { 207 | var activePanel, 208 | self = this; 209 | 210 | ui.on(this._bar, 'click', '.pdebug-menu-item', function(e) { 211 | e.preventDefault(); 212 | 213 | var panel = self.panels[e.target.getAttribute('href').replace('#', '')]; 214 | 215 | if(!panel) { 216 | return; 217 | } 218 | 219 | if(activePanel) { 220 | activePanel.toggle(); 221 | ui.removeClass(activePanel._menuItem, 'active'); 222 | 223 | if(activePanel.name === panel.name) { 224 | activePanel = null; 225 | return; 226 | } 227 | } 228 | 229 | ui.addClass(e.target, 'active'); 230 | panel.toggle(); 231 | activePanel = panel; 232 | }); 233 | }; 234 | 235 | Debug.prototype._createElement = function () { 236 | var c = this._container = document.createElement('div'), 237 | bar = this._bar = document.createElement('div'); 238 | 239 | //container 240 | ui.addClass(c, 'pdebug'); 241 | c.appendChild(bar); 242 | 243 | //the menu bar 244 | ui.addClass(bar, 'pdebug-menu'); 245 | bar.appendChild(this._createMenuHead()); 246 | bar.appendChild(this._createMenuStats()); 247 | 248 | //add the panels 249 | for(var p in this.panels) { 250 | bar.appendChild(this.panels[p].createMenuElement()); 251 | c.appendChild(this.panels[p].createPanelElement()); 252 | } 253 | 254 | return c; 255 | }; 256 | 257 | Debug.prototype._createMenuHead = function () { 258 | var div = document.createElement('span'), 259 | r = this.game.renderType, 260 | type = (r === Phaser.WEBGL ? 'WebGL' : (r === Phaser.HEADLESS ? 'Headless' : 'Canvas')); 261 | 262 | ui.addClass(div, 'pdebug-head'); 263 | ui.setText(div, 'Phaser Debug (' + type + '):'); 264 | 265 | return div; 266 | }; 267 | 268 | Debug.prototype._createMenuStats = function () { 269 | var div = document.createElement('div'); 270 | 271 | ui.addClass(div, 'pdebug-stats'); 272 | 273 | this._stats.ms = document.createElement('span'); 274 | this._stats.fps = document.createElement('span'); 275 | this._stats.dpf = document.createElement('span'); 276 | // this._stats.ent = document.createElement('span'); 277 | 278 | ui.addClass(this._stats.ms, 'pdebug-stats-item ms'); 279 | ui.setHtml(this._stats.ms, '0 ms'); 280 | div.appendChild(this._stats.ms); 281 | 282 | ui.addClass(this._stats.fps, 'pdebug-stats-item fps'); 283 | ui.setHtml(this._stats.fps, '0 fps'); 284 | div.appendChild(this._stats.fps); 285 | 286 | ui.addClass(this._stats.dpf, 'pdebug-stats-item dpf'); 287 | ui.setHtml(this._stats.dpf, '0 draws'); 288 | div.appendChild(this._stats.dpf); 289 | 290 | // ui.addClass(this._stats.ent, 'pdebug-stats-item ent'); 291 | // ui.setHtml(this._stats.ent, '0 entities'); 292 | // div.appendChild(this._stats.ent); 293 | 294 | return div; 295 | }; 296 | -------------------------------------------------------------------------------- /dist/phaser-debug.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;"undefined"!=typeof window?n=window:"undefined"!=typeof global?n=global:"undefined"!=typeof self&&(n=self);var f=n;f=f.Phaser||(f.Phaser={}),f=f.Plugin||(f.Plugin={}),f.Debug=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 60 ? 60 : fps; 133 | 134 | // update stats indicators 135 | ui.setText(this._stats.dpf.firstElementChild, dpf === undefined ? '(N/A)' : dpf, 3); 136 | ui.setText(this._stats.ms.firstElementChild, Math.round(this.tickTimings.ms), 4); 137 | ui.setText(this._stats.fps.firstElementChild, Math.round(fps), 2); 138 | }; 139 | 140 | /** 141 | * Marks a point on the performance graph with a label to help you corrolate events and timing on the graph 142 | * 143 | * @method Phaser.Plugin.Debug#mark 144 | */ 145 | Debug.prototype.mark = function (label) { 146 | if (this.panels.performance) { 147 | this.panels.performance.mark(label); 148 | } 149 | }; 150 | 151 | Debug.prototype.destroy = function () { 152 | Phaser.Plugin.prototype.destroy.call(this); 153 | 154 | for (var p in this.panels) { 155 | this.panels[p].destroy(); 156 | } 157 | 158 | this.panels = null; 159 | this.tickTimings = null; 160 | this.timings = null; 161 | 162 | this._container = null; 163 | this._bar = null; 164 | this._stats = null; 165 | 166 | this.timer = null; 167 | }; 168 | 169 | Debug.prototype._wrap = function (obj, component, method, timingStat) { 170 | if (!obj[component] || !obj[component][method]) { 171 | return; 172 | } 173 | 174 | obj[component][method] = (function(self, name, method, stat, fn) { 175 | var start = 0, 176 | end = 0; 177 | 178 | // special tick capture for game update 179 | if (name === 'game' && method === 'update' && !stat) { 180 | return function () { 181 | start = self.timer.now(); 182 | 183 | self.tickTimings.lastStart = self.tickTimings.start; 184 | self.tickTimings.start = start; 185 | 186 | fn.apply(this, arguments); 187 | 188 | end = self.timer.now(); 189 | 190 | self.tickTimings.ms = end - start; 191 | }; 192 | } 193 | else { 194 | return function () { 195 | start = self.timer.now(); 196 | 197 | fn.apply(this, arguments); 198 | 199 | end = self.timer.now(); 200 | 201 | self.timings[method][stat] = end - start; 202 | }; 203 | } 204 | })(this, component, method, timingStat, obj[component][method]); 205 | }; 206 | 207 | Debug.prototype._bindEvents = function () { 208 | var activePanel, 209 | self = this; 210 | 211 | ui.on(this._bar, 'click', '.pdebug-menu-item', function(e) { 212 | e.preventDefault(); 213 | 214 | var panel = self.panels[e.target.getAttribute('href').replace('#', '')]; 215 | 216 | if(!panel) { 217 | return; 218 | } 219 | 220 | if(activePanel) { 221 | activePanel.toggle(); 222 | ui.removeClass(activePanel._menuItem, 'active'); 223 | 224 | if(activePanel.name === panel.name) { 225 | activePanel = null; 226 | return; 227 | } 228 | } 229 | 230 | ui.addClass(e.target, 'active'); 231 | panel.toggle(); 232 | activePanel = panel; 233 | }); 234 | }; 235 | 236 | Debug.prototype._createElement = function () { 237 | var c = this._container = document.createElement('div'), 238 | bar = this._bar = document.createElement('div'); 239 | 240 | //container 241 | ui.addClass(c, 'pdebug'); 242 | c.appendChild(bar); 243 | 244 | //the menu bar 245 | ui.addClass(bar, 'pdebug-menu'); 246 | bar.appendChild(this._createMenuHead()); 247 | bar.appendChild(this._createMenuStats()); 248 | 249 | //add the panels 250 | for(var p in this.panels) { 251 | bar.appendChild(this.panels[p].createMenuElement()); 252 | c.appendChild(this.panels[p].createPanelElement()); 253 | } 254 | 255 | return c; 256 | }; 257 | 258 | Debug.prototype._createMenuHead = function () { 259 | var div = document.createElement('span'), 260 | r = this.game.renderType, 261 | type = (r === Phaser.WEBGL ? 'WebGL' : (r === Phaser.HEADLESS ? 'Headless' : 'Canvas')); 262 | 263 | ui.addClass(div, 'pdebug-head'); 264 | ui.setText(div, 'Phaser Debug (' + type + '):'); 265 | 266 | return div; 267 | }; 268 | 269 | Debug.prototype._createMenuStats = function () { 270 | var div = document.createElement('div'); 271 | 272 | ui.addClass(div, 'pdebug-stats'); 273 | 274 | this._stats.ms = document.createElement('span'); 275 | this._stats.fps = document.createElement('span'); 276 | this._stats.dpf = document.createElement('span'); 277 | // this._stats.ent = document.createElement('span'); 278 | 279 | ui.addClass(this._stats.ms, 'pdebug-stats-item ms'); 280 | ui.setHtml(this._stats.ms, '0 ms'); 281 | div.appendChild(this._stats.ms); 282 | 283 | ui.addClass(this._stats.fps, 'pdebug-stats-item fps'); 284 | ui.setHtml(this._stats.fps, '0 fps'); 285 | div.appendChild(this._stats.fps); 286 | 287 | ui.addClass(this._stats.dpf, 'pdebug-stats-item dpf'); 288 | ui.setHtml(this._stats.dpf, '0 draws'); 289 | div.appendChild(this._stats.dpf); 290 | 291 | // ui.addClass(this._stats.ent, 'pdebug-stats-item ent'); 292 | // ui.setHtml(this._stats.ent, '0 entities'); 293 | // div.appendChild(this._stats.ent); 294 | 295 | return div; 296 | }; 297 | 298 | },{"../package.json":10,"./panels/Performance":15,"./panels/Scene":16,"./styles/main.less":17,"./util/ui":19}],2:[function(require,module,exports){ 299 | "use strict"; 300 | /*globals Handlebars: true */ 301 | var base = require("./handlebars/base"); 302 | 303 | // Each of these augment the Handlebars object. No need to setup here. 304 | // (This is done to easily share code between commonjs and browse envs) 305 | var SafeString = require("./handlebars/safe-string")["default"]; 306 | var Exception = require("./handlebars/exception")["default"]; 307 | var Utils = require("./handlebars/utils"); 308 | var runtime = require("./handlebars/runtime"); 309 | 310 | // For compatibility and usage outside of module systems, make the Handlebars object a namespace 311 | var create = function() { 312 | var hb = new base.HandlebarsEnvironment(); 313 | 314 | Utils.extend(hb, base); 315 | hb.SafeString = SafeString; 316 | hb.Exception = Exception; 317 | hb.Utils = Utils; 318 | hb.escapeExpression = Utils.escapeExpression; 319 | 320 | hb.VM = runtime; 321 | hb.template = function(spec) { 322 | return runtime.template(spec, hb); 323 | }; 324 | 325 | return hb; 326 | }; 327 | 328 | var Handlebars = create(); 329 | Handlebars.create = create; 330 | 331 | Handlebars['default'] = Handlebars; 332 | 333 | exports["default"] = Handlebars; 334 | },{"./handlebars/base":3,"./handlebars/exception":4,"./handlebars/runtime":5,"./handlebars/safe-string":6,"./handlebars/utils":7}],3:[function(require,module,exports){ 335 | "use strict"; 336 | var Utils = require("./utils"); 337 | var Exception = require("./exception")["default"]; 338 | 339 | var VERSION = "2.0.0"; 340 | exports.VERSION = VERSION;var COMPILER_REVISION = 6; 341 | exports.COMPILER_REVISION = COMPILER_REVISION; 342 | var REVISION_CHANGES = { 343 | 1: '<= 1.0.rc.2', // 1.0.rc.2 is actually rev2 but doesn't report it 344 | 2: '== 1.0.0-rc.3', 345 | 3: '== 1.0.0-rc.4', 346 | 4: '== 1.x.x', 347 | 5: '== 2.0.0-alpha.x', 348 | 6: '>= 2.0.0-beta.1' 349 | }; 350 | exports.REVISION_CHANGES = REVISION_CHANGES; 351 | var isArray = Utils.isArray, 352 | isFunction = Utils.isFunction, 353 | toString = Utils.toString, 354 | objectType = '[object Object]'; 355 | 356 | function HandlebarsEnvironment(helpers, partials) { 357 | this.helpers = helpers || {}; 358 | this.partials = partials || {}; 359 | 360 | registerDefaultHelpers(this); 361 | } 362 | 363 | exports.HandlebarsEnvironment = HandlebarsEnvironment;HandlebarsEnvironment.prototype = { 364 | constructor: HandlebarsEnvironment, 365 | 366 | logger: logger, 367 | log: log, 368 | 369 | registerHelper: function(name, fn) { 370 | if (toString.call(name) === objectType) { 371 | if (fn) { throw new Exception('Arg not supported with multiple helpers'); } 372 | Utils.extend(this.helpers, name); 373 | } else { 374 | this.helpers[name] = fn; 375 | } 376 | }, 377 | unregisterHelper: function(name) { 378 | delete this.helpers[name]; 379 | }, 380 | 381 | registerPartial: function(name, partial) { 382 | if (toString.call(name) === objectType) { 383 | Utils.extend(this.partials, name); 384 | } else { 385 | this.partials[name] = partial; 386 | } 387 | }, 388 | unregisterPartial: function(name) { 389 | delete this.partials[name]; 390 | } 391 | }; 392 | 393 | function registerDefaultHelpers(instance) { 394 | instance.registerHelper('helperMissing', function(/* [args, ]options */) { 395 | if(arguments.length === 1) { 396 | // A missing field in a {{foo}} constuct. 397 | return undefined; 398 | } else { 399 | // Someone is actually trying to call something, blow up. 400 | throw new Exception("Missing helper: '" + arguments[arguments.length-1].name + "'"); 401 | } 402 | }); 403 | 404 | instance.registerHelper('blockHelperMissing', function(context, options) { 405 | var inverse = options.inverse, 406 | fn = options.fn; 407 | 408 | if(context === true) { 409 | return fn(this); 410 | } else if(context === false || context == null) { 411 | return inverse(this); 412 | } else if (isArray(context)) { 413 | if(context.length > 0) { 414 | if (options.ids) { 415 | options.ids = [options.name]; 416 | } 417 | 418 | return instance.helpers.each(context, options); 419 | } else { 420 | return inverse(this); 421 | } 422 | } else { 423 | if (options.data && options.ids) { 424 | var data = createFrame(options.data); 425 | data.contextPath = Utils.appendContextPath(options.data.contextPath, options.name); 426 | options = {data: data}; 427 | } 428 | 429 | return fn(context, options); 430 | } 431 | }); 432 | 433 | instance.registerHelper('each', function(context, options) { 434 | if (!options) { 435 | throw new Exception('Must pass iterator to #each'); 436 | } 437 | 438 | var fn = options.fn, inverse = options.inverse; 439 | var i = 0, ret = "", data; 440 | 441 | var contextPath; 442 | if (options.data && options.ids) { 443 | contextPath = Utils.appendContextPath(options.data.contextPath, options.ids[0]) + '.'; 444 | } 445 | 446 | if (isFunction(context)) { context = context.call(this); } 447 | 448 | if (options.data) { 449 | data = createFrame(options.data); 450 | } 451 | 452 | if(context && typeof context === 'object') { 453 | if (isArray(context)) { 454 | for(var j = context.length; i": ">", 810 | '"': """, 811 | "'": "'", 812 | "`": "`" 813 | }; 814 | 815 | var badChars = /[&<>"'`]/g; 816 | var possible = /[&<>"'`]/; 817 | 818 | function escapeChar(chr) { 819 | return escape[chr]; 820 | } 821 | 822 | function extend(obj /* , ...source */) { 823 | for (var i = 1; i < arguments.length; i++) { 824 | for (var key in arguments[i]) { 825 | if (Object.prototype.hasOwnProperty.call(arguments[i], key)) { 826 | obj[key] = arguments[i][key]; 827 | } 828 | } 829 | } 830 | 831 | return obj; 832 | } 833 | 834 | exports.extend = extend;var toString = Object.prototype.toString; 835 | exports.toString = toString; 836 | // Sourced from lodash 837 | // https://github.com/bestiejs/lodash/blob/master/LICENSE.txt 838 | var isFunction = function(value) { 839 | return typeof value === 'function'; 840 | }; 841 | // fallback for older versions of Chrome and Safari 842 | /* istanbul ignore next */ 843 | if (isFunction(/x/)) { 844 | isFunction = function(value) { 845 | return typeof value === 'function' && toString.call(value) === '[object Function]'; 846 | }; 847 | } 848 | var isFunction; 849 | exports.isFunction = isFunction; 850 | /* istanbul ignore next */ 851 | var isArray = Array.isArray || function(value) { 852 | return (value && typeof value === 'object') ? toString.call(value) === '[object Array]' : false; 853 | }; 854 | exports.isArray = isArray; 855 | 856 | function escapeExpression(string) { 857 | // don't escape SafeStrings, since they're already safe 858 | if (string instanceof SafeString) { 859 | return string.toString(); 860 | } else if (string == null) { 861 | return ""; 862 | } else if (!string) { 863 | return string + ''; 864 | } 865 | 866 | // Force a string conversion as this will be done by the append regardless and 867 | // the regex test will do this transparently behind the scenes, causing issues if 868 | // an object's to string has escaped characters in it. 869 | string = "" + string; 870 | 871 | if(!possible.test(string)) { return string; } 872 | return string.replace(badChars, escapeChar); 873 | } 874 | 875 | exports.escapeExpression = escapeExpression;function isEmpty(value) { 876 | if (!value && value !== 0) { 877 | return true; 878 | } else if (isArray(value) && value.length === 0) { 879 | return true; 880 | } else { 881 | return false; 882 | } 883 | } 884 | 885 | exports.isEmpty = isEmpty;function appendContextPath(contextPath, id) { 886 | return (contextPath ? contextPath + '.' : '') + id; 887 | } 888 | 889 | exports.appendContextPath = appendContextPath; 890 | },{"./safe-string":6}],8:[function(require,module,exports){ 891 | // Create a simple path alias to allow browserify to resolve 892 | // the runtime on a supported path. 893 | module.exports = require('./dist/cjs/handlebars.runtime'); 894 | 895 | },{"./dist/cjs/handlebars.runtime":2}],9:[function(require,module,exports){ 896 | module.exports = require("handlebars/runtime")["default"]; 897 | 898 | },{"handlebars/runtime":8}],10:[function(require,module,exports){ 899 | module.exports={ 900 | "name": "phaser-debug", 901 | "version": "1.1.9", 902 | "description": "Simple debug module for phaser", 903 | "author": "Chad Engler ", 904 | "license": "MIT", 905 | "homepage": "https://github.com/englercj/phaser-debug", 906 | "repository": { 907 | "type": "git", 908 | "url": "https://github.com/englercj/phaser-debug.git" 909 | }, 910 | "bugs": { 911 | "url": "https://github.com/englercj/phaser-debug/issues" 912 | }, 913 | "keywords": [ 914 | "phaser", 915 | "debug", 916 | "html5", 917 | "game", 918 | "engine" 919 | ], 920 | "dependencies": { 921 | "handlebars": "^2.0.0", 922 | "node-lessify": "^0.0.5", 923 | "hbsfy": "^2.1.0" 924 | }, 925 | "devDependencies": { 926 | "browserify": "^5.11.1", 927 | "event-stream": "^3.1.7", 928 | "gulp": "^3.8.8", 929 | "gulp-bump": "^0.1.11", 930 | "gulp-git": "^0.5.3", 931 | "gulp-jshint": "^1.8.4", 932 | "gulp-util": "^3.0.1", 933 | "jshint-summary": "^0.4.0", 934 | "vinyl-source-stream": "^0.1.1", 935 | "watchify": "^1.0.2" 936 | }, 937 | "main": "./dist/phaser-debug.js", 938 | "browser": "./src/index.js", 939 | "browserify": { 940 | "transform": [ 941 | "hbsfy", 942 | "node-lessify" 943 | ], 944 | "transform-options": { 945 | "node-lessify": "textMode" 946 | } 947 | } 948 | } 949 | 950 | },{}],11:[function(require,module,exports){ 951 | // hbsfy compiled Handlebars template 952 | var HandlebarsCompiler = require('hbsfy/runtime'); 953 | module.exports = HandlebarsCompiler.template({"1":function(depth0,helpers,partials,data) { 954 | var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression; 955 | return " \n " 956 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.children : depth0)) != null ? stack1.length : stack1), depth0)) 957 | + "\n
    \n"; 958 | },"3":function(depth0,helpers,partials,data) { 959 | var stack1, buffer = " \n"; 960 | stack1 = helpers['if'].call(depth0, ((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.texture : depth0)) != null ? stack1.baseTexture : stack1)) != null ? stack1.source : stack1)) != null ? stack1.src : stack1), {"name":"if","hash":{},"fn":this.program(4, data),"inverse":this.program(6, data),"data":data}); 961 | if (stack1 != null) { buffer += stack1; } 962 | return buffer + "
    \n"; 963 | },"4":function(depth0,helpers,partials,data) { 964 | var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression; 965 | return " " 968 | + escapeExpression(lambda(((stack1 = ((stack1 = ((stack1 = (depth0 != null ? depth0.texture : depth0)) != null ? stack1.baseTexture : stack1)) != null ? stack1.source : stack1)) != null ? stack1.src : stack1), depth0)) 969 | + "\n"; 970 | },"6":function(depth0,helpers,partials,data) { 971 | var stack1, lambda=this.lambda, escapeExpression=this.escapeExpression; 972 | return " " 973 | + escapeExpression(lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.texture : depth0)) != null ? stack1.baseTexture : stack1)) != null ? stack1.source : stack1), depth0)) 974 | + "\n"; 975 | },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { 976 | var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, lambda=this.lambda, buffer = "

    \n\n\n" 977 | + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper))) 978 | + "\n
    \n\n\n" 979 | + escapeExpression(((helper = (helper = helpers.typeString || (depth0 != null ? depth0.typeString : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"typeString","hash":{},"data":data}) : helper))) 980 | + "\n
    \n\n\n" 981 | + escapeExpression(((helper = (helper = helpers.visible || (depth0 != null ? depth0.visible : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"visible","hash":{},"data":data}) : helper))) 982 | + "\n
    \n\n\n" 983 | + escapeExpression(((helper = (helper = helpers.rotation || (depth0 != null ? depth0.rotation : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"rotation","hash":{},"data":data}) : helper))) 984 | + "\n
    \n\n\n" 985 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.position : depth0)) != null ? stack1.x : stack1), depth0)) 986 | + " x " 987 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.position : depth0)) != null ? stack1.y : stack1), depth0)) 988 | + "\n
    \n\n\n" 989 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.scale : depth0)) != null ? stack1.x : stack1), depth0)) 990 | + " x " 991 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.scale : depth0)) != null ? stack1.y : stack1), depth0)) 992 | + "\n
    \n\n\n" 993 | + escapeExpression(((helper = (helper = helpers.alpha || (depth0 != null ? depth0.alpha : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"alpha","hash":{},"data":data}) : helper))) 994 | + "\n
    \n\n
    \n\n\n" 995 | + escapeExpression(((helper = (helper = helpers.worldVisible || (depth0 != null ? depth0.worldVisible : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"worldVisible","hash":{},"data":data}) : helper))) 996 | + "\n
    \n\n\n" 997 | + escapeExpression(((helper = (helper = helpers.worldRotation || (depth0 != null ? depth0.worldRotation : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"worldRotation","hash":{},"data":data}) : helper))) 998 | + "\n
    \n\n\n" 999 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.worldPosition : depth0)) != null ? stack1.x : stack1), depth0)) 1000 | + " x " 1001 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.worldPosition : depth0)) != null ? stack1.y : stack1), depth0)) 1002 | + "\n
    \n\n\n" 1003 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.worldScale : depth0)) != null ? stack1.x : stack1), depth0)) 1004 | + " x " 1005 | + escapeExpression(lambda(((stack1 = (depth0 != null ? depth0.worldScale : depth0)) != null ? stack1.y : stack1), depth0)) 1006 | + "\n
    \n\n\n" 1007 | + escapeExpression(((helper = (helper = helpers.worldAlpha || (depth0 != null ? depth0.worldAlpha : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"worldAlpha","hash":{},"data":data}) : helper))) 1008 | + "\n
    \n\n
    \n\n"; 1009 | stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.children : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data}); 1010 | if (stack1 != null) { buffer += stack1; } 1011 | buffer += "\n"; 1012 | stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.texture : depth0), {"name":"if","hash":{},"fn":this.program(3, data),"inverse":this.noop,"data":data}); 1013 | if (stack1 != null) { buffer += stack1; } 1014 | return buffer; 1015 | },"useData":true}); 1016 | 1017 | },{"hbsfy/runtime":9}],12:[function(require,module,exports){ 1018 | // hbsfy compiled Handlebars template 1019 | var HandlebarsCompiler = require('hbsfy/runtime'); 1020 | module.exports = HandlebarsCompiler.template({"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { 1021 | return "
      \n
    \n\nrefresh\n
    \n
    \n"; 1022 | },"useData":true}); 1023 | 1024 | },{"hbsfy/runtime":9}],13:[function(require,module,exports){ 1025 | // hbsfy compiled Handlebars template 1026 | var HandlebarsCompiler = require('hbsfy/runtime'); 1027 | module.exports = HandlebarsCompiler.template({"1":function(depth0,helpers,partials,data) { 1028 | var helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression; 1029 | return " (" 1030 | + escapeExpression(((helper = (helper = helpers.name || (depth0 != null ? depth0.name : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"name","hash":{},"data":data}) : helper))) 1031 | + ")\n"; 1032 | },"3":function(depth0,helpers,partials,data) { 1033 | var stack1, buffer = "
      \n"; 1034 | stack1 = helpers.each.call(depth0, (depth0 != null ? depth0.children : depth0), {"name":"each","hash":{},"fn":this.program(4, data),"inverse":this.noop,"data":data}); 1035 | if (stack1 != null) { buffer += stack1; } 1036 | return buffer + "
    \n"; 1037 | },"4":function(depth0,helpers,partials,data) { 1038 | var stack1, buffer = ""; 1039 | stack1 = this.invokePartial(partials.sceneTree, ' ', 'sceneTree', depth0, undefined, helpers, partials, data); 1040 | if (stack1 != null) { buffer += stack1; } 1041 | return buffer; 1042 | },"compiler":[6,">= 2.0.0-beta.1"],"main":function(depth0,helpers,partials,data) { 1043 | var stack1, helper, functionType="function", helperMissing=helpers.helperMissing, escapeExpression=this.escapeExpression, buffer = escapeExpression(((helper = (helper = helpers.listItemOpen || (depth0 != null ? depth0.listItemOpen : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"listItemOpen","hash":{},"data":data}) : helper))) 1044 | + "\n " 1045 | + escapeExpression(((helper = (helper = helpers.typeString || (depth0 != null ? depth0.typeString : depth0)) != null ? helper : helperMissing),(typeof helper === functionType ? helper.call(depth0, {"name":"typeString","hash":{},"data":data}) : helper))) 1046 | + "\n\n"; 1047 | stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.name : depth0), {"name":"if","hash":{},"fn":this.program(1, data),"inverse":this.noop,"data":data}); 1048 | if (stack1 != null) { buffer += stack1; } 1049 | buffer += "\n"; 1050 | stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0.children : depth0), {"name":"if","hash":{},"fn":this.program(3, data),"inverse":this.noop,"data":data}); 1051 | if (stack1 != null) { buffer += stack1; } 1052 | return buffer + "
  • \n"; 1053 | },"usePartial":true,"useData":true}); 1054 | 1055 | },{"hbsfy/runtime":9}],14:[function(require,module,exports){ 1056 | var ui = require('../util/ui'); 1057 | 1058 | function Panel(game, parent) { 1059 | this.game = game; 1060 | this.parent = parent; 1061 | 1062 | this.name = ''; 1063 | this.title = ''; 1064 | this.active = false; 1065 | 1066 | this._panel = null; 1067 | } 1068 | 1069 | Panel.prototype.constructor = Panel; 1070 | 1071 | module.exports = Panel; 1072 | 1073 | //builds the html for a panel 1074 | Panel.prototype.createPanelElement = function () { 1075 | var elm = this._panel = document.createElement('div'); 1076 | ui.addClass(elm, 'pdebug-panel ' + this.name); 1077 | 1078 | return elm; 1079 | }; 1080 | 1081 | //builds the html for this panels menu item 1082 | Panel.prototype.createMenuElement = function () { 1083 | var elm = this._menuItem = document.createElement('a'); 1084 | 1085 | elm.href = '#' + this.name; 1086 | 1087 | ui.addClass(elm, 'pdebug-menu-item ' + this.name); 1088 | ui.setText(elm, this.title); 1089 | 1090 | return elm; 1091 | }; 1092 | 1093 | Panel.prototype.toggle = function () { 1094 | if (this.active) { 1095 | this.hide(); 1096 | } else { 1097 | this.show(); 1098 | } 1099 | }; 1100 | 1101 | Panel.prototype.show = function () { 1102 | this.active = true; 1103 | ui.setStyle(this._panel, 'display', 'block'); 1104 | }; 1105 | 1106 | Panel.prototype.hide = function () { 1107 | this.active = false; 1108 | ui.setStyle(this._panel, 'display', 'none'); 1109 | }; 1110 | 1111 | Panel.prototype.destroy = function () { 1112 | this.game = null; 1113 | this.parent = null; 1114 | 1115 | this.name = null; 1116 | this.title = null; 1117 | this.active = null; 1118 | 1119 | this._panel = null; 1120 | }; 1121 | 1122 | },{"../util/ui":19}],15:[function(require,module,exports){ 1123 | // TODO: Not measuring render time!! 1124 | 1125 | var Panel = require('./Panel'), 1126 | Graph = require('../util/Graph'); 1127 | 1128 | function Performance(game, parent) { 1129 | Panel.call(this, game, parent); 1130 | 1131 | this.name = 'performance'; 1132 | this.title = 'Performance'; 1133 | this.eventQueue = []; 1134 | 1135 | this.graph = null; 1136 | 1137 | this.colorPalettes = { 1138 | _default: [ 1139 | // Colors from: https://github.com/highslide-software/highcharts.com/blob/master/js/themes/grid.js 1140 | '#058DC7', '#50B432', '#ED561B', '#DDDF00', 1141 | '#24CBE5', '#64E572', '#FF9655', '#FFF263', 1142 | '#6AF9C4', 1143 | // Colors from: https://github.com/highslide-software/highcharts.com/blob/master/js/themes/dark-unica.js 1144 | '#2b908f', '#90ee7e', '#f45b5b', '#7798BF', 1145 | '#aaeeee', '#ff0066', '#eeaaee', 1146 | '#55BF3B', '#DF5353', '#7798BF', '#aaeeee' 1147 | ] 1148 | }; 1149 | } 1150 | 1151 | Performance.prototype = Object.create(Panel.prototype); 1152 | Performance.prototype.constructor = Performance; 1153 | 1154 | module.exports = Performance; 1155 | 1156 | Performance.prototype.createPanelElement = function () { 1157 | var elm = Panel.prototype.createPanelElement.call(this); 1158 | 1159 | this.graph = new Graph(elm, window.innerWidth - 20, 256, this.colorPalettes._default); 1160 | 1161 | return elm; 1162 | }; 1163 | 1164 | Performance.prototype.update = function () { 1165 | this.graph.addData(this.parent.timings, this.eventQueue.shift()); 1166 | }; 1167 | 1168 | Performance.prototype.mark = function (label) { 1169 | this.eventQueue.push(label); 1170 | }; 1171 | 1172 | Performance.prototype.destroy = function () { 1173 | Panel.prototype.destroy.call(this); 1174 | 1175 | this.graph.destroy(); 1176 | 1177 | this.eventQueue = null; 1178 | this.graph = null; 1179 | this.colorPalettes = null; 1180 | }; 1181 | 1182 | },{"../util/Graph":18,"./Panel":14}],16:[function(require,module,exports){ 1183 | var Panel = require('./Panel'), 1184 | ui = require('../util/ui'), 1185 | Handlebars = require('hbsfy/runtime'); 1186 | 1187 | //require templates 1188 | var panelHtml = require('../hbs/scene/panel.hbs'), 1189 | detailsHtml = require('../hbs/scene/details.hbs'), 1190 | treeHtml = require('../hbs/scene/tree.hbs'), 1191 | _cache = {}, 1192 | _id = 0; 1193 | 1194 | Handlebars.registerPartial('sceneDetails', detailsHtml); 1195 | Handlebars.registerPartial('sceneTree', treeHtml); 1196 | Handlebars.registerHelper('typeString', typeToString); 1197 | Handlebars.registerHelper('listItemOpen', listItemOpen); 1198 | 1199 | function Scene(game, parent) { 1200 | Panel.call(this, game, parent); 1201 | 1202 | this.name = 'scene'; 1203 | this.title = 'Scene Tree'; 1204 | 1205 | this._tree = null; 1206 | 1207 | this.tree = null; 1208 | this.details = null; 1209 | this.refresh = null; 1210 | 1211 | this.selected = null; 1212 | } 1213 | 1214 | Scene.prototype = Object.create(Panel.prototype); 1215 | Scene.prototype.constructor = Scene; 1216 | 1217 | module.exports = Scene; 1218 | 1219 | Scene.prototype.createPanelElement = function () { 1220 | Panel.prototype.createPanelElement.call(this); 1221 | 1222 | this._panel.innerHTML = panelHtml(this.game.stage); 1223 | 1224 | this.tree = this._panel.querySelector('.sidebar'); 1225 | this.details = this._panel.querySelector('.details'); 1226 | this.refresh = this._panel.querySelector('.refresh'); 1227 | 1228 | ui.on(this.tree, 'click', 'li', this._onLiClick.bind(this)); 1229 | ui.on(this.refresh, 'click', this._onRefreshClick.bind(this)); 1230 | 1231 | this.bmd = this.game.add.bitmapData(512, 256); 1232 | 1233 | return this._panel; 1234 | }; 1235 | 1236 | Scene.prototype.rebuildTree = function () { 1237 | ui.empty(this.tree); 1238 | 1239 | _cache = {}; 1240 | 1241 | this.tree.innerHTML = treeHtml(this.game.stage); 1242 | 1243 | this.select(this.tree.querySelector('li:first-child')); 1244 | ui.addClass(this.selected, 'expanded'); 1245 | 1246 | this.reloadDetails(); 1247 | }; 1248 | 1249 | Scene.prototype.reloadDetails = function () { 1250 | var id = this.selected.dataset.id; 1251 | var obj = _cache[id]; 1252 | 1253 | this.details.innerHTML = detailsHtml(obj); 1254 | 1255 | if (obj.texture) { 1256 | this.details.appendChild(this.bmd.canvas); 1257 | 1258 | var w = Math.min(512, obj.width); 1259 | var h = Math.min(256, obj.height); 1260 | 1261 | this.bmd.clear(); 1262 | this.bmd.resize(w, h); 1263 | 1264 | try { 1265 | this.bmd.draw(obj, 0, 0, w, h); 1266 | } catch (e) {}; 1267 | } 1268 | }; 1269 | 1270 | Scene.prototype.select = function (li) { 1271 | if (this.selected) { 1272 | ui.removeClass(this.selected, 'selected'); 1273 | } 1274 | 1275 | this.selected = li; 1276 | ui.addClass(this.selected, 'selected'); 1277 | }; 1278 | 1279 | Scene.prototype.show = function () { 1280 | this.rebuildTree(); 1281 | 1282 | Panel.prototype.show.call(this); 1283 | }; 1284 | 1285 | Scene.prototype.destroy = function () { 1286 | Panel.prototype.destroy.call(this); 1287 | 1288 | this.tree = null; 1289 | this.details = null; 1290 | this.refresh = null; 1291 | }; 1292 | 1293 | Scene.prototype._onLiClick = function (e) { 1294 | e.stopPropagation(); 1295 | 1296 | this.select(e.delegateTarget); 1297 | 1298 | ui.toggleClass(e.delegateTarget, 'expanded'); 1299 | 1300 | this.reloadDetails(); 1301 | }; 1302 | 1303 | Scene.prototype._onRefreshClick = function (e) { 1304 | e.preventDefault(); 1305 | e.stopPropagation(); 1306 | 1307 | this.rebuildTree(); 1308 | }; 1309 | 1310 | function listItemOpen () { 1311 | _cache[++_id] = this; 1312 | 1313 | return new Handlebars.SafeString( 1314 | '
  • ' 1315 | ); 1316 | } 1317 | 1318 | function typeToString () { 1319 | var node = this; 1320 | 1321 | // If no phaser type defined, try to guess 1322 | if (node.type === undefined) { 1323 | // Phaser.Stage does not have its 'type' property defined, so check here. 1324 | if (node instanceof Phaser.Stage) { 1325 | return 'Stage'; 1326 | } 1327 | // PIXI.Stage was removed in Phaser 2.4.4, so make sure it's defined first. 1328 | else if (typeof PIXI.Stage !== 'undefined' && 1329 | node instanceof PIXI.Stage) { 1330 | return 'PIXI Stage'; 1331 | } 1332 | else if (node instanceof PIXI.Sprite) { 1333 | return 'PIXI Sprite'; 1334 | } 1335 | else if (node instanceof PIXI.DisplayObjectContainer) { 1336 | return 'PIXI DisplayObjectContainer'; 1337 | } 1338 | else if (node instanceof PIXI.DisplayObject) { 1339 | return 'PIXI DisplayObject'; 1340 | } 1341 | else { 1342 | return 'Unknown'; 1343 | } 1344 | } 1345 | // return a string for the phaser type 1346 | else { 1347 | switch(node.type) { 1348 | case Phaser.SPRITE: 1349 | return 'Sprite'; 1350 | 1351 | case Phaser.BUTTON: 1352 | return 'Button'; 1353 | 1354 | case Phaser.IMAGE: 1355 | return 'Image'; 1356 | 1357 | case Phaser.GRAPHICS: 1358 | return 'Graphics'; 1359 | 1360 | case Phaser.TEXT: 1361 | return 'Text'; 1362 | 1363 | case Phaser.TILESPRITE: 1364 | return 'Tile Sprite'; 1365 | 1366 | case Phaser.BITMAPTEXT: 1367 | return 'Bitmap Text'; 1368 | 1369 | case Phaser.GROUP: 1370 | return 'Group'; 1371 | 1372 | case Phaser.RENDERTEXTURE: 1373 | return 'Render Texture'; 1374 | 1375 | case Phaser.TILEMAP: 1376 | return 'Tilemap'; 1377 | 1378 | case Phaser.TILEMAPLAYER: 1379 | return 'Tilemap Layer'; 1380 | 1381 | case Phaser.EMITTER: 1382 | return 'Emitter'; 1383 | 1384 | case Phaser.POLYGON: 1385 | return 'Polygon'; 1386 | 1387 | case Phaser.BITMAPDATA: 1388 | return 'Bitmap Data'; 1389 | 1390 | case Phaser.CANVAS_FILTER: 1391 | return 'Canvas Filter'; 1392 | 1393 | case Phaser.WEBGL_FILTER: 1394 | return 'WebGL Filter'; 1395 | 1396 | case Phaser.ELLIPSE: 1397 | return 'Ellipse'; 1398 | 1399 | case Phaser.SPRITEBATCH: 1400 | return 'Sprite Batch'; 1401 | 1402 | case Phaser.RETROFONT: 1403 | return 'Retro Font'; 1404 | 1405 | case Phaser.POINTER: 1406 | return 'Pointer'; 1407 | 1408 | case Phaser.ROPE: 1409 | return 'Rope'; 1410 | 1411 | default: 1412 | return 'Unknown'; 1413 | } 1414 | } 1415 | } 1416 | 1417 | },{"../hbs/scene/details.hbs":11,"../hbs/scene/panel.hbs":12,"../hbs/scene/tree.hbs":13,"../util/ui":19,"./Panel":14,"hbsfy/runtime":9}],17:[function(require,module,exports){ 1418 | module.exports = ".pdebug{font-size:14px;position:fixed;bottom:0;width:100%;color:#aaa;background:#333;border-top:3px solid #00bf00;z-index:999999}.pdebug a{color:#00bf00}.pdebug label{display:inline-block;width:100px}.pdebug strong{font-weight:400;color:#fff}.pdebug .weak{color:#aaa}.pdebug .pdebug-menu{height:32px;padding:0 15px;text-shadow:1px 1px 0 #111;background:#333}.pdebug .pdebug-menu span{display:inline-block;height:32px;line-height:32px}.pdebug .pdebug-menu .pdebug-head{padding-right:25px;border-right:1px solid #666}.pdebug .pdebug-menu .pdebug-stats{float:right;padding:0 0 0 10px}.pdebug .pdebug-menu .pdebug-stats .pdebug-stats-item{display:inline-block;width:100px;text-align:right}.pdebug .pdebug-menu .pdebug-stats .pdebug-stats-item>span{color:#fff}.pdebug .pdebug-menu .pdebug-stats .pdebug-stats-item.obj{width:100px;border:0}.pdebug .pdebug-menu .pdebug-menu-item{color:#fff;display:inline-block;text-decoration:none;padding:0 10px;height:32px;line-height:32px;border-right:1px solid #666}.pdebug .pdebug-menu .pdebug-menu-item.active{color:#00bf00;background:#111}.pdebug .pdebug-panel{display:none;height:265px;overflow:auto;font-size:12px;background:#111}.pdebug .pdebug-panel.scene .sidebar{float:left;height:100%;min-width:175px;max-width:500px;resize:horizontal;overflow:auto}.pdebug .pdebug-panel.scene .details{float:left;height:100%}.pdebug .pdebug-panel.scene .refresh{position:absolute}.pdebug .pdebug-panel.scene>ul{padding:0;margin:0;border-right:solid 1px #aaa;margin-right:10px}.pdebug .pdebug-panel.scene>ul li{color:#fff;list-style:none;cursor:pointer}.pdebug .pdebug-panel.scene>ul li.expanded>ul{display:block}.pdebug .pdebug-panel.scene>ul li.selected{color:#00bf00}.pdebug .pdebug-panel.scene>ul li::before{content:\'-\';display:inline-block;width:12px;height:1px;color:#aaa}.pdebug .pdebug-panel.scene>ul li.has-children::before{content:\'\';display:inline-block;width:0;height:0;margin:0 6px 0 0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-right:0;border-left:6px solid rgba(255,255,255,.3)}.pdebug .pdebug-panel.scene>ul li.has-children.expanded::before{margin:0 4px 0 -4px;border-top:6px solid rgba(255,255,255,.3);border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:0}.pdebug .pdebug-panel.scene>ul li>ul{display:none;padding:0 0 0 10px}.pdebug input[type=checkbox]{visibility:hidden}.pdebug .checkbox{width:75px;height:26px;background:#333;position:relative;line-height:normal;-webkit-border-radius:50px;-moz-border-radius:50px;border-radius:50px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.2);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.2);-o-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.2);-ms-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.2);box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,.2)}.pdebug .checkbox:after{content:\'OFF\';font:12px/26px Arial,sans-serif;color:#000;position:absolute;right:10px;z-index:0;font-weight:700;text-shadow:1px 1px 0 rgba(255,255,255,.15)}.pdebug .checkbox:before{content:\'ON\';font:12px/26px Arial,sans-serif;color:#00bf00;position:absolute;left:10px;z-index:0;font-weight:700}.pdebug .checkbox+span{position:relative;display:block;top:-25px;left:90px;width:200px;color:#fcfff4;font-size:1.1em}.pdebug .checkbox input[type=checkbox]:checked+label{left:38px}.pdebug .checkbox label{display:block;width:34px;height:20px;-webkit-border-radius:50px;-moz-border-radius:50px;border-radius:50px;-webkit-transition:all .4s ease;-moz-transition:all .4s ease;-o-transition:all .4s ease;-ms-transition:all .4s ease;transition:all .4s ease;cursor:pointer;position:absolute;top:3px;left:3px;z-index:1;background:#fcfff4;background:-webkit-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-moz-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-o-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-ms-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);-webkit-box-shadow:0 2px 5px 0 rgba(0,0,0,.3);-moz-box-shadow:0 2px 5px 0 rgba(0,0,0,.3);box-shadow:0 2px 5px 0 rgba(0,0,0,.3)}"; 1419 | },{}],18:[function(require,module,exports){ 1420 | // TODO: Move the legend into DOM? 1421 | 1422 | function Graph(container, width, height, colors, options) { 1423 | options = options || {}; 1424 | 1425 | this.canvas = document.createElement('canvas'); 1426 | this.canvas.width = width; 1427 | this.canvas.height = height; 1428 | container.appendChild(this.canvas); 1429 | 1430 | this.ctx = this.canvas.getContext('2d'); 1431 | 1432 | this.labelStyle = 'rgba(200, 200, 200, 0.6)'; 1433 | 1434 | this.maxValue = options.maxValue || 50; 1435 | this.padding = options.labelPadding || 5; 1436 | 1437 | this.dataLineWidth = options.lineWidth || 1; 1438 | this.legendWidth = 230; 1439 | this.legendBoxSize = 10; 1440 | this.legendIndent = 5; 1441 | 1442 | this.eventY = this.padding * 2; 1443 | 1444 | this.colors = colors; 1445 | 1446 | this.dataCanvas = document.createElement('canvas'); 1447 | this.dataCanvas.width = width - this.legendWidth; 1448 | this.dataCanvas.height = height; 1449 | this.dctx = this.dataCanvas.getContext('2d'); 1450 | 1451 | this.dataCanvasBuffer = document.createElement('canvas'); 1452 | this.dataCanvasBuffer.width = this.dataCanvas.width - this.dataLineWidth; 1453 | this.dataCanvasBuffer.height = this.dataCanvas.height; 1454 | this.bctx = this.dataCanvasBuffer.getContext('2d'); 1455 | } 1456 | 1457 | Graph.prototype.constructor = Graph; 1458 | 1459 | module.exports = Graph; 1460 | 1461 | // render the graph with the new data point 1462 | Graph.prototype.addData = function (values, event) { 1463 | // clear the main canvas 1464 | this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height); 1465 | 1466 | this.drawBg(); 1467 | this.drawLegend(values); 1468 | this.drawData(values, event); 1469 | }; 1470 | 1471 | Graph.prototype.drawBg = function () { 1472 | var fps60 = Math.floor(this.canvas.height - (this.canvas.height * (16 / this.maxValue))) + 0.5, 1473 | fps30 = Math.floor(this.canvas.height - (this.canvas.height * (33 / this.maxValue))) + 0.5; 1474 | 1475 | this.ctx.strokeStyle = this.ctx.fillStyle = this.labelStyle; 1476 | this.ctx.lineWidth = 1; 1477 | 1478 | //draw top marker line 1479 | this.ctx.beginPath(); 1480 | this.ctx.moveTo(this.legendWidth, fps60); 1481 | this.ctx.lineTo(this.canvas.width, fps60); 1482 | this.ctx.stroke(); 1483 | 1484 | this.ctx.fillText('16ms (60 fps)', this.legendWidth + this.padding, fps60 - this.padding); 1485 | 1486 | //draw the second marker line 1487 | this.ctx.beginPath(); 1488 | this.ctx.moveTo(this.legendWidth, fps30); 1489 | this.ctx.lineTo(this.canvas.width, fps30); 1490 | this.ctx.stroke(); 1491 | 1492 | this.ctx.fillText('33ms (30 fps)', this.legendWidth + this.padding, fps30 - this.padding); 1493 | 1494 | //draw baseline marker 1495 | this.ctx.beginPath(); 1496 | this.ctx.moveTo(this.legendWidth, this.canvas.height - 0.5); 1497 | this.ctx.lineTo(this.canvas.width, this.canvas.height - 0.5); 1498 | this.ctx.stroke(); 1499 | }; 1500 | 1501 | Graph.prototype.drawLegend = function (values) { 1502 | var colorIndex = 0, 1503 | yIndex = 0, 1504 | x = this.padding, 1505 | y = 0; 1506 | 1507 | for (var k in values) { 1508 | y = (yIndex * this.legendBoxSize) + (this.padding * (yIndex + 1)) + this.padding; 1509 | 1510 | // Draw parent label 1511 | this.ctx.fillStyle = this.labelStyle; 1512 | this.ctx.fillText(k, x, y); 1513 | 1514 | ++yIndex; 1515 | 1516 | // Draw children 1517 | for (var c in values[k]) { 1518 | y = (yIndex * this.legendBoxSize) + (this.padding * yIndex); 1519 | 1520 | this.ctx.fillStyle = this.colors[colorIndex++ % this.colors.length]; 1521 | this.ctx.fillRect(x + this.legendIndent, y, this.legendBoxSize, this.legendBoxSize); 1522 | 1523 | this.ctx.fillStyle = this.labelStyle; 1524 | this.ctx.fillText( 1525 | Math.round(values[k][c]) + 'ms - ' + c, 1526 | x + this.legendIndent + this.legendBoxSize + this.padding, 1527 | y + this.legendBoxSize 1528 | ); 1529 | 1530 | ++yIndex; 1531 | 1532 | if (yIndex > 16) { 1533 | x += this.legendWidth / 2; 1534 | yIndex = 0; 1535 | } 1536 | } 1537 | } 1538 | }; 1539 | 1540 | Graph.prototype.drawData = function (values, event) { 1541 | var x = this.dataCanvas.width - this.dataLineWidth + 0.5, 1542 | y = this.dataCanvas.height - 0.5; 1543 | 1544 | // clear the buffer 1545 | this.bctx.clearRect(0, 0, this.dataCanvasBuffer.width, this.dataCanvasBuffer.height); 1546 | 1547 | // draw the data canvas to the buffer, skipping the first line 1548 | this.bctx.drawImage( 1549 | this.dataCanvas, 1550 | this.dataLineWidth, 0, x, y, 1551 | 0, 0, x, y 1552 | ); 1553 | 1554 | // clear the data canvas 1555 | this.dctx.clearRect(0, 0, this.dataCanvas.width, this.dataCanvas.height); 1556 | 1557 | // draw the buffer back to the data canvas 1558 | this.dctx.drawImage(this.dataCanvasBuffer, 0, 0); 1559 | 1560 | // draw event to the new line of the data canvas if there was one 1561 | if (event) { 1562 | this.dctx.beginPath(); 1563 | this.dctx.strokeStyle = this.dctx.fillStyle = '#ff0000'; 1564 | this.dctx.lineWidth = this.dataLineWidth; 1565 | 1566 | this.dctx.moveTo(x, y); 1567 | this.dctx.lineTo(x, 0); 1568 | 1569 | this.dctx.stroke(); 1570 | 1571 | this.dctx.textAlign = 'right'; 1572 | this.dctx.fillText(event, x - this.padding, this.eventY); 1573 | 1574 | this.eventY += (this.padding * 2); 1575 | 1576 | if (this.eventY > (this.dataCanvas.height / 2)) { 1577 | this.eventY = (this.padding * 2); 1578 | } 1579 | } 1580 | 1581 | // draws the data values to the new line of the data canvas 1582 | 1583 | // draw the new data points 1584 | var colorIndex = 0, 1585 | step = 0; 1586 | 1587 | for (var k in values) { 1588 | for (var c in values[k]) { 1589 | this.dctx.beginPath(); 1590 | this.dctx.strokeStyle = this.dctx.fillStyle = this.colors[colorIndex++ % this.colors.length]; 1591 | this.dctx.lineWidth = this.dataLineWidth; 1592 | 1593 | step = ((values[k][c] / this.maxValue) * this.dataCanvas.height); 1594 | step = step < 0 ? 0 : step; 1595 | 1596 | this.dctx.moveTo(x, y); 1597 | this.dctx.lineTo(x, y-=step); 1598 | 1599 | this.dctx.stroke(); 1600 | } 1601 | } 1602 | 1603 | // draw the data canvas to the main rendered canvas 1604 | this.ctx.drawImage(this.dataCanvas, this.legendWidth, 0); 1605 | }; 1606 | 1607 | Graph.prototype.destroy = function () { 1608 | this.canvas = null; 1609 | this.ctx = null; 1610 | 1611 | this.labelStyle = null; 1612 | 1613 | this.maxValue = null; 1614 | this.padding = null; 1615 | 1616 | this.dataLineWidth = null; 1617 | this.legendWidth = null; 1618 | this.legendBoxSize = null; 1619 | this.legendIndent = null; 1620 | 1621 | this.colors = null; 1622 | 1623 | this.dataCanvas = null; 1624 | this.dctx = null; 1625 | 1626 | this.dataCanvasBuffer = null; 1627 | this.bctx = null; 1628 | }; 1629 | 1630 | },{}],19:[function(require,module,exports){ 1631 | //Some general dom helpers 1632 | var ui = { 1633 | delegate: function (dom, evt, selector, fn) { 1634 | dom.addEventListener(evt, function(e) { 1635 | window.target = e.target; 1636 | if (e.target && e.target.matches(selector)) { 1637 | e.delegateTarget = e.target; 1638 | 1639 | if (fn) { 1640 | fn(e); 1641 | } 1642 | } 1643 | else if (e.target.parentElement && e.target.parentElement.matches(selector)) { 1644 | e.delegateTarget = e.target.parentElement; 1645 | 1646 | if (fn) { 1647 | fn(e); 1648 | } 1649 | } 1650 | }); 1651 | }, 1652 | 1653 | on: function (dom, evt, delegate, fn) { 1654 | if (typeof delegate === 'function') { 1655 | fn = delegate; 1656 | delegate = null; 1657 | } 1658 | 1659 | if (delegate) { 1660 | return ui.delegate(dom, evt, delegate, fn); 1661 | } 1662 | 1663 | dom.addEventListener(evt, fn); 1664 | }, 1665 | 1666 | removeClass: function (dom, cls) { 1667 | var classes = dom.className.split(' '), 1668 | i = classes.indexOf(cls); 1669 | 1670 | if(i !== -1) { 1671 | classes.splice(i, 1); 1672 | dom.className = classes.join(' ').trim(); 1673 | } 1674 | }, 1675 | 1676 | addClass: function (dom, cls) { 1677 | var classes = dom.className.split(' '); 1678 | 1679 | classes.push(cls); 1680 | dom.className = classes.join(' ').trim(); 1681 | }, 1682 | 1683 | hasClass: function (dom, cls) { 1684 | return dom.className.split(' ').indexOf(cls) !== -1; 1685 | }, 1686 | 1687 | toggleClass: function (dom, cls) { 1688 | if (ui.hasClass(dom, cls)) { 1689 | ui.removeClass(dom, cls); 1690 | } else { 1691 | ui.addClass(dom, cls); 1692 | } 1693 | }, 1694 | 1695 | setText: function (dom, txt) { 1696 | dom.textContent = txt; 1697 | }, 1698 | 1699 | setHtml: function (dom, html) { 1700 | dom.innerHTML = html; 1701 | }, 1702 | 1703 | setStyle: function (dom, style, value) { 1704 | if(typeof style === 'string') { 1705 | dom.style[style] = value; 1706 | } else { 1707 | for(var key in style) { 1708 | dom.style[key] = style[key]; 1709 | } 1710 | } 1711 | }, 1712 | 1713 | empty: function (dom) { 1714 | while(dom.firstChild) { 1715 | dom.removeChild(dom.firstChild); 1716 | } 1717 | }, 1718 | 1719 | show: function (dom) { 1720 | ui.setStyle(dom, 'display', 'block'); 1721 | }, 1722 | 1723 | hide: function (dom) { 1724 | ui.setStyle(dom, 'display', 'none'); 1725 | }, 1726 | 1727 | clear: function () { 1728 | var br = document.createElement('br'); 1729 | ui.setStyle(br, 'clear', 'both'); 1730 | 1731 | return br; 1732 | }, 1733 | 1734 | addCss: function (css) { 1735 | var style = document.createElement('style'); 1736 | 1737 | style.type = 'text/css'; 1738 | 1739 | if (style.styleSheet){ 1740 | style.styleSheet.cssText = css; 1741 | } else { 1742 | style.appendChild(document.createTextNode(css)); 1743 | } 1744 | 1745 | document.head.appendChild(style); 1746 | } 1747 | }; 1748 | 1749 | module.exports = ui; 1750 | 1751 | // polyfill for matchesSelector 1752 | if (!HTMLElement.prototype.matches) { 1753 | var htmlprot = HTMLElement.prototype; 1754 | 1755 | htmlprot.matches = 1756 | htmlprot.matches || 1757 | htmlprot.webkitMatchesSelector || 1758 | htmlprot.mozMatchesSelector || 1759 | htmlprot.msMatchesSelector || 1760 | htmlprot.oMatchesSelector || 1761 | function (selector) { 1762 | // poorman's polyfill for matchesSelector 1763 | var elements = this.parentElement.querySelectorAll(selector), 1764 | element, 1765 | i = 0; 1766 | 1767 | while (element = elements[i++]) { 1768 | if (element === this) { 1769 | return true; 1770 | } 1771 | } 1772 | 1773 | return false; 1774 | }; 1775 | } 1776 | 1777 | },{}]},{},[1])(1) 1778 | }); --------------------------------------------------------------------------------