From 3406721d93819b04be00ffe5386f1eaa643dcded Mon Sep 17 00:00:00 2001 From: Bram Kok Date: Sat, 31 Oct 2015 21:34:59 +0100 Subject: [PATCH 1/7] Init npm --- package.json | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..4bb26bd --- /dev/null +++ b/package.json @@ -0,0 +1,25 @@ +{ + "name": "gendyjs", + "version": "0.0.1", + "description": "GendyJS is a Web Audio API dynamic stochastic synthesis oscilator. Dynamic stochastic synthesis is a technique pioneered by the composer and theoretician Iannis Xenakis.", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/abbernie/gendy.git" + }, + "keywords": [ + "Stochastic", + "Generative", + "Aleatoric", + "Sythesis" + ], + "author": "Andrew Bernstein", + "license": "MIT", + "bugs": { + "url": "https://github.com/abbernie/gendy/issues" + }, + "homepage": "https://github.com/abbernie/gendy#readme" +} From 2c4c30b18b75a7cb5f090e81f3a54f4a0759b1a8 Mon Sep 17 00:00:00 2001 From: Bram Kok Date: Sat, 31 Oct 2015 21:40:19 +0100 Subject: [PATCH 2/7] Add gitignore --- .gitignore | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b38069d --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git +node_modules From 632e339a2e77e76021a193ca36f123f36e137b2b Mon Sep 17 00:00:00 2001 From: Bram Kok Date: Sat, 31 Oct 2015 21:41:02 +0100 Subject: [PATCH 3/7] Add Nexus UI --- package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 4bb26bd..60ea73f 100644 --- a/package.json +++ b/package.json @@ -21,5 +21,8 @@ "bugs": { "url": "https://github.com/abbernie/gendy/issues" }, - "homepage": "https://github.com/abbernie/gendy#readme" + "homepage": "https://github.com/abbernie/gendy#readme", + "dependencies": { + "nexusui": "^1.0.8" + } } From e021af78d8dda4d7fe58872e009e7c91ae9c220e Mon Sep 17 00:00:00 2001 From: Bram Kok Date: Sat, 31 Oct 2015 21:55:21 +0100 Subject: [PATCH 4/7] Remove static Nexus UI source, point to node dir --- gendy_constuctor_demo.html | 4 +- index.html | 5 +- js/nexusUI.js | 8533 ------------------------------------ spline.html | 4 +- 4 files changed, 6 insertions(+), 8540 deletions(-) delete mode 100644 js/nexusUI.js diff --git a/gendy_constuctor_demo.html b/gendy_constuctor_demo.html index ee4dd2a..ff7bc28 100644 --- a/gendy_constuctor_demo.html +++ b/gendy_constuctor_demo.html @@ -1,7 +1,7 @@ - + @@ -170,4 +170,4 @@

More?

} - \ No newline at end of file + diff --git a/index.html b/index.html index fb9c0b4..911e728 100644 --- a/index.html +++ b/index.html @@ -1,8 +1,7 @@ - - + '; - - document.head.innerHTML = document.head.innerHTML + htmlstr -} - -/** @method setViewport - Set mobile viewport scale (similar to a zoom) - @param {integer} [scale] Zoom ratio (i.e. 0.5, 1, 2) */ -manager.prototype.setViewport = function(scale) { - for (i=0; i=1) { - var newClickPos = domUtils.getTouchPosition(e, this.offset); - this.clickPos = newClickPos; - } else { - this.clicked = false; - } - this.touchRelease(); -} - - -/** @method init - Initialize or re-initialize the widget. Defined separately within each widget. - */ - -/** @method draw - Draw the widget onto the canvas. - */ -widget.prototype.draw = function() { -} - - -/** @method click - Executes when the widget is clicked on - */ -widget.prototype.click = function() { -} - - -/** @method move - Executes on drag (mouse moves while clicked). - */ -widget.prototype.move = function() { -} - - -/** @method release - Executes when the mouse releases after having clicked on the widget. - */ -widget.prototype.release = function() { -} - -/** @method touch - Executes when the widget is touched on a touch device. - */ -widget.prototype.touch = function() { - this.click(); -} - -/** @method touchMove - Executes on drag (touch then move) on a touch device - */ -widget.prototype.touchMove = function() { - this.move(); -} - -/** @method touchRelease - Executes when the touch releases after having touched the widget. - */ -widget.prototype.touchRelease = function() { - this.release(); -} - -widget.prototype.adjustSizeIfDefault = function() { - if (this.width==300 && this.height==150) { - this.canvas.width = this.defaultSize.width; - this.canvas.height = this.defaultSize.height; - this.width = this.defaultSize.width; - this.height = this.defaultSize.height; - } -} - -widget.prototype.makeRoundedBG = function() { - this.bgLeft = this.lineWidth; - this.bgRight = this.width - this.lineWidth; - this.bgTop = this.lineWidth; - this.bgBottom = this.height - this.lineWidth; - this.bgHeight = this.bgBottom - this.lineWidth; - this.bgWidth = this.bgRight - this.lineWidth; - - drawingUtils.makeRoundRect(this.context, this.bgLeft, this.bgTop, this.bgWidth, this.bgHeight); -} - -/** @method erase - Erase the widget's canvas. - */ -widget.prototype.erase = function() { - this.context.clearRect(0,0,this.width,this.height); -} - -widget.prototype.hideCursor = function() { - this.canvas.style.cursor = "none"; -} - -widget.prototype.showCursor = function() { - this.canvas.style.cursor = "auto"; -} - -// allow us to get the constructor function name programatically -//i.e. if element is a dial, this function will return "dial" -//deprecated -widget.prototype.getName = function() { - return "deprecated -- use widget.type instead" -} - -/** @method set -Manually set a widget's value (that is, set any properties of a widget's .val). See widget.val or the .val property of individual widgets for more info. -@param {object} [data] Parameter/value pairs in object notation. -@param {boolean} [transmit] (optional) Whether or not to transmit new value after being set. -Sets the value of an object. - -```js - position1.set({ -   x: 100, -   y: 250 - }) -``` - -An optional second argument decides whether the object then transmits its new value. -```js - button1.set({ -   press: 100 - }, true) -``` -*/ -widget.prototype.set = function(data, transmit) { - - this.actuated = false; - - if (typeof this.val == "object" && this.val !== "null") { - if (typeof data == "object" && data !== "null") { - for (var key in data) { - this.val[key] = data[key]; - } - } - } else if (typeof this.val == "string" || typeof this.val == "number") { - if (typeof data == "object" && data !== "null") { - this.val = data["value"]; - this.draw(); - } else if (typeof data == "string" || typeof data == "number") { - this.val = data; - } - } - this.draw(); - - if (transmit) { - this.transmit(this.val,true) - } -} - -/** @method destroy - Remove the widget object, canvas, and all related event listeners from the document. - */ -widget.prototype.destroy = function() { - var type = nx.elemTypeArr.indexOf(this.getName()) - nx.elemTypeArr.splice(type,1) - - this.canvas.ontouchmove = null; - this.canvas.ontouchend = null; - this.canvas.onclick = null; - this.canvas.onmousemove = null; - this.canvas.onmouseoff = null; - document.removeEventListener("mousemove", this.preMove, false); - document.removeEventListener("mouseup", this.preRelease, false); - - var elemToKill = document.getElementById(this.canvasID) - if (elemToKill) { - elemToKill.parentNode.removeChild(elemToKill); - } - - this.customDestroy(); - - var id = this.canvasID - delete nx.widgets[id]; - delete window[id]; - -} - -widget.prototype.customDestroy = function() { - -} - -widget.prototype.wrapText = function(text, x, y, maxWidth, lineHeight) { - if (text) { - var words = text.split(' '); - var line = ''; - - for(var n = 0; n < words.length; n++) { - var testLine = line + words[n] + ' '; - var metrics = this.context.measureText(testLine); - var testWidth = metrics.width; - if (testWidth > maxWidth && n > 0) { - this.context.fillText(line, x, y); - line = words[n] + ' '; - y += lineHeight; - } - else { - line = testLine; - } - } - this.context.fillText(line, x, y); - } -} - -widget.prototype.drawLabel = function() { - if (this.showLabels || nx.showLabels) { - with(this.context) { - globalAlpha = 0.4; - fillStyle = this.colors.white; - fillRect(this.width-this.canvasID.length * 6-10,this.height-16,this.canvasID.length * 6+10,16); - globalAlpha = 0.4; - beginPath(); - fillStyle = this.colors.black; - font = "normal 10px courier"; - textAlign = "right"; - textBaseline = "alphabetic"; - fillText(this.canvasID,this.width-4,this.height-4); - textAlign = "left"; - closePath(); - globalAlpha = 1; - } - } -} - -/** @method saveCanv - Download the widget's current graphical state as an image (png). - */ -widget.prototype.saveCanv = function() { - var data = this.canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); - window.location.href = data -} - -widget.prototype.setFont = function() { - with (this.context) { - textAlign = "center"; - textBaseline = "middle"; - font = this.fontWeight+" "+this.fontSize+"px "+this.font; - fillStyle = this.colors.black; - globalAlpha = 0.7; - } -} - - -/* Percentage width support */ - - -widget.prototype.checkPercentage = function() { - var wstr = this.canvas.style.width; - var hstr = this.canvas.style.height; - if (wstr.indexOf("%") >= 0 || hstr.indexOf("%") >= 0) { - this.percent = { - w: (wstr.indexOf("%") >= 0) ? wstr.replace("%","") : false, - h: (hstr.indexOf("%") >= 0) ? hstr.replace("%","") : false - } - this.stretch(); - } -} - -widget.prototype.stretch = function() { - window.addEventListener("resize", function(e) { - if (this.percent.w) { - var newWidth = window.getComputedStyle(this.canvas.parentNode, null).getPropertyValue("width").replace("px",""); - newWidth *= this.percent.w/100 - } else { - var newWidth = false; - } - if (this.percent.h) { - var newHeight = window.getComputedStyle(this.canvas.parentNode, null).getPropertyValue("height").replace("px",""); - newHeight *= this.percent.h/100 - } else { - var newHeight = false; - } - this.resize(newWidth,newHeight); - }.bind(this)) -} - -widget.prototype.resize = function(w,h) { - - this.canvas.width = w ? w*2 : this.canvas.width; - this.canvas.height = h ? h*2 : this.canvas.height; - this.width = w ? w : this.width; - this.height = h ? h : this.height; - this.canvas.style.width = this.width+"px"; - this.canvas.style.height = this.height+"px"; - this.context.scale(2,2) - - this.center = { - x: this.width/2, - y: this.height/2 - }; - - this.init(); - this.draw(); - -} -},{"../utils/dom":4,"../utils/drawing":5,"../utils/timing":7,"../utils/transmit":8,"events":43,"util":47}],4:[function(require,module,exports){ - -/** @class utils - Shared utility functions. These functions are exposed as methods of nx in NexusUI projects, i.e. .mtof() here can be accessed in your project with nx.mtof(). -*/ - - -/** @method findPosition - Returns the offset of an HTML element. Returns an object with 'top' and 'left' properties. - @param {DOM element} [element] - ```js - var button1Offset = nx.findPosition(button1.canvas) - ``` -*/ -exports.findPosition = function(element) { - var body = document.body, - win = document.defaultView, - docElem = document.documentElement, - box = document.createElement('div'); - box.style.paddingLeft = box.style.width = "1px"; - body.appendChild(box); - var isBoxModel = box.offsetWidth == 2; - body.removeChild(box); - box = element.getBoundingClientRect(); - var clientTop = docElem.clientTop || body.clientTop || 0, - clientLeft = docElem.clientLeft || body.clientLeft || 0, - scrollTop = win.pageYOffset || isBoxModel && docElem.scrollTop || body.scrollTop, - scrollLeft = win.pageXOffset || isBoxModel && docElem.scrollLeft || body.scrollLeft; - return { - top : box.top + scrollTop - clientTop, - left: box.left + scrollLeft - clientLeft - }; -} - -exports.getCursorPosition = function(e, canvas_offset) { - var x; - var y; - if (e.pageX != undefined && e.pageY != undefined) { - x = e.pageX; - y = e.pageY; - } else { - x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; - y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop; - } - x -= canvas_offset.left; - y -= canvas_offset.top; - var click_position = {x: x, y: y}; - click_position.touches = [ {x: x, y: y } ]; - return click_position; -} - -exports.getTouchPosition = function(e, canvas_offset) { - var x; - var y; - x = e.targetTouches[0].pageX; - y = e.targetTouches[0].pageY; - x -= canvas_offset.left; - y -= canvas_offset.top; - var click_position = {x: x, y: y}; - - click_position.touches = new Array(); - for (var i=0;i currObject.x && clickedNode.x < (currObject.x+currObject.w) && clickedNode.y > currObject.y && clickedNode.y < (currObject.y+currObject.h)) { - return true; - } else { - return false; - } -} - -exports.makeRoundRect = function(ctx,xpos,ypos,wid,hgt,depth) { - var x1 = xpos; - var y1 = ypos; - var x2 = wid+x1; - var y2 = hgt+y1; - if (!depth) { - depth = 2; - } - - ctx.beginPath(); - ctx.moveTo(x1+depth, y1); //TOP LEFT - ctx.lineTo(x2-depth, y1); //TOP RIGHT - ctx.quadraticCurveTo(x2, y1, x2, y1+depth); - ctx.lineTo(x2, y2-depth); //BOTTOM RIGHT - ctx.quadraticCurveTo(x2, y2, x2-depth, y2); - ctx.lineTo(x1+depth, y2); //BOTTOM LEFT - ctx.quadraticCurveTo(x1, y2, x1, y2-depth); - ctx.lineTo(x1, y1+depth); //TOP LEFT - ctx.quadraticCurveTo(x1, y1, x1+depth, y1); - ctx.closePath(); -} - -exports.text = function(context, text, position) { - if (!position) { - position = [10 , 10]; - } - with(context) { - beginPath(); - font = "bold 12px sans-serif"; - fillText(text,position[0],position[1]); - closePath(); - } -} -},{"./math":6}],6:[function(require,module,exports){ - - -/** @method toPolar - Receives cartesian coordinates and returns polar coordinates as an object with 'radius' and 'angle' properties. - @param {float} [x] - @param {float} [y] - ```js - var ImOnACircle = nx.toPolar({ x: 20, y: 50 }}) - ``` -*/ -exports.toPolar = function(x,y) { - var r = Math.sqrt(x*x + y*y); - - var theta = Math.atan2(y,x); - if (theta < 0.) { - theta = theta + (2 * Math.PI); - } - return {radius: r, angle: theta}; -} - -/** @method toCartesian - Receives polar coordinates and returns cartesian coordinates as an object with 'x' and 'y' properties. - @param {float} [radius] - @param {float} [angle] -*/ -exports.toCartesian = function(radius, angle){ - var cos = Math.cos(angle); - var sin = Math.sin(angle); - return {x: radius*cos, y: radius*sin*-1}; -} - - -/** @method clip - Limits a number to within low and high values. - @param {float} [input value] - @param {float} [low limit] - @param {float} [high limit] - ```js - nx.clip(5,0,10) // returns 5 - nx.clip(15,0,10) // returns 10 - nx.clip(-1,0,10) // returns 0 - ``` -*/ -exports.clip = function(value, low, high) { - return Math.min(high, Math.max(low, value)); -} - -/** @method prune - Limits a float to within a certain number of decimal places - @param {float} [input value] - @param {integer} [max decimal places] - ```js - nx.prine(1.2345, 3) // returns 1.234 - nx.prune(1.2345, 1) // returns 1.2 - ``` -*/ - -exports.prune = function(data, scale) { - if (typeof data === "number") { - data = parseFloat(data.toFixed(scale)); - } else if (data instanceof Array) { - for (var i=0;i borderMin && posIn < borderMax) { - return delta; - } else if (posIn <= borderMin) { - return Math.abs(delta); - } else if (posIn >= borderMax) { - return Math.abs(delta) * (-1); - } -} - - -/** @method mtof - MIDI to frequency conversion. Returns frequency in Hz. - @param {float} [MIDI] MIDI value to convert - ```js - nx.mtof(69) // returns 440 - ``` -*/ -exports.mtof = function(midi) { - return Math.pow(2, ((midi-69)/12)) * 440; -} - - -/** @method random - Returns a random integer between 0 a given scale parameter. - @param {float} [scale] Upper limit of random range. - ```js - nx.random(10) // returns a random number from 0 to 9. - ``` -*/ -exports.random = function(scale) { - return Math.floor(Math.random() * scale); -} - - -exports.interp = function(loc,min,max) { - return loc * (max - min) + min; -} - -exports.lphistory = {} - - -exports.lp = function(tag,value,limit) { - - if (!this.lphistory[tag]) { - this.lphistory[tag] = [] - } - - var total = 0; - - this.lphistory[tag].push(value) - - if (this.lphistory[tag].length>limit) { - this.lphistory[tag].splice(0,1) - } - - for (var i=0;ilimit) { - this.lphistory.splice(0,1) - } - - return newvalue; -} - - -exports.lp3 = function(value,pvalue,limit) { - - var total = value + pvalue * limit; - newvalue = total / (limit + 1) - - return newvalue; -} -},{}],7:[function(require,module,exports){ - - -exports.throttle = function(func, wait) { - var timeout; - return function() { - var context = this, args = arguments; - if (!timeout) { - // the first time the event fires, we setup a timer, which - // is used as a guard to block subsequent calls; once the - // timer's handler fires, we reset it and create a new one - timeout = setTimeout(function() { - timeout = null; - try { - func.apply(context, args); - } catch (err) { - console.log(err); - } - }, wait); - } - } -} -},{}],8:[function(require,module,exports){ -exports.defineTransmit = function(protocol) { - - var newTransmit; - - if (typeof(protocol)=="function") { - return protocol; - } else { - switch (protocol) { - case 'js': - newTransmit = function(data,passive) { - this.makeOSC(this.emit, data, passive); - this.emit('*',data, passive); - } - return newTransmit - - case 'ajax': - newTransmit = function(data) { - this.makeOSC(exports.ajaxTransmit, data); - } - return newTransmit - - case 'node': - newTransmit = function(data) { - this.makeOSC(exports.nodeTransmit, data); - } - return newTransmit - - case 'ios': - newTransmit = function(data) { - - } - return newTransmit - - case 'max': - newTransmit = function(data) { - this.makeOSC(exports.maxTransmit, data); - } - return newTransmit - - case 'wc': - newTransmit = function(data, passive) { - this.emit('internal',data, passive); - } - return newTransmit - } - } -} - -exports.setGlobalTransmit = function(protocol) { - var newTransmit = exports.defineTransmit(protocol) - this.transmit = newTransmit - this.destination = protocol - for (var key in nx.widgets) { - this.widgets[key].transmit = newTransmit; - this.widgets[key].destination = protocol; - } -} - -exports.setWidgetTransmit = function(protocol) { - var newTransmit = exports.defineTransmit(protocol) - this.transmit = newTransmit - this.destination = protocol -} - - -exports.ajaxTransmit = function(subPath, data) { - - var oscPath = subPath=='value' ? this.oscPath : this.oscPath+"/"+subPath; - - xmlhttp=new XMLHttpRequest(); - xmlhttp.open("POST",nx.ajaxPath,true); - xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); - xmlhttp.send('oscName='+oscPath+'&data='+data); - -} - -exports.setAjaxPath = function(path) { - this.ajaxPath = path; -} - -exports.nodeTransmit = function(subPath, data) { - - var msg = { - oscName: subPath=='value' ? this.oscPath : this.oscPath+"/"+subPath, - value: data - } - socket.emit('nx', msg) - -} - -exports.maxTransmit = function (subPath, data) { - var oscPath = subPath=='value' ? this.oscPath : this.oscPath+"/"+subPath; - window.max.outlet(oscPath + " " + data); -} -},{}],9:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class banner - "Powered by NexusUI" tag with a link to our website. Use it if you want to share the positive vibes of NexusUI. Thanks for using! - ```html - - ``` - -*/ - -var banner = module.exports = function (target) { - this.defaultSize = { width: 100, height: 40 }; - widget.call(this, target); - - //unique attributes - /** @property {string} message1 The first line of text on the banner. */ - this.message1 = "Powered By"; - /** @property {string} message2 The second line of text on the banner. */ - this.message2 = "NexusUI"; - /** @property {string} link The URL the banner will link to. */ - this.link = "http://www.nexusosc.com"; - /** @property {boolean} isLink Whether or not the banner is a hyperlink. Defaults to true. */ - this.isLink = true; -} -util.inherits(banner, widget); - -banner.prototype.init = function() { - this.draw(); -} - -banner.prototype.draw = function() { - with (this.context) { - - globalAlpha = 0.1; - fillStyle = this.colors.accent; - beginPath(); - moveTo(0,10); - lineTo(10,this.height/2+5); - lineTo(0,this.height); - lineTo(30,this.height); - lineTo(30,10); - fill(); - moveTo(this.width-30,10); - lineTo(this.width-30,this.height); - lineTo(this.width,this.height); - lineTo(this.width-10,this.height/2+5); - lineTo(this.width,10); - fill(); - closePath(); - globalAlpha = 1; - - fillStyle = this.colors.accent; - fillRect(15,0,this.width-30,this.height-10); - - fillStyle = this.colors.white; - font = this.fontWeight + " " +this.height/5+"px "+this.font; - textAlign = "center"; - fillText(this.message1, this.width/2, this.height/3.3); - fillText(this.message2, this.width/2, (this.height/3.3)*2); - - fillStyle = this.colors.black; - beginPath(); - moveTo(15,this.height-10); - lineTo(30,this.height); - lineTo(30,this.height-10); - lineTo(15,this.height-10); - fill(); - moveTo(this.width-15,this.height-10); - lineTo(this.width-30,this.height); - lineTo(this.width-30,this.height-10); - lineTo(this.width-15,this.height-10); - fill(); - closePath(); - - } -} - -banner.prototype.click = function() { - if (this.isLink) { - window.location = this.link; - } -} -},{"../core/widget":3,"util":47}],10:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); -var drawing = require('../utils/drawing'); - -var button = module.exports = function(target) { - -/** - - @public - @class button - - Touch button with three modes of interaction ("toggle", "impulse", and "aftertouch"). - ```html - - ``` - -*/ - - this.defaultSize = { width: 50, height: 50 }; - widget.call(this, target); - - /** - @property {object} val Main value set and output, with sub-properties: - |   | data - | --- | --- - | *press* | 0 (clicked) or 1 (unclicked) - | *x* | 0-1 float of x-position of click ("aftertouch" mode only) - | *y* | 0-1 float of y-position of click ("aftertouch" mode only) - - When the widget is interacted with, val is sent as the output data for the widget. - ```js - button1.on('*', function(data) { - // some code using data.press, data.x, and data.y - }); - ``` - Or, if NexusUI is outputting OSC (e.g. if nx.sendsTo("ajax")), val will be broken into OSC messages: - ```html - /button1/press 1 - /button1/x 37 - /button1/y 126 - ``` - */ - this.val = { - press: 0 - } - - /** @property {string} mode Interaction mode. Options: - impulse   1 on click
- toggle   1 on click, 0 on release
- aftertouch   1, x, y on click; x, y on move; 0, x, y on release _(default)_
- ```js - button1.mode = "aftertouch" - ``` - */ - this.mode = "aftertouch"; - - this.lockResize = true; - - this.image = null; - this.imageHover = null; - this.imageTouch = null; - - this.subval = new Object(); - - this.init(); - -} -util.inherits(button, widget); - -button.prototype.init = function() { - this.center = { - x: this.width/2, - y: this.height/2 - } - this.radius = (Math.min(this.center.x, this.center.y)-this.lineWidth/2) - this.draw(); -} - -button.prototype.draw = function() { - - this.erase(); - - with (this.context) { - - if (this.image !== null) { - // Image Button - if (!this.val.press) { - // Draw Image if not touched - drawImage(this.image, 0, 0); - } else { - if (!this.imageTouch) { - - drawImage(this.image, 0, 0); - - // No touch image, apply highlighting - globalAlpha = 0.5; - fillStyle = this.colors.accent; - fillRect (0, 0, this.width, this.height); - globalAlpha = 1; - - } else { - // Draw Touch Image - drawImage(this.imageTouch, 0, 0); - } - } - - } else { - - // Regular Button - if (!this.val.press) { - fillStyle = this.colors.fill; - } else if (this.val.press) { - fillStyle = this.colors.accent; - } - - beginPath(); - arc(this.center.x, this.center.y, this.radius, 0, Math.PI*2, true); - fill(); - closePath(); - - if (this.val.press && this.mode=="aftertouch") { - - var x = nx.clip(this.clickPos.x,this.width*.2,this.width/1.3) - var y = nx.clip(this.clickPos.y,this.height*.2,this.height/1.3) - - var gradient = this.context.createRadialGradient(x,y,this.width/6,this.center.x,this.center.y,this.radius*1.3); - gradient.addColorStop(0,this.colors.accent); - gradient.addColorStop(1,"white"); - - strokeStyle = gradient; - lineWidth = this.width/20; - - beginPath() - arc(this.center.x, this.center.y, this.radius-this.width/40, 0, Math.PI*2, true); - stroke() - closePath() - - - } - } - - this.drawLabel(); - - } -} - -button.prototype.click = function(e) { - if (drawing.isInside(this.clickPos,{x: this.center.x-this.radius, y:this.center.y-this.radius, w:this.radius*2, h:this.radius*2})) { - this.val["press"] = 1; - if (this.mode=="aftertouch") { - this.val["x"] = this.clickPos.x; - this.val["y"] = this.clickPos.y; - } - this.transmit(this.val); - this.draw(); - } -} - -button.prototype.move = function () { - // use to track movement on the button - if (this.mode=="aftertouch") { - this.val["x"] = this.clickPos.x; - this.val["y"] = this.clickPos.y; - this.subval["x"] = this.clickPos.x; - this.subval["y"] = this.clickPos.y; - this.transmit(this.subval); - this.draw(); - } -} - -button.prototype.release = function() { - this.val["press"] = 0; - if (this.mode=="toggle" || this.mode=="aftertouch") { - this.transmit(this.val); - } - this.draw(); -} - - -/** @method setImage - Turns the button into an image button with custom image. Sets the default (unclicked) button image. - @param {string} [src] Image source */ -button.prototype.setImage = function(image) { - this.image = new Image(); - this.image.onload = function() { this.draw() } - this.image.src = image; -} - -button.prototype.setHoverImage = function(image) { - this.imageHover = new Image(); - this.imageHover.onload = function() { this.draw() } - this.imageHover.src = image; -} - -/** @method setTouchImage - Sets the image that will show when the button is clicked. - @param {string} [src] Image source */ -button.prototype.setTouchImage = function(image) { - this.imageTouch = new Image(); - this.imageTouch.onload = this.draw(); - this.imageTouch.src = image; -} -},{"../core/widget":3,"../utils/drawing":5,"util":47}],11:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class colors - Color picker that outputs RBG values - ```html - - ``` - -*/ - -var colors = module.exports = function (target) { - - this.defaultSize = { width: 100, height: 100 }; - widget.call(this, target); - - this.init(); - -} -util.inherits(colors, widget); - -colors.prototype.init = function() { - - /* new tactic */ - - this.gradient1 = this.context.createLinearGradient(0,0,this.width,0) - this.gradient1.addColorStop(0, '#F00'); - this.gradient1.addColorStop(0.17, '#FF0'); - this.gradient1.addColorStop(0.34, '#0F0'); - this.gradient1.addColorStop(0.51, '#0FF'); - this.gradient1.addColorStop(0.68, '#00F'); - this.gradient1.addColorStop(0.85, '#F0F'); - this.gradient1.addColorStop(1, '#F00'); - - this.gradient2 = this.context.createLinearGradient(0,0,0,this.height) - this.gradient2.addColorStop(0, 'rgba(0,0,0,255)'); - this.gradient2.addColorStop(0.49, 'rgba(0,0,0,0)'); - this.gradient2.addColorStop(0.51, 'rgba(255,255,255,0)'); - this.gradient2.addColorStop(0.95, 'rgba(255,255,255,255)'); - - this.draw(); -} - -colors.prototype.draw = function() { - this.erase(); - - with(this.context) { - fillStyle = this.gradient1; - fillRect(0,0,this.width,this.height) - fillStyle = this.gradient2; - fillRect(0,0,this.width,this.height) - } - - this.drawLabel(); -} - -colors.prototype.drawColor = function() { - with(this.context) { - fillStyle = "rgb("+this.val.r+","+this.val.g+","+this.val.b+")" - fillRect(0,this.height * 0.95,this.width,this.height* 0.05) - - } -} - -colors.prototype.click = function(e) { - if (this.clickPos.x > 0 && this.clickPos.y > 0 && this.clickPos.x < this.width && this.clickPos.y < this.height) { - var imgData = this.context.getImageData(this.clickPos.x*2,this.clickPos.y*2,1,1); - } else { - return; - } - - - /** @property {object} val RGB color value at mouse position.
This is also the widget's data output (See widget.val).
Properties: - |   | data - | --- | --- - | *r* | red value 0-256 - | *g* | green value 0-256 - | *b* | blue value 0-256 - ```js - colors1.on('*', function(data) { - // some code using data.r, data.g, and data.b - } - ``` - */ - - this.val = { - r: imgData.data[0], - g: imgData.data[1], - b: imgData.data[2] - } - this.transmit(this.val); - this.drawColor(); -} - - -colors.prototype.move = function(e) { - this.click(e); -} -},{"../core/widget":3,"util":47}],12:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class comment - Text comment - ```html - - ``` - -*/ - -var comment = module.exports = function (target) { - - this.defaultSize = { width: 75, height: 25 }; - widget.call(this, target); - - /** @property {object} val - |   | data - | --- | --- - | *text* | text of comment area (as string) - ```js - comment1.val.text = "This is my comment" - comment1.draw() - ``` - */ - - this.val = { - text: "comment" - } - this.sizeSet = false; - - this.init(); -} -util.inherits(comment, widget); - -/** @method setSize - Set the font size of the comment text - @param {integer} [size] Text size in pixels -*/ -comment.prototype.setSize = function(size) { - this.size = size; - this.sizeSet = true; - this.draw(); -} - -comment.prototype.init = function() { - this.draw(); -} - -comment.prototype.draw = function() { - if (!this.sizeSet) { - this.size = Math.sqrt((this.width * this.height) / (this.val.text.length)); - } - - this.erase(); - with (this.context) { - - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - beginPath(); - moveTo(0,this.height); - lineTo(this.width,this.height); - closePath(); - - fillStyle = this.colors.black; - textAlign = "left"; - font = this.size+"px Gill Sans"; - } - this.wrapText(this.val.text, 6, 3+this.size, this.width-6, this.size); -} -},{"../core/widget":3,"util":47}],13:[function(require,module,exports){ -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class crossfade - Crossfade for panning or mixing - ```html - - ``` - -*/ - -var crossfade = module.exports = function (target) { - this.defaultSize = { width: 100, height: 30 }; - widget.call(this, target); - - /** @property {object} val - |   | data - | --- | --- - | *value* | Crossfade value (float -1 to 1) - */ - this.val.value = 0.7 - - this.label = ""; - - this.init(); -} -util.inherits(crossfade, widget); - -crossfade.prototype.init = function() { - - if (this.canvas.getAttribute("label")!=null) { - this.label = this.canvas.getAttribute("label"); - } - - this.draw(); -} - -crossfade.prototype.draw = function() { - - this.erase(); - - with (this.context) { - - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - - if (nx.showLabels) { - this.setFont(); - fillText(this.label, this.width/2, this.height/2); - globalAlpha = 1; - - } - - var x1 = this.width/2; - var y1 = 0; - var x2 = (this.val.value/2)*this.width; - var y2 = this.height; - - - fillStyle = this.colors.accent; - fillRect(x1,y1,x2,y2); - - fillRect(x1-1,y1,2,y2); - - } -} - -crossfade.prototype.click = function() { - this.move(); -} - -crossfade.prototype.move = function() { - var x = nx.scale(this.clickPos.x/this.width,0,1,-1,1) - this.val.value = math.prune(math.clip(x, -1, 1),3) - this.draw(); - this.transmit(this.val); -} -},{"../core/widget":3,"../utils/math":6,"util":47}],14:[function(require,module,exports){ -var math = require('../utils/math'); -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class dial - Circular dial - ```html - - ``` - -*/ - -var dial = module.exports = function(target) { - - this.defaultSize = { width: 50, height: 50 }; - widget.call(this, target); - - //define unique attributes - this.circleSize; - this.handleLength; - - /** @property {object} val - |   | data - | --- | --- - | *value* | Current value of dial as float 0-1 - */ - this.val = { - value: 0 - } - /** @property {float} responsivity How much the dial increments on drag. Default: 0.004
- */ - this.responsivity = 0.004; - - this.aniStart = 0; - this.aniStop = 1; - this.aniMove = 0.01; - - this.lockResize = true; - - this.init(); - -} - -util.inherits(dial, widget); - -dial.prototype.init = function() { - - this.circleSize = (Math.min(this.center.x, this.center.y)); - this.handleLength = this.circleSize; - this.mindim = Math.min(this.width,this.height) - - if (this.mindim<101) { - this.handleLength--; - } - - if (this.mindim<101 || this.mindim<101) { - this.accentWidth = this.lineWidth * 1; - } else { - this.accentWidth = this.lineWidth * 2; - } - - this.draw(); - - return 1; -} - -dial.prototype.draw = function() { - var dial_angle = (((1.0 - this.val.value) * 2 * Math.PI) + (1.5 * Math.PI)); - var dial_position = (this.val.value + 0.25) * 2 * Math.PI - var point = math.toCartesian(this.handleLength, dial_angle); - - this.erase(); - - with (this.context) { - - fillStyle = this.colors.fill; - - //draw main circle - beginPath(); - arc(this.center.x, this.center.y, this.circleSize-1, 0, Math.PI*2, true); - fill(); - closePath(); - - //draw color fill - beginPath(); - lineWidth = this.accentWidth; - arc(this.center.x, this.center.y, this.circleSize, Math.PI* 0.5, dial_position, false); - lineTo(this.center.x,this.center.y); - globalAlpha = 0.1; - fillStyle = this.colors.accent; - fill(); - globalAlpha = 1; - closePath(); - - //draw round accent - beginPath(); - lineWidth = this.accentWidth; - arc(this.center.x, this.center.y, this.circleSize-this.lineWidth , Math.PI* 0.5, dial_position, false); - strokeStyle = this.colors.accent; - stroke(); - closePath(); - - //draw bar accent - beginPath(); - lineWidth = this.accentWidth; - strokeStyle = this.colors.accent; - moveTo(this.center.x, this.center.y); - lineTo(point.x + this.center.x, point.y + this.center.y); - stroke(); - closePath(); - - //draw circle in center - beginPath(); - fillStyle = this.colors.accent; - arc(this.center.x, this.center.y, this.circleSize/8, 0, Math.PI*2, false); - fill(); - closePath(); - - } - - this.drawLabel(); -} - - -dial.prototype.click = function(e) { - this.val.value = math.prune(this.val.value, 4) - this.transmit(this.val); - this.draw(); - this.aniStart = this.val.value; -} - - -dial.prototype.move = function() { - this.val.value = math.clip((this.val.value - (this.deltaMove.y * this.responsivity)), 0, 1); - this.val.value = math.prune(this.val.value, 4) - this.transmit(this.val); - - this.draw(); -} - - -dial.prototype.release = function() { - this.aniStop = this.val.value; -} - -/** @method animate - Animates the dial - @param {string} [type] Type of animation. Currently accepts "bounce" (bounces between mousedown and mouserelease points) or "none" */ -dial.prototype.animate = function(aniType) { - - switch (aniType) { - case "bounce": - nx.aniItems.push(this.aniBounce.bind(this)); - break; - case "none": - nx.aniItems.splice(nx.aniItems.indexOf(this.aniBounce)); - break; - } - -} - -dial.prototype.aniBounce = function() { - if (!this.clicked) { - this.val.value += this.aniMove; - if (this.aniStop < this.aniStart) { - this.stopPlaceholder = this.aniStop; - this.aniStop = this.aniStart; - this.aniStart = this.stopPlaceholder; - } - this.aniMove = math.bounce(this.val.value, this.aniStart, this.aniStop, this.aniMove); - this.draw(); - this.val.value = math.prune(this.val.value, 4) - this.transmit(this.val); - } -} - - -},{"../core/widget":3,"../utils/math":6,"util":47}],15:[function(require,module,exports){ -var startTime = 0; - -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class envelope - Multi-point line ramp generator - ```html - - ``` - -*/ - -var envelope = module.exports = function (target) { - this.defaultSize = { width: 200, height: 100 }; - widget.call(this, target); - - this.nodeSize = 1; - /** @property {boolean} active Whether or not the envelope is currently animating. */ - this.active = false; - /** @property {integer} duration The envelope's duration in ms. */ - this.duration = 1000; // 1000 ms - /** @property {boolean} looping Whether or not the envelope loops. */ - this.looping = false - - - this.scanIndex = 0 - - //define unique attributes - - /** @property {object} val - |   | data - | --- | --- - | *amp* | amplitude at current point of ramp (float 0-1) - | *index* | current progress through ramp (float 0-1) - | *points* | array containing x/y coordinates of each node. - */ - - this.val = { - index: 0, - amp: 0, - points: [ - { - x: 0.1, - y: 0.4 - }, - { - x: 0.35, - y: 0.6 - }, - { - x: 0.65, - y: 0.2 - }, - { - x: 0.9, - y: 0.4 - } - ] - } - - // Index of which node was clicked - var selectedNode = null; - - nx.aniItems.push(this.pulse.bind(this)); - - this.init(); -} - -util.inherits(envelope, widget); - -envelope.prototype.init = function() { - this.mindim = this.width < this.height ? this.width : this.height; - this.draw(); -} - -envelope.prototype.draw = function() { - this.erase(); - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - fillStyle = this.colors.accent; - var centerx = this.mindim/10 - var centery = this.height-this.mindim/10 - beginPath() - moveTo(centerx,centery) - arc(centerx,centery,this.mindim/10,Math.PI*1.5,Math.PI*2*this.val.index+Math.PI*1.5,false); - fill() - closePath() - - // draw all the points - var drawingX = []; - var drawingY = []; - - for (var i = 0; i < this.val.points.length; i++) { - drawingX[i] = this.val.points[i].x * this.width; - drawingY[i] = (1 - this.val.points[i].y) * this.height; - - //stay within right/left bounds - if (drawingX[i]<(this.bgLeft+this.nodeSize)) { - drawingX[i] = this.bgLeft + this.nodeSize; - } else if (drawingX[i]>(this.bgRight-this.nodeSize)) { - drawingX[i] = this.bgRight - this.nodeSize; - } - //stay within top/bottom bounds - if (drawingY[i]<(this.bgTop+this.nodeSize)) { - drawingY[i] = this.bgTop + this.nodeSize; - } else if (drawingY[i]>(this.bgBottom-this.nodeSize)) { - drawingY[i] = this.bgBottom - this.nodeSize; - } - } - - // draw rectangles - for (var j = 0; j < drawingX.length; j++) { - var size = this.mindim/25; - beginPath() - arc(drawingX[j],drawingY[j],size,0,Math.PI*2,false); - fillStyle = this.colors.accent - fill() - closePath() - } - - - // draw shape - beginPath(); - strokeStyle = this.colors.accent; - moveTo(-5,this.height); - lineTo(-5,(1-this.val.points[0].y)*this.height); - - // draw each line - for (var j = 0; j < drawingX.length; j++) { - lineTo(drawingX[j],drawingY[j]); - } - - lineTo(this.width+5,(1-this.val.points[this.val.points.length-1].y)*this.height); - lineTo(this.width+5,this.height); - stroke(); - globalAlpha = 0.2; - fillStyle = this.colors.accent; - fill(); - globalAlpha = 1 - closePath(); - - - - } - - this.drawLabel(); -} - -envelope.prototype.scaleNode = function(nodeIndex) { - var i = nodeIndex; - var prevX = 0; - var nextX = this.width; - - var actualX = this.val.points[i].x; - var actualY = (this.height - this.val.points[i].y); - var clippedX = math.clip(actualX/this.width, 0, 1); - var clippedY = math.clip(actualY/this.height, 0, 1); - - this.val.points[i].x = math.prune(clippedX, 3); - this.val.points[i].y = math.prune(clippedY, 3); - - // find x value of nodes to the right and left - if (i > 0) { - prevX = this.val.points[i-1].x; - } - if (this.val.points.length > i+1) { - nextX = this.val.points[i+1].x; - } - - if (this.val.points[i].x < prevX) { - this.val.points.splice(i-1, 0, this.val.points.splice(i, 1)[0]) - i = i-1; - selectedNode = i; - } - - if (this.val.points[i].x > nextX) { - this.val.points.splice(i+1, 0, this.val.points.splice(i, 1)[0]) - i = i+1; - selectedNode = i; - } - -} - -envelope.prototype.click = function() { - - // find nearest node and set selectedNode (index) - selectedNode = this.findNearestNode(this.clickPos.x/this.width, this.clickPos.y/this.height, this.val.points); - - this.transmit(this.val); - this.draw(); -} - -envelope.prototype.move = function() { - if (this.clicked) { - this.val.points[selectedNode].x = this.clickPos.x; - this.val.points[selectedNode].y = this.clickPos.y; - this.scaleNode(selectedNode); - this.transmit(this.val); - this.draw(); - } -} - -envelope.prototype.release = function() { - - if (!this.hasMoved) { - this.val.points.splice(selectedNode,1) - } - - this.draw(); - - // reset the selectedNode - selectedNode = null; -} - -// update index and amp -envelope.prototype.pulse = function() { - if (this.active) { - - // calculate index based on audio context - var percentDone = (nx.context.currentTime - startTime) / (this.duration/1000); - if (percentDone >= 1) { - if (this.looping) { - percentDone -= 1; - startTime += this.duration/1000; - this.val.index = 0 - this.scanIndex = 0 - } else { - this.stop(); - } - - } - this.val.index = percentDone; - - if (this.val.index > this.val.points[this.val.points.length-1].x) { - this.val.amp = this.val.points[this.val.points.length-1].y - } else if (this.val.index < this.val.points[0].x) { - this.val.amp = this.val.points[0].y - } else { - - while (percentDone > this.val.points[this.scanIndex].x) { - this.scanIndex++; - } - - var nextPX = this.val.points[this.scanIndex].x; - var prevPX = this.val.points[this.scanIndex-1].x; - var nextPY = this.val.points[this.scanIndex].y; - var prevPY = this.val.points[this.scanIndex-1].y; - - this.val.amp = math.interp((this.val.index-prevPX)/(nextPX - prevPX),prevPY,nextPY); - - } - - this.transmit(this.val); - this.draw(); - } -} - -/** @method start - Start ramp from beginning. If set to loop, will loop the ramp until stopped. */ -envelope.prototype.start = function() { - this.active = true; - this.val.index = 0; - - // set startTime - startTime = nx.context.currentTime; -} - -/** @method stop - Stop the ramp and set progress to 0. */ -envelope.prototype.stop = function() { - this.active = false; - this.val.index = 0; - this.draw(); -} - -envelope.prototype.findNearestNode = function(x, y, nodes) { - var nearestIndex = null; - var nearestDist = 1000; - var before = false; - y = 1 - y; - for (var i = 0; i nodes[i].x - } - } - - if (nearestDist>.1) { - if (before) { nearestIndex++ } - this.val.points.splice(nearestIndex,0,{ - x: this.clickPos.x/this.width, - y: (this.height-this.clickPos.y)/this.height - }) - //nearestIndex++; - } - - return nearestIndex; -} -},{"../core/widget":3,"../utils/math":6,"util":47}],16:[function(require,module,exports){ -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class ghost (alpha) - Interface gesture capture / playback (in development) - - ```html - - ``` - -*/ - -var ghost = module.exports = function(target) { - - this.defaultSize = { width: 100, height: 50 }; - widget.call(this, target); - - //define unique attributes - this.recording = false; - this.playing = false; - this.maxLength = 2000; - this.components = new Array(); - this.buffer = new Array(); - //this.moment is for the record head - this.moment = 0; - //this.needle is for the playback head - this.needle = 0; - this.val = new Object(); - this.rate = 1; - this.start = 0; - this.end = 1; - this.size = 0; - this.looping = true; - this.boundLog = this.log.bind(this) - this.direction = 1; - //settings - this.noise = 0; - this.loopstart = 0; - this.loopend = 0; - this.mode = "linear"; // linear,bounce,random,wander,pattern/dream - //init - this.init(); - - this.boundAdv = this.advance.bind(this); - nx.aniItems.push(this.boundAdv) - -} - -util.inherits(ghost, widget); - - -ghost.prototype.init = function() { - this.draw(); -} - -ghost.prototype.watch = function() { -} - - //sets a new component to be recorded -ghost.prototype.connect = function(target) { - var compIndex = this.components.length; - this.components.push(target); - target.tapeNum = compIndex; - target.isRecording = true; - target.recorder = this; - this.buffer[compIndex] = new Object(); - for (var key in target.val) { - this.buffer[compIndex][key] = new Array(); - } - -} - - //the actual recording function -ghost.prototype.write = function(index, val) { - if (this.moment>=this.maxLength) { - this.stop(); - } - for (var key in val) { - if (this.buffer[index][key]) { - // if an array or object, must make a copy, otherwise it is a reference to the original and will not record properly - if (typeof val[key] == "object") { - if (Array.isArray(val[key])) { - // this.buffer[index][key][this.moment] = val[key].slice() - // above line should work, but is still only a reference, not a copy - this.buffer[index][key][this.moment] = JSON.parse(JSON.stringify(val[key])) - } else { - this.buffer[index][key][this.moment] = {} - for (var subkey in val[key]) { - this.buffer[index][key][this.moment][subkey] = val[key][subkey] - } - } - } else { - this.buffer[index][key][this.moment] = val[key]; - } - } - } - this.draw(); -} - - -ghost.prototype.draw = function() { - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height) - } - - var quad = this.width/4; - var quad2 = this.width-quad; - - if (!this.recording) { - with (this.context) { - fillStyle = "#e33"; - beginPath() - arc(quad,this.height/2,quad*0.8,0,Math.PI*2) - fill() - closePath(); - textAlign = "center" - textBaseline = "middle" - font = "normal "+this.height/6+"px courier" - fillStyle = this.colors.fill - fillText("rec",quad,this.height/2) - } - } else { - with (this.context) { - fillStyle = "#e33"; - fillRect(quad*0.4,quad*0.4,quad*1.2,quad*1.2) - } - } - - if (!this.playing) { - with (this.context) { - fillStyle = this.colors.border - beginPath() - arc(quad2,this.height/2,quad*0.8,0,Math.PI*2) - fill() - closePath() - textAlign = "center" - textBaseline = "middle" - font = "normal "+this.height/6+"px courier" - fillStyle = this.colors.fill - fillText("play",quad2,this.height/2) - } - } else { - with (this.context) { - strokeStyle = this.colors.border - lineWidth = this.width/30 - beginPath() - arc(quad2,this.height/2,quad*0.8,0,Math.PI*2) - stroke() - closePath() - var sec = ~~(this.needle/30) - textAlign = "center" - textBaseline = "middle" - font = "normal "+this.height/3+"px courier" - fillStyle = this.colors.border - fillText(sec,quad2,this.height/2+2) - } - } -} - -ghost.prototype.record = function() { - if (!this.playing) { - this.components = new Array(); - for (var key in nx.widgets) { - this.connect(nx.widgets[key]); - } - } - this.moment = 0; - nx.aniItems.push(this.boundLog) - this.recording = true; -} - -ghost.prototype.log = function() { - for (var i=0;i this.size*0.75 ? dir-- : null; - this.needle < this.size*0.25 ? dir++ : null; - this.needle += this.rate*this.direction * (nx.random(dir)-1); - } - - if (this.needle/this.size < this.end && this.needle/this.size > this.start) { - this.scan(); - } else if (this.looping) { - if (this.mode=="linear") { - this.needle = this.start*this.size + 1; - } else { - this.direction = this.direction * -1 - } - } else { - this.playing = false; - } - this.draw(); - } -} - - -ghost.prototype.click = function(e) { - if (this.clickPos.x - ``` - -*/ - -var joints = module.exports = function (target) { - this.defaultSize = { width: 150, height: 150 }; - widget.call(this, target); - - /* @property {integer} nodeSize The size of the proximity points in pixels */ - this.nodeSize = this.width/14; - this.values = [0,0]; - - /** @property {object} val - |   | data - | --- | --- - | *x* | x position of touch/mouse - | *y* | y position of touch/mouse - | *node0* | nearness to first node if within range (float 0-1) - | *node1* | nearness to second node if within range (float 0-1) - | *node2* | nearness to third node if within range (float 0-1) - | etc... |   - - */ - this.val = { - x: 0.35, - y: 0.35, - node1: 0 - } - /** @property {array} joints An array of objects with x and y properties detailing coordinates of each proximity node. - ```js - // The widget will now have only 2 proximity points, instead of 8 - joints1.joints = [ -   { x: 20 , y: 100 }, -   { x: 75 , y: 150 } - ] - ``` - */ - this.joints = [ - { x: this.width/1.2 , y: this.height/1.2 }, - { x: this.width/2 , y: this.height/1.3 }, - { x: this.width/4.2 , y: this.height/1.1 }, - - { x: this.width/1.4 , y: this.height/2.2 }, - { x: this.width/2.1 , y: this.height/1.8 }, - { x: this.width/5 , y: this.height/2.4 }, - - { x: this.width/2.8 , y: this.height/6 }, - { x: this.width/6 , y: this.height/3.7 } - - ] - this.threshold = this.width / 3; -} -util.inherits(joints, widget); - -joints.prototype.init = function() { - this.draw(); -} - -joints.prototype.draw = function() { - this.erase(); - - this.drawingX = this.val.x * this.width; - this.drawingY = this.val.y * this.height; - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - if (this.val.x != null) { - this.drawNode(); - } - else { - fillStyle = this.colors.border; - font = "14px courier"; - fillText(this.default_text, 10, 20); - } - fillStyle = this.colors.accent; - strokeStyle = this.colors.border; - for (var i in this.joints) { - beginPath(); - arc(this.joints[i].x, this.joints[i].y, this.nodeSize/2, 0, Math.PI*2, true); - fill(); - closePath(); - var cnctX = Math.abs(this.joints[i].x-this.drawingX); - var cnctY = Math.abs(this.joints[i].y-this.drawingY); - var strength = cnctX + cnctY; - if (strength < this.threshold) { - beginPath(); - moveTo(this.joints[i].x, this.joints[i].y); - lineTo(this.drawingX,this.drawingY); - strokeStyle = this.colors.accent; - lineWidth = math.scale( strength, 0, this.threshold, this.nodeSize/2, 5 ); - stroke(); - closePath(); - var scaledstrength = math.scale( strength, 0, this.threshold, 1, 0 ); - this.val["node"+i] = scaledstrength; - } - } - } - - this.drawLabel(); -} - -joints.prototype.drawNode = function() { - //stay within right/left bounds - if (this.drawingX<(this.nodeSize)) { - this.drawingX = this.nodeSize; - } else if (this.drawingX>(this.width-this.nodeSize)) { - this.drawingX = this.width - this.nodeSize; - } - //stay within top/bottom bounds - if (this.drawingY < this.nodeSize) { - this.drawingY = this.nodeSize; - } else if (this.drawingY>(this.height-this.nodeSize)) { - this.drawingY = this.height - this.nodeSize; - } - - with (this.context) { - globalAlpha=1; - beginPath(); - fillStyle = this.colors.accent; - strokeStyle = this.colors.border; - lineWidth = this.lineWidth; - arc(this.drawingX, this.drawingY, this.nodeSize, 0, Math.PI*2, true); - fill(); - closePath(); - } -} - -joints.prototype.click = function() { - this.val = new Object(); - this.val.x = this.clickPos.x/this.width; - this.val.y = this.clickPos.y/this.height; - this.draw(); - this.transmit(this.val); - this.connections = new Array(); - -} - -joints.prototype.move = function() { - this.val = new Object(); - if (this.clicked) { - this.val.x = this.clickPos.x/this.width; - this.val.y = this.clickPos.y/this.height; - this.draw(); - this.transmit(this.val); - this.connections = new Array(); - } -} - - -joints.prototype.release = function() { - this.anix = this.deltaMove.x/this.width; - this.aniy = (this.deltaMove.y)/this.height; - -} - -/** @method animate - Add simple physics to the widget - @param {string} [type] Currently accepts "bounce" or "none". -*/ - -joints.prototype.animate = function(aniType) { - - switch (aniType) { - case "bounce": - nx.aniItems.push(this.aniBounce.bind(this)); - break; - case "none": - nx.aniItems.splice(nx.aniItems.indexOf(this.aniBounce)); - break; - } - -} - -joints.prototype.anix = 0; -joints.prototype.aniy = 0; - -joints.prototype.aniBounce = function() { - if (!this.clicked && this.val.x) { - this.val.x += (this.anix); - this.val.y += (this.aniy); - this.anix = math.bounce(this.val.x, 0.1, 0.9, this.anix); - this.aniy = math.bounce(this.val.y, 0.1, 0.9, this.aniy); - this.draw(); - this.transmit(this.val); - } -} - -},{"../core/widget":3,"../utils/math":6,"util":47}],19:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); -var drawing = require('../utils/drawing'); -var math = require('../utils/math'); - -/** - @class keyboard - Piano keyboard which outputs MIDI - ```html - - ``` - -*/ - -var keyboard = module.exports = function (target) { - - this.defaultSize = { width: 300, height: 75 }; - widget.call(this, target); - - /** @property {integer} octaves Number of octaves on the keyboard - ```js - //This key pattern would put a black key between every white key - keyboard1.octaves = 1 - keyboard1.init() - ``` - - */ - - this.octaves = 3; - - this.white = { - width:0, - height:0 - } - this.black = { - width:0, - height:0 - } - this.wkeys = new Array(); - this.bkeys = new Array(); - - /** @property {array} keypattern Array of 'w' and 'b' denoting the pattern of white and black keys. This can be customized! The pattern can be any number of keys, however each black key must be surrounded by two white keys. - ```js - //This key pattern would put a black key between every white key - keyboard1.keypattern = ['w','b','w','b','w','b','w','b','w','b','w','b'] - keyboard1.init() - - //This key pattern uses only white keys - keyboard2.keypattern = ['w','w','w','w','w','w','w','w','w','w','w','w'] - keyboard2.init() - ``` - - - */ - this.keypattern = ['w','b','w','b','w','w','b','w','b','w','b','w'] - this.keys = new Array(); - /** @property {integer} midibase The MIDI note value of the lowest note on the keyboard. Defaults to 48. */ - this.midibase = 48; - this.lineWidth = 1; - - //to enable multitouch - this.fingers = [ - { - key: -1, - pkey: -1 - - } - ] - this.multitouch = false; // will auto switch to true if experiences 2 simultaneous touches - this.oneleft = false; - - /** @property {string} mode Play mode. Currently accepts "button" (default) or "sustain" in which each key acts as a toggle. */ - this.mode = "button" // modes: "button", "sustain" and, possibly in future, "aftertouch" - - // for each key: x, y, w, h, color, on, note - - /** @property {object} val Core interactive values and data output - |   | data - | --- | --- - | *on* | 0 if noteon, 1 if noteoff - | *note* | MIDI value of key pressed - | *midi* | paired MIDI message as a string - example "20 0" - This is to allow for simultaneous arrival of the MIDI pair if sent as an OSC message. - */ - this.val = { - on: 0, - note: 0, - midi: "0 0" - }; - - this.init(); - -} -util.inherits(keyboard, widget); - -keyboard.prototype.init = function() { - - //recap from header - this.white = { - width:0, - height:0 - } - this.black = { - width:0, - height:0 - } - this.wkeys = new Array(); - this.bkeys = new Array(); - - /** @property {array} keys Array of key objects. This may be of use in combination with the keyboard.toggle method. */ - this.keys = new Array(); - - //new stuff - this.white.num = 0; - for (var i=0;i=this.wkeys.length) { keyx = this.wkeys.length-1 } - if (keyx<0) { keyx = 0 } - return this.wkeys[keyx]; -} - -keyboard.prototype.click = function(e) { - - if (this.clickPos.touches.length>1 || this.multitouch) { - this.multitouch = true; - if (this.clickPos.touches.length>=2 && this.oneleft) { - this.oneleft = false; - } - this.keysinuse = new Array(); - for (var j=0;j1 || this.multitouch) { - this.keysinuse = new Array(); - for (var j=0;j1 || this.multitouch) { - this.keysinuse = new Array(); - for (var j=0;j - ``` - -*/ - - -var matrix = module.exports = function (target) { - this.defaultSize = { width: 100, height: 100 }; - widget.call(this, target); - - - /** @property {integer} row Number of rows in the matrix - ```js - matrix1.row = 2; - matrix1.init() - ``` - */ - this.row = 4; - - /** @property {integer} col Number of columns in the matrix - ```js - matrix1.col = 10; - matrix1.init() - ``` - */ - this.col = 4; - - this.cellHgt; - this.cellWid; - - /** @property {array} matrix Nested array of matrix values. Cells can be manually altered using .matrix (see code), however this will *not* cause the new value to be transmit. See .setCell() to set/transmit cell values. - ```js - //Turn on the cell at row 1 column 2 - matrix1.matrix[1][2] = 1 - matrix1.draw() - - - //Turn off the cell at row 3 column 0 - matrix1.matrix[3][0] = 0 - matrix1.draw() - ``` - */ - this.matrix; - - /** @property {object} val Core values and data output - |   | data - | --- | --- - | *row* | Current row being changed - | *col* | Current column being changed - | *level* | Whether cell is on or off (0 or 1) - | *list * | Array of values in highlighted column (if sequencing) - */ - this.val = { - row: 0, - col: 0, - level: 0, - list: new Array() - } - - //for mouse logic - this.cur; - this.prev; - - /** @property {boolean} erasing Whether or not mouse clicks will erase cells. Set to true automatically if you click on an "on" cell. */ - this.erasing = false; - - /** @property {integer} place When sequencing, the current column. */ - this.place = null; - - this.starttime; - this.lastbeat; - this.thisframe = 0; - this.lastframe = 0; - this.context.lineWidth = 1; - - this.sequencing = false; - - /** @property {integer} cellBuffer How much padding between matrix cells, in pixels */ - this.cellBuffer = 4; - - /** @property {string} sequenceMode Sequence pattern (currently accepts "linear" which is default, or "random") */ - this.sequenceMode = "linear"; // "linear" or "random". future options would be "wander" (drunk) or "markov" - - /** @property {integer} bpm Beats per minute (if sequencing) - ```js - matrix1.bpm = 120; - ``` - */ - this.bpm = 120; - this.pbpm = this.bpm - - this.starttime = nx.starttime; - - this.init(); - -} -util.inherits(matrix, widget); - - - -matrix.prototype.init = function() { - - - this.pmatrix = this.matrix ? this.matrix : false; - - this.matrix = null; - // generate 2D matrix array - this.matrix = new Array(this.col) - for (var i=0;i 0) { - fillStyle = this.colors.accent; - } else { - fillStyle = this.colors.fill; - } - fillRect(st_x+this.cellBuffer/2, st_y+this.cellBuffer/2, boxwid-this.cellBuffer, boxhgt-this.cellBuffer); - - // sequencer highlight - if (this.place == j) { - globalAlpha = 0.4; - fillStyle = this.colors.border; - fillRect(st_x, st_y, boxwid, boxhgt); - globalAlpha = 1; - } - - } - } - } - - this.drawLabel(); -} - - - -matrix.prototype.click = function(e) { - - this.cur = { - col: ~~(this.clickPos.x/this.cellWid), - row: ~~(this.clickPos.y/this.cellHgt) - } - - if (this.matrix[this.cur.col][this.cur.row]) { - this.matrix[this.cur.col][this.cur.row] = 0; - this.erasing = true; - } else { - this.matrix[this.cur.col][this.cur.row] = 1; - this.erasing = false; - } - - this.cur.value = this.matrix[this.cur.col][this.cur.row] - this.prev = this.cur; - -// var data = this.matrix[this.cur.col]; -// data = data.join(); -// data = data.replace(/\,/g," "); - - this.val = { - row: this.cur.row, - col: this.cur.col, - level: this.cur.value - } - - this.transmit(this.val); - this.draw(); -} - -matrix.prototype.move = function(e) { - if (this.clicked) { - - this.cur = { - col: ~~(this.clickPos.x/this.cellWid), - row: ~~(this.clickPos.y/this.cellHgt) - } - - if (this.cur.row < this.row && this.cur.col < this.col && this.cur.row >= 0 && this.cur.col >=0) { - if (this.cur.col!=this.prev.col || this.cur.row != this.prev.row) { - if (this.erasing) { - this.matrix[this.cur.col][this.cur.row] = 0; - } else { - this.matrix[this.cur.col][this.cur.row] = 1; - } - - this.cur.value = this.matrix[this.cur.col][this.cur.row] - this.prev = this.cur; - - this.val = { - row: this.cur.row, - col: this.cur.col, - level: this.cur.value - } - - this.transmit(this.val); - this.draw(); - } - } - - } -} - - -/** @method setCell -Manually set an individual cell on/off and transmit the new value. -@param {integer} [col] The column of the cell to be turned on/off -@param {integer} [row] The row of the cell to be turned on/off -@param {boolean} [on/off] Whether the cell should be turned on/off - -```js - // Turns cell on at column 1 row 3 - matrix1.setCell(1,3,true); -``` -*/ -matrix.prototype.setCell = function(col,row,on) { - - var value = on ? 1 : 0; - this.matrix[col][row] = value - - this.val = { - row: row, - col: col, - level: value - } - - this.transmit(this.val); - this.draw(); - -} - -/** @method sequence -@param {float} [bpm] Beats per minute of the pulse -Turns the matrix into a sequencer. - -```js - matrix1.sequence(240); -``` -*/ -matrix.prototype.sequence = function(bpm) { - - if (bpm) { - this.bpm = bpm; - } - this.sequencing = true; - requestAnimationFrame(this.seqStep.bind(this)); - -} - -matrix.prototype.setBPM = function(bpm) { - this.bpm = bpm - //console.log(bpm) - //nx.interval.bpm(this.pulse,bpm) -} - -/** @method stop -Stops the matrix sequencer. - -```js - matrix1.stop(); -``` -*/ -matrix.prototype.stop = function() { - this.sequencing = false; -} - -matrix.prototype.seqStep = function() { - - if (this.bpm == 0) { this.bpm = 1 } - - //current time - var now = new Date().getTime(); - - //delta time since start - var dt = now - this.starttime; - - if (this.bpm != this.pbpm) { - - //frame + decimal since last beat, in old bpm - var timeP = (dt/(60000/this.pbpm)) - - // scale to new bpm - dt = timeP * (60000/this.bpm) - - //adjust the starttime reference point - this.starttime = now - dt - - //calculate new frame # - this.thisframe = ~~(dt/(60000/this.bpm)); - - } else { - - //this.thisframe is a constantly ascending integer counter - //to compare with this.lastframe to determine when to increment this.place - //this.thisframe IS NOT the current column. - //the current column is this.place, which is set conditionally below. - this.thisframe = ~~(dt/(60000/this.bpm)); - - } - - this.pbpm = this.bpm; - - if (this.thisframe != this.lastframe) { - - this.lastbeat = now; - - if (this.sequenceMode=="linear") { - this.place++; - } else if (this.sequenceMode=="random") { - this.place = math.random(this.col); - } - if (this.place>=this.col) { - this.place = 0; - } - - if (this.place==null) { - this.place = 0; - } - - this.jumpToCol(this.place); - - } - - this.lastframe = this.thisframe; - if (this.sequencing) { - requestAnimationFrame(this.seqStep.bind(this)); - } -} - -/** @method jumpToCol -Jump to a certain column of the matrix, highlight it, and output its values as an array. Column numbers start at 0. - -```js - matrix1.jumpToCol(1); -``` -*/ - -matrix.prototype.jumpToCol = function(place) { - this.place = place - this.val = { - list: this.matrix[this.place] - } - this.transmit(this.val); - this.draw(); -} - - -matrix.prototype.customDestroy = function() { - this.stop(); -} - -matrix.prototype.unboundlife = function() { - if (!this.clicked) { - this.newmatrix = [] - for (var i=0;i= 0) { - total += this.matrix[i-1][j-1] ? this.matrix[i-1][j-1] : 0 - total += this.matrix[i-1][j] ? this.matrix[i-1][j] : 0 - total += this.matrix[i-1][j+1] ? this.matrix[i-1][j+1] : 0 - } - total += this.matrix[i][j-1] ? this.matrix[i][j-1] : 0 - total += this.matrix[i][j+1] ? this.matrix[i][j+1] : 0 - if (i+1 < this.col) { - total += this.matrix[i+1][j-1] ? this.matrix[i+1][j-1] : 0 - total += this.matrix[i+1][j] ? this.matrix[i+1][j] : 0 - total += this.matrix[i+1][j+1] ? this.matrix[i+1][j+1] : 0 - } - - if (this.matrix[i][j]) { - if (total < 2) { - this.newmatrix[i][j] = 0 - } else if (total ==2 || total == 3) { - this.newmatrix[i][j] = 1 - } else if (total > 3) { - this.newmatrix[i][j] = 0 - } - } else if (!this.matrix[i][j] && total == 3) { - this.newmatrix[i][j] = 1 - } else { - this.newmatrix[i][j] = this.matrix[i][j] - } - } - } - this.matrix = this.newmatrix - } - this.transmit({ grid: this.matrix}) - this.draw() -} - -/** @method life -Alters the matrix according to Conway's Game of Life. Matrix.life() constitutes one tick through the game. To simulate the game, you might use setInterval. - -```js - //one tick - matrix1.life(); - - //repeated ticks at 80ms - setInterval(matrix1.life,80) -``` -*/ -matrix.prototype.life = function() { - return false; -} - -},{"../core/widget":3,"../utils/drawing":5,"../utils/math":6,"util":47}],21:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class message - Send a string of text. - ```html - - ``` - -*/ - -var message = module.exports = function (target) { - - this.defaultSize = { width: 100, height: 30 }; - widget.call(this, target); - - - /** @property {object} val - |   | data - | --- | --- - | *value* | Text of message, as string - */ - - this.val = { - value: "send a message" - } - - /** @property {integer} size Text size in px */ - this.size = 14; - -} -util.inherits(message, widget); - -message.prototype.init = function() { - if (this.canvas.getAttribute("label")) { - this.val.value = this.canvas.getAttribute("label"); - } - //this.size = Math.sqrt((this.width * this.height) / (this.val.message.length)); - this.draw(); -} - -message.prototype.draw = function() { - this.erase(); - with (this.context) { - if (this.clicked) { - fillStyle = this.colors.border; - } else { - fillStyle = this.colors.fill; - } - fillRect(0,0,this.width,this.height) - - if (this.clicked) { - fillStyle = this.colors.black; - } else { - fillStyle = this.colors.black; - } - textAlign = "left"; - font = this.size+"px "+nx.font; - } - this.wrapText(this.val.value, 5, 1+this.size, this.width-6, this.size); -} - -message.prototype.click = function(e) { - this.draw(); - this.transmit(this.val); -} - -message.prototype.release = function(e) { - this.draw(); -} -},{"../core/widget":3,"util":47}],22:[function(require,module,exports){ -var util = require('util'); -var drawing = require('../utils/drawing'); -var widget = require('../core/widget'); - -/** - - @public - @class meter - - Decibel level meter. - - ```html - - ``` - -*/ - -var meter = module.exports = function(target) { - - // to update, eventually (note to self) - // possibly a less-frequent animation request, to lighten the graphics load - // option for stereo meter? i.e. optional third .setup(ctx,s1,s2) argument - - this.defaultSize = { width: 20, height: 50 }; - widget.call(this, target); - - this.val = { - level: 0 - } - this.dataArray; - this.bars = 10; - - this.init(); - -} -util.inherits(meter, widget); - - -meter.prototype.init = function(){ - this.bar = { - x: 0, - y: 0, - w: this.width, - h: this.height/this.bars - } - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width, this.height); - } -} - - - -/** @method setup - Connect the meter to an audio source and start the meter's graphics. - @param {audio context} [context] The audio context hosting the source node - @param {audio node} [source] The audio source node to analyze - */ -meter.prototype.setup = function(actx,source){ - this.actx = actx; - this.source = source; - - this.analyser = this.actx.createAnalyser(); - this.analyser.smoothingTimeConstant = 0.85; - this.analyser.fftsize = 1024; - this.bufferLength = this.analyser.frequencyBinCount; - this.dataArray = new Uint8Array(this.bufferLength); - this.source.connect(this.analyser); - - this.draw(); -} - -meter.prototype.draw = function(){ - - if(this.dataArray) { - this.analyser.getByteTimeDomainData(this.dataArray); - - var max = Math.max.apply(null, this.dataArray); - var min = Math.min.apply(null, this.dataArray); - var amp = max - min; - amp /= 240 - - //converts amps to db - var db = 20 * (Math.log(amp) / Math.log(10)) - - with (this.context){ - fillStyle = this.colors.fill; - fillRect(0,0,this.width, this.height); - - //scales: -40 to +10 db range => a number of bars - var dboffset = Math.floor((db + 40) / (50/this.bars) ); - - for (var i = 0; i= this.bars*.8) { - fillStyle = 'rgb(255,0,0)'; - - // -5 to 0 db is yellow - } else if (i < this.bars*.8 && i >= this.bars*.69) { - fillStyle = 'rgb(255,255,0)'; - - // -40 to -5 db is green - } else if (i < this.bars*.69) { - fillStyle = 'rgb(0,255,0)'; - } - - // draw bar - if (i - ``` - -*/ - -var metro = module.exports = function (target) { - this.defaultSize = { width: 100, height: 20 }; - widget.call(this, target); - - //define unique attributes - - /** @property {object} val - |   | data - | --- | --- - | *beat* | Which side the ball is bouncing on (0 if left, 1 if right) - */ - this.val = { - beat: 0 - } - - this.x = 10; - this.y = 10; - this.loc = 10; - this.nodeSize = 10; - /** @property {float} speed Speed of the ball (default 1) */ - this.speed = 1; - this.direction = 1; - /** @property {string} orientation Orientation of metro. Default is "horizontal". */ - this.orientation = "horizontal" - this.boundary = this.width - - nx.aniItems.push(this.advance.bind(this)); - this.active = true; - - this.init(); -} -util.inherits(metro, widget); - -metro.prototype.init = function() { - this.nodeSize = Math.min(this.width,this.height)/2; - if (this.width=0) { - this.loc += this.speed * this.direction; - } else { - this.loc += this.speed * this.direction; - } - if (this.loc-this.nodeSize<0 || this.loc+this.nodeSize>this.boundary) { - this.val.beat = math.scale(this.direction,-1,1,0,1) - this.transmit(this.val); - this.direction *= -1 - } - if (this.orientation == "vertical") { - this.y = this.loc - } else { - this.x = this.loc - } - this.draw(); -} - -metro.prototype.customDestroy = function() { - nx.removeAni(this.advance.bind(this)) -} -},{"../core/widget":3,"../utils/math":6,"util":47}],24:[function(require,module,exports){ -var math = require('../utils/math'); -var drawing = require('../utils/drawing'); -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class metroball - Bouncy-balls for rhythms - ```html - - ``` - -*/ - - -var metroball = module.exports = function (target) { - this.defaultSize = { width: 300, height: 200 }; - widget.call(this, target); - - - //define unique attributes - this.CurrentBalls = new Array(); - this.ballpos = new Object(); - this.clickField = null; - this.globalMetro; - this.tempo = 1; - this.tempoMarker = 150; - this.quantize = false; - this.tiltLR; - this.tiltFB; - this.z; - - /** @property {object} val - |   | data - | --- | --- - | *x* | x position of the bouncing ball - | *side* | 0 or 1 int (which side is hit) - | *ball* | Which ball is doing the bouncing - | *all* | All three values together in a string - */ - this.val = { - x: false, - side: false, - ball: false, - all: false - } - - nx.aniItems.push(this.metro.bind(this)); - - this.init(); -} -util.inherits(metroball, widget); - -metroball.prototype.init = function() { - //this.metro(); - this.draw() -} - -metroball.prototype.metro = function() { - with (this.context) { - clearRect(0,0, this.width, this.height); - } - this.drawSpaces(); - this.drawBalls(); - this.drawLabel(); -} - -metroball.prototype.drawSpaces = function() { - - with (this.context) { - - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height) - - fillStyle=this.colors.border; - fillRect(0,0,this.width,this.height/4) - - font="normal "+this.height/8+"px "+nx.font; - textAlign = "center"; - textBaseline = "middle" - fillText("add",this.width/2,this.height/1.66) - - - fillStyle = this.colors.fill; - fillText("delete",this.width/2,this.height/8) - - } -} - -metroball.prototype.drawBalls = function() { - with (this.context) { - for (var i=0;i=0;i--) { - if (Math.abs(this.CurrentBalls[i].xpos-ballpos.x)<10) { - this.CurrentBalls[i].kill(); - } - } - - //reset CurrentBalls - for (var i=0;i(parent.height-this.size-2) || this.ypos<(this.size+2) ) { - this.bounce(); - } - - if (this.yposthis.space.ypos+this.space.hgt-this.size) { - this.ypos=this.space.ypos+this.space.hgt-this.size-5; - } - - - if (this.xposthis.space.xpos2) { - this.xpos = this.space.xpos; - } - - } - - this.bounce = function() { - var dirMsg = this.direction/2+1; - this.bounceside = (this.direction+1)/2; - this.direction = this.direction * (-1); - var xMsg = math.prune(this.xpos/this.space.wid, 3); - this.val = { - x: xMsg, - side: this.bounceside, - ball: this.thisIndex, - all: xMsg + " " + this.bounceside + " " + this.thisIndex - } - parent.transmit(this.val); - } - - this.kill = function() { - parent.CurrentBalls.splice(this.thisIndex,1); - } - - this.draw = function() { - - with (parent.context) { - beginPath(); - fillStyle = this.color; - if (this.direction==1) { - this.radius = this.size * (Math.abs((this.ypos-this.space.ypos-this.space.hgt/2)/(this.space.hgt-this.space.ypos)*2)); - this.radius = this.radius/2 + this.size/2; - - this.radius = this.size; - - this.radius = this.speed; - - this.radius = Math.abs(15-this.speed); - - } else { - this.radius = this.size * Math.abs(2-(Math.abs((this.ypos-this.space.ypos-this.space.hgt/2)/(this.space.hgt-this.space.ypos)*2))); - this.radius = this.radius/2 + this.size/2; - - this.radius = this.size; - - this.radius = Math.abs(15-this.speed); - } - arc(this.xpos, this.ypos, this.radius, 0, Math.PI*2, true); - fill(); - } - } -} -},{"../core/widget":3,"../utils/drawing":5,"../utils/math":6,"util":47}],25:[function(require,module,exports){ -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class motion - Mobile motion sensor. Does not work on all devices!
**Notes:** Clicking on this widget toggles it inactive or active.
- We recommend not calling .init() on this object after the original initialization, because it will add additional redundant motion listeners to your document. - ```html - - ``` - -*/ - -var motion = module.exports = function (target) { - this.defaultSize = { width: 75, height: 75 }; - widget.call(this, target); - - this.motionLR; - this.motionFB; - this.z; - /** @property {boolean} active Whether or not the motion widget is on (animating and transmitting data). */ - this.active = true; - - this.px = 0; - this.py = 0; - this.pz = 0; - - /** @property {object} val Object containing the core interactive aspects of the widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *x* | X-axis motion if supported (-1 to 1) - | *y* | Y-axis motion if supported (-1 to 1) - | *z* | Z-axis motion if supported (-1 to 1 or 0 to 360 depending on device) - */ - this.val = { - x: 0, - y: 0, - z: 0 - } - - /** @property {string} text Text shown on motion object - */ - - this.text = "Motion"; - this.init(); - - this.boundMotion = this.motionlistener.bind(this) - - if (window.DeviceMotionEvent) { - window.addEventListener('devicemotion', this.boundMotion, false); - } else { - with (this.context) { - fillText("incompatible",0,0) - this.active = false; - } - } - -} -util.inherits(motion, widget); - -motion.prototype.deviceMotionHandler = function() { - - this.val = { - x: math.prune(this.motionLR/10,4), - y: math.prune(this.motionFB/10,4), - z: math.prune(this.z/10,4) - } - - this.transmit(this.val); - -} - -motion.prototype.motionlistener = function(e) { - var data = e.acceleration - - if (this.active) { - - - this.motionLR = nx.lp(this.canvasID+"motionx",data.x,20) - this.motionFB = nx.lp(this.canvasID+"motiony",data.y,20) - this.z = nx.lp(this.canvasID+"motionz",data.z,20) - this.deviceMotionHandler() - - this.draw(); - - if (data.x===null || data.x===undefined) { - this.erase() - with (this.context) { - fillStyle = this.colors.fill - fillRect(0,0,this.width,this.height) - fillStyle = this.colors.black - font="12px courier"; - textAlign = "center" - fillText("no data",this.width/2,this.height/2) - } - this.active = false; - } - } -} - -motion.prototype.init = function() { - this.draw() -} - -motion.prototype.draw = function() { - - this.erase() - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - fillStyle = this.colors.accent; - var eighth = Math.PI/4 - if (this.motionFB<0) { - beginPath() - moveTo(this.width/2,this.height/2) - arc(this.width/2,this.height/2,this.width/2,eighth*5,eighth*7,false) - globalAlpha = Math.pow(this.motionFB, 2) - fill() - closePath() - } else { - beginPath() - moveTo(this.width/2,this.height/2) - arc(this.width/2,this.height/2,this.width/2,eighth*1,eighth*3,false) - globalAlpha = Math.pow(this.motionFB, 2) - fill() - closePath() - } - if (this.motionLR<0) { - beginPath() - moveTo(this.width/2,this.height/2) - arc(this.width/2,this.height/2,this.width/2,eighth*7,eighth*1,false) - globalAlpha = Math.pow(this.motionLR, 2) - fill() - closePath() - } else { - beginPath() - moveTo(this.width/2,this.height/2) - arc(this.width/2,this.height/2,this.width/2,eighth*3,eighth*5,false) - globalAlpha = Math.pow(this.motionLR, 2) - fill() - closePath() - } - beginPath() - moveTo(this.width/2,this.height/2) - arc(this.width/2,this.height/2,this.width/6,0,Math.PI*2,false) - globalAlpha = Math.pow(this.z, 2) - fill() - closePath() - globalAlpha = 1 - } - this.drawLabel(); -} - -motion.prototype.click = function() { - this.active = !this.active; - this.draw() -} - -motion.prototype.customDestroy = function() { - this.active = false; - window.removeEventListener("devicemotion",this.motionlistener,false); -} -},{"../core/widget":3,"../utils/math":6,"util":47}],26:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); -var math = require('../utils/math'); - -/** - @class mouse - Mouse tracker, relative to web browser window. - ```html - - ``` - -*/ - -var mouse = module.exports = function (target) { - - this.defaultSize = { width: 98, height: 100 }; - widget.call(this, target); - - /** @property {object} val - |   | data - | --- | --- - | *x* | x value of mouse relative to browser - | *y* | y value of mouse relative to browser - | *deltax* | x change in mouse from last position - | *deltay* | y change in mouse from last position - */ - this.val = { - x: 0, - y: 0, - deltax: 0, - deltay: 0 - } - this.inside = new Object(); - this.boundmove = this.preMove.bind(this) - this.mousing = window.addEventListener("mousemove", this.boundmove, false); - - this.init(); -} -util.inherits(mouse, widget); - -mouse.prototype.init = function() { - - this.inside.height = this.height; - this.inside.width = this.width; - this.inside.left = 0; - this.inside.top = 0; - this.inside.quarterwid = (this.inside.width)/4; - - this.draw(); -} - -mouse.prototype.draw = function() { - this.erase(); - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - var scaledx = -(this.val.x) * this.height; - var scaledy = -(this.val.y) * this.height; - var scaleddx = -(this.val.deltax) * this.height - this.height/2; - var scaleddy = -(this.val.deltay) * this.height - this.height/2; - - fillStyle = this.colors.accent; - fillRect(this.inside.left, this.inside.height, this.inside.quarterwid, scaledx); - fillRect(this.inside.quarterwid, this.inside.height, this.inside.quarterwid, scaledy); - fillRect(this.inside.quarterwid*2, this.inside.height, this.inside.quarterwid, scaleddx); - fillRect(this.inside.quarterwid*3, this.inside.height, this.inside.quarterwid, scaleddy); - - globalAlpha = 1; - fillStyle = this.colors.fill; - textAlign = "center"; - font = this.width/7+"px "+this.font; - fillText("x", this.inside.quarterwid*0 + this.inside.quarterwid/2, this.height-7); - fillText("y", this.inside.quarterwid*1 + this.inside.quarterwid/2, this.height-7); - fillText("dx", this.inside.quarterwid*2 + this.inside.quarterwid/2, this.height-7); - fillText("dy", this.inside.quarterwid*3 + this.inside.quarterwid/2, this.height-7); - - globalAlpha = 1; - } - - this.drawLabel(); -} - -mouse.prototype.move = function(e) { - this.val = { - deltax: e.clientX/window.innerWidth - this.val.x, - deltay: math.invert(e.clientY/window.innerHeight) - this.val.y, - x: e.clientX/window.innerWidth, - y: math.invert(e.clientY/window.innerHeight) - } - this.draw(); - this.transmit(this.val); - -} - -mouse.prototype.customDestroy = function() { - window.removeEventListener("mousemove", this.boundmove, false); -} -},{"../core/widget":3,"../utils/math":6,"util":47}],27:[function(require,module,exports){ -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class multislider - Multiple vertical sliders in one interface. - ```html - - ``` - -*/ -var multislider = module.exports = function (target) { - - this.defaultSize = { width: 100, height: 75 }; - widget.call(this, target); - - /** @property {integer} sliders Number of sliders in the multislider. (Must call .init() after changing this setting, or set with .setNumberOfSliders) */ - this.sliders = 15; - - /** @property {array} val Array of slider values.
**Note:** This widget's output is not .val! Transmitted output is: - - |   | data - | --- | --- - | *(slider index)* | value of currently changed slider - | list | all multislider values as list. (if the interface sends to js or node, this list will be an array. if sending to ajax, max7, etc, the list will be a string of space-separated values) - - */ - - this.val = new Object(); - for (var i=0;i1) { - - for (var i=0;i sliderToMove + 1) { - var missed = this.oldSliderToMove - sliderToMove - 1; - for (var i=1;i<=missed;i++) { - this.val[sliderToMove+i] = this.val[sliderToMove] + (this.val[this.oldSliderToMove] - this.val[sliderToMove]) * ((i/(missed+1))); - } - } else if (this.oldSliderToMove && sliderToMove > this.oldSliderToMove + 1) { - var missed = sliderToMove - this.oldSliderToMove - 1; - for (var i=1;i<=missed;i++) { - this.val[this.oldSliderToMove+i] = this.val[this.oldSliderToMove] + (this.val[sliderToMove] - this.val[this.oldSliderToMove]) * ((i/(missed+1))); - } - } - - } - this.draw(); - } - var msg = new Object() - msg[sliderToMove] = this.val[sliderToMove] - if (this.destination=="js" || this.destination=="node") { - msg["list"] = this.val; - } else { - msg["list"] = new String(); - for (var key in this.val) { msg["list"] += this.val[key] + " " } - } - this.transmit(msg); - this.oldSliderToMove = sliderToMove; - -} - -/** @method setNumberOfSliders -@param {integer} [num] New number of sliders in the multislider */ -multislider.prototype.setNumberOfSliders = function(numOfSliders) { - this.sliders = numOfSliders; - this.val = new Array(); - for (var i=0;i - ``` - -*/ - -var multitouch = module.exports = function (target) { - - this.defaultSize = { width: 200, height: 200 }; - widget.call(this, target); - - //unique attributes - this.nodeSize = this.width/10; - - /** @property {object} val - |   | data - | --- | --- - | *touch1.x* | x position of first touch - | *touch1.y* | y position of first touch - | *touch2.x* | x position of second touch (if 2 touches) - | *touch2.y* | y position of second touch (if 2 touches) - | *etc* |   - */ - this.val = { - touch1: { - x: 0, - y: 0 - } - } - - this.nodes = new Array(); - - /** @property {string} text Text that will show when object is static */ - this.text = "multitouch"; - - this.rainbow = ["#00f", "#04f", "#08F", "0AF", "0FF"]; - - /** @property {string} mode "normal" or "matrix" mode. "matrix" mode has a GUI of discrete touch areas. - */ - this.mode = "normal"; - - /** @property {integer} rows How many rows in the matrix (matrix mode only) - */ - this.rows = 10; - - /** @property {integer} cols How many rows in the matrix (matrix mode only) - */ - this.cols = 10; - - /** @property {array} matrixLabels An array of strings that can provide text labels on cells of the matrix. If shorter than the matrix cells, the array will repeat. - ``` - this.mode = "matrix" - this.matrixLabels = [ "A", "A#", "B", "C" ] - this.init(); - ``` - */ - this.matrixLabels = false; - - this.init(); -} -util.inherits(multitouch, widget); - -multitouch.prototype.init = function() { - this.nodeSize = this.width/10; - this.draw(); -} - -multitouch.prototype.draw = function() { - this.erase(); - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - var count = 0; - - if (this.mode == "matrix") { - for (var j=0;j=1) { - for (var k=0;k=1) { - for (var i=0;i - ``` - -*/ - -var number = module.exports = function (target) { - this.defaultSize = { width: 50, height: 20 }; - widget.call(this, target); - - /** @property {object} val - |   | data - | --- | --- - | *value* | Number value - - ```js - // Sets number1.val.value to 20 - number1.set({ -   value: 20 - }) - ``` - */ - this.val = { - value: 0 - } - - /** @property {float} min The minimum number allowed. Default is -20000. - - ```js - // only allow positive numbers - number1.min = 0; - ``` - */ - this.min = -20000 - - /** @property {float} max The maximum number allowed. Default is 20000. - - ```js - // only allow negative numbers - number1.max = 0; - ``` - */ - this.max = 20000 - - /** @property {float} step The increment. Default is 1. - - ```js - // count by 10s - number1.step = 10; - ``` - */ - this.step = 1 - - - /** @property {float} rate Sensitivity of dragging. Default is .25 - - ```js - // For fine tuning - number1.rate = .001; - ``` - */ - this.rate = .25 - - /** @property {integer} decimalPlaces How many decimal places on the number. This applies to both the output and the interface text. Default is 2. To achieve an int (non-float), set decimalPlaces to 0. - - ```js - // For an int counter - number1.decimalPlaces = 0; - ``` - */ - this.decimalPlaces = 3; - this.lostdata = 0; - this.actual = 0; - - this.init(); -} -util.inherits(number, widget); - -number.prototype.init = function() { - - this.canvas.ontouchstart = null; - this.canvas.ontouchmove = null; - this.canvas.ontouchend = null; - - var htmlstr = '' - var canv = this.canvas - var cstyle = this.canvas.style - var parent = canv.parentNode; - var newdiv = document.createElement("span"); - newdiv.innerHTML = htmlstr; - parent.replaceChild(newdiv,canv) - this.el = document.getElementById(this.canvasID) - for (var prop in cstyle) - this.el.style[prop] = cstyle[prop]; - - this.canvas = document.getElementById(this.canvasID); - this.canvas.style.fontSize = this.height * .6 + "px" - this.canvas.style.textAlign = "left" - this.canvas.style.backgroundColor = this.colors.fill - this.canvas.style.highlight = this.colors.fill - this.canvas.style.border = "none" - this.canvas.style.outline = "none" - this.canvas.style.padding = "4px 10px" - this.canvas.style.cursor = "pointer" - this.canvas.style.display = "block" - - this.canvas.addEventListener("blur", function () { - //this.canvas.style.border = "none"; - - this.canvas.style.backgroundColor = this.colors.fill; - this.canvas.style.color = this.colors.black; - if (this.canvas.value != this.val.value) { - this.actual = parseFloat(this.canvas.value) - this.actual = math.clip(this.actual,this.min,this.max) - this.actual = math.prune(this.actual,this.decimalPlaces); - this.set({"value": this.actual}, true) - } - }.bind(this)); - - this.canvas.addEventListener("keydown", function (e) { - if (e.which < 48 || e.which > 57) { - if (e.which != 189 && e.which != 190 && e.which != 8) { - e.preventDefault(); - } - } - if (e.which==13) { - /* this.actual = parseFloat(this.canvas.value) - this.actual = math.clip(this.actual,this.min,this.max) - this.actual = math.prune(this.actual,this.decimalPlaces); - this.set({"value": this.actual}, true) */ - //this.canvas.style.outline = "none"; - this.canvas.blur() - } - }.bind(this)); - - - // Setup interaction - if (nx.isTouchDevice) { - this.canvas.ontouchstart = this.preTouch; - this.canvas.ontouchmove = this.preTouchMove; - this.canvas.ontouchend = this.preTouchRelease; - } else { - this.canvas.addEventListener('mousedown', this.preClick, false); - } - - - this.canvas.style.userSelect = "none !important"; - this.canvas.style.mozUserSelect = "none !important"; - this.canvas.style.webkitUserSelect = "none !important"; - - this.draw(); -} - -number.prototype.draw = function() { - - this.canvas.value = this.val.value; - -} - - -number.prototype.click = function(e) { - this.canvas.readOnly = true - this.actual = this.val.value -} - -number.prototype.move = function(e) { - if (this.clicked) { - this.canvas.style.border = "none"; - - this.actual -= (this.deltaMove.y*(this.rate*this.step)); - this.actual = math.clip(this.actual,this.min,this.max) - this.val.value = Math.floor(this.actual / this.step) * this.step; - this.val.value = math.prune(this.val.value,this.decimalPlaces); - this.draw(); - this.transmit(this.val); - } -} - - -number.prototype.release = function(e) { - if (!this.hasMoved && this.canvas.readOnly) { - this.canvas.readOnly = false; - this.canvas.focus() - this.canvas.setSelectionRange(0, this.canvas.value.length) - this.canvas.style.backgroundColor = this.colors.accent; - this.canvas.style.color = this.colors.fill; - } -} - -},{"../core/widget":3,"../utils/math":6,"util":47}],30:[function(require,module,exports){ -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class position - Two-dimensional touch slider. - ```html - - ``` - -*/ - -var position = module.exports = function (target) { - - // define a default size - this.defaultSize = { width: 150, height: 100 }; - - widget.call(this, target); - - /** @property {integer} nodeSize Size of touch node graphic. */ - this.nodeSize = 15; - - /** @property {object} val val is an object containing the main interactive / actionable aspects of the widget. - |   | data - | --- | --- - | *x* | x position of slider (float 0-1) - | *y* | y position of slider (float 0-1) - */ - this.val = { - x: 0.5, - y: 0.5 - } - - this.init(); -} - -// inherit the widget object template -util.inherits(position, widget); - -// .init() is called automatically when the widget is created on a webpage. -position.prototype.init = function() { - this.nodeSize = Math.min(this.height,this.width)/10; - this.nodeSize = Math.max(this.nodeSize,10) - this.actualWid = this.width - this.nodeSize*2; - this.actualHgt = this.height - this.nodeSize*2; - this.draw(); -} - -// .draw() should be used for any graphics activity -position.prototype.draw = function() { - this.erase(); - with (this.context) { - - // use this.colors.fill for the widget background color (default: very light gray) - // use this.colors.border for any extra structural needs (default: light gray) - // use this.colors.accent for important or highlighted parts (default: a bright color) - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - var drawingX = this.val.x * this.actualWid + this.nodeSize - var drawingY = math.invert(this.val.y) * this.actualHgt + this.nodeSize - - //stay within right/left bounds - if (drawingX<(this.nodeSize)) { - drawingX = this.nodeSize; - } else if (drawingX>(this.width-this.nodeSize)) { - drawingX = this.width - this.nodeSize; - } - //stay within top/bottom bounds - if (drawingY<(this.nodeSize)) { - drawingY = this.nodeSize; - } else if (drawingY>(this.height-this.nodeSize)) { - drawingY = this.height - this.nodeSize; - } - - with (this.context) { - - // draw the touch point - beginPath(); - fillStyle = this.colors.accent; - arc(drawingX, drawingY, this.nodeSize, 0, Math.PI*2, true); - fill(); - closePath(); - - if (this.clicked) { - // draw the emphasis circle - beginPath(); - fillStyle = this.colors.accent; - arc(drawingX, drawingY, this.nodeSize*2, 0, Math.PI*2, true); - fill(); - closePath(); - - } - } - } - - this.drawLabel(); -} - -// .click() will be fired when the interface is interacted with -// this.clicked is automatically set to true -// this.clickPos is already and object with x and y properties detailing click point. -position.prototype.click = function() { - this.val.x = this.clickPos.x; - this.val.y = this.clickPos.y; - this.scaleNode(); - this.val["state"] = "click" - this.transmit(this.val); - this.draw(); -} - -// .move() will be fired when the interface is moved over after being clicked -// this.clickPos is already and object with x and y properties detailing click point. -position.prototype.move = function() { - this.val.x = this.clickPos.x; - this.val.y = this.clickPos.y; - this.scaleNode(); - this.val["state"] = "move" - this.transmit(this.val); - this.draw(); -} - -// .release() will be fired on mouse up (unclick) -position.prototype.release = function() { - this.val.x = this.clickPos.x; - this.val.y = this.clickPos.y; - this.scaleNode(); - this.val["state"] = "release" - this.transmit(this.val); - this.draw(); -} - -/* TOUCH SPECIFIC EVENTS - currently, ontouch, ontouchmove, and ontouchrelease automatically execute .click, .move, and .release - so you only need to write one function for these events, and they will be touch compatible by default - however if you would like to create a touch-specific event you may define the following functions. - in these functions, .clickPos and .clicked will refer to your touch interactions. - -position.prototype.touch = function() { - -} - -position.prototype.touchmove = function() { - -} - -position.prototype.touchrelease = function() { - -} - - - - -*/ - - - -/* - extra functions pertaining only to this widget -*/ - -position.prototype.scaleNode = function() { - var actualX = this.val.x - this.nodeSize; - var actualY = this.val.y - this.nodeSize; - var clippedX = math.clip(actualX/this.actualWid, 0, 1); - var clippedY = math.clip(actualY/this.actualHgt, 0, 1); - this.val.x = math.prune(clippedX, 3) - this.val.y = math.prune(clippedY, 3) - this.val.y = math.invert(this.val.y); -} - -/** @method animate - Adds animation to the widget. - @param {string} [type] Type of animation. Currently accepts "none" or "bounce", in which case the touch node can be tossed and bounces. -*/ -position.prototype.animate = function(aniType) { - - switch (aniType) { - case "bounce": - nx.aniItems.push(this.aniBounce.bind(this)); - break; - case "none": - nx.aniItems.splice(nx.aniItems.indexOf(this.aniBounce)); - break; - } - -} - -position.prototype.aniBounce = function() { - if (!this.clicked && this.val.x) { - this.val.x += (this.deltaMove.x/2)/this.width; - this.val.y -= (this.deltaMove.y/2)/this.height; - this.val["state"] = "animated"; - if (math.bounce(this.val.x, 0, 1, this.deltaMove.x) != this.deltaMove.x) { - this.deltaMove.x = math.bounce(this.val.x, 0, 1, this.deltaMove.x); - this.val["state"] = "bounce"; - } - if (this.val.y >= 1 || this.val.y <= 0) { - this.deltaMove.y = math.bounce(this.val.y, 0, 1, this.deltaMove.y) * -1; - this.val["state"] = "bounce"; - } - this.transmit(this.val); - this.draw(); - } -} - -position.prototype.customDestroy = function() { - nx.removeAni(this.aniBounce); -} -},{"../core/widget":3,"../utils/math":6,"util":47}],31:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); -var math = require('../utils/math') - -/** - @class range - Range slider - ```html - - ``` - -*/ - -var range = module.exports = function (target) { - this.defaultSize = { width: 100, height: 30 }; - widget.call(this, target); - - /** @property {object} val Object containing core interactive aspects of widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *start* | Range start value (float 0-1) - | *stop* | Range end value (float 0-1) - | *size* | Distance between ends (float 0-1) - */ - this.val = { - start: 0.3, - stop: 0.7, - size: 0.4 - } - - - // handling horiz possibility - /** @property {boolean} hslider Whether or not the slider is a horizontal slider. Default is false, but set automatically to true if the slider is wider than it is tall. */ - this.hslider = false; - this.handle; - this.relhandle; - this.cap; - this.firsttouch = "start"; - - /** @property {string} mode Mode of interaction. "edge" mode lets you drag each edge of the range individually. "area" mode (default) lets you drag the range as a whole (with parallel mouse movement) or scale the range as a whole (with transverse mouse movement) */ - this.mode = "area" // modes: "edge", "area" - this.touchdown = new Object(); - this.init(); -} -util.inherits(range, widget); - -range.prototype.init = function() { - - //decide if hslider or vslider - if (this.height>=this.width) { - this.hslider = false; - } else { - this.hslider = true; - } - - if (this.canvas.getAttribute("label")!=null) { - this.label = this.canvas.getAttribute("label"); - } - - this.draw(); -} - -range.prototype.draw = function() { - this.erase(); - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - if (!this.hslider) { - - if (nx.showLabels && this.label) { - save(); - translate(this.width/2, 0); - rotate(Math.PI/2); - this.setFont(); - fillText(this.label, this.height/2, 0); - globalAlpha = 1; - restore(); - } - - var x1 = 0; - var y1 = this.height-this.val.stop*this.height; - var x2 = this.width; - var y2 = this.height-this.val.start*this.height; - - fillStyle = this.colors.accent; - fillRect(x1,y1,x2-x1,y2-y1); - - } else { - - if (nx.showLabels && this.label) { - this.setFont(); - fillText(this.label, this.width/2, this.height/2); - globalAlpha = 1; - } - - var x1 = this.val.start*this.width; - var y1 = 0; - var x2 = this.val.stop*this.width; - var y2 = this.height; - - - fillStyle = this.colors.accent; - fillRect(x1,y1,x2-x1,y2-y1); - } - } -} - -range.prototype.click = function() { - if (this.mode=="edge") { - if (this.hslider) { - if (Math.abs(this.clickPos.x-this.val.start*this.width) < Math.abs(this.clickPos.x-this.val.stop*this.width)) { - this.firsttouch = "start" - } else { - this.firsttouch = "stop" - } - } else { - if (Math.abs(Math.abs(this.clickPos.y-this.height)-this.val.start*this.height) < Math.abs(Math.abs(this.clickPos.y-this.height)-this.val.stop*this.height)) { - this.firsttouch = "start" - } else { - this.firsttouch = "stop" - } - } - } else if (this.mode=="area") { - this.touchdown = { - x: this.clickPos.x, - y: this.clickPos.y - } - this.startval = new Object(); - this.startval.size = this.val.stop - this.val.start; - this.startval.loc = this.val.start + this.startval.size/2; - } - this.move(); -} - -range.prototype.move = function() { - - if (this.mode=="edge") { - if (this.hslider) { - if (this.firsttouch=="start") { - this.val.start = this.clickPos.x/this.width; - if (this.clickPos.touches.length>1) { - this.val.stop = this.clickPos.touches[1].x/this.width; - } - } else { - this.val.stop = this.clickPos.x/this.width; - if (this.clickPos.touches.length>1) { - this.val.start = this.clickPos.touches[1].x/this.width; - } - } - } else { - if (this.firsttouch=="start") { - this.val.start = math.invert(this.clickPos.y/this.height); - if (this.clickPos.touches.length>1) { - this.val.stop = math.invert(this.clickPos.touches[1].y/this.height); - } - } else { - this.val.stop = math.invert(this.clickPos.y/this.height); - if (this.clickPos.touches.length>1) { - this.val.start = math.invert(this.clickPos.touches[1].y/this.height); - } - } - } - - if (this.val.stop < this.val.start) { - this.tempstart = this.val.start; - this.val.start = this.val.stop; - this.val.stop = this.tempstart; - if (this.firsttouch=="start") { - this.firsttouch = "stop"; - } else { - this.firsttouch = "start"; - } - } - this.val = { - start: math.clip(this.val.start, 0, 1), - stop: math.clip(this.val.stop, 0, 1), - } - this.val['size'] = math.prune(math.clip(Math.abs(this.val.stop - this.val.start), 0, 1), 3) - - this.draw(); - - this.transmit(this.val); - - } else if (this.mode=="area") { - - if (this.hslider) { - var moveloc = this.clickPos.x/this.width; - var movesize = (this.touchdown.y - this.clickPos.y)/this.height; - } else { - var moveloc = nx.invert(this.clickPos.y/this.height); - var movesize = (this.touchdown.x - this.clickPos.x)/this.width; - // moveloc *= -1; - movesize *= -1; - } - movesize /= 3; - var size = this.startval.size + movesize; - size = math.clip(size,0.001,1); - - this.val = { - start: moveloc - size/2, - stop: moveloc + size/2 - } - - this.val.start = math.clip(this.val.start,0,1); - this.val.stop = math.clip(this.val.stop,0,1); - - this.draw(); - - this.transmit(this.val); - - } -} -},{"../core/widget":3,"../utils/math":6,"util":47}],32:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class select - HTML-style option selector. Outputs the chosen text string.
**Note:** Currently the canvas is actaully replaced by an HTML select object. Any inline style on your canvas may be lost in this transformation. To style the resultant select element, we recommend creating CSS styles for the select object using its ID or the select tag. - ```html - - ``` - -*/ - -var select = module.exports = function (target) { - this.defaultSize = { width: 200, height: 30 }; - widget.call(this, target); - - /** @property {array} choices Desired choices, as an array of strings. Can be initialized with a "choices" HTML attribute of comma-separated text (see example above). - ```js - select1.choices = ["PartA", "PartB", "GoNuts"] - select1.init() - ``` - */ - this.choices = [ ]; - - /** @property {object} val - |   | data - | --- | --- - | *value* | Text string of option chosen - */ - this.val = new Object(); - - - this.canvas.ontouchstart = null; - this.canvas.ontouchmove = null; - this.canvas.ontouchend = null; - - if (this.canvas.getAttribute("choices")) { - this.choices = this.canvas.getAttribute("choices"); - this.choices = this.choices.split(","); - } - - var htmlstr = '' - var canv = this.canvas - var cstyle = this.canvas.style - var parent = canv.parentNode; - var newdiv = document.createElement("span"); - newdiv.innerHTML = htmlstr; - parent.replaceChild(newdiv,canv) - this.sel = document.getElementById(this.canvasID) - this.sel.style.float = "left" - this.sel.style.display = "block" - for (var prop in cstyle) - this.sel.style[prop] = cstyle[prop]; - - this.canvas = document.getElementById(this.canvasID); - - this.canvas.style.backgroundColor = this.colors.fill; - this.canvas.style.color = this.colors.black; - - for (var i=0;i - ``` - -*/ - -var slider = module.exports = function (target) { - this.defaultSize = { width: 30, height: 100 }; - widget.call(this, target); - - /** @property {object} val - |   | data - | --- | --- - | *value* | Slider value (float 0-1) - */ - this.val.value = 0.7 - - /** @property {string} mode Set "absolute" or "relative" mode. In absolute mode, slider will jump to click/touch position. In relative mode, it will not. - ```js - nx.onload = function() { -   // Slider will not jump to touch position. -   slider1.mode = "relative" - } - ``` - */ - this.mode = "absolute"; - - /** @property {boolean} hslider Whether or not the slider should be horizontal. This is set to true automatically if the canvas is wider than it is tall. To override the default decision, set this property to true to create a horizontal slider, or false to create a vertical slider. - - ```js - nx.onload = function() { -   //forces horizontal slider -   slider1.hslider = true -   slider1.draw(); -   //forces vertical slider -   slider2.hslider = false -   slider2.draw(); - } - ``` - */ - this.hslider = false; - this.label = ""; - this.handle; - this.relhandle; - this.cap; - - - this.init(); -} -util.inherits(slider, widget); - -slider.prototype.init = function() { - - //decide if hslider or vslider - if (this.height>=this.width) { - this.hslider = false; - } else { - this.hslider = true; - } - - if (this.canvas.getAttribute("label")!=null) { - this.label = this.canvas.getAttribute("label"); - } - - this.draw(); -} - -slider.prototype.draw = function() { - - this.erase(); - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - if (!this.hslider) { - - if (nx.showLabels) { - - save(); - translate(this.width/2, 0); - rotate(Math.PI/2); - this.setFont(); - fillText(this.label, this.height/2, 0); - globalAlpha = 1; - restore(); - - } - - var x1 = 0; - var y1 = this.height-this.val.value*this.height; - var x2 = this.width; - var y2 = this.height; - - - fillStyle = this.colors.accent; - if (this.val.value>0.01) { - fillRect(x1,y1,x2-x1,y2-y1); - } - - } else { - - if (nx.showLabels) { - this.setFont(); - fillText(this.label, this.width/2, this.height/2); - globalAlpha = 1; - - } - - var x1 = 0; - var y1 = 0; - var x2 = this.val.value*this.width; - var y2 = this.height; - - - fillStyle = this.colors.accent; - if (this.val.value>0.01) { - fillRect(x1,y1,x2-x1,y2-y1); - } - } - } -} - -slider.prototype.click = function() { - this.move(); -} - -slider.prototype.move = function() { - if (this.hslider) { - this.handle = this.clickPos.x; - this.relhandle = this.deltaMove.x; - this.cap = this.width; - } else { - this.handle = this.clickPos.y; - this.relhandle = this.deltaMove.y*-1; - this.cap = this.height - } - - if (this.mode=="absolute") { - if (this.clicked) { - if (!this.hslider) { - this.val.value = math.prune((Math.abs((math.clip(this.clickPos.y/this.height, 0, 1)) - 1)),3); - } else { - this.val.value = math.prune(math.clip(this.clickPos.x/this.width, 0, 1),3); - } - this.draw(); - } - } else if (this.mode=="relative") { - if (this.clicked) { - if (!this.hslider) { - this.val.value = math.clip((this.val.value + ((this.deltaMove.y*-1)/this.height)),0,1); - } else { - this.val.value = math.clip((this.val.value + ((this.deltaMove.x)/this.width)),0,1); - } - this.draw(); - } - } - this.transmit(this.val); -} -},{"../core/widget":3,"../utils/math":6,"util":47}],34:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class string - Animated model of a plucked string interface. - ```html - - ``` - -*/ - -var string = module.exports = function (target) { - this.defaultSize = { width: 150, height: 75 }; - widget.call(this, target); - - /** @property {object} val Object containing the core interactive aspects of the widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *string* | Index of the string that is plucked (starts at 0) - | *x* | Where on the string the pluck occured (float 0-1); - */ - this.val = { - string: 0, - x: 0 - } - /** @property {integer} numberOfStrings How many strings in the widget. We recommend setting this property with .setStrings() */ - this.numberOfStrings = 10; - this.strings = new Array(); - this.abovestring = new Array(); - /** @property {integer} friction How quickly the string slows down */ - this.friction = 1; - - var stringdiv; - - this.init(); - - nx.aniItems.push(this.draw.bind(this)); -} -util.inherits(string, widget); - -string.prototype.init = function() { - stringdiv = this.height/(this.numberOfStrings + 1); - for (var i=0;i st.maxstretch) { - //st.direction *= (-0.99); - st.direction *= -1; - st.stretch = st.stretch + st.direction; - st.maxstretch = st.maxstretch - this.friction; - - st.direction = (st.direction / Math.abs(st.direction)) * (st.maxstretch/1) - } - - beginPath(); - moveTo(st.x1, st.y1); - quadraticCurveTo(this.width/2, st.y1+st.stretch, st.x2, st.y2); - stroke(); - closePath(); - st.on = true; - - - } else if (st.held) { - //will draw rounded - //if mouse is higher than string and gripup - //or if mouse is - // if (this.clickPos.y-st.y1<0 && st.gripup || this.clickPos.y-st.y1>0 && !st.gripup) { - beginPath(); - moveTo(st.x1, st.y1); - quadraticCurveTo(this.clickPos.x, this.clickPos.y, st.x2, st.y2); - stroke(); - closePath(); - st.on = true; - /* } else { - beginPath(); - moveTo(st.x1, st.y1); - lineTo(st.x2, st.y2); - stroke(); - closePath(); - } */ - } else { - beginPath(); - moveTo(st.x1, st.y1); - lineTo(st.x2, st.y2); - stroke(); - closePath(); - if (st.on) { - st.on = false; - } - } - } - } - this.drawLabel(); -} - -string.prototype.click = function() { - for (var i = 0;i this.height/(this.strings.length*3)) { - - this.pluck(i) - - } - } - } -} - -string.prototype.release = function() { - for (var i = 0;i - ``` - -*/ - -var tabs = module.exports = function(target) { - - this.defaultSize = { width: 150, height: 50 }; - widget.call(this, target); - - //define unique attributes - this.choice = 0; - this.val = { - index: 0, - text: "" - } - this.tabwid = 0; - this.options = ["one", "two", "three"] - //init - this.init(); - -} - -util.inherits(tabs, widget); - - -tabs.prototype.init = function() { - this.draw(); -} - - -tabs.prototype.draw = function() { - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height) - - textAlign = "center" - textBaseline = "middle" - font = "normal "+this.height/5+"px courier" - } - - this.tabwid = this.width/this.options.length - - for (var i=0;i **Note:** Currently the canvas is actaully replaced by an HTML textarea object. Any inline style on your canvas may be lost in this transformation. To style the resultant textarea element, we recommend creating CSS styles for the textarea element using its ID or the textarea tag. - ```html - - ``` - -*/ - -var text = module.exports = function (target) { - this.defaultSize = { width: 200, height: 100 }; - widget.call(this, target); - - /** @property {object} val - |   | data - | --- | --- - | *text* | Text string - */ - this.val = { - text: "" - } - - var htmlstr = '' - var canv = this.canvas - var cstyle = this.canvas.style - var parent = canv.parentNode; - var newdiv = document.createElement("span"); - newdiv.innerHTML = htmlstr; - parent.replaceChild(newdiv,canv) - this.el = document.getElementById(this.canvasID) - - for (var prop in cstyle) - this.el.style[prop] = cstyle[prop]; - - this.el.style.display = "block" - this.el.style.backgroundColor = this.colors.fill - this.el.style.border = "none" - this.el.style.color = this.colors.black - this.el.style.outline = "none" - this.el.style.resize = "none" - this.el.style.boxSizing = "border-box" - this.el.style.padding = "5px" - this.el.style.fontFamily = nx.font - this.el.style.fontSize = "16px" - - - this.canvas = document.getElementById(this.canvasID); - - -} -util.inherits(text, widget); - -text.prototype.init = function() { - - this.canvas.ontouchstart = null; - this.canvas.ontouchmove = null; - this.canvas.ontouchend = null; - - this.canvas.style.backgroundColor = this.colors.fill; - this.canvas.style.color = this.colors.black; - -} - -// should have a modified "set" function -text.prototype.change = function(e,el) { - this.val.text = el.value - if (e.which=="13") { - this.transmit(this.val) - this.val.text = "" - this.draw() - e.preventDefault() - } -} - -text.prototype.draw = function() { - // needed especially for ghost - this.el.value = this.val.text - - this.canvas.style.backgroundColor = this.colors.fill; - this.canvas.style.color = this.colors.black; -} -},{"../core/widget":3,"util":47}],37:[function(require,module,exports){ -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class tilt - Mobile and Mac/Chrome-compatible tilt sensor. May not work on all devices!
**Notes:** Clicking on this widget toggles it inactive or active.
- We recommend not calling .init() on this object after the original initialization, because it will add additional redundant tilt listeners to your document. - ```html - - ``` - -*/ - -var tilt = module.exports = function (target) { - this.defaultSize = { width: 50, height: 50 }; - widget.call(this, target); - - this.tiltLR; - this.tiltFB; - this.z; - /** @property {boolean} active Whether or not the tilt widget is on (animating and transmitting data). */ - this.active = true; - - /** @property {object} val Object containing the core interactive aspects of the widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *x* | X-axis rotation if supported (-1 to 1) - | *y* | Y-axis rotation if supported (-1 to 1) - | *z* | Z-axis rotation if supported (-1 to 1 or possibly 0 to 360 depending on device) - */ - this.val = { - x: 0, - y: 0, - z: 0 - } - - /** @property {string} text Text shown on tilt object - */ - - this.text = "TILT"; - this.init(); - - this.boundChromeTilt = this.chromeTilt.bind(this) - this.boundMozTilt = this.mozTilt.bind(this) - - if (window.DeviceOrientationEvent) { - window.addEventListener('deviceorientation', this.boundChromeTilt, false); - } else if (window.OrientationEvent) { - window.addEventListener('MozOrientation', this.boundMozTilt, false); - } else { - console.log("Not supported on your device or browser.") - } - -} -util.inherits(tilt, widget); - -tilt.prototype.deviceOrientationHandler = function() { - - this.val = { - x: math.prune(this.tiltLR/90,3), - y: math.prune(this.tiltFB/90,3), - z: math.prune(this.z,3) - } - - if (this.active) { - this.transmit(this.val); - } - -} - -tilt.prototype.chromeTilt = function(eventData) { - this.tiltLR = eventData.gamma; - this.tiltFB = eventData.beta; - this.z = eventData.alpha - this.deviceOrientationHandler(); - this.draw(); -} - -tilt.prototype.mozTilt = function(eventData) { - this.tiltLR = eventData.x * 90; - // y is the front-to-back tilt from -1 to +1, so we need to convert to degrees - // We also need to invert the value so tilting the device towards us (forward) - // results in a positive value. - this.tiltFB = eventData.y * -90; - this.z = eventData.z; - this.deviceOrientationHandler(); - this.draw(); -} - -tilt.prototype.init = function() { - this.draw(); -} - -tilt.prototype.draw = function() { - - this.erase(); - - with (this.context) { - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - save(); - translate(this.width/2,this.height/2) - rotate(-this.val.x*Math.PI/2); - translate(-this.width/2,-this.height/2) - globalAlpha = 0.4; - - if (this.active) { - fillStyle = this.colors.accent; - } else { - fillStyle = this.colors.border; - } - - fillRect(-this.width,this.height*(this.val.y/2)+this.height/2,this.width*3,this.height*2) - font = "bold "+this.height/5+"px "+this.font; - textAlign = "center"; - fillText(this.text, this.width/2, this.height*(this.val.y/2)+this.height/2+this.height/15); - globalAlpha = 1; - restore(); - } - this.drawLabel(); -} - -tilt.prototype.click = function() { - this.active = !this.active; -} - -tilt.prototype.customDestroy = function() { - this.active = false; - window.removeEventListener("deviceorientation",this.boundChromeTilt,false); - window.removeEventListener("mozOrientation",this.boundMozTilt,false); -} -},{"../core/widget":3,"../utils/math":6,"util":47}],38:[function(require,module,exports){ -var drawing = require('../utils/drawing'); -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class toggle - On/off toggle - ```html - - ``` - -*/ - -var toggle = module.exports = function (target) { - this.defaultSize = { width: 50, height: 50 }; - widget.call(this, target); - - this.mindim = this.height>this.width ? this.width : this.height; - - /** @property {object} val Object containing the core interactive aspects of the widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *value*| 1 if on, 0 if off - */ - this.val = { - value: 0 - } - this.init(); -} -util.inherits(toggle, widget); - -toggle.prototype.init = function() { - this.fontsize = this.mindim/4; - this.draw(); -} - -toggle.prototype.draw = function() { - - this.erase() - - with (this.context) { - if (this.val.value) { - fillStyle = this.colors.accent; - } else { - fillStyle = this.colors.fill; - } - fillRect(0,0,this.width,this.height); - if (this.val.value) { - this.setFont(); - fillStyle = this.colors.white - globalAlpha = 1; - fillText("on", this.width/2, this.height/2); - } else { - this.setFont(); - fillText("off", this.width/2, this.height/2); - globalAlpha = 1; - } - } - - this.drawLabel(); - -} - -toggle.prototype.click = function() { - if (!this.val.value) { - this.val.value = 1; - } else { - this.val.value = 0; - } - this.draw(); - this.transmit(this.val); -} -},{"../core/widget":3,"../utils/drawing":5,"util":47}],39:[function(require,module,exports){ -var drawing = require('../utils/drawing'); -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class typewriter - Computer keyboard listener and visualization. (Desktop only)
**Note:** Clicking on the widget toggles it inactive or active, which can be useful if you need to temporarily type without triggering the widget's events. - ```html - - ``` - -*/ - -var typewriter = module.exports = function(target) { - this.defaultSize = { width: 300, height: 100 }; - widget.call(this, target); - - - this.letter = "" - this.keywid = this.width/14.5; - this.keyhgt = this.height/5 - - /** @property {boolean} active Whether or not the widget is on (listening for events and transmitting values).*/ - this.active = true; - - /** @property {object} val Object containing the core interactive aspects of the widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *key* | symbol of key pressed (example: "a") - | *ascii* | ascii value of key pressed (example: 48) - | *on* | 0 if key is being pressed, 1 if key is being released - */ - this.val = { - key: "", - ascii: 0, - on: 0 - } - - this.rows = [ - [ - { symbol: "`", value: 192, width: 1, on: false }, - { symbol: "1", value: 49, width: 1, on: false }, - { symbol: "2", value: 50, width: 1, on: false }, - { symbol: "3", value: 51, width: 1, on: false }, - { symbol: "4", value: 52, width: 1, on: false }, - { symbol: "5", value: 53, width: 1, on: false }, - { symbol: "6", value: 54, width: 1, on: false }, - { symbol: "7", value: 55, width: 1, on: false }, - { symbol: "8", value: 56, width: 1, on: false }, - { symbol: "9", value: 57, width: 1, on: false }, - { symbol: "0", value: 48, width: 1, on: false }, - { symbol: "-", value: 189, width: 1, on: false }, - { symbol: "=", value: 187, width: 1, on: false }, - { symbol: "delete", value: 46, width: 1.5, on: false } - ], - [ - { symbol: "tab", value: 9, width: 1.5, on: false }, - { symbol: "q", value: 81, width: 1, on: false }, - { symbol: "w", value: 87, width: 1, on: false }, - { symbol: "e", value: 69, width: 1, on: false }, - { symbol: "r", value: 82, width: 1, on: false }, - { symbol: "t", value: 84, width: 1, on: false }, - { symbol: "y", value: 89, width: 1, on: false }, - { symbol: "u", value: 85, width: 1, on: false }, - { symbol: "i", value: 73, width: 1, on: false }, - { symbol: "o", value: 79, width: 1, on: false }, - { symbol: "p", value: 80, width: 1, on: false }, - { symbol: "[", value: 219, width: 1, on: false }, - { symbol: "]", value: 221, width: 1, on: false }, - { symbol: "\\", value: 220, width: 1, on: false } - ], - [ - { symbol: "caps", value: 20, width: 1.75, on: false }, - { symbol: "a", value: 65, width: 1, on: false }, - { symbol: "s", value: 83, width: 1, on: false }, - { symbol: "d", value: 68, width: 1, on: false }, - { symbol: "f", value: 70, width: 1, on: false }, - { symbol: "g", value: 71, width: 1, on: false }, - { symbol: "h", value: 72, width: 1, on: false }, - { symbol: "j", value: 74, width: 1, on: false }, - { symbol: "k", value: 75, width: 1, on: false }, - { symbol: "l", value: 76, width: 1, on: false }, - { symbol: ";", value: 186, width: 1, on: false }, - { symbol: "'", value: 222, width: 1, on: false }, - { symbol: "enter", value: 13, width: 1.75, on: false } - ], - [ - { symbol: "shift", value: 16, width: 2.25, on: false }, - { symbol: "z", value: 90, width: 1, on: false }, - { symbol: "x", value: 88, width: 1, on: false }, - { symbol: "c", value: 67, width: 1, on: false }, - { symbol: "v", value: 86, width: 1, on: false }, - { symbol: "b", value: 66, width: 1, on: false }, - { symbol: "n", value: 78, width: 1, on: false }, - { symbol: "m", value: 77, width: 1, on: false }, - { symbol: ",", value: 188, width: 1, on: false }, - { symbol: ".", value: 190, width: 1, on: false }, - { symbol: "/", value: 191, width: 1, on: false }, - { symbol: "shift", value: 16, width: 2.25, on: false } - ], - [ - { symbol: "fn", value: 10, width: 1, on: false }, - { symbol: "ctrl", value: 17, width: 1, on: false }, - { symbol: "opt", value: 10, width: 1, on: false }, - { symbol: "cmd", value: 10, width: 1.25, on: false }, - { symbol: "space", value: 32, width: 5, on: false }, - { symbol: "cmd", value: 10, width: 1, on: false }, - { symbol: "opt", value: 10, width: 1, on: false }, - { symbol: "left", value: 37, width: .81, on: false }, - { symbol: "up", value: 38, width: .81, on: false }, - { symbol: "down", value: 40, width: .81, on: false }, - { symbol: "right", value: 39, width: .81, on: false } - ] - ] - - this.boundType = this.typekey.bind(this); - this.boundUntype = this.untype.bind(this); - window.addEventListener("keydown", this.boundType); - window.addEventListener("keyup", this.boundUntype); - - this.init(); -} -util.inherits(typewriter, widget); - -typewriter.prototype.init = function() { - - this.keywid = this.width/14.5; - this.keyhgt = this.height/5 - - this.draw(); -} - -typewriter.prototype.draw = function() { // erase - this.erase(); - - if (!this.active) { - this.context.globalAlpha = 0.4 - } else { - this.context.globalAlpha = 1 - } - - with (this.context) { - - strokeStyle = this.colors.border - fillStyle = this.colors.accent - lineWidth = 1 - - for (var i=0;i - ``` - -*/ - -var vinyl = module.exports = function (target) { - this.defaultSize = { width: 100, height: 100 }; - widget.call(this, target); - - this.circleSize; - - /** @property speed The rotation increment. Default is 0.05. Not to be confused with .val.speed (see below) which is the data output. During rotation, .speed will always move towards .defaultSpeed */ - this.speed = 0.05; - /** @property defaultSpeed The "steady-state" rotation increment. Default is 0.05. During rotation, if .speed is changed, it will gradually move towards this. */ - this.defaultspeed = 0.05 - this.rotation = 0; - this.hasMovedOnce = false; - - this.lockResize = true; - - /** @property {object} val Object containing the core interactive aspects of the widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *speed*| Current speed of the record player's rotation. (Normal is 1.) - */ - this.val = { - speed: 0 - } - this.init(); - nx.aniItems.push(this.spin.bind(this)); -} -util.inherits(vinyl, widget); - -vinyl.prototype.init = function() { - - this.circleSize = (Math.min(this.center.x, this.center.y)-this.lineWidth); - this.draw(); -} - -vinyl.prototype.draw = function() { - this.erase() - - with (this.context) { - strokeStyle = this.colors.border; - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height) - - //draw main circle - beginPath(); - fillStyle = this.colors.black; - arc(this.center.x, this.center.y, this.circleSize-5, 0, Math.PI*2, true); - fill(); - closePath(); - - - //draw circle in center - beginPath(); - fillStyle = this.colors.accent; - arc(this.center.x, this.center.y*1, this.circleSize/4, 0, Math.PI*2, false); - fill() - closePath(); - - - //draw tint - beginPath(); - globalAlpha = 0.5; - fillStyle = this.colors.fill; - arc(this.center.x, this.center.y, this.circleSize, this.rotation, this.rotation + 0.4, false); - lineTo(this.center.x, this.center.y); - arc(this.center.x, this.center.y, this.circleSize, this.rotation+Math.PI, this.rotation +Math.PI+ 0.4, false); - lineTo(this.center.x, this.center.y); - fill(); - globalAlpha = 1; - closePath(); - - - //draw white circle in center - beginPath(); - fillStyle = this.colors.white; - arc(this.center.x, this.center.y*1, this.circleSize/16, 0, Math.PI*2, false); - fill() - closePath(); - - } - - this.drawLabel(); -} - -vinyl.prototype.click = function(e) { - this.hasMovedOnce = false; - this.lastRotation = this.rotation - this.grabAngle = this.rotation % (Math.PI*2) - this.grabPos = math.toPolar(this.clickPos.x-this.center.x,this.clickPos.y-this.center.y).angle - -} - -vinyl.prototype.move = function() { - - if (!this.hasMovedOnce) { - this.hasMovedOnce = true; - this.grabAngle = this.rotation % (Math.PI*2) - this.grabPos = math.toPolar(this.clickPos.x-this.center.x,this.clickPos.y-this.center.y).angle - } - - this.rotation = math.toPolar(this.clickPos.x-this.center.x,this.clickPos.y-this.center.y).angle + this.grabAngle - this.grabPos - - -} - -vinyl.prototype.release = function() { - this.speed = ((this.rotation - this.lastRotation) + (this.lastRotation-this.lastRotation2))/2 ; -} - -vinyl.prototype.spin = function() { - - if (this.clicked) { - this.speed /= 1.1; - } else { - this.speed = this.speed*0.9 + this.defaultspeed*0.1 - } - - // may need to math.clip(this.val.speed,-10,10); - this.val.speed = (this.rotation - this.lastRotation) * 20; // normalizes it to 1 - - this.lastRotation2 = this.lastRotation - this.lastRotation = this.rotation - - this.rotation += this.speed - - this.draw(); - - this.transmit(this.val) - -} - -vinyl.prototype.customDestroy = function() { - nx.removeAni(this.spin.bind(this)); -} -},{"../core/widget":3,"../utils/math":6,"util":47}],41:[function(require,module,exports){ -var util = require('util'); -var widget = require('../core/widget'); -var math = require('../utils/math') - -/** - @class waveform - Waveform visualizer and selecter - ```html - - ``` -*/ - -var waveform = module.exports = function (target) { - this.defaultSize = { width: 400, height: 125 }; - widget.call(this, target); - - /** @property {object} val Object containing core interactive aspects of widget, which are also its data output. Has the following properties: - |   | data - | --- | --- - | *starttime* | Waveform selection start position in milliseconds (integer) - | *stoptime* | Waveform selection end position in milliseconds (integer) - | *looptime* | Selection size, in milliseconds (integer) - | *start* | Waveform selection start, as fraction of waveform (float 0-1) - | *stop* | Waveform selection end, as fraction of waveform (float 0-1) - | *size* | Selection size, as fraction of waveform (float 0-1) - */ - this.val = { - start: 0, - stop: 0, - size: 0, - starttime: 0, - stoptime: 0, - looptime: 0 - } - - this.handle; - this.relhandle; - this.cap; - this.firsttouch = "start"; - - /** @property {Array} buffer Contains multiple arrays of reduced buffer data, for visualization */ - this.buffer = [] - - if (nx.isMobile) { - /** @property {integer} definition Horizontal definition of the visualization. Value of 3 means the waveform will be represented in 3 pixel chunks. Higher numbers (4+) lead to a smaller graphics load. Smaller numbers (1-3) look better. Default is 1 for desktop renders, 3 for mobile renders. */ - this.definition = 3; - } else { - this.definition = 1; - } - - this.pieces = false; - - /** @property {integer} channels How many channels in the waveform */ - this.channels = 1 - this.rawbuffer = [] - - this.times = [ - { dur: 10 , format: 1 }, - { dur: 50 , format: 1 }, - { dur: 100 , format: 1 }, - { dur: 200 , format: 1 }, - { dur: 500 , format: 1 }, - { dur: 1000 , format: 1 }, - { dur: 2000 , format: 1 }, - { dur: 5000 , format: 1 }, - { dur: 10000 , format: 3 }, - { dur: 15000 , format: 3 }, - { dur: 60000 , format: 3 }, // 1 min - { dur: 120000 , format: 3 }, // 2 mins - { dur: 300000 , format: 3 }, // 5 mins - { dur: 600000 , format: 3 }, // 10 mins - ] - this.timescale = false - - // to do -- - // // sample rate adjustments - // .select(500,1000) - - /** @property {string} mode Mode of interaction. "edge" mode lets you drag each edge of the waveform individually. "area" mode (default) lets you drag the waveform as a whole (with parallel mouse movement) or scale the waveform as a whole (with transverse mouse movement) */ - this.mode = "area" // modes: "edge", "area" - this.touchdown = new Object(); - this.init(); -} -util.inherits(waveform, widget); - -waveform.prototype.init = function() { - - this.pieces = ~~(this.width/this.definition); - - this.draw(); -} - - -/** - @method setBuffer - Load a web audio AudioBuffer into the waveform ui, for analysis and visualization. - @param {AudioBuffer} [buffer] The buffer to be loaded. - */ -waveform.prototype.setBuffer = function(prebuff) { - - this.channels = prebuff.numberOfChannels - this.duration = prebuff.duration - this.sampleRate = prebuff.sampleRate - this.waveHeight = this.height / this.channels - - // timescale - this.durationMS = (this.duration * 1000) - this.timescale = 0 - while (~~(this.durationMS/this.times[this.timescale].dur) > 7 && this.timescale < this.times.length ) { - this.timescale++; - } - this.timescale = this.times[this.timescale] - - this.rawbuffer = [] - this.buffer = [] - - // reduce/crush buffers - for (var i=0;i0) { - cmax = Math.max(cmax,this.rawbuffer[i][j]) - } else { - cmin = Math.min(cmin,this.rawbuffer[i][j]) - } - if (j > group * groupsize) { - this.buffer[i].push([cmax,cmin]) - group++ - cmin = 0 - cmax = 0 - } - } - } - - if (this.val.start && this.val.stop) { - - } - - this.val.starttime = Math.round(this.val.start * this.durationMS) - this.val.stoptime = Math.round(this.val.stop * this.durationMS) - this.val.looptime = Math.round(this.val.size * this.durationMS) - - - this.draw() - -} - -/** - @method select - Set the selection start and end points. - @param {integer} [start] Selection start point in milliseconds - @param {integer} [end] Selection end point in milliseconds - */ -waveform.prototype.select = function(start,stop) { - this.val.start = math.clip(start / this.durationMS,0,1) - this.val.stop = math.clip(stop / this.durationMS,0,1) - this.val.size = this.val.stop - this.val.start - this.val.starttime = start - this.val.stoptime = stop - this.val.looptime = start - stop - this.transmit(this.val) - this.draw() -} - - -waveform.prototype.draw = function() { - //this.erase(); - - with (this.context) { - //bg - fillStyle = this.colors.fill; - fillRect(0,0,this.width,this.height); - - //waveform - for (var i=0;i 1000) { - dur /= 1000 - math.prune(dur,2) - dur += ' s' - } else { - math.prune(dur,0) - dur += ' ms' - } - fillText(dur,x1 + (x2-x1)/2,this.height/2) - } - - globalAlpha = 1 - - - } - -} - -waveform.prototype.msToTime = function(rawms,format) { - - var format = format ? format : 2 - - var s = ~~(rawms / 1000) - var secs = s % 60; - s = (s - secs) / 60; - var mins = s % 60; - var hrs = (s - mins) / 60; - var ms = rawms % 1000 - - //correct digits - secs = (secs < 10 && mins) ? secs + '0' : secs; - //ms = (ms < 10 && secs) ? ms + '0' : ms; - - if (format==1) { - return secs + '.' + ms; - } else if (format==2) { - return mins + ':' + secs + '.' + ms; - } else if (format==3) { - return mins + ':' + secs; - } - -} - -waveform.prototype.click = function() { - if (this.mode=="edge") { - if (Math.abs(this.clickPos.x-this.val.start*this.width) < Math.abs(this.clickPos.x-this.val.stop*this.width)) { - this.firsttouch = "start" - } else { - this.firsttouch = "stop" - } - } else if (this.mode=="area") { - this.touchdown = { - x: this.clickPos.x, - y: this.clickPos.y - } - this.startval = new Object(); - this.startval.size = this.val.stop - this.val.start; - this.startval.loc = this.val.start + this.startval.size/2; - } - this.move(); -} - -waveform.prototype.move = function() { - - if (this.mode=="edge") { - if (this.firsttouch=="start") { - this.val.start = this.clickPos.x/this.width; - if (this.clickPos.touches.length>1) { - this.val.stop = this.clickPos.touches[1].x/this.width; - } - } else { - this.val.stop = this.clickPos.x/this.width; - if (this.clickPos.touches.length>1) { - this.val.start = this.clickPos.touches[1].x/this.width; - } - } - - - if (this.val.stop < this.val.start) { - this.tempstart = this.val.start; - this.val.start = this.val.stop; - this.val.stop = this.tempstart; - if (this.firsttouch=="start") { - this.firsttouch = "stop"; - } else { - this.firsttouch = "start"; - } - } - - } else if (this.mode=="area") { - - var moveloc = this.clickPos.x/this.width; - var movesize = (this.touchdown.y - this.clickPos.y)/this.height; - - movesize /= 4; - var size = this.startval.size + movesize; - size = math.clip(size,0.001,1); - - this.val = { - start: moveloc - size/2, - stop: moveloc + size/2, - } - - } - - this.val.start = math.clip(this.val.start,0,1); - this.val.stop = math.clip(this.val.stop,0,1); - - this.val['size'] = math.clip(Math.abs(this.val.stop - this.val.start), 0, 1) - - if (this.durationMS) { - this.val["starttime"] = Math.round(this.val.start * this.durationMS) - this.val["stoptime"] = Math.round(this.val.stop * this.durationMS) - this.val["looptime"] = Math.round(this.val.size * this.durationMS) - } - - this.transmit(this.val); - this.draw(); - -} -},{"../core/widget":3,"../utils/math":6,"util":47}],42:[function(require,module,exports){ -var math = require('../utils/math') -var util = require('util'); -var widget = require('../core/widget'); - -/** - @class windows - Scalable windows - ```html - - ``` - -*/ - -var windows = module.exports = function (target) { - - this.defaultSize = { width: 200, height: 200 }; - - widget.call(this, target); - - this.val = { - items: [], - add: false, - remove: false, - change: false - } - - //this.val.items = [] - this.size = .25; - this.meta = false; - this.resizing = false; - - this.init(); - - document.addEventListener('keydown',function(e) { - if (e.shiftKey && !this.meta) { - this.meta = true; - this.draw(); - } - }.bind(this)) - document.addEventListener('keyup',function(e) { - if (!e.shiftKey && this.meta) { - this.meta = false; - this.draw(); - } - }.bind(this)) -} -util.inherits(windows, widget); - -windows.prototype.init = function() { - this.draw(); -} - -windows.prototype.add = function(x,y,w,h) { - this.val.items.push({ - x: x, - y: y, - w: w, - h: h - }) - this.draw(); -} - -windows.prototype.setWindow = function(index, loc) { - this.val.items[index] = loc; - this.draw(); -} - -windows.prototype.remove = function(index) { - this.val.items.splice(index,1) - this.val.add = false - this.val.remove = index - this.val.change = false - /* this.val = { - remove: index, - items: this.val.items - } */ - this.transmit(this.val) - this.draw(); -} - -windows.prototype.draw = function() { -// this.erase() - with (this.context) { - - if (!this.meta) { - fillStyle = this.colors.fill; - } else { - fillStyle = this.colors.border; - } - - fillRect(0,0,this.width,this.height); - - globalAlpha = 0.8; - - for (var i=0;i (this.val.items[i].x+this.val.items[i].w)*this.width - 10 && this.clickPos.x < (this.val.items[i].x+this.val.items[i].w)*this.width && this.clickPos.y > (this.val.items[i].y+this.val.items[i].h)*this.height - 10 && this.clickPos.y < (this.val.items[i].y+this.val.items[i].h)*this.height) { - this.resizing = true; - } - } - } - - if (this.holds===false) { - this.val.items.push({ - x: cx, - y: cy, - w: this.size, - h: this.size - }) - this.holds = this.val.items.length-1; - this.hasMoved = true; - this.val.add = this.val.items[this.holds] - this.val.remove = false - this.val.change = false - /* this.val = { - add: this.val.items[this.holds], - items: this.val.items - } */ - this.transmit(this.val) - } - if (this.meta) { - for (var i=0;i 1) { - item.x = 1 - item.w - } - if (item.y + item.h > 1) { - item.y = 1 - item.h - } - return item; -} -},{"../core/widget":3,"../utils/math":6,"util":47}],43:[function(require,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - -},{}],44:[function(require,module,exports){ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } -} - -},{}],45:[function(require,module,exports){ -// shim for using process in browser - -var process = module.exports = {}; - -process.nextTick = (function () { - var canSetImmediate = typeof window !== 'undefined' - && window.setImmediate; - var canPost = typeof window !== 'undefined' - && window.postMessage && window.addEventListener - ; - - if (canSetImmediate) { - return function (f) { return window.setImmediate(f) }; - } - - if (canPost) { - var queue = []; - window.addEventListener('message', function (ev) { - var source = ev.source; - if ((source === window || source === null) && ev.data === 'process-tick') { - ev.stopPropagation(); - if (queue.length > 0) { - var fn = queue.shift(); - fn(); - } - } - }, true); - - return function nextTick(fn) { - queue.push(fn); - window.postMessage('process-tick', '*'); - }; - } - - return function nextTick(fn) { - setTimeout(fn, 0); - }; -})(); - -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -} - -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; - -},{}],46:[function(require,module,exports){ -module.exports = function isBuffer(arg) { - return arg && typeof arg === 'object' - && typeof arg.copy === 'function' - && typeof arg.fill === 'function' - && typeof arg.readUInt8 === 'function'; -} -},{}],47:[function(require,module,exports){ -(function (process,global){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (!isString(f)) { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': - try { - return JSON.stringify(args[i++]); - } catch (_) { - return '[Circular]'; - } - default: - return x; - } - }); - for (var x = args[i]; i < len; x = args[++i]) { - if (isNull(x) || !isObject(x)) { - str += ' ' + x; - } else { - str += ' ' + inspect(x); - } - } - return str; -}; - - -// Mark that a method should not be used. -// Returns a modified function which warns once by default. -// If --no-deprecation is set, then it is a no-op. -exports.deprecate = function(fn, msg) { - // Allow for deprecating things in the process of starting up. - if (isUndefined(global.process)) { - return function() { - return exports.deprecate(fn, msg).apply(this, arguments); - }; - } - - if (process.noDeprecation === true) { - return fn; - } - - var warned = false; - function deprecated() { - if (!warned) { - if (process.throwDeprecation) { - throw new Error(msg); - } else if (process.traceDeprecation) { - console.trace(msg); - } else { - console.error(msg); - } - warned = true; - } - return fn.apply(this, arguments); - } - - return deprecated; -}; - - -var debugs = {}; -var debugEnviron; -exports.debuglog = function(set) { - if (isUndefined(debugEnviron)) - debugEnviron = process.env.NODE_DEBUG || ''; - set = set.toUpperCase(); - if (!debugs[set]) { - if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { - var pid = process.pid; - debugs[set] = function() { - var msg = exports.format.apply(exports, arguments); - console.error('%s %d: %s', set, pid, msg); - }; - } else { - debugs[set] = function() {}; - } - } - return debugs[set]; -}; - - -/** - * Echos the value of a value. Trys to print the value out - * in the best way possible given the different types. - * - */ -/* legacy: obj, showHidden, depth, colors*/ -function inspect(obj, opts) { - // default options - var ctx = { - seen: [], - stylize: stylizeNoColor - }; - // legacy... - if (arguments.length >= 3) ctx.depth = arguments[2]; - if (arguments.length >= 4) ctx.colors = arguments[3]; - if (isBoolean(opts)) { - // legacy... - ctx.showHidden = opts; - } else if (opts) { - // got an "options" object - exports._extend(ctx, opts); - } - // set default options - if (isUndefined(ctx.showHidden)) ctx.showHidden = false; - if (isUndefined(ctx.depth)) ctx.depth = 2; - if (isUndefined(ctx.colors)) ctx.colors = false; - if (isUndefined(ctx.customInspect)) ctx.customInspect = true; - if (ctx.colors) ctx.stylize = stylizeWithColor; - return formatValue(ctx, obj, ctx.depth); -} -exports.inspect = inspect; - - -// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics -inspect.colors = { - 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] -}; - -// Don't use 'blue' not visible on cmd.exe -inspect.styles = { - 'special': 'cyan', - 'number': 'yellow', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' -}; - - -function stylizeWithColor(str, styleType) { - var style = inspect.styles[styleType]; - - if (style) { - return '\u001b[' + inspect.colors[style][0] + 'm' + str + - '\u001b[' + inspect.colors[style][1] + 'm'; - } else { - return str; - } -} - - -function stylizeNoColor(str, styleType) { - return str; -} - - -function arrayToHash(array) { - var hash = {}; - - array.forEach(function(val, idx) { - hash[val] = true; - }); - - return hash; -} - - -function formatValue(ctx, value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (ctx.customInspect && - value && - isFunction(value.inspect) && - // Filter out the util module, it's inspect function is special - value.inspect !== exports.inspect && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - var ret = value.inspect(recurseTimes, ctx); - if (!isString(ret)) { - ret = formatValue(ctx, ret, recurseTimes); - } - return ret; - } - - // Primitive types cannot have properties - var primitive = formatPrimitive(ctx, value); - if (primitive) { - return primitive; - } - - // Look up the keys of the object. - var keys = Object.keys(value); - var visibleKeys = arrayToHash(keys); - - if (ctx.showHidden) { - keys = Object.getOwnPropertyNames(value); - } - - // IE doesn't make error fields non-enumerable - // http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx - if (isError(value) - && (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { - return formatError(value); - } - - // Some type of object without properties can be shortcutted. - if (keys.length === 0) { - if (isFunction(value)) { - var name = value.name ? ': ' + value.name : ''; - return ctx.stylize('[Function' + name + ']', 'special'); - } - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } - if (isDate(value)) { - return ctx.stylize(Date.prototype.toString.call(value), 'date'); - } - if (isError(value)) { - return formatError(value); - } - } - - var base = '', array = false, braces = ['{', '}']; - - // Make Array say that they are Array - if (isArray(value)) { - array = true; - braces = ['[', ']']; - } - - // Make functions say that they are functions - if (isFunction(value)) { - var n = value.name ? ': ' + value.name : ''; - base = ' [Function' + n + ']'; - } - - // Make RegExps say that they are RegExps - if (isRegExp(value)) { - base = ' ' + RegExp.prototype.toString.call(value); - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + Date.prototype.toUTCString.call(value); - } - - // Make error with message first say the error - if (isError(value)) { - base = ' ' + formatError(value); - } - - if (keys.length === 0 && (!array || value.length == 0)) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); - } else { - return ctx.stylize('[Object]', 'special'); - } - } - - ctx.seen.push(value); - - var output; - if (array) { - output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); - } else { - output = keys.map(function(key) { - return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); - }); - } - - ctx.seen.pop(); - - return reduceToSingleString(output, base, braces); -} - - -function formatPrimitive(ctx, value) { - if (isUndefined(value)) - return ctx.stylize('undefined', 'undefined'); - if (isString(value)) { - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return ctx.stylize(simple, 'string'); - } - if (isNumber(value)) - return ctx.stylize('' + value, 'number'); - if (isBoolean(value)) - return ctx.stylize('' + value, 'boolean'); - // For some reason typeof null is "object", so special case here. - if (isNull(value)) - return ctx.stylize('null', 'null'); -} - - -function formatError(value) { - return '[' + Error.prototype.toString.call(value) + ']'; -} - - -function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { - var output = []; - for (var i = 0, l = value.length; i < l; ++i) { - if (hasOwnProperty(value, String(i))) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - String(i), true)); - } else { - output.push(''); - } - } - keys.forEach(function(key) { - if (!key.match(/^\d+$/)) { - output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, - key, true)); - } - }); - return output; -} - - -function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { - var name, str, desc; - desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; - if (desc.get) { - if (desc.set) { - str = ctx.stylize('[Getter/Setter]', 'special'); - } else { - str = ctx.stylize('[Getter]', 'special'); - } - } else { - if (desc.set) { - str = ctx.stylize('[Setter]', 'special'); - } - } - if (!hasOwnProperty(visibleKeys, key)) { - name = '[' + key + ']'; - } - if (!str) { - if (ctx.seen.indexOf(desc.value) < 0) { - if (isNull(recurseTimes)) { - str = formatValue(ctx, desc.value, null); - } else { - str = formatValue(ctx, desc.value, recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (array) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = ctx.stylize('[Circular]', 'special'); - } - } - if (isUndefined(name)) { - if (array && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = ctx.stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = ctx.stylize(name, 'string'); - } - } - - return name + ': ' + str; -} - - -function reduceToSingleString(output, base, braces) { - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; - }, 0); - - if (length > 60) { - return braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - } - - return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; -} - - -// NOTE: These type checking functions intentionally don't use `instanceof` -// because it is fragile and can be easily faked with `Object.create()`. -function isArray(ar) { - return Array.isArray(ar); -} -exports.isArray = isArray; - -function isBoolean(arg) { - return typeof arg === 'boolean'; -} -exports.isBoolean = isBoolean; - -function isNull(arg) { - return arg === null; -} -exports.isNull = isNull; - -function isNullOrUndefined(arg) { - return arg == null; -} -exports.isNullOrUndefined = isNullOrUndefined; - -function isNumber(arg) { - return typeof arg === 'number'; -} -exports.isNumber = isNumber; - -function isString(arg) { - return typeof arg === 'string'; -} -exports.isString = isString; - -function isSymbol(arg) { - return typeof arg === 'symbol'; -} -exports.isSymbol = isSymbol; - -function isUndefined(arg) { - return arg === void 0; -} -exports.isUndefined = isUndefined; - -function isRegExp(re) { - return isObject(re) && objectToString(re) === '[object RegExp]'; -} -exports.isRegExp = isRegExp; - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} -exports.isObject = isObject; - -function isDate(d) { - return isObject(d) && objectToString(d) === '[object Date]'; -} -exports.isDate = isDate; - -function isError(e) { - return isObject(e) && - (objectToString(e) === '[object Error]' || e instanceof Error); -} -exports.isError = isError; - -function isFunction(arg) { - return typeof arg === 'function'; -} -exports.isFunction = isFunction; - -function isPrimitive(arg) { - return arg === null || - typeof arg === 'boolean' || - typeof arg === 'number' || - typeof arg === 'string' || - typeof arg === 'symbol' || // ES6 symbol - typeof arg === 'undefined'; -} -exports.isPrimitive = isPrimitive; - -exports.isBuffer = require('./support/isBuffer'); - -function objectToString(o) { - return Object.prototype.toString.call(o); -} - - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - - -// log is just a thin wrapper to console.log that prepends a timestamp -exports.log = function() { - console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); -}; - - -exports.inherits = require('inherits'); - -exports._extend = function(origin, add) { - // Don't do anything if add isn't an object - if (!add || !isObject(add)) return origin; - - var keys = Object.keys(add); - var i = keys.length; - while (i--) { - origin[keys[i]] = add[keys[i]]; - } - return origin; -}; - -function hasOwnProperty(obj, prop) { - return Object.prototype.hasOwnProperty.call(obj, prop); -} - -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":46,"_process":45,"inherits":44}],48:[function(require,module,exports){ -var hasOwn = Object.prototype.hasOwnProperty; -var toString = Object.prototype.toString; -var undefined; - -var isPlainObject = function isPlainObject(obj) { - 'use strict'; - if (!obj || toString.call(obj) !== '[object Object]') { - return false; - } - - var has_own_constructor = hasOwn.call(obj, 'constructor'); - var has_is_property_of_method = obj.constructor && obj.constructor.prototype && hasOwn.call(obj.constructor.prototype, 'isPrototypeOf'); - // Not own constructor property must be Object - if (obj.constructor && !has_own_constructor && !has_is_property_of_method) { - return false; - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - var key; - for (key in obj) {} - - return key === undefined || hasOwn.call(obj, key); -}; - -module.exports = function extend() { - 'use strict'; - var options, name, src, copy, copyIsArray, clone, - target = arguments[0], - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if (typeof target === 'boolean') { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } else if ((typeof target !== 'object' && typeof target !== 'function') || target == null) { - target = {}; - } - - for (; i < length; ++i) { - options = arguments[i]; - // Only deal with non-null/undefined values - if (options != null) { - // Extend the base object - for (name in options) { - src = target[name]; - copy = options[name]; - - // Prevent never-ending loop - if (target === copy) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - if (copyIsArray) { - copyIsArray = false; - clone = src && Array.isArray(src) ? src : []; - } else { - clone = src && isPlainObject(src) ? src : {}; - } - - // Never move original objects, clone them - target[name] = extend(deep, clone, copy); - - // Don't bring in undefined values - } else if (copy !== undefined) { - target[name] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - - -},{}]},{},[1]); diff --git a/spline.html b/spline.html index 9e093b5..a30ddd1 100644 --- a/spline.html +++ b/spline.html @@ -1,7 +1,7 @@ - +