├── bower.json ├── examples ├── index.html ├── demo.js └── Percussion.js ├── LICENSE ├── README.md └── dist ├── Percussion.min.js └── Percussion.js /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Percussion", 3 | "version": "0.1.0", 4 | "description": "Debugging tool for JS reactive programming libraries.", 5 | "main": "dist/Percussion.js", 6 | "moduleType": [ 7 | "globals" 8 | ], 9 | "keywords": [ 10 | "percussion", 11 | "reactive", 12 | "programming", 13 | "bacon.js", 14 | "rxjs", 15 | "kefir.js" 16 | ], 17 | "authors": [ 18 | "Francisco J. Cruz Romanos " 19 | ], 20 | "license": "MIT" 21 | } 22 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Francisco José Cruz Romanos 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 all 13 | 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 THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /examples/demo.js: -------------------------------------------------------------------------------- 1 | var single = null; 2 | var double = null; 3 | var poll = null; 4 | 5 | var percussion = new Percussion(); 6 | 7 | if (typeof(Bacon) !== 'undefined') { 8 | single = Bacon.fromEventTarget(document.getElementById('demo'), 'click').map( 9 | function(data) { 10 | return 'click'; 11 | } 12 | ); 13 | double = single.bufferWithTimeOrCount(300, 2).filter( 14 | function(x) { 15 | return x.length >= 2; 16 | } 17 | ).map( 18 | function(data) { 19 | return 'dblclick'; 20 | } 21 | ); 22 | poll = Bacon.fromPoll( 23 | 5000, 24 | function() { 25 | return 'time!'; 26 | } 27 | ).startWith('init'); 28 | } 29 | else if (typeof(Rx) !== 'undefined') { 30 | single = Rx.Observable.fromEvent(document.getElementById('demo'), 'click') 31 | .map(function() { return 'click'; }); 32 | double = single.buffer(function() { return single.throttle(300); }) 33 | .map(function(list) { return list.length; }) 34 | .filter(function(x) { return x >= 2; }) 35 | .map(function() { return 'dblclick'; }); 36 | poll = Rx.Observable.interval(5000) 37 | .map(function(list) { return 'time!'; }) 38 | .startWith('init'); 39 | } 40 | else if (typeof(Kefir) !== 'undefined') { 41 | single = Kefir.fromEvents(document.getElementById('demo'), 'click') 42 | .map(function() { return 'click'; }); 43 | double = single.bufferBy(single.debounce(300)) 44 | .map(function(list) { return list.length; }) 45 | .filter(function(x) { return x >= 2; }) 46 | .map(function() { return 'dblclick'; }); 47 | poll = Kefir.interval(5000, 'time!').toProperty( 48 | function() { 49 | return 'init'; 50 | } 51 | ); 52 | } 53 | 54 | percussion.addStream(single); 55 | percussion.addStream(double); 56 | percussion.addStream(poll); 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Percussion 2 | Debugging tool for JS reactive programming libraries. 3 | 4 | This library allows to visualize streams in order to debug reactive javascript programming applications. Currently supported libraries are: 5 | * Bacon.js - [https://baconjs.github.io/](https://baconjs.github.io/) 6 | * RxJS - [http://reactivex.io/](http://reactivex.io/) 7 | * Kefir.js - [https://rpominov.github.io/kefir/](https://rpominov.github.io/kefir/) 8 | 9 | 10 | ## Simple usage 11 | 12 | You can just initialize constructor without options: 13 | ```javascript 14 | var percussion = new Percussion(); 15 | ``` 16 | 17 | And then add as many streams as you want: 18 | ```javascript 19 | percussion.addStream(stream1); 20 | percussion.addStream(stream2); 21 | percussion.addStream(stream3); 22 | ... 23 | ``` 24 | Then, you will see streams represented as lines, and events represented as circles in those lines. You can mouse-hover in the circles in order to see their values in a tooltip, or click them to see their values in the browser debugger console. 25 | 26 | ## Methods 27 | 28 | You can stop debugging with: 29 | ```javascript 30 | percussion.stop(); 31 | ``` 32 | 33 | And then recover execution with: 34 | ```javascript 35 | percussion.start(); 36 | ``` 37 | 38 | By default, data visualization will automatically be scrolled in order to see last stream events. You can disable this in runtime with: 39 | ```javascript 40 | percussion.setAutoScroll(false); 41 | ``` 42 | and enable again with: 43 | ```javascript 44 | percussion.setAutoScroll(true); 45 | ``` 46 | 47 | ## Constructor options 48 | 49 | * **lineSize**: Height of the stream line in px. *Default: 20* 50 | * **pointSize**: Width of the event point in px. *Default: 10* 51 | * **speed**: Speed of stream visualization in px/sample. *Default: 20* 52 | * **timeout**: Time of each sample in ms. *Default: 250* 53 | * **autoScroll**: Whether if data visualization will automatically do scroll or not. *Default: true* 54 | * **print** = Whether if event values will be printed in the stream visualization or not. *Default: false* 55 | * **colors**: Array of colors for events in each stream. Will be repeated cyclically. *Default: ['#F00', '#0F0', '#00F']* 56 | * **textColors** = Array of text colors for events in each stream (visible only if print == true). Should be the same size as colors, and also, will be repeated cyclically. *Default: ['#FFF', '#FFF', '#FFF']* 57 | * **position** = HTML Element where data visualization will be injected. Notice this needs to be a pure Element, so if you use libraries like jQuery, you need to convert it (i.e.: $('#canvas')[0]). *Default: document.body* 58 | 59 | Example: 60 | ```javascript 61 | var percussion = new Percussion( 62 | { 63 | position: document.getElementById('canvas'), 64 | speed: 200 65 | } 66 | ); 67 | ``` 68 | 69 | ## Contributors 70 | 71 | grisendo: Francisco J. Cruz Romanos 72 | 73 | ## License 74 | 75 | [MIT License](http://en.wikipedia.org/wiki/MIT_License) 76 | -------------------------------------------------------------------------------- /dist/Percussion.min.js: -------------------------------------------------------------------------------- 1 | /*! Percussion v0.1.0 | (c) 2015 grisendo */ 2 | !function(){var a=function(a){"undefined"==typeof a&&(a={}),this.lineSize=20,this.pointSize=10,this.speed=20,this.timeout=250,this.autoScroll=!0,this.colors=[],this.textColors=[],this.eventIn=null,this.eventOut=null,this.position=document.body,this.print=!1,this._setOptions(a),this.interval=null,this.canvas=null,this.canvasIn=null,this.running=!1,this.lines=0,this.time=0,this.counter=0,this.streams=[],this.events=[],this._startCanvas()};a.prototype._setOptions=function(a){"undefined"!=typeof a.lineSize?this.lineSize=a.lineSize:null,"undefined"!=typeof a.pointSize?this.pointSize=a.pointSize:null,"undefined"!=typeof a.speed?this.speed=a.speed:null,"undefined"!=typeof a.timeout?this.timeout=a.timeout:null,"undefined"!=typeof a.autoScroll?this.autoScroll=a.autoScroll:null,"undefined"!=typeof a.colors?this.colors=a.colors:null,"undefined"!=typeof a.textColors?this.textColors=a.textColors:null,"undefined"!=typeof a.eventIn?this.eventIn=a.eventIn:null,"undefined"!=typeof a.eventOut?this.eventOut=a.eventOut:null,"undefined"!=typeof a.position?this.position=a.position:null,"undefined"!=typeof a.print?this.print=a.print:null},a.prototype._startCanvas=function(){this.lines=0,this.time=0,this.counter=0,this.running=!1,this.colors&&0!=this.colors.length||(this.colors=["#FF0000","#00FF00","#0000FF"]),this.textColors&&0!=this.textColors.length||(this.textColors=["#FFFFFF","#FFFFFF","#FFFFFF"]),this.eventIn||("undefined"!=typeof Bacon||"undefined"!=typeof Kefir?this.eventIn="onValue":"undefined"!=typeof Rx&&(this.eventIn="subscribe")),this.eventOut||("undefined"!=typeof Bacon?this.eventOut="":"undefined"!=typeof Rx?this.eventOut="dispose":"undefined"!=typeof Kefir&&(this.eventOut="_clear")),this.canvas=document.createElement("DIV"),this.canvasIn=document.createElement("DIV"),this.canvas.style.position="relative",this.canvas.style.width="100%",this.canvas.style.overflowX="auto",this.canvas.style.overflowY="hidden",this.canvasIn.style.position="relative",this.canvasIn.style.width=0,this.canvas.appendChild(this.canvasIn),this.position.appendChild(this.canvas),this.start();for(var a in this.streams)this.addStream(this.streams[a],!0)},a.prototype.addStream=function(a,b){"undefined"==typeof b&&(b=!1),b||this.streams.push(a);var c=this.lines,d=document.createElement("DIV"),e=this.colors[this.counter],f=this.textColors[this.counter];if(d.style.position="absolute",d.style.width="100%",d.style.top=this.lines*this.lineSize+this.pointSize+"px",d.style.left=0,d.style.height="1px",d.style.background="#000",this.canvasIn.appendChild(d),this.eventIn&&"function"==typeof a[this.eventIn]){var g=this,h=a[this.eventIn](function(a){if(g.running){var b=document.createElement("DIV");b.style.borderRadius="50%",b.style.minWidth=g.pointSize+"px",b.style.minHeight=g.pointSize+"px",b.style.position="absolute",b.style.top=c*g.lineSize+g.pointSize/2+"px",b.style.background=e,b.style.cursor="pointer",b.style.left=g.time+"px",b.style.color=f,"object"!=typeof a?(b.title=a,g.print&&(b.innerHTML=a)):b.title="Object: Click to view value via Javascript Console",b.onclick=function(){console.log(a)},g.canvasIn.appendChild(b)}});this.events.push(h)}this.counter++,this.counter=this.counter%3,this.lines++,this.canvas.style.height=(this.lines+1)*this.lineSize+"px",this.canvasIn.style.height=this.canvas.style.height},a.prototype.stop=function(){this.running&&(this.running=!1,this.interval&&clearInterval(this.interval))},a.prototype.start=function(){if(!this.running){this.running=!0;var a=this;this.interval=setInterval(function(){a.running&&(a.time+=a.speed,a.canvasIn.style.width=a.time+"px",a.autoScroll&&(a.canvas.scrollLeft=a.time))},this.timeout)}},a.prototype.setAutoScroll=function(a){this.autoScroll=a},a.prototype.restart=function(){this.stop(),this.canvas.parentNode.removeChild(this.canvas);for(var a in this.events)""===this.eventOut?this.events[a]():eventOut&&this.events[a][this.eventOut]();this.events=[],this._startCanvas()},window.Percussion=a}(); 3 | -------------------------------------------------------------------------------- /dist/Percussion.js: -------------------------------------------------------------------------------- 1 | /*! Percussion v0.1.0 | (c) 2015 grisendo */ 2 | 3 | (function() { 4 | 5 | var Percussion = function(options) { 6 | 7 | if (typeof(options) === 'undefined') { 8 | options = {}; 9 | } 10 | 11 | this.lineSize = 20; 12 | this.pointSize = 10; 13 | this.speed = 20; 14 | this.timeout = 250; 15 | this.autoScroll = true; 16 | this.colors = []; 17 | this.textColors = []; 18 | this.eventIn = null; 19 | this.eventOut = null; 20 | this.position = document.body; 21 | this.print = false; 22 | 23 | this._setOptions(options); 24 | 25 | this.interval = null; 26 | this.canvas = null; 27 | this.canvasIn = null; 28 | this.running = false; 29 | this.lines = 0; 30 | this.time = 0; 31 | this.counter = 0; 32 | this.streams = []; 33 | this.events = []; 34 | 35 | this._startCanvas(); 36 | 37 | }; 38 | 39 | Percussion.prototype._setOptions = function(options) { 40 | (typeof(options.lineSize) !== 'undefined') ? (this.lineSize = options.lineSize) : null; 41 | (typeof(options.pointSize) !== 'undefined') ? (this.pointSize = options.pointSize) : null; 42 | (typeof(options.speed) !== 'undefined') ? (this.speed = options.speed) : null; 43 | (typeof(options.timeout) !== 'undefined') ? (this.timeout = options.timeout) : null; 44 | (typeof(options.autoScroll) !== 'undefined') ? (this.autoScroll = options.autoScroll) : null; 45 | (typeof(options.colors) !== 'undefined') ? (this.colors = options.colors) : null; 46 | (typeof(options.textColors) !== 'undefined') ? (this.textColors = options.textColors) : null; 47 | (typeof(options.eventIn) !== 'undefined') ? (this.eventIn = options.eventIn) : null; 48 | (typeof(options.eventOut) !== 'undefined') ? (this.eventOut = options.eventOut) : null; 49 | (typeof(options.position) !== 'undefined') ? (this.position = options.position) : null; 50 | (typeof(options.print) !== 'undefined') ? (this.print = options.print) : null; 51 | }; 52 | 53 | Percussion.prototype._startCanvas = function() { 54 | this.lines = 0; 55 | this.time = 0; 56 | this.counter = 0; 57 | this.running = false; 58 | if (!this.colors || this.colors.length == 0) { 59 | this.colors = ['#FF0000', '#00FF00', '#0000FF']; 60 | } 61 | if (!this.textColors || this.textColors.length == 0) { 62 | this.textColors = ['#FFFFFF', '#FFFFFF', '#FFFFFF']; 63 | } 64 | if (!this.eventIn) { 65 | if ((typeof(Bacon) !== 'undefined') || (typeof(Kefir) !== 'undefined')) { 66 | this.eventIn = 'onValue'; 67 | } 68 | else if (typeof(Rx) !== 'undefined') { 69 | this.eventIn = 'subscribe'; 70 | } 71 | } 72 | if (!this.eventOut) { 73 | if (typeof(Bacon) !== 'undefined') { 74 | this.eventOut = ''; 75 | } 76 | else if (typeof(Rx) !== 'undefined') { 77 | this.eventOut = 'dispose'; 78 | } 79 | else if (typeof(Kefir) !== 'undefined') { 80 | this.eventOut = '_clear'; 81 | } 82 | } 83 | this.canvas = document.createElement('DIV'); 84 | this.canvasIn = document.createElement('DIV'); 85 | this.canvas.style.position = 'relative'; 86 | this.canvas.style.width = '100%'; 87 | this.canvas.style.overflowX = 'auto'; 88 | this.canvas.style.overflowY = 'hidden'; 89 | this.canvasIn.style.position = 'relative'; 90 | this.canvasIn.style.width = 0; 91 | this.canvas.appendChild(this.canvasIn); 92 | this.position.appendChild(this.canvas); 93 | this.start(); 94 | for (var key in this.streams) { 95 | this.addStream(this.streams[key], true); 96 | } 97 | }; 98 | 99 | Percussion.prototype.addStream = function(stream, recover) { 100 | if (typeof(recover) === 'undefined') { 101 | recover = false; 102 | } 103 | if (!recover) { 104 | this.streams.push(stream); 105 | } 106 | var currentLine = this.lines; 107 | var line = document.createElement('DIV'); 108 | var color = this.colors[this.counter]; 109 | var textColor = this.textColors[this.counter]; 110 | line.style.position = 'absolute'; 111 | line.style.width = '100%'; 112 | line.style.top = (this.lines * this.lineSize + this.pointSize) + 'px'; 113 | line.style.left = 0; 114 | line.style.height = '1px'; 115 | line.style.background = '#000'; 116 | this.canvasIn.appendChild(line); 117 | if (this.eventIn && (typeof(stream[this.eventIn]) === 'function')) { 118 | var percussion = this; 119 | var event = stream[this.eventIn]( 120 | function(data) { 121 | if (percussion.running) { 122 | var hit = document.createElement('DIV'); 123 | hit.style.borderRadius = '50%'; 124 | hit.style.minWidth = percussion.pointSize + 'px'; 125 | hit.style.minHeight = percussion.pointSize + 'px'; 126 | hit.style.position = 'absolute'; 127 | hit.style.top = (currentLine * percussion.lineSize + (percussion.pointSize / 2)) + 'px'; 128 | hit.style.background = color; 129 | hit.style.cursor = 'pointer'; 130 | hit.style.left = percussion.time + 'px'; 131 | hit.style.color = textColor; 132 | if (typeof(data) !== 'object') { 133 | hit.title = data; 134 | if (percussion.print) { 135 | hit.innerHTML = data; 136 | } 137 | } 138 | else { 139 | hit.title = 'Object: Click to view value via Javascript Console'; 140 | } 141 | hit.onclick = function() { 142 | console.log(data); 143 | }; 144 | percussion.canvasIn.appendChild(hit); 145 | } 146 | } 147 | ); 148 | this.events.push(event); 149 | } 150 | this.counter++; 151 | this.counter = this.counter % 3; 152 | this.lines++; 153 | this.canvas.style.height = ((this.lines + 1) * this.lineSize) + 'px'; 154 | this.canvasIn.style.height = this.canvas.style.height; 155 | }; 156 | 157 | Percussion.prototype.stop = function() { 158 | if (!this.running) { 159 | return; 160 | } 161 | this.running = false; 162 | if (this.interval) { 163 | clearInterval(this.interval); 164 | } 165 | }; 166 | 167 | Percussion.prototype.start = function() { 168 | if (this.running) { 169 | return; 170 | } 171 | this.running = true; 172 | var percussion = this; 173 | this.interval = setInterval( 174 | function() { 175 | if (percussion.running) { 176 | percussion.time += percussion.speed; 177 | percussion.canvasIn.style.width = percussion.time + 'px'; 178 | if (percussion.autoScroll) { 179 | percussion.canvas.scrollLeft = percussion.time; 180 | } 181 | } 182 | }, 183 | this.timeout 184 | ); 185 | }; 186 | 187 | Percussion.prototype.setAutoScroll = function(value) { 188 | this.autoScroll = value; 189 | }; 190 | 191 | Percussion.prototype.restart = function() { 192 | this.stop(); 193 | this.canvas.parentNode.removeChild(this.canvas); 194 | for (var key in this.events) { 195 | if (this.eventOut === '') { 196 | this.events[key](); 197 | } 198 | else if(eventOut) { 199 | this.events[key][this.eventOut](); 200 | } 201 | } 202 | this.events = []; 203 | this._startCanvas(); 204 | }; 205 | 206 | window.Percussion = Percussion; 207 | 208 | })(); 209 | -------------------------------------------------------------------------------- /examples/Percussion.js: -------------------------------------------------------------------------------- 1 | /*! Percussion v0.1.0 | (c) 2015 grisendo */ 2 | 3 | (function() { 4 | 5 | var Percussion = function(options) { 6 | 7 | if (typeof(options) === 'undefined') { 8 | options = {}; 9 | } 10 | 11 | this.lineSize = 20; 12 | this.pointSize = 10; 13 | this.speed = 20; 14 | this.timeout = 250; 15 | this.autoScroll = true; 16 | this.colors = []; 17 | this.textColors = []; 18 | this.eventIn = null; 19 | this.eventOut = null; 20 | this.position = document.body; 21 | this.print = false; 22 | 23 | this._setOptions(options); 24 | 25 | this.interval = null; 26 | this.canvas = null; 27 | this.canvasIn = null; 28 | this.running = false; 29 | this.lines = 0; 30 | this.time = 0; 31 | this.counter = 0; 32 | this.streams = []; 33 | this.events = []; 34 | 35 | this._startCanvas(); 36 | 37 | }; 38 | 39 | Percussion.prototype._setOptions = function(options) { 40 | (typeof(options.lineSize) !== 'undefined') ? (this.lineSize = options.lineSize) : null; 41 | (typeof(options.pointSize) !== 'undefined') ? (this.pointSize = options.pointSize) : null; 42 | (typeof(options.speed) !== 'undefined') ? (this.speed = options.speed) : null; 43 | (typeof(options.timeout) !== 'undefined') ? (this.timeout = options.timeout) : null; 44 | (typeof(options.autoScroll) !== 'undefined') ? (this.autoScroll = options.autoScroll) : null; 45 | (typeof(options.colors) !== 'undefined') ? (this.colors = options.colors) : null; 46 | (typeof(options.textColors) !== 'undefined') ? (this.textColors = options.textColors) : null; 47 | (typeof(options.eventIn) !== 'undefined') ? (this.eventIn = options.eventIn) : null; 48 | (typeof(options.eventOut) !== 'undefined') ? (this.eventOut = options.eventOut) : null; 49 | (typeof(options.position) !== 'undefined') ? (this.position = options.position) : null; 50 | (typeof(options.print) !== 'undefined') ? (this.print = options.print) : null; 51 | }; 52 | 53 | Percussion.prototype._startCanvas = function() { 54 | this.lines = 0; 55 | this.time = 0; 56 | this.counter = 0; 57 | this.running = false; 58 | if (!this.colors || this.colors.length == 0) { 59 | this.colors = ['#FF0000', '#00FF00', '#0000FF']; 60 | } 61 | if (!this.textColors || this.textColors.length == 0) { 62 | this.textColors = ['#FFFFFF', '#FFFFFF', '#FFFFFF']; 63 | } 64 | if (!this.eventIn) { 65 | if ((typeof(Bacon) !== 'undefined') || (typeof(Kefir) !== 'undefined')) { 66 | this.eventIn = 'onValue'; 67 | } 68 | else if (typeof(Rx) !== 'undefined') { 69 | this.eventIn = 'subscribe'; 70 | } 71 | } 72 | if (!this.eventOut) { 73 | if (typeof(Bacon) !== 'undefined') { 74 | this.eventOut = ''; 75 | } 76 | else if (typeof(Rx) !== 'undefined') { 77 | this.eventOut = 'dispose'; 78 | } 79 | else if (typeof(Kefir) !== 'undefined') { 80 | this.eventOut = '_clear'; 81 | } 82 | } 83 | this.canvas = document.createElement('DIV'); 84 | this.canvasIn = document.createElement('DIV'); 85 | this.canvas.style.position = 'relative'; 86 | this.canvas.style.width = '100%'; 87 | this.canvas.style.overflowX = 'auto'; 88 | this.canvas.style.overflowY = 'hidden'; 89 | this.canvasIn.style.position = 'relative'; 90 | this.canvasIn.style.width = 0; 91 | this.canvas.appendChild(this.canvasIn); 92 | this.position.appendChild(this.canvas); 93 | this.start(); 94 | for (var key in this.streams) { 95 | this.addStream(this.streams[key], true); 96 | } 97 | }; 98 | 99 | Percussion.prototype.addStream = function(stream, recover) { 100 | if (typeof(recover) === 'undefined') { 101 | recover = false; 102 | } 103 | if (!recover) { 104 | this.streams.push(stream); 105 | } 106 | var currentLine = this.lines; 107 | var line = document.createElement('DIV'); 108 | var color = this.colors[this.counter]; 109 | var textColor = this.textColors[this.counter]; 110 | line.style.position = 'absolute'; 111 | line.style.width = '100%'; 112 | line.style.top = (this.lines * this.lineSize + this.pointSize) + 'px'; 113 | line.style.left = 0; 114 | line.style.height = '1px'; 115 | line.style.background = '#000'; 116 | this.canvasIn.appendChild(line); 117 | if (this.eventIn && (typeof(stream[this.eventIn]) === 'function')) { 118 | var percussion = this; 119 | var event = stream[this.eventIn]( 120 | function(data) { 121 | if (percussion.running) { 122 | var hit = document.createElement('DIV'); 123 | hit.style.borderRadius = '50%'; 124 | hit.style.minWidth = percussion.pointSize + 'px'; 125 | hit.style.minHeight = percussion.pointSize + 'px'; 126 | hit.style.position = 'absolute'; 127 | hit.style.top = (currentLine * percussion.lineSize + (percussion.pointSize / 2)) + 'px'; 128 | hit.style.background = color; 129 | hit.style.cursor = 'pointer'; 130 | hit.style.left = percussion.time + 'px'; 131 | hit.style.color = textColor; 132 | if (typeof(data) !== 'object') { 133 | hit.title = data; 134 | if (percussion.print) { 135 | hit.innerHTML = data; 136 | } 137 | } 138 | else { 139 | hit.title = 'Object: Click to view value via Javascript Console'; 140 | } 141 | hit.onclick = function() { 142 | console.log(data); 143 | }; 144 | percussion.canvasIn.appendChild(hit); 145 | } 146 | } 147 | ); 148 | this.events.push(event); 149 | } 150 | this.counter++; 151 | this.counter = this.counter % 3; 152 | this.lines++; 153 | this.canvas.style.height = ((this.lines + 1) * this.lineSize) + 'px'; 154 | this.canvasIn.style.height = this.canvas.style.height; 155 | }; 156 | 157 | Percussion.prototype.stop = function() { 158 | if (!this.running) { 159 | return; 160 | } 161 | this.running = false; 162 | if (this.interval) { 163 | clearInterval(this.interval); 164 | } 165 | }; 166 | 167 | Percussion.prototype.start = function() { 168 | if (this.running) { 169 | return; 170 | } 171 | this.running = true; 172 | var percussion = this; 173 | this.interval = setInterval( 174 | function() { 175 | if (percussion.running) { 176 | percussion.time += percussion.speed; 177 | percussion.canvasIn.style.width = percussion.time + 'px'; 178 | if (percussion.autoScroll) { 179 | percussion.canvas.scrollLeft = percussion.time; 180 | } 181 | } 182 | }, 183 | this.timeout 184 | ); 185 | }; 186 | 187 | Percussion.prototype.setAutoScroll = function(value) { 188 | this.autoScroll = value; 189 | }; 190 | 191 | Percussion.prototype.restart = function() { 192 | this.stop(); 193 | this.canvas.parentNode.removeChild(this.canvas); 194 | for (var key in this.events) { 195 | if (this.eventOut === '') { 196 | this.events[key](); 197 | } 198 | else if(eventOut) { 199 | this.events[key][this.eventOut](); 200 | } 201 | } 202 | this.events = []; 203 | this._startCanvas(); 204 | }; 205 | 206 | window.Percussion = Percussion; 207 | 208 | })(); 209 | --------------------------------------------------------------------------------