From 1d95ba978f96ef5d8d0fa5fc273c4ce35ec033ee Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 20 Feb 2018 20:42:20 -0500 Subject: [PATCH 001/155] auto version --- package.json | 4 +++- src/environments/version.ts | 14 ++++++++++++++ version.js | 24 ++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/environments/version.ts create mode 100644 version.js diff --git a/package.json b/package.json index 4e89542..4e4059d 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "build": "ng build", "test": "ng test", "lint": "ng lint", - "e2e": "ng e2e" + "e2e": "ng e2e", + "postinstall": "node version.js" }, "private": true, "dependencies": { @@ -27,6 +28,7 @@ "core-js": "^2.4.1", "d3": "^4.12.0", "font-awesome": "^4.7.0", + "git-describe": "^4.0.2", "gsap": "^1.20.3", "immutable": "^3.8.2", "interactjs": "^1.3.1", diff --git a/src/environments/version.ts b/src/environments/version.ts new file mode 100644 index 0000000..7604554 --- /dev/null +++ b/src/environments/version.ts @@ -0,0 +1,14 @@ +// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN! +/* tslint:disable */ +export const VERSION = { + "dirty": true, + "raw": "2d0d4ee-dirty", + "hash": "2d0d4ee", + "distance": null, + "tag": null, + "semver": null, + "suffix": "2d0d4ee-dirty", + "semverString": null, + "version": "1.0.0" +}; +/* tslint:enable */ diff --git a/version.js b/version.js new file mode 100644 index 0000000..265be02 --- /dev/null +++ b/version.js @@ -0,0 +1,24 @@ +const {gitDescribeSync} = require('git-describe'); +const {version} = require('./package.json'); +const {resolve,relative} = require('path'); + +const {writeFileSync} = require('fs-extra'); + +const gitInfo = gitDescribeSync({ + dirtyMark: false, + dirtySemver: false +}); + +gitInfo.version = version; + +const file = resolve(__dirname, './', 'src', 'environments', 'version.ts'); +writeFileSync(file, + `// IMPORTANT: THIS FILE IS AUTO GENERATED! DO NOT MANUALLY EDIT OR CHECKIN! +/* tslint:disable */ +export const VERSION = ${JSON.stringify(gitInfo, null, 4)}; +/* tslint:enable */ +`, { + encoding: 'utf-8' + }); + +console.log(`Wrote version info ${gitInfo.raw} to ${relative(resolve(__dirname, './'), file)}`); From 481de00c8ba31b5f5ed0822a869162234dbc2300 Mon Sep 17 00:00:00 2001 From: Steve Strong Date: Thu, 22 Feb 2018 21:02:31 -0500 Subject: [PATCH 002/155] with predraw --- src/app/foundry/shapes/foPath2D.model.ts | 70 +++++++++++++++++++----- src/app/foundry/shapes/foPathSVG.ts | 6 +- src/app/foundry/shapes/foText2D.model.ts | 26 ++------- 3 files changed, 66 insertions(+), 36 deletions(-) diff --git a/src/app/foundry/shapes/foPath2D.model.ts b/src/app/foundry/shapes/foPath2D.model.ts index 3ea8a15..0737a89 100644 --- a/src/app/foundry/shapes/foPath2D.model.ts +++ b/src/app/foundry/shapes/foPath2D.model.ts @@ -36,9 +36,23 @@ declare var Path2D: Path2DConstructor; export class foPath2D extends foShape2D { path: string; scale: number; + tx: number = 0; + ty: number = 0; + + symbol: Path2D; constructor(properties?: any, subcomponents?: Array, parent?: foObject) { super(properties, subcomponents, parent); + + this.setupPreDraw(); + } + + + protected toJson(): any { + return Tools.mixin(super.toJson(), { + path: this.path, + scale:this.scale, + }); } drawBox(ctx: CanvasRenderingContext2D) { @@ -47,30 +61,60 @@ export class foPath2D extends foShape2D { ctx.fill(p); } - public draw = (ctx: CanvasRenderingContext2D): void => { - let scale = this.scale ? this.scale : 1; + setupPreDraw() { - let data = this.path ? this.path : heart; - let [left, top, right, bottom] = PathSVG.pathBounds(data); - this.width = scale * (right - left); - this.height = scale * (bottom - top); + let preDraw = (ctx: CanvasRenderingContext2D): void => { + let scale = this.scale ? this.scale : 1; + let data = this.path ? this.path : heart; - this.drawBox(ctx); + let result = PathSVG.pathBounds(data); + this.symbol = new Path2D(result.normal); + + let [left, top, right, bottom] = result.bounds + this.width = scale * (right - left); + this.height = scale * (bottom - top); + + this.tx = -scale * left; + this.ty = -scale * top; - //https://github.com/jkroso/normalize-svg-path - let norm = PathSVG.convert(data); + //https://github.com/jkroso/normalize-svg-path + this.preDraw = undefined; + }; + + this.preDraw = preDraw; + } + + + public draw = (ctx: CanvasRenderingContext2D): void => { + let scale = this.scale ? this.scale : 1; + this.drawBox(ctx); - //console.log (left, top, right, bottom); ctx.save(); - ctx.translate(-scale * left, -scale * top); + ctx.translate(this.tx, this.ty); ctx.scale(scale, scale); ctx.fillStyle = this.color; - let path = new Path2D(norm); - ctx.fill(path); + + ctx.fill(this.symbol); ctx.restore(); } + public drawOutline(ctx: CanvasRenderingContext2D) { + ctx.beginPath() + ctx.setLineDash([15, 5]); + ctx.rect(0, 0, this.width, this.height); + ctx.stroke(); + } + + public drawSelected = (ctx: CanvasRenderingContext2D): void => { + ctx.strokeStyle = "red"; + ctx.lineWidth = 1; + this.drawOutline(ctx); + this.drawHandles(ctx); + //this.drawConnectionPoints(ctx); + this.drawPin(ctx); + } + } import { RuntimeType } from '../foRuntimeType'; diff --git a/src/app/foundry/shapes/foPathSVG.ts b/src/app/foundry/shapes/foPathSVG.ts index c4f72db..ea946e8 100644 --- a/src/app/foundry/shapes/foPathSVG.ts +++ b/src/app/foundry/shapes/foPathSVG.ts @@ -407,6 +407,7 @@ export class foPathSVG { let a = this.parse(path); let b = this.absolutize(a); let c = this.normalize(b); + let normal = c.map(seg => seg.join(' ')).join(''); var bounds = [Infinity, Infinity, -Infinity, -Infinity] @@ -421,7 +422,10 @@ export class foPathSVG { } } - return bounds + return { + normal, + bounds + } } } diff --git a/src/app/foundry/shapes/foText2D.model.ts b/src/app/foundry/shapes/foText2D.model.ts index 103d766..85e00ae 100644 --- a/src/app/foundry/shapes/foText2D.model.ts +++ b/src/app/foundry/shapes/foText2D.model.ts @@ -51,13 +51,13 @@ export class foText2D extends foShape2D { protected toJson(): any { return Tools.mixin(super.toJson(), { text: this.text, - background:this.background, - fontSize:this.fontSize, - margin:this.margin + background: this.background, + fontSize: this.fontSize, + margin: this.margin }); } - get size():number { + get size(): number { return (this.fontSize || 12); } @@ -82,25 +82,7 @@ export class foText2D extends foShape2D { this.preDraw = preDraw; } - public render(ctx: CanvasRenderingContext2D, deep: boolean = true) { - ctx.save(); - - //this.drawOrigin(ctx); - this.updateContext(ctx); - //this.drawOriginX(ctx); - - this.preDraw && this.preDraw(ctx); - this.draw(ctx); - this.drawHover && this.drawHover(ctx); - this.postDraw && this.postDraw(ctx); - - this.isSelected && this.drawSelected(ctx); - deep && this._subcomponents.forEach(item => { - item.render(ctx, deep); - }); - ctx.restore(); - } public drawOutline(ctx: CanvasRenderingContext2D) { ctx.beginPath() From 5842f426220bf59a25292ffa0e011b2d1f1544f0 Mon Sep 17 00:00:00 2001 From: Steve Strong Date: Thu, 22 Feb 2018 21:05:52 -0500 Subject: [PATCH 003/155] save it --- src/app/foundry/shapes/foPath2D.model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/foundry/shapes/foPath2D.model.ts b/src/app/foundry/shapes/foPath2D.model.ts index 0737a89..8e1cb1b 100644 --- a/src/app/foundry/shapes/foPath2D.model.ts +++ b/src/app/foundry/shapes/foPath2D.model.ts @@ -88,7 +88,7 @@ export class foPath2D extends foShape2D { public draw = (ctx: CanvasRenderingContext2D): void => { let scale = this.scale ? this.scale : 1; - this.drawBox(ctx); + //this.drawBox(ctx); ctx.save(); ctx.translate(this.tx, this.ty); From 3508136231a1ba784f0fc0bf9544a64565e50231 Mon Sep 17 00:00:00 2001 From: Steve Strong Date: Sun, 11 Mar 2018 06:42:12 -0400 Subject: [PATCH 004/155] added svg --- src/app/canvas/devsecops.model.ts | 8 ++++++++ src/app/foundry/shapes/foPath2D.model.ts | 7 +++++-- src/assets/svg/drawn scorpion.svg | 1 + src/assets/svg/font curlies.svg | 1 + src/assets/svg/left curlie.svg | 1 + src/assets/svg/person filled.svg | 1 + src/assets/svg/right curlie.svg | 1 + src/assets/svg/two curlies.svg | 1 + 8 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 src/assets/svg/drawn scorpion.svg create mode 100644 src/assets/svg/font curlies.svg create mode 100644 src/assets/svg/left curlie.svg create mode 100644 src/assets/svg/person filled.svg create mode 100644 src/assets/svg/right curlie.svg create mode 100644 src/assets/svg/two curlies.svg diff --git a/src/app/canvas/devsecops.model.ts b/src/app/canvas/devsecops.model.ts index 7533618..3886f3c 100644 --- a/src/app/canvas/devsecops.model.ts +++ b/src/app/canvas/devsecops.model.ts @@ -71,6 +71,14 @@ DevSecOpsShapes.define('rocket', foPath2D, { }).mixin(core); +DevSecOpsShapes.define('body', foPath2D, { + path: "M13.38,201.93a101.41,101.41,0,0,1,2-19.62,99.45,99.45,0,0,1,27-50.85,96.1,96.1,0,0,1,21.5-16.3c1.32-.74,2-.19,2.86.56a64,64,0,0,0,82.22.46l2-1.62c34.2,17.57,52.4,55.17,51.68,87.36Z", +}).mixin(core); + +DevSecOpsShapes.define('head', foPath2D, { + path: "M55.62,66.49c-.22-28.7,23.73-52.88,53.65-52.41,28,.44,51.48,24.15,51.41,52.53a52.53,52.53,0,1,1-105.06-.13Z", +}).mixin(core); + class shapeUI extends shapeDevOps { drawTriangle(ctx: CanvasRenderingContext2D, x1, y1, x2, y2, x3, y3) { diff --git a/src/app/foundry/shapes/foPath2D.model.ts b/src/app/foundry/shapes/foPath2D.model.ts index 8e1cb1b..4908c69 100644 --- a/src/app/foundry/shapes/foPath2D.model.ts +++ b/src/app/foundry/shapes/foPath2D.model.ts @@ -20,6 +20,9 @@ let star = "M 262.6 182.4 C 261.7 179.7 259.3 177.7 256.4 177.2 C 245.3 175.7 23 let rocket = "M 201.2 222.1 C 210 216.5 218.6 210.1 225.7 203 C 249.9 178.8 252.6 157.5 250.1 149.9 C 253.7 146.3 257.3 142.7 260.9 139.1 C 261.9 138.1 261.9 136.5 260.9 135.5 C 259.9 134.5 258.3 134.5 257.3 135.5 C 253.7 139.1 250.1 142.7 246.5 146.3 C 238.9 143.8 217.6 146.5 193.4 170.7 C 186.3 177.8 179.9 186.4 174.3 195.2 C 166.2 193.2 152.1 193.2 142.3 204.1 C 131.1 216.4 137.7 228.1 140.2 225.7 C 142.2 223.6 145.6 211.3 160.4 220.8 C 158 225.8 158.1 228.9 159.7 230.4 C 161.8 232.5 163.9 234.6 166 236.7 C 167.6 238.3 170.6 238.5 175.7 236 C 185.1 250.8 172.8 254.2 170.8 256.3 C 168.3 258.7 180 265.3 192.3 254.1 C 203.2 244.3 203.2 230.2 201.2 222.1M 216.5 179.9 C 212.9 176.3 212.9 170.3 216.5 166.7 C 220.2 163 226.1 163 229.7 166.7 C 233.4 170.4 233.4 176.2 229.7 179.9 C 226.1 183.5 220.2 183.5 216.5 179.9M 156.4 233.5 C 156.4 233.5 146.4 235.3 142.7 253.7 C 161.1 250.1 162.9 240 162.9 240 C 160.8 237.8 158.6 235.7 156.4 233.5z"; +let body = "M13.38,201.93a101.41,101.41,0,0,1,2-19.62,99.45,99.45,0,0,1,27-50.85,96.1,96.1,0,0,1,21.5-16.3c1.32-.74,2-.19,2.86.56a64,64,0,0,0,82.22.46l2-1.62c34.2,17.57,52.4,55.17,51.68,87.36Z"; +let head = "M55.62,66.49c-.22-28.7,23.73-52.88,53.65-52.41,28,.44,51.48,24.15,51.41,52.53a52.53,52.53,0,1,1-105.06-.13Z"; + //https://codepen.io/osublake/pen/pRNYRM @@ -47,11 +50,11 @@ export class foPath2D extends foShape2D { this.setupPreDraw(); } - + protected toJson(): any { return Tools.mixin(super.toJson(), { path: this.path, - scale:this.scale, + scale: this.scale, }); } diff --git a/src/assets/svg/drawn scorpion.svg b/src/assets/svg/drawn scorpion.svg new file mode 100644 index 0000000..183d5a7 --- /dev/null +++ b/src/assets/svg/drawn scorpion.svg @@ -0,0 +1 @@ +drawn scorpion \ No newline at end of file diff --git a/src/assets/svg/font curlies.svg b/src/assets/svg/font curlies.svg new file mode 100644 index 0000000..cf03d5b --- /dev/null +++ b/src/assets/svg/font curlies.svg @@ -0,0 +1 @@ +font curlies{ } \ No newline at end of file diff --git a/src/assets/svg/left curlie.svg b/src/assets/svg/left curlie.svg new file mode 100644 index 0000000..ce1b14c --- /dev/null +++ b/src/assets/svg/left curlie.svg @@ -0,0 +1 @@ +left curlie \ No newline at end of file diff --git a/src/assets/svg/person filled.svg b/src/assets/svg/person filled.svg new file mode 100644 index 0000000..3cc7438 --- /dev/null +++ b/src/assets/svg/person filled.svg @@ -0,0 +1 @@ +person filled \ No newline at end of file diff --git a/src/assets/svg/right curlie.svg b/src/assets/svg/right curlie.svg new file mode 100644 index 0000000..d473c58 --- /dev/null +++ b/src/assets/svg/right curlie.svg @@ -0,0 +1 @@ +right curlie \ No newline at end of file diff --git a/src/assets/svg/two curlies.svg b/src/assets/svg/two curlies.svg new file mode 100644 index 0000000..817927b --- /dev/null +++ b/src/assets/svg/two curlies.svg @@ -0,0 +1 @@ +two curlies \ No newline at end of file From 3ed104394d5b880a7fe84a0de10ca218240222a3 Mon Sep 17 00:00:00 2001 From: Steve Strong Date: Sun, 11 Mar 2018 07:44:22 -0400 Subject: [PATCH 005/155] editable text --- src/app/canvas/devsecops.model.ts | 11 +- src/app/foundry/shapes/foText2D.model.ts | 4 + src/app/foundryDrivers/canvasInput.js | 1475 ++++++++++++++++++++++ wa-games-pdf.pdf | Bin 0 -> 335477 bytes 4 files changed, 1489 insertions(+), 1 deletion(-) create mode 100644 src/app/foundryDrivers/canvasInput.js create mode 100644 wa-games-pdf.pdf diff --git a/src/app/canvas/devsecops.model.ts b/src/app/canvas/devsecops.model.ts index 3886f3c..f0f3b07 100644 --- a/src/app/canvas/devsecops.model.ts +++ b/src/app/canvas/devsecops.model.ts @@ -5,8 +5,10 @@ import { foWorkspace } from "../foundry/foWorkspace.model"; import { foComponent } from "../foundry/foComponent.model"; import { foModel } from "../foundry/foModel.model"; import { foImage2D } from "../foundry/shapes/foImage2D.model"; +import { foText2D, foInputText2D } from "../foundry/shapes/foText2D.model"; +import { foShape2D } from "../foundry/shapes/foShape2D.model"; import { foShape3D } from "../foundry/solids/foShape3D.model"; -import { foShape2D } from "./particle.model"; +//import { foShape2D } from "./particle.model"; import { iPoint2D } from '../foundry/foInterface'; import { foGlyph2D } from '../foundry/shapes/foGlyph2D.model'; @@ -27,6 +29,11 @@ DevSecOps.context.define('DevOpsFactory', foModel, { subtitle: 'Strutured Flexability' }) +DevSecOpsShapes.define('Text', foInputText2D, { + text: 'Understand DevSecOps', + fontSize:30, +}); + DevSecOpsShapes.define('Image', foImage2D, { background: 'green', imageURL: "https://lorempixel.com/900/500?r=2", @@ -182,6 +189,8 @@ DevSecOpsShapes.define('Data', shapeData, { }).mixin(core); + + class shapeApp extends shapeDevOps { } diff --git a/src/app/foundry/shapes/foText2D.model.ts b/src/app/foundry/shapes/foText2D.model.ts index 85e00ae..85f804f 100644 --- a/src/app/foundry/shapes/foText2D.model.ts +++ b/src/app/foundry/shapes/foText2D.model.ts @@ -193,5 +193,9 @@ export class foText2D extends foShape2D { // } } +export class foInputText2D extends foText2D { +} + import { RuntimeType } from '../foRuntimeType'; RuntimeType.define(foText2D); +RuntimeType.define(foInputText2D); diff --git a/src/app/foundryDrivers/canvasInput.js b/src/app/foundryDrivers/canvasInput.js new file mode 100644 index 0000000..36f1020 --- /dev/null +++ b/src/app/foundryDrivers/canvasInput.js @@ -0,0 +1,1475 @@ +/*! + * CanvasInput v1.2.7 + * http://goldfirestudios.com/blog/108/CanvasInput-HTML5-Canvas-Text-Input + * + * (c) 2013-2017, James Simpson of GoldFire Studios + * goldfirestudios.com + * + * MIT License + */ + +(function() { + // create a buffer that stores all inputs so that tabbing + // between them is made possible. + var inputs = []; + + // initialize the Canvas Input + var CanvasInput = window.CanvasInput = function(o) { + var self = this; + + o = o ? o : {}; + + // setup the defaults + self._canvas = o.canvas || null; + self._ctx = self._canvas ? self._canvas.getContext('2d') : null; + self._x = o.x || 0; + self._y = o.y || 0; + self._extraX = o.extraX || 0; + self._extraY = o.extraY || 0; + self._fontSize = o.fontSize || 14; + self._fontFamily = o.fontFamily || 'Arial'; + self._fontColor = o.fontColor || '#000'; + self._placeHolderColor = o.placeHolderColor || '#bfbebd'; + self._fontWeight = o.fontWeight || 'normal'; + self._fontStyle = o.fontStyle || 'normal'; + self._fontShadowColor = o.fontShadowColor || ''; + self._fontShadowBlur = o.fontShadowBlur || 0; + self._fontShadowOffsetX = o.fontShadowOffsetX || 0; + self._fontShadowOffsetY = o.fontShadowOffsetY || 0; + self._readonly = o.readonly || false; + self._maxlength = o.maxlength || null; + self._width = o.width || 150; + self._height = o.height || self._fontSize; + self._padding = o.padding >= 0 ? o.padding : 5; + self._borderWidth = o.borderWidth >= 0 ? o.borderWidth : 1; + self._borderColor = o.borderColor || '#959595'; + self._borderRadius = o.borderRadius >= 0 ? o.borderRadius : 3; + self._backgroundImage = o.backgroundImage || ''; + self._boxShadow = o.boxShadow || '1px 1px 0px rgba(255, 255, 255, 1)'; + self._innerShadow = o.innerShadow || '0px 0px 4px rgba(0, 0, 0, 0.4)'; + self._selectionColor = o.selectionColor || 'rgba(179, 212, 253, 0.8)'; + self._placeHolder = o.placeHolder || ''; + self._value = (o.value || self._placeHolder) + ''; + self._onsubmit = o.onsubmit || function() {}; + self._onkeydown = o.onkeydown || function() {}; + self._onkeyup = o.onkeyup || function() {}; + self._onfocus = o.onfocus || function() {}; + self._onblur = o.onblur || function() {}; + self._cursor = false; + self._cursorPos = 0; + self._hasFocus = false; + self._selection = [0, 0]; + self._wasOver = false; + + // parse box shadow + self.boxShadow(self._boxShadow, true); + + // calculate the full width and height with padding, borders and shadows + self._calcWH(); + + // setup the off-DOM canvas + self._renderCanvas = document.createElement('canvas'); + self._renderCanvas.setAttribute('width', self.outerW); + self._renderCanvas.setAttribute('height', self.outerH); + self._renderCtx = self._renderCanvas.getContext('2d'); + + // setup another off-DOM canvas for inner-shadows + self._shadowCanvas = document.createElement('canvas'); + self._shadowCanvas.setAttribute('width', self._width + self._padding * 2); + self._shadowCanvas.setAttribute('height', self._height + self._padding * 2); + self._shadowCtx = self._shadowCanvas.getContext('2d'); + + // setup the background color + if (typeof o.backgroundGradient !== 'undefined') { + self._backgroundColor = self._renderCtx.createLinearGradient( + 0, + 0, + 0, + self.outerH + ); + self._backgroundColor.addColorStop(0, o.backgroundGradient[0]); + self._backgroundColor.addColorStop(1, o.backgroundGradient[1]); + } else { + self._backgroundColor = o.backgroundColor || '#fff'; + } + + // setup main canvas events + if (self._canvas) { + self._canvas.addEventListener('mousemove', function(e) { + e = e || window.event; + self.mousemove(e, self); + }, false); + + self._canvas.addEventListener('mousedown', function(e) { + e = e || window.event; + self.mousedown(e, self); + }, false); + + self._canvas.addEventListener('mouseup', function(e) { + e = e || window.event; + self.mouseup(e, self); + }, false); + } + + // setup a global mouseup to blur the input outside of the canvas + var autoBlur = function(e) { + e = e || window.event; + + if (self._hasFocus && !self._mouseDown) { + self.blur(); + } + }; + window.addEventListener('mouseup', autoBlur, true); + window.addEventListener('touchend', autoBlur, true); + + // create the hidden input element + self._hiddenInput = document.createElement('input'); + self._hiddenInput.type = 'text'; + self._hiddenInput.style.position = 'absolute'; + self._hiddenInput.style.opacity = 0; + self._hiddenInput.style.pointerEvents = 'none'; + self._hiddenInput.style.zIndex = 0; + // hide native blue text cursor on iOS + self._hiddenInput.style.transform = 'scale(0)'; + + self._updateHiddenInput(); + if (self._maxlength) { + self._hiddenInput.maxLength = self._maxlength; + } + document.body.appendChild(self._hiddenInput); + self._hiddenInput.value = self._value; + + // setup the keydown listener + self._hiddenInput.addEventListener('keydown', function(e) { + e = e || window.event; + + if (self._hasFocus) { + // hack to fix touch event bug in iOS Safari + window.focus(); + self._hiddenInput.focus(); + + // continue with the keydown event + self.keydown(e, self); + } + }); + + // setup the keyup listener + self._hiddenInput.addEventListener('keyup', function(e) { + e = e || window.event; + + // update the canvas input state information from the hidden input + self._value = self._hiddenInput.value; + self._cursorPos = self._hiddenInput.selectionStart; + // update selection to hidden input's selection in case user did keyboard-based selection + self._selection = [self._hiddenInput.selectionStart, self._hiddenInput.selectionEnd]; + self.render(); + + if (self._hasFocus) { + self._onkeyup(e, self); + } + }); + + // add this to the buffer + inputs.push(self); + self._inputsIndex = inputs.length - 1; + + // draw the text box + self.render(); + }; + + // setup the prototype + CanvasInput.prototype = { + /** + * Get/set the main canvas. + * @param {Object} data Canvas reference. + * @return {Mixed} CanvasInput or current canvas. + */ + canvas: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._canvas = data; + self._ctx = self._canvas.getContext('2d'); + + return self.render(); + } else { + return self._canvas; + } + }, + + /** + * Get/set the x-position. + * @param {Number} data The pixel position along the x-coordinate. + * @return {Mixed} CanvasInput or current x-value. + */ + x: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._x = data; + self._updateHiddenInput(); + + return self.render(); + } else { + return self._x; + } + }, + + /** + * Get/set the y-position. + * @param {Number} data The pixel position along the y-coordinate. + * @return {Mixed} CanvasInput or current y-value. + */ + y: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._y = data; + self._updateHiddenInput(); + + return self.render(); + } else { + return self._y; + } + }, + + /** + * Get/set the extra x-position (generally used when no canvas is specified). + * @param {Number} data The pixel position along the x-coordinate. + * @return {Mixed} CanvasInput or current x-value. + */ + extraX: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._extraX = data; + self._updateHiddenInput(); + + return self.render(); + } else { + return self._extraX; + } + }, + + /** + * Get/set the extra y-position (generally used when no canvas is specified). + * @param {Number} data The pixel position along the y-coordinate. + * @return {Mixed} CanvasInput or current y-value. + */ + extraY: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._extraY = data; + self._updateHiddenInput(); + + return self.render(); + } else { + return self._extraY; + } + }, + + /** + * Get/set the font size. + * @param {Number} data Font size. + * @return {Mixed} CanvasInput or current font size. + */ + fontSize: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontSize = data; + + return self.render(); + } else { + return self._fontSize; + } + }, + + /** + * Get/set the font family. + * @param {String} data Font family. + * @return {Mixed} CanvasInput or current font family. + */ + fontFamily: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontFamily = data; + + return self.render(); + } else { + return self._fontFamily; + } + }, + + /** + * Get/set the font color. + * @param {String} data Font color. + * @return {Mixed} CanvasInput or current font color. + */ + fontColor: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontColor = data; + + return self.render(); + } else { + return self._fontColor; + } + }, + + /** + * Get/set the place holder font color. + * @param {String} data Font color. + * @return {Mixed} CanvasInput or current place holder font color. + */ + placeHolderColor: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._placeHolderColor = data; + + return self.render(); + } else { + return self._placeHolderColor; + } + }, + + /** + * Get/set the font weight. + * @param {String} data Font weight. + * @return {Mixed} CanvasInput or current font weight. + */ + fontWeight: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontWeight = data; + + return self.render(); + } else { + return self._fontWeight; + } + }, + + /** + * Get/set the font style. + * @param {String} data Font style. + * @return {Mixed} CanvasInput or current font style. + */ + fontStyle: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontStyle = data; + + return self.render(); + } else { + return self._fontStyle; + } + }, + + /** + * Get/set the font shadow color. + * @param {String} data Font shadow color. + * @return {Mixed} CanvasInput or current font shadow color. + */ + fontShadowColor: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontShadowColor = data; + + return self.render(); + } else { + return self._fontShadowColor; + } + }, + + /** + * Get/set the font shadow blur. + * @param {String} data Font shadow blur. + * @return {Mixed} CanvasInput or current font shadow blur. + */ + fontShadowBlur: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontShadowBlur = data; + + return self.render(); + } else { + return self._fontShadowBlur; + } + }, + + /** + * Get/set the font shadow x-offset. + * @param {String} data Font shadow x-offset. + * @return {Mixed} CanvasInput or current font shadow x-offset. + */ + fontShadowOffsetX: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontShadowOffsetX = data; + + return self.render(); + } else { + return self._fontShadowOffsetX; + } + }, + + /** + * Get/set the font shadow y-offset. + * @param {String} data Font shadow y-offset. + * @return {Mixed} CanvasInput or current font shadow y-offset. + */ + fontShadowOffsetY: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._fontShadowOffsetY = data; + + return self.render(); + } else { + return self._fontShadowOffsetY; + } + }, + + /** + * Get/set the width of the text box. + * @param {Number} data Width in pixels. + * @return {Mixed} CanvasInput or current width. + */ + width: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._width = data; + self._calcWH(); + self._updateCanvasWH(); + self._updateHiddenInput(); + + return self.render(); + } else { + return self._width; + } + }, + + /** + * Get/set the height of the text box. + * @param {Number} data Height in pixels. + * @return {Mixed} CanvasInput or current height. + */ + height: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._height = data; + self._calcWH(); + self._updateCanvasWH(); + self._updateHiddenInput(); + + return self.render(); + } else { + return self._height; + } + }, + + /** + * Get/set the padding of the text box. + * @param {Number} data Padding in pixels. + * @return {Mixed} CanvasInput or current padding. + */ + padding: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._padding = data; + self._calcWH(); + self._updateCanvasWH(); + + return self.render(); + } else { + return self._padding; + } + }, + + /** + * Get/set the border width. + * @param {Number} data Border width. + * @return {Mixed} CanvasInput or current border width. + */ + borderWidth: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._borderWidth = data; + self._calcWH(); + self._updateCanvasWH(); + + return self.render(); + } else { + return self._borderWidth; + } + }, + + /** + * Get/set the border color. + * @param {String} data Border color. + * @return {Mixed} CanvasInput or current border color. + */ + borderColor: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._borderColor = data; + + return self.render(); + } else { + return self._borderColor; + } + }, + + /** + * Get/set the border radius. + * @param {Number} data Border radius. + * @return {Mixed} CanvasInput or current border radius. + */ + borderRadius: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._borderRadius = data; + + return self.render(); + } else { + return self._borderRadius; + } + }, + + /** + * Get/set the background color. + * @param {Number} data Background color. + * @return {Mixed} CanvasInput or current background color. + */ + backgroundColor: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._backgroundColor = data; + + return self.render(); + } else { + return self._backgroundColor; + } + }, + + /** + * Get/set the background gradient. + * @param {Number} data Background gradient. + * @return {Mixed} CanvasInput or current background gradient. + */ + backgroundGradient: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._backgroundColor = self._renderCtx.createLinearGradient( + 0, + 0, + 0, + self.outerH + ); + self._backgroundColor.addColorStop(0, data[0]); + self._backgroundColor.addColorStop(1, data[1]); + + return self.render(); + } else { + return self._backgroundColor; + } + }, + + /** + * Get/set the box shadow. + * @param {String} data Box shadow in CSS format (1px 1px 1px rgba(0, 0, 0.5)). + * @param {Boolean} doReturn (optional) True to prevent a premature render. + * @return {Mixed} CanvasInput or current box shadow. + */ + boxShadow: function(data, doReturn) { + var self = this; + + if (typeof data !== 'undefined') { + // parse box shadow + var boxShadow = data.split('px '); + self._boxShadow = { + x: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[0], 10), + y: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[1], 10), + blur: self._boxShadow === 'none' ? 0 : parseInt(boxShadow[2], 10), + color: self._boxShadow === 'none' ? '' : boxShadow[3] + }; + + // take into account the shadow and its direction + if (self._boxShadow.x < 0) { + self.shadowL = Math.abs(self._boxShadow.x) + self._boxShadow.blur; + self.shadowR = self._boxShadow.blur + self._boxShadow.x; + } else { + self.shadowL = Math.abs(self._boxShadow.blur - self._boxShadow.x); + self.shadowR = self._boxShadow.blur + self._boxShadow.x; + } + if (self._boxShadow.y < 0) { + self.shadowT = Math.abs(self._boxShadow.y) + self._boxShadow.blur; + self.shadowB = self._boxShadow.blur + self._boxShadow.y; + } else { + self.shadowT = Math.abs(self._boxShadow.blur - self._boxShadow.y); + self.shadowB = self._boxShadow.blur + self._boxShadow.y; + } + + self.shadowW = self.shadowL + self.shadowR; + self.shadowH = self.shadowT + self.shadowB; + + self._calcWH(); + + if (!doReturn) { + self._updateCanvasWH(); + + return self.render(); + } + } else { + return self._boxShadow; + } + }, + + /** + * Get/set the inner shadow. + * @param {String} data In the format of a CSS box shadow (1px 1px 1px rgba(0, 0, 0.5)). + * @return {Mixed} CanvasInput or current inner shadow. + */ + innerShadow: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._innerShadow = data; + + return self.render(); + } else { + return self._innerShadow; + } + }, + + /** + * Get/set the text selection color. + * @param {String} data Color. + * @return {Mixed} CanvasInput or current selection color. + */ + selectionColor: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._selectionColor = data; + + return self.render(); + } else { + return self._selectionColor; + } + }, + + /** + * Get/set the place holder text. + * @param {String} data Place holder text. + * @return {Mixed} CanvasInput or current place holder text. + */ + placeHolder: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._placeHolder = data; + + return self.render(); + } else { + return self._placeHolder; + } + }, + + /** + * Get/set the current text box value. + * @param {String} data Text value. + * @return {Mixed} CanvasInput or current text value. + */ + value: function(data) { + var self = this; + + if (typeof data !== 'undefined') { + self._value = data + ''; + self._hiddenInput.value = data + ''; + + // update the cursor position + self._cursorPos = self._clipText().length; + + self.render(); + + return self; + } else { + return (self._value === self._placeHolder) ? '' : self._value; + } + }, + + /** + * Set or fire the onsubmit event. + * @param {Function} fn Custom callback. + */ + onsubmit: function(fn) { + var self = this; + + if (typeof fn !== 'undefined') { + self._onsubmit = fn; + + return self; + } else { + self._onsubmit(); + } + }, + + /** + * Set or fire the onkeydown event. + * @param {Function} fn Custom callback. + */ + onkeydown: function(fn) { + var self = this; + + if (typeof fn !== 'undefined') { + self._onkeydown = fn; + + return self; + } else { + self._onkeydown(); + } + }, + + /** + * Set or fire the onkeyup event. + * @param {Function} fn Custom callback. + */ + onkeyup: function(fn) { + var self = this; + + if (typeof fn !== 'undefined') { + self._onkeyup = fn; + + return self; + } else { + self._onkeyup(); + } + }, + + /** + * Place focus on the CanvasInput box, placing the cursor + * either at the end of the text or where the user clicked. + * @param {Number} pos (optional) The position to place the cursor. + * @return {CanvasInput} + */ + focus: function(pos) { + var self = this; + + // only fire the focus event when going from unfocussed + if (!self._hasFocus) { + self._onfocus(self); + + // remove focus from all other inputs + for (var i=0; i