├── .gitignore ├── LICENSE ├── README.md └── src └── aerys └── monitor └── Monitor.as /.gitignore: -------------------------------------------------------------------------------- 1 | .actionScriptProperties 2 | .flexLibProperties 3 | .project 4 | .settings 5 | bin 6 | .svn 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Aerys, http://aerys.in 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Aerys Monitor 2 | ============= 3 | 4 | ![Capture 1](http://blogs.aerys.in/jeanmarc-leroux/wp-content/uploads/2010/11/aerys_monitor_2.png) ![Capture 2](http://blogs.aerys.in/jeanmarc-leroux/wp-content/uploads/2010/11/aerys_monitor_1.png) 5 | 6 | Lightweight customizable ActionScript 3.0 property monitor: 7 | 8 | * watch **any property** of **any class** 9 | * customizable update rate 10 | * customizable per-property color 11 | * **chat rendering** for numeric values 12 | * watch framerate, memory and Flash Player version 13 | * ready to use framerate property 14 | 15 | 16 | Usage 17 | ----- 18 | 19 | // get a singleton Monitor object 20 | var monitor : Monitor = Monitor.monitor; 21 | 22 | // set the update (refresh) rate to 15 updates per second 23 | monitor.updateRate = 15.; 24 | 25 | // add the monitor to the display list 26 | stage.addChild(monitor); 27 | 28 | // watch the rotationX property of the camera object with a scale value of 1 / (PI / 2) 29 | monitor.watch(camera, "rotationX", 0x55ff00, 1. / (Math.PI / 2.), true); 30 | // watch the rotationY property of the camera object with a scale value of 1 / (2 * PI) 31 | monitor.watch(camera, "rotationY", 0xff5500, 1. / (2. * Math.PI), true); 32 | // watch the rotationZ property of the camera object with no scale value (=> no chart rendering) 33 | monitor.watch(camera, "rotationZ", 0x5599ff); 34 | 35 | // watch multiple properties 36 | monitor.watchProperties(physics, 37 | ["processingTime", "speed"], 38 | [0x00ff00, 0xff0000], 39 | [1. / 40., 1. / 10.]); 40 | 41 | // change the background color (0xAARRGGBB) 42 | monitor.backgroundColor = 0x7f000000; 43 | 44 | 45 | Contribute 46 | ---------- 47 | 48 | `aerys-monitor` is MIT-licensed. Make sure you tell us everything that's wrong! 49 | 50 | * [Source code](https://github.com/aerys/monitor) 51 | * [Issue tracker](https://github.com/aerys/monitor/issues) 52 | -------------------------------------------------------------------------------- /src/aerys/monitor/Monitor.as: -------------------------------------------------------------------------------- 1 | package aerys.monitor 2 | { 3 | import flash.display.Bitmap; 4 | import flash.display.BitmapData; 5 | import flash.display.Sprite; 6 | import flash.events.Event; 7 | import flash.geom.Point; 8 | import flash.geom.Rectangle; 9 | import flash.system.Capabilities; 10 | import flash.system.System; 11 | import flash.text.StyleSheet; 12 | import flash.text.TextField; 13 | import flash.text.TextFieldAutoSize; 14 | import flash.utils.Dictionary; 15 | import flash.utils.getTimer; 16 | 17 | public class Monitor extends Sprite 18 | { 19 | //{ region static 20 | public static const DEFAULT_UPDATE_RATE : Number = 1; 21 | 22 | private static const DEFAULT_PADDING : uint = 10; 23 | private static const DEFAULT_BACKGROUND : uint = 0x7f000000; 24 | private static const DEFAULT_CHART_WIDTH : uint = 100; 25 | private static const DEFAULT_CHART_HEIGHT : uint = 50; 26 | 27 | private static const DEFAULT_COLOR : uint = 0xffffffff; 28 | 29 | private static var _instance : Monitor = null; 30 | public static function get monitor() : Monitor 31 | { 32 | return _instance || (_instance = new Monitor()); 33 | } 34 | //} endregion 35 | 36 | private var _defaultColor : uint = DEFAULT_COLOR; 37 | 38 | private var _updateRate : Number = 0.; 39 | private var _intervalId : int = 0; 40 | 41 | private var _targets : Dictionary = new Dictionary(); 42 | private var _xml : XML = 43 | 44 | framerate: 45 | memory: 46 | ; 47 | private var _colors : Object = new Object(); 48 | 49 | private var _scales : Object = new Object(); 50 | private var _overflow : Object = new Object(); 51 | private var _style : StyleSheet = new StyleSheet(); 52 | private var _label : TextField = new TextField(); 53 | private var _bitmapData : BitmapData = new BitmapData(DEFAULT_CHART_WIDTH, 54 | DEFAULT_CHART_HEIGHT, 55 | true, 56 | 0); 57 | private var _chart : Bitmap = new Bitmap(_bitmapData); 58 | 59 | private var _numFrames : int = 0; 60 | private var _updateTime : int = 0; 61 | private var _framerate : int = 0; 62 | private var _maxMemory : int = 0; 63 | 64 | private var _background : uint = 0; 65 | 66 | public function get defaultColor() : uint { return _defaultColor; } 67 | 68 | public function get framerate() : int { return _framerate; } 69 | 70 | public function get chartWidth() : int { return _bitmapData.width; } 71 | 72 | public function get chartHeight() : int { return _bitmapData.height; } 73 | 74 | public function set defaultColor(value : uint) : void 75 | { 76 | _defaultColor = value; 77 | } 78 | 79 | public function set chartWidth(value : int) : void 80 | { 81 | setChartSize(value, _bitmapData.height); 82 | } 83 | 84 | public function set chartHeight(value : int) : void 85 | { 86 | setChartSize(_bitmapData.width, value); 87 | } 88 | 89 | public function set updateRate(value : Number) : void 90 | { 91 | _updateRate = value; 92 | } 93 | 94 | public function get updateRate() : Number 95 | { 96 | return _updateRate; 97 | } 98 | 99 | public function set backgroundColor(value : uint) : void 100 | { 101 | _background = value; 102 | updateBackground(); 103 | } 104 | 105 | public function get backgroundColor() : uint 106 | { 107 | return _background; 108 | } 109 | 110 | /** 111 | * Create a new Monitor object. 112 | * @param myUpdateRate The number of update per second the monitor will perform. 113 | * 114 | */ 115 | public function Monitor(myUpdateRate : Number = DEFAULT_UPDATE_RATE) 116 | { 117 | super(); 118 | 119 | _updateRate = myUpdateRate; 120 | 121 | _style.setStyle("monitor", {fontSize: "9px", 122 | fontFamily: "_sans", 123 | leading: "-2px"}); 124 | 125 | setStyle("framerate", {color: "#ffaa00"}); 126 | setStyle("memory", {color: "#0066ff"}); 127 | setStyle("version", {color: "#7f7f7f"}); 128 | 129 | _label.styleSheet = _style; 130 | _label.condenseWhite = true; 131 | _label.autoSize = TextFieldAutoSize.LEFT; 132 | 133 | addChild(_label); 134 | addChild(_chart); 135 | 136 | _xml.version = Capabilities.version + (Capabilities.isDebugger ? " (debug)" : "") 137 | 138 | addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler); 139 | //addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler); 140 | 141 | _background = DEFAULT_BACKGROUND; 142 | } 143 | 144 | public function setChartSize(width : int, height : int) : void 145 | { 146 | var bmp : BitmapData = new BitmapData(width, height, true, 0); 147 | 148 | bmp.copyPixels(_bitmapData, 149 | new Rectangle(0, 0, width, height), 150 | new Point(width - _bitmapData.width, 151 | height - _bitmapData.height)); 152 | 153 | _bitmapData = bmp; 154 | _chart.bitmapData = _bitmapData; 155 | } 156 | 157 | public function setStyle(styleName : String, value : Object) : void 158 | { 159 | _style.setStyle(styleName, value); 160 | 161 | if (value.color) 162 | _colors[styleName] = 0xff000000 | parseInt(value.color.substr(1), 16); 163 | } 164 | 165 | private function enterFrameHandler(event : Event) : void 166 | { 167 | ++_numFrames; 168 | 169 | var time : int = getTimer(); 170 | 171 | if ((time - _updateTime) >= 1000. / _updateRate) 172 | { 173 | // framerate 174 | _framerate = _numFrames / ((time - _updateTime) / 1000.); 175 | 176 | if (!visible || !stage) 177 | { 178 | _updateTime = time; 179 | _numFrames = 0; 180 | 181 | return ; 182 | } 183 | 184 | // prepare bitmap data 185 | _bitmapData.scroll(1, 0); 186 | _bitmapData.fillRect(new Rectangle(0, 0, 1, _bitmapData.height), 187 | 0); 188 | _bitmapData.lock(); 189 | 190 | 191 | _xml.framerate = "framerate: " + _framerate + " / " + stage.frameRate; 192 | _bitmapData.setPixel32(0, 193 | (1. - _framerate / stage.frameRate) * (_bitmapData.height - 1), 194 | 0xff000000 | _colors["framerate"]) 195 | 196 | // memory 197 | var totalMemory : int = System.totalMemory; 198 | 199 | if (totalMemory > _maxMemory) 200 | _maxMemory = totalMemory; 201 | 202 | _xml.memory = "memory: " + (totalMemory / 1e6).toFixed(3) + " M."; 203 | _bitmapData.setPixel32(0, 204 | (1. - totalMemory / _maxMemory) * (_bitmapData.height - 1), 205 | 0xff000000 | _colors["memory"]) 206 | 207 | // properties 208 | for (var target : Object in _targets) 209 | { 210 | var properties : Array = _targets[target]; 211 | var numProperties : int = properties.length; 212 | 213 | for (var i : int = 0; i < numProperties; ++i) 214 | { 215 | var property : String = properties[i]; 216 | var value : Object = target[property]; 217 | var scale : Number = _scales[property]; 218 | 219 | _xml[property] = property + ": " + value; 220 | 221 | if ((scale = _scales[property]) != 0.) 222 | { 223 | var n : Number = Number(value); 224 | var scaledValue : Number = scale * (_overflow[property] ? Math.abs(n) % (1. / scale) : n); 225 | 226 | _bitmapData.setPixel32(0, 227 | (1. - scaledValue) * (_bitmapData.height - 1), 228 | 0xff000000 | _colors[property]); 229 | } 230 | } 231 | } 232 | 233 | _bitmapData.unlock(); 234 | _label.htmlText = _xml; 235 | 236 | _numFrames = 0; 237 | _updateTime = time; 238 | 239 | updateBackground(); 240 | } 241 | 242 | _chart.y = _label.textHeight + DEFAULT_PADDING; 243 | } 244 | 245 | private function addedToStageHandler(e : Event) : void 246 | { 247 | _maxMemory = System.totalMemory; 248 | addEventListener(Event.ENTER_FRAME, enterFrameHandler); 249 | } 250 | 251 | private function removedFromStageHandler(e : Event) : void 252 | { 253 | removeEventListener(Event.ENTER_FRAME, enterFrameHandler); 254 | } 255 | 256 | public function setColor(property : String, color : int) : void 257 | { 258 | _colors[property] = color; 259 | } 260 | 261 | public function getColor(property : String) : int 262 | { 263 | return _colors[property]; 264 | } 265 | 266 | public function getScale(property : String) : Number 267 | { 268 | return _scales[property]; 269 | } 270 | 271 | public function setScale(property : String, scale : Number) : void 272 | { 273 | _scales[property] = scale; 274 | } 275 | 276 | public function getOverflow(property : String) : Boolean 277 | { 278 | return _overflow[property]; 279 | } 280 | 281 | public function setOverflow(property : String, overflow : Boolean) : void 282 | { 283 | _overflow[property] = overflow; 284 | } 285 | 286 | /** 287 | * Watch a property of a specified object. 288 | * 289 | * @param myTarget The object containing the property to watch. 290 | * @param myProperty The name of the property to watch. 291 | * @param myColor The color of the displayed label/chart. 292 | * @param myScale The scale used to display the chart. Use "0" to disable the chart. 293 | * @param myOverflow If true, the modulo operator is used to make 294 | * sure the value can be drawn on the chart. 295 | */ 296 | public function watchProperty(target : Object, 297 | property : String, 298 | color : int = 0, 299 | scale : Number = 0., 300 | overflow : Boolean = false) : Monitor 301 | { 302 | if (!_targets[target]) 303 | _targets[target] = new Array(); 304 | 305 | color ||= _defaultColor; 306 | 307 | _targets[target].push(property); 308 | _xml[property] = property + ": " + target[property]; 309 | 310 | _colors[property] = color; 311 | _scales[property] = scale; 312 | _overflow[property] = overflow; 313 | 314 | _style.setStyle(property, {color: "#" + (color as Number & 0xffffff).toString(16)}); 315 | _label.htmlText = _xml; 316 | _chart.y = _label.textHeight + DEFAULT_PADDING; 317 | _label.autoSize = TextFieldAutoSize.LEFT; 318 | 319 | updateBackground(); 320 | 321 | return this; 322 | } 323 | 324 | public function watch(target : Object, 325 | properties : Array, 326 | colors : Array = null, 327 | scales : Array = null, 328 | overflows : Array = null) : Monitor 329 | { 330 | var numProperties : int = properties.length; 331 | 332 | for (var i : int = 0; i < numProperties; ++i) 333 | { 334 | watchProperty(target, 335 | properties[i], 336 | colors ? colors[i] : _defaultColor, 337 | scales && scales[i] ? scales[i] : 0., 338 | overflows ? overflows[i] : false); 339 | } 340 | 341 | return this; 342 | } 343 | 344 | public function watchObject(target : Object) : Monitor 345 | { 346 | for (var property : String in target) 347 | watchProperty(target, property); 348 | 349 | return this; 350 | } 351 | 352 | private function updateBackground() : void 353 | { 354 | if (_label.textWidth == width && _label.textHeight == height) 355 | return ; 356 | 357 | graphics.clear(); 358 | graphics.beginFill(_background & 0xffffff, ((_background >> 24) & 0xff) / 255.); 359 | graphics.drawRect(0, 0, width, height); 360 | graphics.endFill(); 361 | } 362 | } 363 | } --------------------------------------------------------------------------------