(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o'; 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" /** @method getName Returns the widget's constructor function name (i.e. "dial") */ widget.prototype.getName = function() { var funcNameRegex = /function (.{1,})\(/; var results = (funcNameRegex).exec((this).constructor.toString()); return (results && results.length > 1) ? results[1] : ""; } /** @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) { 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) } } /** @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) { with(this.context) { globalAlpha = 0.9; fillStyle = this.colors.fill; fillRect(this.width-100,this.height-20,100,20); globalAlpha = 1; beginPath(); fillStyle = this.colors.border; font = "bold 15px courier"; textAlign = "center"; fillText(this.oscPath,this.width-50,this.height-5); textAlign = "left"; closePath(); } } } /** @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 } },{"../utils/dom":4,"../utils/drawing":5,"../utils/timing":7,"../utils/transmit":8,"events":36,"util":40}],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; } },{}],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) { this.makeOSC(this.emit, data); this.emit('*',data); } 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 } } } 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.height/5+"px gill sans"; 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":40}],10:[function(require,module,exports){ var util = require('util'); var widget = require('../core/widget'); 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 _(default)_
aftertouch   1, x, y on click; x, y on move; 0, x, y on release
```js button1.mode = "aftertouch" ``` */ this.mode = "toggle"; 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.width = this.canvas.width; this.height = this.canvas.height; 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, (Math.min(this.center.x, this.center.y)-this.lineWidth/2), 0, Math.PI*2, true); fill(); closePath(); if (this.val.press && this.mode=="node") { globalAlpha = 0.2; fillStyle = this.colors.white; beginPath(); arc(this.val.x, this.val.y, (Math.min(this.center.x, this.center.y)/2), 0, Math.PI*2, true); fill(); closePath(); globalAlpha = 1; } } this.drawLabel(); } } button.prototype.click = function(e) { this.val["press"] = 1; if (this.mode=="node") { 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=="node") { 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=="node") { 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,"util":40}],11:[function(require,module,exports){ var util = require('util'); var widget = require('../core/widget'); /** @class colors Color picker that outputs RBG values ```html ``` */ // this object is poor when it is resized // because it calculates hsl based on // hsl max values / width of object... var colors = module.exports = function (target) { this.defaultSize = { width: 100, height: 100 }; widget.call(this, target); //define unique attributes this.color_width = this.width - this.lineWidth*2; this.color_height = this.height - this.lineWidth*2; this.color_table = new Array(); /** @property {float} saturation Saturation percentage of the color picker (0-100)*/ this.saturation = 100; this.color = [0,0,0]; this.init(); } util.inherits(colors, widget); colors.prototype.init = function() { this.color_width = this.width - this.lineWidth*2; this.color_height = this.height - this.lineWidth*2; this.color_table = new Array(); this.color = [0,0,0]; //prep color picker this.color_table = new Array(this.color_width); for (var i=0;i 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":40}],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":40}],13:[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.005
*/ this.responsivity = 0.005; 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.lineWidth); this.handleLength = this.circleSize+this.lineWidth; if (this.width<101) { this.handleLength--; // this.handleLength--; } if (this.width<101 || this.width<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, 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 , 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, 3) 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, 3) 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, 3) this.transmit(this.val); } } },{"../core/widget":3,"../utils/math":6,"util":40}],14:[function(require,module,exports){ var math = require('../utils/math') var util = require('util'); var widget = require('../core/widget'); /** @class envelope Three-point line ramp generator ```html ``` */ var envelope = module.exports = function (target) { this.defaultSize = { width: 75, height: 75 }; widget.call(this, target); this.nodeSize = 0; /** @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 //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) | *x* | x of envelope peak point (float 0-1) | *y* | y of envelope peak point (float 0-1) */ this.val = { x: 0.15, y: 0.5, amp: 0, index: 0 } this.init(); } util.inherits(envelope, widget); envelope.prototype.init = function() { this.actualWid = this.width- this.nodeSize*2; this.actualHgt = this.height- this.nodeSize*2; this.draw(); nx.aniItems.push(this.pulse.bind(this)); } envelope.prototype.draw = function() { this.erase(); with (this.context) { fillStyle = this.colors.fill; fillRect(0,0,this.width,this.height); var drawingX = this.val.x * this.actualWid + this.nodeSize var drawingY = this.val.y * this.actualHgt + this.nodeSize //stay within right/left bounds if (drawingX<(this.bgLeft+this.nodeSize)) { drawingX = this.bgLeft + this.nodeSize; } else if (drawingX>(this.bgRight-this.nodeSize)) { drawingX = this.bgRight - this.nodeSize; } //stay within top/bottom bounds if (drawingY<(this.bgTop+this.nodeSize)) { drawingY = this.bgTop + this.nodeSize; } else if (drawingY>(this.bgBottom-this.nodeSize)) { drawingY = this.bgBottom - this.nodeSize; } with (this.context) { beginPath(); strokeStyle = this.colors.accent; moveTo(0,this.height); lineTo(drawingX,drawingY); lineTo(this.width,this.height); stroke(); globalAlpha = 0.2; fillStyle = this.colors.accent; fill(); globalAlpha = 1; closePath(); beginPath(); fillStyle = this.colors.accent; strokeStyle = this.colors.border; arc(drawingX, drawingY, this.nodeSize, 0, Math.PI*2, true); fill(); closePath(); globalAlpha = 0.1 fillRect(0,0,this.val.index*this.width,this.height); globalAlpha = 1; } } this.drawLabel(); } envelope.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) } envelope.prototype.click = function() { this.val.x = this.clickPos.x; this.val.y = this.clickPos.y; this.scaleNode(); this.transmit(this.val); this.draw(); } envelope.prototype.move = function() { if (this.clicked) { this.val.x = this.clickPos.x; this.val.y = this.clickPos.y; this.scaleNode(); this.transmit(this.val); this.draw(); } } envelope.prototype.release = function() { this.val.x = this.clickPos.x; this.val.y = this.clickPos.y; this.scaleNode(); this.draw(); } envelope.prototype.pulse = function() { if (this.active) { this.val.index += ((this.width/3.3)/this.duration); this.val.index = math.clip(this.val.index, 0, 1) if (this.val.index < this.val.x) { var guiy = (this.val.index/this.val.x) * (1-this.val.y); this.val.amp = math.clip(guiy, 0, 1) } else { var guiy = ((1-this.val.index)/(1-this.val.x)) * (1-this.val.y); this.val.amp = math.clip(guiy, 0, 1) } this.transmit(this.val); this.draw(); if (this.val.index >= 1) { if (this.looping) { this.val.index -= 1; } else { this.stop(); } } } } /** @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; } /** @method stop Stop the ramp and set progress to 0. */ envelope.prototype.stop = function() { this.active = false; this.val.index = 0; this.draw(); } },{"../core/widget":3,"../utils/math":6,"util":40}],15:[function(require,module,exports){ var math = require('../utils/math') var util = require('util'); var widget = require('../core/widget'); /** @class ghost (alpha) ```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 = 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; 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() { for (var key in nx.widgets) { this.connect(nx.widgets[key]); } } //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]) { 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() { this.moment = 0; nx.aniItems.push(this.boundLog) this.recording = true; } ghost.prototype.log = function() { for (var i=0;i this.start) { this.scan(); } else if (this.looping) { // this.needle = this.start; 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":40}],18:[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 */ 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) { if (this.clickPos.touches.length>=2 && this.oneleft) { this.oneleft = false; } 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 | *value* | New value of matrix point (0-1 float) */ 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.thisframe = 0; this.lastframe = 0; this.context.lineWidth = 1; this.sequencing = false; /** @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.init(); } util.inherits(matrix, widget); matrix.prototype.init = function() { this.lineWidth = 1; 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, st_y, boxwid, boxhgt); strokeRect(st_x, st_y, boxwid, boxhgt); // 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)); } /** @method stop Stops the matrix sequencer. ```js matrix1.stop(); ``` */ matrix.prototype.stop = function() { this.sequencing = false; } matrix.prototype.seqStep = function() { var now = new Date().getTime(); var dt = now - nx.starttime; this.thisframe = ~~(dt/(60000/this.bpm)); if (this.thisframe != this.lastframe) { 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.draw(); // var data = this.matrix[this.place] // data = data.join(); // data = data.replace(/\,/g," "); this.val.list = this.matrix[this.place]; this.transmit(this.val); } this.lastframe = this.thisframe; if (this.sequencing) { requestAnimationFrame(this.seqStep.bind(this)); } } matrix.prototype.customDestroy = function() { this.stop(); } },{"../core/widget":3,"../utils/drawing":5,"../utils/math":6,"util":40}],20:[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 = 12; } 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.accent; } else { fillStyle = this.colors.fill; } fillRect(0,0,this.width,this.height) if (this.clicked) { fillStyle = this.colors.white; } else { fillStyle = this.colors.black; } textAlign = "left"; font = this.size+"px courier"; } 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":40}],21:[function(require,module,exports){ var math = require('../utils/math') var util = require('util'); var widget = require('../core/widget'); /** @class metro Bouncing ball metronome ```html ``` */ 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":40}],22:[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 = 0.5; fillStyle = this.colors.white; textAlign = "center"; font = this.width/7+"px gill sans"; 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":40}],23:[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 } this.init(); } util.inherits(number, widget); number.prototype.init = function() { this.draw(); } number.prototype.draw = function() { this.erase(); with (this.context) { fillStyle = this.colors.fill; fillRect(0,0,this.width,this.height); fillStyle = this.colors.black; textAlign = "left"; font = this.height*.6+"px courier"; textBaseline = 'middle'; fillText(this.val.value, 10, this.height/2-1); } } number.prototype.move = function(e) { if (this.clicked) { this.val.value += (this.deltaMove.y*-.1); this.val.value = math.prune(this.val.value,1); this.draw(); this.transmit(this.val); } } },{"../core/widget":3,"../utils/math":6,"util":40}],26:[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) { this.defaultSize = { width: 150, height: 100 }; widget.call(this, target); /** @property {integer} nodeSize Size of touch node graphic. */ this.nodeSize = 15; /** @property {object} val |   | 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(); } util.inherits(position, widget); position.prototype.init = function() { this.nodeSize = Math.min(this.height,this.width)/10; this.actualWid = this.width - this.nodeSize*2; this.actualHgt = this.height - this.nodeSize*2; this.draw(); } position.prototype.draw = function() { this.erase(); with (this.context) { 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) { beginPath(); strokeStyle = this.colors.accent; lineWidth = 5; moveTo(0,this.height); lineTo(this.val.x*this.width,this.height); moveTo(0,this.height); lineTo(0,math.invert(this.val.y)*this.height); stroke(); closePath(); beginPath(); fillStyle = this.colors.accent; arc(drawingX, drawingY, this.nodeSize, 0, Math.PI*2, true); fill(); closePath(); } } this.drawLabel(); } 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); } 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(); } position.prototype.move = function() { if (this.clicked) { this.val.x = this.clickPos.x; this.val.y = this.clickPos.y; this.scaleNode(); this.val["state"] = "move" this.transmit(this.val); this.draw(); } } 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(); } /** @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 (math.bounce(this.val.y, 0, 1, this.deltaMove.y) != this.deltaMove.y) { this.deltaMove.y = math.bounce(this.val.y, 0, 1, this.deltaMove.y); 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":40}],27:[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); fillStyle = this.colors.accent; if (!this.hslider) { 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; fillRect(x1,y1,x2-x1,y2-y1); if (nx.showLabels) { save(); translate(this.width/2, 0); rotate(Math.PI/2); textAlign = "left"; textBaseline = "middle"; font = "bold 15px courier"; fillStyle = this.colors.accent; globalAlpha = 0.3; fillText(this.label, this.width/2, 0); globalAlpha = 1; restore(); } } else { var x1 = this.val.start*this.width; var y1 = 0; var x2 = this.val.stop*this.width; var y2 = this.height; fillRect(x1,y1,x2-x1,y2-y1); if (nx.showLabels) { textAlign = "center"; textBaseline = "middle"; font = "bold 15px courier"; fillStyle = this.colors.accent; globalAlpha = 0.3; fillText(this.label, this.width/2, this.height/2); globalAlpha = 1; } } } } 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 = 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":40}],28:[function(require,module,exports){ var math = require('../utils/math') var util = require('util'); var widget = require('../core/widget'); /** @class remix (alpha) ```html ``` */ var remix = module.exports = function(target) { this.defaultSize = { width: 400, height: 150 }; widget.call(this, target); //define unique attributes this.maxLength = 2000; this.components = new Array(); this.buffer = new Array(); this.moment = 0; this.val = { x: 0.15, y: 0.5 } this.rate = 1; this.start = 0; this.end = 1; this.size = 0; this.looping = false; this.boundLog = this.log.bind(this) this.init(); this.boundAdv = this.advance.bind(this); nx.aniItems.push(this.boundAdv) } util.inherits(remix, widget); remix.prototype.init = function() { this.draw(); } //sets a new component to be recorded remix.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 remix.prototype.write = function(index, val) { if (this.moment>=this.maxLength) { this.stop(); } for (var key in val) { if (this.buffer[index][key]) { this.buffer[index][key][this.moment] = val[key]; } } this.draw(); } remix.prototype.draw = function() { with (this.context) { fillStyle = this.colors.fill; fillRect(0,0,this.width,this.height) } if (this.moment>= 0) { var nodeWid = this.width / this.moment } else { var nodeWid = this.width; } var nodeDrawWid = 5; var nodeX = this.moment*nodeWid+this.lineWidth/2; var nodeY; if (!this.recording) { with (this.context) { strokeStyle = this.colors.accent; lineWidth = 1; for (var i=0;i **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(); } util.inherits(select, widget); select.prototype.init = function() { 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 parent = canv.parentNode; var newdiv = document.createElement("div"); newdiv.innerHTML = htmlstr; parent.replaceChild(newdiv,canv) this.canvas = document.getElementById(this.canvasID); 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.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); fillStyle = this.colors.accent; if (!this.hslider) { var x1 = 0; var y1 = this.height-this.val.value*this.height; var x2 = this.width; var y2 = this.height; if (this.val.value>0.01) { fillRect(x1,y1,x2-x1,y2-y1); } if (nx.showLabels) { save(); translate(this.width/2, 0); rotate(Math.PI/2); textAlign = "left"; textBaseline = "middle"; font = "bold 15px courier"; fillStyle = this.colors.accent; globalAlpha = 0.3; fillText(this.label, this.width/2, 0); globalAlpha = 1; restore(); } } else { var x1 = 0; var y1 = 0; var x2 = this.val.value*this.width; var y2 = this.height; if (this.val.value>0.01) { fillRect(x1,y1,x2-x1,y2-y1); } if (nx.showLabels) { textAlign = "center"; textBaseline = "middle"; font = "bold 15px courier"; fillStyle = this.colors.accent; globalAlpha = 0.3; fillText(this.label, this.width/2, this.height/2); globalAlpha = 1; } } } } 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":40}],31:[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 **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 gill sans"; 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":40}],33:[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); font = "bold "+this.fontsize+"px gill sans" textAlign = "center" if (this.val.value) { fillStyle = this.colors.white fillText("on", this.width/2, this.height/2 + this.fontsize/3.5 ); } else { globalAlpha = 0.6; fillStyle = this.colors.black fillText("off", this.width/2, this.height/2 + this.fontsize/3.5 ); 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":40}],34:[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: 175, height: 75 }; 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: 10, 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: 10, width: 1, on: false }, { symbol: ".", value: 10, width: 1, on: false }, { symbol: "/", value: 10, 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: "<", value: 37, width: .81, on: false }, { symbol: "^", value: 38, width: .81, on: false }, { symbol: "v", value: 39, width: .81, on: false }, { symbol: ">", value: 40, width: .81, on: false } ] ] this.boundType = this.type.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; /** @property {float} 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":40}],36:[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; } },{}],37:[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 } } },{}],38:[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'); }; },{}],39:[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'; } },{}],40:[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":39,"_process":38,"inherits":37}],41:[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]);