diff options
| author | Jules Laplace <jules@okfoc.us> | 2013-03-03 17:50:39 -0500 |
|---|---|---|
| committer | Jules Laplace <jules@okfoc.us> | 2013-03-03 17:50:39 -0500 |
| commit | 7b5362f5edcc9ddb91b0a5224ff107d57e12902a (patch) | |
| tree | 9efad43c1951c437ec6afa58e140b4c0e419dacd /public | |
| parent | c506e9a524084951a9164eb99b3038fe0131045b (diff) | |
canvasquery
Diffstat (limited to 'public')
| -rw-r--r-- | public/js/canvasquery.js | 1599 | ||||
| -rw-r--r-- | public/js/canvasquery.min.js | 51 | ||||
| -rw-r--r-- | public/js/draw.js | 23 |
3 files changed, 1668 insertions, 5 deletions
diff --git a/public/js/canvasquery.js b/public/js/canvasquery.js new file mode 100644 index 0000000..70257ea --- /dev/null +++ b/public/js/canvasquery.js @@ -0,0 +1,1599 @@ +/* + Canvas Query 0.8.1 + http://canvasquery.org + (c) 2012-2013 http://rezoner.net + Canvas Query may be freely distributed under the MIT license. +*/ + +(function(window, undefined) { + + var MOBILE = /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent); + + + window.requestAnimationFrame = (function() { + return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || + function(callback) { + window.setTimeout(callback, 1000 / 60); + }; + })(); + + + var $ = function(selector) { + if(arguments.length === 0) { + var canvas = $.createCanvas(window.innerWidth, window.innerHeight); + window.addEventListener("resize", function() { + // canvas.width = window.innerWidth; + // canvas.height = window.innerHeight; + }); + } else if(typeof selector === "string") { + var canvas = document.querySelector(selector); + } else if(typeof selector === "number") { + var canvas = $.createCanvas(arguments[0], arguments[1]); + } else if(selector instanceof Image || selector instanceof HTMLImageElement) { + var canvas = $.createCanvas(selector); + } else if(selector instanceof $.Wrapper) { + return selector; + } else { + var canvas = selector; + } + + return new $.Wrapper(canvas); + } + + $.extend = function() { + for(var i = 1; i < arguments.length; i++) { + for(var j in arguments[i]) { + arguments[0][j] = arguments[i][j]; + } + } + + return arguments[0]; + } + + $.augment = function() { + for(var i = 1; i < arguments.length; i++) { + _.extend(arguments[0], arguments[i]); + arguments[i](arguments[0]); + } + } + + $.extend($, { + + keycodes: { + 37: "left", + 38: "up", + 39: "right", + 40: "down", + 45: "insert", + 46: "delete", + 8: "backspace", + 9: "tab", + 13: "enter", + 16: "shift", + 17: "ctrl", + 18: "alt", + 19: "pause", + 20: "capslock", + 27: "escape", + 32: "space", + 33: "pageup", + 34: "pagedown", + 35: "end", + 112: "f1", + 113: "f2", + 114: "f3", + 115: "f4", + 116: "f5", + 117: "f6", + 118: "f7", + 119: "f8", + 120: "f9", + 121: "f10", + 122: "f11", + 123: "f12", + 144: "numlock", + 145: "scrolllock", + 186: "semicolon", + 187: "equal", + 188: "comma", + 189: "dash", + 190: "period", + 191: "slash", + 192: "graveaccent", + 219: "openbracket", + 220: "backslash", + 221: "closebraket", + 222: "singlequote" + }, + + cleanArray: function(array, property) { + + var lastArgument = arguments[arguments.length - 1]; + var isLastArgumentFunction = typeof lastArgument === "function"; + + for(var i = 0, len = array.length; i < len; i++) { + if(array[i] === null || (property && array[i][property])) { + if(isLastArgumentFunction) { + lastArgument(array[i]); + } + array.splice(i--, 1); + len--; + } + } + }, + + specialBlendFunctions: ["color", "value", "hue", "saturation"], + + blendFunctions: { + normal: function(a, b) { + return b; + }, + + overlay: function(a, b) { + a /= 255; + b /= 255; + var result = 0; + + if(a < 0.5) result = 2 * a * b; + else result = 1 - 2 * (1 - a) * (1 - b); + + return Math.min(255, Math.max(0, result * 255 | 0)); + }, + + hardLight: function(a, b) { + return $.blendFunctions.overlay(b, a); + }, + + softLight: function(a, b) { + a /= 255; + b /= 255; + + var v = (1 - 2 * b) * (a * a) + 2 * b * a; + return $.limitValue(v * 255, 0, 255); + }, + + dodge: function(a, b) { + return Math.min(256 * a / (255 - b + 1), 255); + }, + + burn: function(a, b) { + return 255 - Math.min(256 * (255 - a) / (b + 1), 255); + }, + + multiply: function(a, b) { + return b * a / 255; + }, + + divide: function(a, b) { + return Math.min(256 * a / (b + 1), 255); + }, + + screen: function(a, b) { + return 255 - (255 - b) * (255 - a) / 255; + }, + + grainExtract: function(a, b) { + return $.limitValue(a - b + 128, 0, 255); + }, + + grainMerge: function(a, b) { + return $.limitValue(a + b - 128, 0, 255); + }, + + difference: function(a, b) { + return Math.abs(a - b); + }, + + addition: function(a, b) { + return Math.min(a + b, 255); + }, + + substract: function(a, b) { + return Math.max(a - b, 0); + }, + + darkenOnly: function(a, b) { + return Math.min(a, b); + }, + + lightenOnly: function(a, b) { + return Math.max(a, b); + }, + + color: function(a, b) { + var aHSL = $.rgbToHsl(a); + var bHSL = $.rgbToHsl(b); + + return $.hslToRgb(bHSL[0], bHSL[1], aHSL[2]); + }, + + hue: function(a, b) { + var aHSV = $.rgbToHsv(a); + var bHSV = $.rgbToHsv(b); + + if(!bHSV[1]) return $.hsvToRgb(aHSV[0], aHSV[1], aHSV[2]); + else return $.hsvToRgb(bHSV[0], aHSV[1], aHSV[2]); + }, + + value: function(a, b) { + var aHSV = $.rgbToHsv(a); + var bHSV = $.rgbToHsv(b); + + return $.hsvToRgb(aHSV[0], aHSV[1], bHSV[2]); + }, + + saturation: function(a, b) { + var aHSV = $.rgbToHsv(a); + var bHSV = $.rgbToHsv(b); + + return $.hsvToRgb(aHSV[0], bHSV[1], aHSV[2]); + } + }, + + blend: function(below, above, mode, mix) { + if(typeof mix === "undefined") mix = 1; + + var below = $(below); + var above = $(above); + + var belowCtx = below.context; + var aboveCtx = above.context; + + var belowData = belowCtx.getImageData(0, 0, below.canvas.width, below.canvas.height); + var aboveData = aboveCtx.getImageData(0, 0, above.canvas.width, above.canvas.height); + + var belowPixels = belowData.data; + var abovePixels = aboveData.data; + + var imageData = this.createImageData(below.canvas.width, below.canvas.height); + var pixels = imageData.data; + + var blendingFunction = $.blendFunctions[mode]; + + if($.specialBlendFunctions.indexOf(mode) !== -1) { + for(var i = 0, len = belowPixels.length; i < len; i += 4) { + var rgb = blendingFunction([belowPixels[i + 0], belowPixels[i + 1], belowPixels[i + 2]], [abovePixels[i + 0], abovePixels[i + 1], abovePixels[i + 2]]); + + pixels[i + 0] = belowPixels[i + 0] + (rgb[0] - belowPixels[i + 0]) * mix; + pixels[i + 1] = belowPixels[i + 1] + (rgb[1] - belowPixels[i + 1]) * mix; + pixels[i + 2] = belowPixels[i + 2] + (rgb[2] - belowPixels[i + 2]) * mix; + + pixels[i + 3] = belowPixels[i + 3]; + } + } else { + + for(var i = 0, len = belowPixels.length; i < len; i += 4) { + var r = blendingFunction(belowPixels[i + 0], abovePixels[i + 0]); + var g = blendingFunction(belowPixels[i + 1], abovePixels[i + 1]); + var b = blendingFunction(belowPixels[i + 2], abovePixels[i + 2]); + + pixels[i + 0] = belowPixels[i + 0] + (r - belowPixels[i + 0]) * mix; + pixels[i + 1] = belowPixels[i + 1] + (g - belowPixels[i + 1]) * mix; + pixels[i + 2] = belowPixels[i + 2] + (b - belowPixels[i + 2]) * mix; + + pixels[i + 3] = belowPixels[i + 3]; + } + } + + below.context.putImageData(imageData, 0, 0); + + return below; + }, + + wrapValue: function(value, min, max) { + var d = Math.abs(max - min); + return min + (value - min) % d; + }, + + limitValue: function(value, min, max) { + return value < min ? min : value > max ? max : value; + }, + + mix: function(a, b, ammount) { + return a + (b - a) * ammount; + }, + + hexToRgb: function(hex) { + return ['0x' + hex[1] + hex[2] | 0, '0x' + hex[3] + hex[4] | 0, '0x' + hex[5] + hex[6] | 0]; + }, + + rgbToHex: function(r, g, b) { + return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1, 7); + }, + + /* author: http://mjijackson.com/ */ + + rgbToHsl: function(r, g, b) { + + if(r instanceof Array) { + b = r[2]; + g = r[1]; + r = r[0]; + } + + r /= 255, g /= 255, b /= 255; + var max = Math.max(r, g, b), + min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + + return [h, s, l]; + }, + + /* author: http://mjijackson.com/ */ + + hslToRgb: function(h, s, l) { + var r, g, b; + + if(s == 0) { + r = g = b = l; // achromatic + } else { + function hue2rgb(p, q, t) { + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1 / 6) return p + (q - p) * 6 * t; + if(t < 1 / 2) return q; + if(t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; + return p; + } + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [r * 255 | 0, g * 255 | 0, b * 255 | 0]; + }, + + rgbToHsv: function(r, g, b) { + if(r instanceof Array) { + b = r[2]; + g = r[1]; + r = r[0]; + } + + r = r / 255, g = g / 255, b = b / 255; + var max = Math.max(r, g, b), + min = Math.min(r, g, b); + var h, s, v = max; + + var d = max - min; + s = max == 0 ? 0 : d / max; + + if(max == min) { + h = 0; // achromatic + } else { + switch(max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + + return [h, s, v]; + }, + + hsvToRgb: function(h, s, v) { + var r, g, b; + + var i = Math.floor(h * 6); + var f = h * 6 - i; + var p = v * (1 - s); + var q = v * (1 - f * s); + var t = v * (1 - (1 - f) * s); + + switch(i % 6) { + case 0: + r = v, g = t, b = p; + break; + case 1: + r = q, g = v, b = p; + break; + case 2: + r = p, g = v, b = t; + break; + case 3: + r = p, g = q, b = v; + break; + case 4: + r = t, g = p, b = v; + break; + case 5: + r = v, g = p, b = q; + break; + } + + return [r * 255, g * 255, b * 255]; + }, + + color: function() { + var result = new $.Color(); + result.parse(arguments); + return result; + }, + + createCanvas: function(width, height) { + var result = document.createElement("canvas"); + + if(arguments[0] instanceof Image || arguments[0] instanceof HTMLImageElement) { + var image = arguments[0]; + result.width = image.width; + result.height = image.height; + result.getContext("2d").drawImage(image, 0, 0); + } else { + result.width = width; + result.height = height; + } + + return result; + }, + + createImageData: function(width, height) { + return document.createElement("Canvas").getContext("2d").createImageData(width, height); + }, + + + /* https://gist.github.com/3781251 */ + + mousePosition: function(event) { + var totalOffsetX = 0, + totalOffsetY = 0, + coordX = 0, + coordY = 0, + currentElement = event.target || event.srcElement, + mouseX = 0, + mouseY = 0; + + // Traversing the parents to get the total offset + do { + totalOffsetX += currentElement.offsetLeft; + totalOffsetY += currentElement.offsetTop; + } + while ((currentElement = currentElement.offsetParent)); + // Set the event to first touch if using touch-input + if(event.changedTouches && event.changedTouches[0] !== undefined) { + event = event.changedTouches[0]; + } + // Use pageX to get the mouse coordinates + if(event.pageX || event.pageY) { + mouseX = event.pageX; + mouseY = event.pageY; + } + // IE8 and below doesn't support event.pageX + else if(event.clientX || event.clientY) { + mouseX = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft; + mouseY = event.clientY + document.body.scrollTop + document.documentElement.scrollTop; + } + // Subtract the offset from the mouse coordinates + coordX = mouseX - totalOffsetX; + coordY = mouseY - totalOffsetY; + + return { + x: coordX, + y: coordY + }; + } + }); + + $.Wrapper = function(canvas) { + this.context = canvas.getContext("2d"); + this.canvas = canvas; + } + + $.Wrapper.prototype = { + appendTo: function(selector) { + if(typeof selector === "object") { + var element = selector; + } else { + var element = document.querySelector(selector); + } + + element.appendChild(this.canvas); + + return this; + }, + + blendOn: function(what, mode, mix) { + $.blend(what, this, mode, mix); + + return this; + }, + + blend: function(what, mode, mix) { + if(typeof what === "string") { + var color = what; + what = $($.createCanvas(this.canvas.width, this.canvas.height)); + what.fillStyle(color).fillRect(0, 0, this.canvas.width, this.canvas.height); + } + + $.blend(this, what, mode, mix); + + return this; + }, + + circle: function(x, y, r) { + this.context.arc(x, y, r, 0, Math.PI * 2); + return this; + }, + + crop: function(x, y, w, h) { + + var canvas = $.createCanvas(w, h); + var context = canvas.getContext("2d"); + + context.drawImage(this.canvas, x, y, w, h, 0, 0, w, h); + this.canvas.width = w; + this.canvas.height = h; + this.clear(); + this.context.drawImage(canvas, 0, 0); + + return this; + }, + + set: function(properties) { + $.extend(this.context, properties); + }, + + resize: function(width, height) { + var w = width, + h = height; + if(height === null) { + if(this.canvas.width > width) { + h = this.canvas.height * (width / this.canvas.width) | 0; + w = width; + } else { + w = this.canvas.width; + h = this.canvas.height; + } + } else if(width === null) { + if(this.canvas.width > width) { + w = this.canvas.width * (height / this.canvas.height) | 0; + h = height; + } else { + w = this.canvas.width; + h = this.canvas.height; + } + } + + var $resized = $(w, h).drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, w, h); + this.canvas = $resized.canvas; + this.context = $resized.context; + + return this; + }, + + trim: function(color) { + var transparent; + + if(color) { + color = $.color(color).toArray(); + transparent = !color[3]; + } else transparent = true; + + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + + var bound = [this.canvas.width, this.canvas.height, 0, 0]; + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + if(transparent) { + if(!sourcePixels[i + 3]) continue; + } else if(sourcePixels[i + 0] === color[0] && sourcePixels[i + 1] === color[1] && sourcePixels[i + 2] === color[2]) continue; + var x = (i / 4 | 0) % this.canvas.width | 0; + var y = (i / 4 | 0) / this.canvas.width | 0; + + if(x < bound[0]) bound[0] = x; + if(x > bound[2]) bound[2] = x; + + if(y < bound[1]) bound[1] = y; + if(y > bound[3]) bound[3] = y; + } + + if(bound[2] === 0 || bound[3] === 0) { + + } else this.crop(bound[0], bound[1], bound[2] - bound[0] + 1, bound[3] - bound[1] + 1); + + return this; + }, + + resizePixel: function(pixelSize) { + + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + var canvas = document.createElement("canvas"); + var context = canvas.context = canvas.getContext("2d"); + + canvas.width = this.canvas.width * pixelSize | 0; + canvas.height = this.canvas.height * pixelSize | 0; + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + if(!sourcePixels[i + 3]) continue; + context.fillStyle = $.rgbToHex(sourcePixels[i + 0], sourcePixels[i + 1], sourcePixels[i + 2]); + + var x = (i / 4) % this.canvas.width; + var y = (i / 4) / this.canvas.width | 0; + + context.fillRect(x * pixelSize, y * pixelSize, pixelSize, pixelSize); + } + + this.canvas.width = canvas.width; + this.canvas.height = canvas.height; + this.clear().drawImage(canvas, 0, 0); + + return this; + + /* this very clever method is working only under Chrome */ + + var x = 0, + y = 0; + + var canvas = document.createElement("canvas"); + var context = canvas.context = canvas.getContext("2d"); + + canvas.width = this.canvas.width * pixelSize | 0; + canvas.height = this.canvas.height * pixelSize | 0; + + while(x < this.canvas.width) { + y = 0; + while(y < this.canvas.height) { + context.drawImage(this.canvas, x, y, 1, 1, x * pixelSize, y * pixelSize, pixelSize, pixelSize); + y++; + } + x++; + } + + this.canvas = canvas; + this.context = context; + + return this; + }, + + + matchPalette: function(palette) { + var imgData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + + var rgbPalette = []; + for(var i = 0; i < palette.length; i++) { + rgbPalette.push($.color(palette[i])); + } + + + for(var i = 0; i < imgData.data.length; i += 4) { + var difList = []; + for(var j = 0; j < rgbPalette.length; j++) { + var rgbVal = rgbPalette[j]; + var rDif = Math.abs(imgData.data[i] - rgbVal[0]), + gDif = Math.abs(imgData.data[i + 1] - rgbVal[1]), + bDif = Math.abs(imgData.data[i + 2] - rgbVal[2]); + difList.push(rDif + gDif + bDif); + } + + var closestMatch = 0; + for(var j = 0; j < palette.length; j++) { + if(difList[j] < difList[closestMatch]) { + closestMatch = j; + } + } + + var paletteRgb = cq.hexToRgb(palette[closestMatch]); + imgData.data[i] = paletteRgb[0]; + imgData.data[i + 1] = paletteRgb[1]; + imgData.data[i + 2] = paletteRgb[2]; + } + + this.context.putImageData(imgData, 0, 0); + + return this; + }, + + getPalette: function() { + var palette = []; + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + if(sourcePixels[i + 3]) { + var hex = $.rgbToHex(sourcePixels[i + 0], sourcePixels[i + 1], sourcePixels[i + 2]); + if(palette.indexOf(hex) === -1) palette.push(hex); + } + } + + return palette; + }, + + pixelize: function(size) { + if(!size) return this; + size = size || 4; + + var mozImageSmoothingEnabled = this.context.mozImageSmoothingEnabled; + var webkitImageSmoothingEnabled = this.context.webkitImageSmoothingEnabled; + + this.context.mozImageSmoothingEnabled = false; + this.context.webkitImageSmoothingEnabled = false; + + var scale = (this.canvas.width / size) / this.canvas.width; + + var temp = cq(this.canvas.width, this.canvas.height); + + temp.drawImage(this.canvas, 0, 0, this.canvas.width, this.canvas.height, 0, 0, this.canvas.width * scale | 0, this.canvas.height * scale | 0); + this.clear().drawImage(temp.canvas, 0, 0, this.canvas.width * scale | 0, this.canvas.height * scale | 0, 0, 0, this.canvas.width, this.canvas.height); + + this.context.mozImageSmoothingEnabled = mozImageSmoothingEnabled; + this.context.webkitImageSmoothingEnabled = webkitImageSmoothingEnabled; + + return this; + }, + + colorToMask: function(color, inverted) { + color = $.color(color).toArray(); + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + + var mask = []; + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + if(sourcePixels[i + 0] == color[0] && sourcePixels[i + 1] == color[1] && sourcePixels[i + 2] == color[2]) mask.push(inverted || false); + else mask.push(!inverted); + } + + return mask; + }, + + grayscaleToMask: function(color) { + color = $.color(color).toArray(); + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + + var mask = []; + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + mask.push((sourcePixels[i + 0] + sourcePixels[i + 1] + sourcePixels[i + 2]) / 3 | 0); + } + + return mask; + }, + + grayscaleToAlpha: function() { + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + + var mask = []; + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + sourcePixels[i + 3] = (sourcePixels[i + 0] + sourcePixels[i + 1] + sourcePixels[i + 2]) / 3 | 0; + + sourcePixels[i + 0] = sourcePixels[i + 1] = sourcePixels[i + 2] = 255; + } + + this.context.putImageData(sourceData, 0, 0); + + return this; + }, + + applyMask: function(mask) { + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + + var mode = typeof mask[0] === "boolean" ? "bool" : "byte"; + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + var value = mask[i / 4]; + + if(mode === "bool") sourcePixels[i + 3] = 255 * value | 0; + else { + sourcePixels[i + 3] = value | 0; + } + } + + + this.context.putImageData(sourceData, 0, 0); + return this; + }, + + fillMask: function(mask) { + + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var sourcePixels = sourceData.data; + + var maskType = typeof mask[0] === "boolean" ? "bool" : "byte"; + var colorMode = arguments.length === 2 ? "normal" : "gradient"; + + var color = $.color(arguments[1]); + if(colorMode === "gradient") colorB = $.color(arguments[2]); + + for(var i = 0, len = sourcePixels.length; i < len; i += 4) { + var value = mask[i / 4]; + + if(maskType === "byte") value /= 255; + + if(colorMode === "normal") { + if(value) { + sourcePixels[i + 0] = color[0] | 0; + sourcePixels[i + 1] = color[1] | 0; + sourcePixels[i + 2] = color[2] | 0; + sourcePixels[i + 3] = value * 255 | 0; + } + } else { + sourcePixels[i + 0] = color[0] + (colorB[0] - color[0]) * value | 0; + sourcePixels[i + 1] = color[1] + (colorB[1] - color[1]) * value | 0; + sourcePixels[i + 2] = color[2] + (colorB[2] - color[2]) * value | 0; + sourcePixels[i + 3] = 255; + } + } + + this.context.putImageData(sourceData, 0, 0); + return this; + }, + + clear: function(color) { + if(color) { + this.context.fillStyle = color; + this.context.fillRect(0, 0, this.canvas.width, this.canvas.height); + } else { + this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); + } + + return this; + }, + + clone: function() { + var result = $.createCanvas(this.canvas.width, this.canvas.height); + result.getContext("2d").drawImage(this.canvas, 0, 0); + return $(result); + }, + + fillStyle: function(fillStyle) { + this.context.fillStyle = fillStyle; + return this; + }, + + strokeStyle: function(strokeStyle) { + this.context.strokeStyle = strokeStyle; + return this; + }, + + gradientText: function(text, x, y, maxWidth, gradient) { + + var words = text.split(" "); + + var h = this.font().match(/\d+/g)[0] * 2; + + var ox = 0; + var oy = 0; + + if(maxWidth) { + var line = 0; + var lines = [""]; + + for(var i = 0; i < words.length; i++) { + var word = words[i] + " "; + var wordWidth = this.context.measureText(word).width; + + if(ox + wordWidth > maxWidth) { + lines[++line] = ""; + ox = 0; + } + + lines[line] += word; + + ox += wordWidth; + } + } else var lines = [text]; + + for(var i = 0; i < lines.length; i++) { + var oy = y + i * h * 0.6 | 0; + var lingrad = this.context.createLinearGradient(0, oy, 0, oy + h * 0.6 | 0); + + for(var j = 0; j < gradient.length; j += 2) { + lingrad.addColorStop(gradient[j], gradient[j + 1]); + } + + var text = lines[i]; + + this.fillStyle(lingrad).fillText(text, x, oy); + } + + return this; + }, + + setHsl: function() { + + if(arguments.length === 1) { + var args = arguments[0]; + } else { + var args = arguments; + } + + var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var pixels = data.data; + var r, g, b, a, h, s, l, hsl = [], + newPixel = []; + + for(var i = 0, len = pixels.length; i < len; i += 4) { + hsl = $.rgbToHsl(pixels[i + 0], pixels[i + 1], pixels[i + 2]); + + h = args[0] === null ? hsl[0] : $.limitValue(args[0], 0, 1); + s = args[1] === null ? hsl[1] : $.limitValue(args[1], 0, 1); + l = args[2] === null ? hsl[2] : $.limitValue(args[2], 0, 1); + + newPixel = $.hslToRgb(h, s, l); + + pixels[i + 0] = newPixel[0]; + pixels[i + 1] = newPixel[1]; + pixels[i + 2] = newPixel[2]; + } + + this.context.putImageData(data, 0, 0); + + return this; + }, + + shiftHsl: function() { + + if(arguments.length === 1) { + var args = arguments[0]; + } else { + var args = arguments; + } + + var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var pixels = data.data; + var r, g, b, a, h, s, l, hsl = [], + newPixel = []; + + for(var i = 0, len = pixels.length; i < len; i += 4) { + hsl = $.rgbToHsl(pixels[i + 0], pixels[i + 1], pixels[i + 2]); + + h = args[0] === null ? hsl[0] : $.wrapValue(hsl[0] + args[0], 0, 1); + s = args[1] === null ? hsl[1] : $.limitValue(hsl[1] + args[1], 0, 1); + l = args[2] === null ? hsl[2] : $.limitValue(hsl[2] + args[2], 0, 1); + + newPixel = $.hslToRgb(h, s, l); + + pixels[i + 0] = newPixel[0]; + pixels[i + 1] = newPixel[1]; + pixels[i + 2] = newPixel[2]; + } + + + this.context.putImageData(data, 0, 0); + + return this; + }, + + replaceHue: function(src, dst) { + + var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var pixels = data.data; + var r, g, b, a, h, s, l, hsl = [], + newPixel = []; + + for(var i = 0, len = pixels.length; i < len; i += 4) { + hsl = $.rgbToHsl(pixels[i + 0], pixels[i + 1], pixels[i + 2]); + + if(Math.abs(hsl[0] - src) < 0.05) h = $.wrapValue(dst, 0, 1); + else h = hsl[0]; + + newPixel = $.hslToRgb(h, hsl[1], hsl[2]); + + pixels[i + 0] = newPixel[0]; + pixels[i + 1] = newPixel[1]; + pixels[i + 2] = newPixel[2]; + } + + this.context.putImageData(data, 0, 0); + + return this; + }, + + invert: function(src, dst) { + + var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var pixels = data.data; + var r, g, b, a, h, s, l, hsl = [], + newPixel = []; + + for(var i = 0, len = pixels.length; i < len; i += 4) { + pixels[i + 0] = 255 - pixels[i + 0]; + pixels[i + 1] = 255 - pixels[i + 1]; + pixels[i + 2] = 255 - pixels[i + 2]; + } + + this.context.putImageData(data, 0, 0); + + return this; + }, + + roundRect: function(x, y, width, height, radius) { + + this.beginPath(); + this.moveTo(x + radius, y); + this.lineTo(x + width - radius, y); + this.quadraticCurveTo(x + width, y, x + width, y + radius); + this.lineTo(x + width, y + height - radius); + this.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + this.lineTo(x + radius, y + height); + this.quadraticCurveTo(x, y + height, x, y + height - radius); + this.lineTo(x, y + radius); + this.quadraticCurveTo(x, y, x + radius, y); + this.closePath(); + + return this; + }, + + wrappedText: function(text, x, y, maxWidth, newlineCallback) { + + var words = text.split(" "); + + var h = this.font().match(/\d+/g)[0] * 2; + + var ox = 0; + var oy = 0; + + if(maxWidth) { + var line = 0; + var lines = [""]; + + for(var i = 0; i < words.length; i++) { + var word = words[i] + " "; + var wordWidth = this.context.measureText(word).width; + + if(ox + wordWidth > maxWidth) { + lines[++line] = ""; + ox = 0; + } + + lines[line] += word; + + ox += wordWidth; + } + } else { + var lines = [text]; + } + + for(var i = 0; i < lines.length; i++) { + var oy = y + i * h * 0.6 | 0; + + var text = lines[i]; + + if(newlineCallback) newlineCallback.call(this, x, y + oy); + + this.fillText(text, x, oy); + } + + return this; + }, + + textBoundaries: function(text, maxWidth) { + var words = text.split(" "); + + var h = this.font().match(/\d+/g)[0] * 2; + + var ox = 0; + var oy = 0; + + if(maxWidth) { + var line = 0; + var lines = [""]; + + for(var i = 0; i < words.length; i++) { + var word = words[i] + " "; + var wordWidth = this.context.measureText(word).width; + + if(ox + wordWidth > maxWidth) { + lines[++line] = ""; + ox = 0; + } + + lines[line] += word; + + ox += wordWidth; + } + } else { + var lines = [text]; + maxWidth = this.measureText(text).width; + } + + return { + height: lines.length * h * 0.6 | 0, + width: maxWidth + } + }, + + paperBag: function(x, y, width, height, blowX, blowY) { + var lx, ly; + this.beginPath(); + this.moveTo(x, y); + this.quadraticCurveTo(x + width / 2 | 0, y + height * blowY | 0, x + width, y); + this.quadraticCurveTo(x + width - width * blowX | 0, y + height / 2 | 0, x + width, y + height); + this.quadraticCurveTo(x + width / 2 | 0, y + height - height * blowY | 0, x, y + height); + this.quadraticCurveTo(x + width * blowX | 0, y + height / 2 | 0, x, y); + }, + + borderImage: function(image, x, y, w, h, t, r, b, l, fill) { + + /* top */ + this.drawImage(image, l, 0, image.width - l - r, t, x + l, y, w - l - r, t); + + /* bottom */ + this.drawImage(image, l, image.height - b, image.width - l - r, b, x + l, y + h - b, w - l - r, b); + + /* left */ + this.drawImage(image, 0, t, l, image.height - b - t, x, y + t, l, h - b - t); + + /* right */ + this.drawImage(image, image.width - r, t, r, image.height - b - t, x + w - r, y + t, r, h - b - t); + + /* top-left */ + this.drawImage(image, 0, 0, l, t, x, y, l, t); + + /* top-right */ + this.drawImage(image, image.width - r, 0, r, t, x + w - r, y, r, t); + + /* bottom-right */ + this.drawImage(image, image.width - r, image.height - b, r, b, x + w - r, y + h - b, r, b); + + /* bottom-left */ + this.drawImage(image, 0, image.height - b, l, b, x, y + h - b, l, b); + + if(fill) { + if(typeof fill === "string") { + this.fillStyle(fill).fillRect(x + l, y + t, w - l - r, h - t - b); + } else { + this.drawImage(image, l, t, image.width - r - l, image.height - b - t, x + l, y + t, w - l - r, h - t - b); + } + } + }, + + /* www.html5rocks.com/en/tutorials/canvas/imagefilters/ */ + + convolve: function(matrix, mix, divide) { + + if(typeof divide === "undefined") divide = 1; + if(typeof mix === "undefined") mix = 1; + + var sourceData = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var matrixSize = Math.sqrt(matrix.length) + 0.5 | 0; + var halfMatrixSize = matrixSize / 2 | 0; + var src = sourceData.data; + var sw = sourceData.width; + var sh = sourceData.height; + var w = sw; + var h = sh; + var output = $.createImageData(this.canvas.width, this.canvas.height); + var dst = output.data; + + for(var y = 1; y < h - 1; y++) { + for(var x = 1; x < w - 1; x++) { + + var dstOff = (y * w + x) * 4; + var r = 0, + g = 0, + b = 0, + a = 0; + for(var cy = 0; cy < matrixSize; cy++) { + for(var cx = 0; cx < matrixSize; cx++) { + var scy = y + cy - halfMatrixSize; + var scx = x + cx - halfMatrixSize; + if(scy >= 0 && scy < sh && scx >= 0 && scx < sw) { + var srcOff = (scy * sw + scx) * 4; + var wt = matrix[cy * matrixSize + cx] / divide; + r += src[srcOff + 0] * wt; + g += src[srcOff + 1] * wt; + b += src[srcOff + 2] * wt; + a += src[srcOff + 3] * wt; + } + } + } + dst[dstOff + 0] = $.mix(src[dstOff + 0], r, mix); + dst[dstOff + 1] = $.mix(src[dstOff + 1], g, mix); + dst[dstOff + 2] = $.mix(src[dstOff + 2], b, mix); + dst[dstOff + 3] = src[dstOff + 3]; + } + } + + this.context.putImageData(output, 0, 0); + + return this; + }, + + blur: function(mix) { + return this.convolve([1, 1, 1, 1, 1, 1, 1, 1, 1], mix, 9); + }, + + gaussianBlur: function(mix) { + return this.convolve([0.00000067, 0.00002292, 0.00019117, 0.00038771, 0.00019117, 0.00002292, 0.00000067, 0.00002292, 0.00078633, 0.00655965, 0.01330373, 0.00655965, 0.00078633, 0.00002292, 0.00019117, 0.00655965, 0.05472157, 0.11098164, 0.05472157, 0.00655965, 0.00019117, 0.00038771, 0.01330373, 0.11098164, 0.22508352, 0.11098164, 0.01330373, 0.00038771, 0.00019117, 0.00655965, 0.05472157, 0.11098164, 0.05472157, 0.00655965, 0.00019117, 0.00002292, 0.00078633, 0.00655965, 0.01330373, 0.00655965, 0.00078633, 0.00002292, 0.00000067, 0.00002292, 0.00019117, 0.00038771, 0.00019117, 0.00002292, 0.00000067], mix, 1); + }, + + sharpen: function(mix) { + return this.convolve([0, -1, 0, -1, 5, -1, 0, -1, 0], mix); + }, + + threshold: function(threshold) { + var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var pixels = data.data; + var r, g, b; + + for(var i = 0; i < pixels.length; i += 4) { + var r = pixels[i]; + var g = pixels[i + 1]; + var b = pixels[i + 2]; + var v = (0.2126 * r + 0.7152 * g + 0.0722 * b >= threshold) ? 255 : 0; + pixels[i] = pixels[i + 1] = pixels[i + 2] = v + } + + this.context.putImageData(data, 0, 0); + + return this; + }, + + sepia: function() { + var data = this.context.getImageData(0, 0, this.canvas.width, this.canvas.height); + var pixels = data.data; + var r, g, b; + + for(var i = 0; i < pixels.length; i += 4) { + pixels[i + 0] = $.limitValue((pixels[i + 0] * .393) + (pixels[i + 1] * .769) + (pixels[i + 2] * .189), 0, 255); + pixels[i + 1] = $.limitValue((pixels[i + 0] * .349) + (pixels[i + 1] * .686) + (pixels[i + 2] * .168), 0, 255); + pixels[i + 2] = $.limitValue((pixels[i + 0] * .272) + (pixels[i + 1] * .534) + (pixels[i + 2] * .131), 0, 255); + } + + this.context.putImageData(data, 0, 0); + + return this; + }, + + measureText: function() { + return this.context.measureText.apply(this.context, arguments); + }, + + createRadialGradient: function() { + return this.context.createRadialGradient.apply(this.context, arguments); + }, + + createLinearGradient: function() { + return this.context.createLinearGradient.apply(this.context, arguments); + }, + + getImageData: function() { + return this.context.getImageData.apply(this.context, arguments); + }, + + /* framework */ + + framework: function(args, context) { + if(context) { + this.tempContext = context === true ? args : context; + } + + for(var name in args) { + if(this[name]) this[name](args[name], undefined, undefined); + } + + this.tempContext = null; + + return this; + }, + + onStep: function(callback, interval) { + var self = this.tempContext || this; + var lastTick = Date.now(); + + this.timer = setInterval(function() { + var delta = Date.now() - lastTick; + lastTick = Date.now(); + callback.call(self, delta, lastTick); + }, interval); + + return this; + }, + + onRender: function(callback) { + var self = this.tempContext || this; + + var lastTick = Date.now(); + + function step() { + var delta = Date.now() - lastTick; + lastTick = Date.now(); + requestAnimationFrame(step) + callback.call(self, delta, lastTick); + }; + + requestAnimationFrame(step); + + return this; + }, + + onMouseMove: function(callback) { + var self = this.tempContext || this; + + if(!MOBILE) this.canvas.addEventListener("mousemove", function(e) { + var pos = $.mousePosition(e); + callback.call(self, pos.x, pos.y); + }); + + else this.canvas.addEventListener("touchmove", function(e) { + e.preventDefault(); + var pos = $.mousePosition(e); + callback.call(self, pos.x, pos.y); + }); + + return this; + }, + + onMouseDown: function(callback) { + var self = this.tempContext || this; + + if(!MOBILE) { + this.canvas.addEventListener("mousedown", function(e) { + var pos = $.mousePosition(e); + callback.call(self, pos.x, pos.y, e.button); + }); + } else { + this.canvas.addEventListener("touchstart", function(e) { + var pos = $.mousePosition(e); + callback.call(self, pos.x, pos.y, e.button); + }); + } + + return this; + }, + + onMouseUp: function(callback) { + var self = this.tempContext || this; + + if(!MOBILE) { + this.canvas.addEventListener("mouseup", function(e) { + var pos = $.mousePosition(e); + callback.call(self, pos.x, pos.y, e.button); + }); + } else { + this.canvas.addEventListener("touchend", function(e) { + var pos = $.mousePosition(e); + callback.call(self, pos.x, pos.y, e.button); + }); + } + + return this; + }, + + + onSwipe: function(callback, threshold, timeout) { + var self = this.tempContext || this; + + var swipeThr = threshold || 35; + var swipeTim = timeout || 350; + + var swipeSP = 0; + var swipeST = 0; + var swipeEP = 0; + var swipeET = 0; + + function swipeStart(e) { + e.preventDefault(); + swipeSP = $.mousePosition(e); + swipeST = Date.now(); + } + + function swipeUpdate(e) { + e.preventDefault(); + swipeEP = $.mousePosition(e); + swipeET = Date.now(); + } + + function swipeEnd(e) { + e.preventDefault(); + + var xDif = (swipeSP.x - swipeEP.x); + var yDif = (swipeSP.y - swipeEP.y); + var x = (xDif * xDif); + var y = (yDif * yDif); + var swipeDist = Math.sqrt(x + y); + var swipeTime = (swipeET - swipeST); + var swipeDir = undefined; + + if(swipeDist > swipeThr && swipeTime < swipeTim) { + if(Math.abs(xDif) > Math.abs(yDif)) { + if(xDif > 0) { + swipeDir = "left"; + } else { + swipeDir = "right"; + } + } else { + if(yDif > 0) { + swipeDir = "up"; + } else { + swipeDir = "down"; + } + } + callback.call(self, swipeDir); + } + } + + this.canvas.addEventListener("touchstart", function(e) { + swipeStart(e); + }); + this.canvas.addEventListener("touchmove", function(e) { + swipeUpdate(e); + }); + this.canvas.addEventListener("touchend", function(e) { + swipeEnd(e); + }); + this.canvas.addEventListener("mousedown", function(e) { + swipeStart(e); + }); + this.canvas.addEventListener("mousemove", function(e) { + swipeUpdate(e); + }); + this.canvas.addEventListener("mouseup", function(e) { + swipeEnd(e); + }); + + return this; + }, + + onKeyDown: function(callback) { + document.addEventListener("keydown", function(e) { + if(e.which >= 48 && e.which <= 90) var keyName = String.fromCharCode(e.which).toLowerCase(); + else var keyName = $.keycodes[e.which]; + callback.call(self, keyName); + }); + return this; + }, + + onKeyUp: function(callback) { + document.addEventListener("keyup", function(e) { + if(e.which >= 48 && e.which <= 90) var keyName = String.fromCharCode(e.which).toLowerCase(); + else var keyName = $.keycodes[e.which]; + callback.call(self, keyName); + }); + return this; + }, + + onResize: function(callback) { + var self = this; + + window.addEventListener("resize", function() { + callback.call(self, window.innerWidth, window.innerHeight); + }); + + callback.call(self, window.innerWidth, window.innerHeight); + + return this; + }, + + onDropImage: function(callback) { + var self = this; + document.addEventListener('drop', function(e) { + e.stopPropagation(); + e.preventDefault(); + + var file = e.dataTransfer.files[0]; + + if(!(/image/i).test(file.type)) return false; + var reader = new FileReader(); + + reader.onload = function(e) { + var image = new Image; + + image.onload = function() { + callback.call(self, this); + }; + + image.src = e.target.result; + }; + + reader.readAsDataURL(file); + + }); + + document.addEventListener("dragover", function(e) { + e.preventDefault(); + }); + + return this; + } + + }; + + /* extend wrapper with drawing context methods */ + + var methods = ["arc", "arcTo", "beginPath", "bezierCurveTo", "clearRect", "clip", "closePath", "createImageData", "createLinearGradient", "createRadialGradient", "createPattern", "drawFocusRing", "drawImage", "fill", "fillRect", "fillText", "getImageData", "isPointInPath", "lineTo", "measureText", "moveTo", "putImageData", "quadraticCurveTo", "rect", "restore", "rotate", "save", "scale", "setTransform", "stroke", "strokeRect", "strokeText", "transform", "translate"]; + for(var i = 0; i < methods.length; i++) { + var name = methods[i]; + if(!$.Wrapper.prototype[name]) $.Wrapper.prototype[name] = Function("this.context." + name + ".apply(this.context, arguments); return this;"); + }; + + /* create setters and getters */ + + var properties = ["canvas", "fillStyle", "font", "globalAlpha", "globalCompositeOperation", "lineCap", "lineJoin", "lineWidth", "miterLimit", "shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor", "strokeStyle", "textAlign", "textBaseline"]; + for(var i = 0; i < properties.length; i++) { + var name = properties[i]; + if(!$.Wrapper.prototype[name]) $.Wrapper.prototype[name] = Function("if(arguments.length) { this.context." + name + " = arguments[0]; return this; } else { return this.context." + name + "; }"); + }; + + /* color */ + + $.Color = function() { + if(arguments.length) this.parse(arguments); + } + + $.Color.prototype = { + parse: function(args) { + if(typeof args[0] === "string") { + var rgb = $.hexToRgb(args[0]); + this[0] = rgb[0]; + this[1] = rgb[1]; + this[2] = rgb[2]; + this[3] = 255; + } else { + this[0] = args[0]; + this[1] = args[1]; + this[2] = args[2]; + this[3] = typeof args[3] === "undefined" ? 255 : args[3]; + } + }, + + toArray: function() { + return [this[0], this[1], this[2], this[3]]; + }, + + toRgb: function() { + return "rgb(" + this[0] + ", " + this[1] + ", " + this[2] + ")"; + }, + + toRgba: function() { + return "rgb(" + this[0] + ", " + this[1] + ", " + this[2] + ", " + this[3] + ")"; + }, + + toHex: function() { + return $.rgbToHex(this[0], this[1], this[2]); + }, + + toHsl: function() { + return $.rgbToHsl(this[0], this[1], this[2]); + }, + + toHsv: function() { + return $.rgbToHsv(this[0], this[1], this[2]); + } + + }; + + window["cq"] = window["CanvasQuery"] = $; + + if(typeof define === "function" && define.amd) { + define([], function() { + return $; + }); + } + +})(window);
\ No newline at end of file diff --git a/public/js/canvasquery.min.js b/public/js/canvasquery.min.js new file mode 100644 index 0000000..0fff546 --- /dev/null +++ b/public/js/canvasquery.min.js @@ -0,0 +1,51 @@ +/* + Canvas Query 0.8.1 + http://canvasquery.org + (c) 2012-2013 http://rezoner.net + Canvas Query may be freely distributed under the MIT license. +*/ + +(function(l,v){var y=/Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(navigator.userAgent);l.requestAnimationFrame=l.requestAnimationFrame||l.webkitRequestAnimationFrame||l.mozRequestAnimationFrame||l.oRequestAnimationFrame||l.msRequestAnimationFrame||function(a){l.setTimeout(a,1E3/60)};var g=function(a){if(0===arguments.length){var c=g.createCanvas(l.innerWidth,l.innerHeight);l.addEventListener("resize",function(){})}else if("string"===typeof a)c=document.querySelector(a);else if("number"===typeof a)c= +g.createCanvas(arguments[0],arguments[1]);else if(a instanceof Image||a instanceof HTMLImageElement)c=g.createCanvas(a);else{if(a instanceof g.Wrapper)return a;c=a}return new g.Wrapper(c)};g.extend=function(){for(var a=1;a<arguments.length;a++)for(var c in arguments[a])arguments[0][c]=arguments[a][c];return arguments[0]};g.augment=function(){for(var a=1;a<arguments.length;a++)_.extend(arguments[0],arguments[a]),arguments[a](arguments[0])};g.extend(g,{keycodes:{37:"left",38:"up",39:"right",40:"down", +45:"insert",46:"delete",8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"capslock",27:"escape",32:"space",33:"pageup",34:"pagedown",35:"end",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",144:"numlock",145:"scrolllock",186:"semicolon",187:"equal",188:"comma",189:"dash",190:"period",191:"slash",192:"graveaccent",219:"openbracket",220:"backslash",221:"closebraket",222:"singlequote"},cleanArray:function(a,c){for(var b= +arguments[arguments.length-1],d="function"===typeof b,f=0,e=a.length;f<e;f++)if(null===a[f]||c&&a[f][c])d&&b(a[f]),a.splice(f--,1),e--},specialBlendFunctions:["color","value","hue","saturation"],blendFunctions:{normal:function(a,c){return c},overlay:function(a,c){a/=255;c/=255;return Math.min(255,Math.max(0,255*(0.5>a?2*a*c:1-2*(1-a)*(1-c))|0))},hardLight:function(a,c){return g.blendFunctions.overlay(c,a)},softLight:function(a,c){a/=255;c/=255;return g.limitValue(255*((1-2*c)*a*a+2*c*a),0,255)},dodge:function(a, +c){return Math.min(256*a/(255-c+1),255)},burn:function(a,c){return 255-Math.min(256*(255-a)/(c+1),255)},multiply:function(a,c){return c*a/255},divide:function(a,c){return Math.min(256*a/(c+1),255)},screen:function(a,c){return 255-(255-c)*(255-a)/255},grainExtract:function(a,c){return g.limitValue(a-c+128,0,255)},grainMerge:function(a,c){return g.limitValue(a+c-128,0,255)},difference:function(a,c){return Math.abs(a-c)},addition:function(a,c){return Math.min(a+c,255)},substract:function(a,c){return Math.max(a- +c,0)},darkenOnly:function(a,c){return Math.min(a,c)},lightenOnly:function(a,c){return Math.max(a,c)},color:function(a,c){var b=g.rgbToHsl(a),d=g.rgbToHsl(c);return g.hslToRgb(d[0],d[1],b[2])},hue:function(a,c){var b=g.rgbToHsv(a),d=g.rgbToHsv(c);return d[1]?g.hsvToRgb(d[0],b[1],b[2]):g.hsvToRgb(b[0],b[1],b[2])},value:function(a,c){var b=g.rgbToHsv(a),d=g.rgbToHsv(c);return g.hsvToRgb(b[0],b[1],d[2])},saturation:function(a,c){var b=g.rgbToHsv(a),d=g.rgbToHsv(c);return g.hsvToRgb(b[0],d[1],b[2])}}, +blend:function(a,c,b,d){"undefined"===typeof d&&(d=1);a=g(a);c=g(c);var f=c.context,e=a.context.getImageData(0,0,a.canvas.width,a.canvas.height);c=f.getImageData(0,0,c.canvas.width,c.canvas.height);e=e.data;c=c.data;var f=this.createImageData(a.canvas.width,a.canvas.height),h=f.data,m=g.blendFunctions[b];if(-1!==g.specialBlendFunctions.indexOf(b)){b=0;for(var j=e.length;b<j;b+=4){var k=m([e[b+0],e[b+1],e[b+2]],[c[b+0],c[b+1],c[b+2]]);h[b+0]=e[b+0]+(k[0]-e[b+0])*d;h[b+1]=e[b+1]+(k[1]-e[b+1])*d;h[b+ +2]=e[b+2]+(k[2]-e[b+2])*d;h[b+3]=e[b+3]}}else{b=0;for(j=e.length;b<j;b+=4){var k=m(e[b+0],c[b+0]),n=m(e[b+1],c[b+1]),l=m(e[b+2],c[b+2]);h[b+0]=e[b+0]+(k-e[b+0])*d;h[b+1]=e[b+1]+(n-e[b+1])*d;h[b+2]=e[b+2]+(l-e[b+2])*d;h[b+3]=e[b+3]}}a.context.putImageData(f,0,0);return a},wrapValue:function(a,c,b){b=Math.abs(b-c);return c+(a-c)%b},limitValue:function(a,c,b){return a<c?c:a>b?b:a},mix:function(a,c,b){return a+(c-a)*b},hexToRgb:function(a){return["0x"+a[1]+a[2]|0,"0x"+a[3]+a[4]|0,"0x"+a[5]+a[6]|0]},rgbToHex:function(a, +c,b){return"#"+(16777216+(a<<16)+(c<<8)+b).toString(16).slice(1,7)},rgbToHsl:function(a,c,b){a instanceof Array&&(b=a[2],c=a[1],a=a[0]);a/=255;c/=255;b/=255;var d=Math.max(a,c,b),f=Math.min(a,c,b),e,h=(d+f)/2;if(d==f)e=f=0;else{var g=d-f,f=0.5<h?g/(2-d-f):g/(d+f);switch(d){case a:e=(c-b)/g+(c<b?6:0);break;case c:e=(b-a)/g+2;break;case b:e=(a-c)/g+4}e/=6}return[e,f,h]},hslToRgb:function(a,c,b){if(0==c)b=c=a=b;else{var d=function(a,b,c){0>c&&(c+=1);1<c&&(c-=1);return c<1/6?a+6*(b-a)*c:0.5>c?b:c<2/3? +a+6*(b-a)*(2/3-c):a},f=0.5>b?b*(1+c):b+c-b*c,e=2*b-f;b=d(e,f,a+1/3);c=d(e,f,a);a=d(e,f,a-1/3)}return[255*b|0,255*c|0,255*a|0]},rgbToHsv:function(a,c,b){a instanceof Array&&(b=a[2],c=a[1],a=a[0]);a/=255;c/=255;b/=255;var d=Math.max(a,c,b),f=Math.min(a,c,b),e,h=d-f;if(d==f)e=0;else{switch(d){case a:e=(c-b)/h+(c<b?6:0);break;case c:e=(b-a)/h+2;break;case b:e=(a-c)/h+4}e/=6}return[e,0==d?0:h/d,d]},hsvToRgb:function(a,c,b){var d,f,e,h=Math.floor(6*a),g=6*a-h;a=b*(1-c);var j=b*(1-g*c);c=b*(1-(1-g)*c);switch(h% +6){case 0:d=b;f=c;e=a;break;case 1:d=j;f=b;e=a;break;case 2:d=a;f=b;e=c;break;case 3:d=a;f=j;e=b;break;case 4:d=c;f=a;e=b;break;case 5:d=b,f=a,e=j}return[255*d,255*f,255*e]},color:function(){var a=new g.Color;a.parse(arguments);return a},createCanvas:function(a,c){var b=document.createElement("canvas");a instanceof Image||a instanceof HTMLImageElement?(b.width=a.width,b.height=a.height,b.getContext("2d").drawImage(a,0,0)):(b.width=a,b.height=c);return b},createImageData:function(a,c){return document.createElement("Canvas").getContext("2d").createImageData(a, +c)},mousePosition:function(a){var c=0,b=0,d=a.target||a.srcElement,f=0,e=0;do c+=d.offsetLeft,b+=d.offsetTop;while(d=d.offsetParent);a.changedTouches&&a.changedTouches[0]!==v&&(a=a.changedTouches[0]);if(a.pageX||a.pageY)f=a.pageX,e=a.pageY;else if(a.clientX||a.clientY)f=a.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,e=a.clientY+document.body.scrollTop+document.documentElement.scrollTop;return{x:f-c,y:e-b}}});g.Wrapper=function(a){this.context=a.getContext("2d");this.canvas= +a};g.Wrapper.prototype={appendTo:function(a){("object"===typeof a?a:document.querySelector(a)).appendChild(this.canvas);return this},blendOn:function(a,c,b){g.blend(a,this,c,b);return this},blend:function(a,c,b){if("string"===typeof a){var d=a;a=g(g.createCanvas(this.canvas.width,this.canvas.height));a.fillStyle(d).fillRect(0,0,this.canvas.width,this.canvas.height)}g.blend(this,a,c,b);return this},circle:function(a,c,b){this.context.arc(a,c,b,0,2*Math.PI);return this},crop:function(a,c,b,d){var f= +g.createCanvas(b,d);f.getContext("2d").drawImage(this.canvas,a,c,b,d,0,0,b,d);this.canvas.width=b;this.canvas.height=d;this.clear();this.context.drawImage(f,0,0);return this},set:function(a){g.extend(this.context,a)},resize:function(a,c){var b=a,d=c;null===c?this.canvas.width>a?(d=this.canvas.height*(a/this.canvas.width)|0,b=a):(b=this.canvas.width,d=this.canvas.height):null===a&&(this.canvas.width>a?(b=this.canvas.width*(c/this.canvas.height)|0,d=c):(b=this.canvas.width,d=this.canvas.height));b= +g(b,d).drawImage(this.canvas,0,0,this.canvas.width,this.canvas.height,0,0,b,d);this.canvas=b.canvas;this.context=b.context;return this},trim:function(a){var c;a?(a=g.color(a).toArray(),c=!a[3]):c=!0;for(var b=this.context.getImageData(0,0,this.canvas.width,this.canvas.height).data,d=[this.canvas.width,this.canvas.height,0,0],f=0,e=b.length;f<e;f+=4){if(c){if(!b[f+3])continue}else if(b[f+0]===a[0]&&b[f+1]===a[1]&&b[f+2]===a[2])continue;var h=(f/4|0)%this.canvas.width|0,m=(f/4|0)/this.canvas.width| +0;h<d[0]&&(d[0]=h);h>d[2]&&(d[2]=h);m<d[1]&&(d[1]=m);m>d[3]&&(d[3]=m)}0===d[2]||0===d[3]||this.crop(d[0],d[1],d[2]-d[0]+1,d[3]-d[1]+1);return this},resizePixel:function(a){var c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height).data,b=document.createElement("canvas"),d=b.context=b.getContext("2d");b.width=this.canvas.width*a|0;b.height=this.canvas.height*a|0;for(var f=0,e=c.length;f<e;f+=4)c[f+3]&&(d.fillStyle=g.rgbToHex(c[f+0],c[f+1],c[f+2]),d.fillRect(f/4%this.canvas.width*a,(f/ +4/this.canvas.width|0)*a,a,a));this.canvas.width=b.width;this.canvas.height=b.height;this.clear().drawImage(b,0,0);return this},matchPalette:function(a){for(var c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),b=[],d=0;d<a.length;d++)b.push(g.color(a[d]));for(d=0;d<c.data.length;d+=4){for(var f=[],e=0;e<b.length;e++){var h=b[e],m=Math.abs(c.data[d]-h[0]),j=Math.abs(c.data[d+1]-h[1]),h=Math.abs(c.data[d+2]-h[2]);f.push(m+j+h)}for(e=m=0;e<a.length;e++)f[e]<f[m]&&(m=e);f=cq.hexToRgb(a[m]); +c.data[d]=f[0];c.data[d+1]=f[1];c.data[d+2]=f[2]}this.context.putImageData(c,0,0);return this},getPalette:function(){for(var a=[],c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height).data,b=0,d=c.length;b<d;b+=4)if(c[b+3]){var f=g.rgbToHex(c[b+0],c[b+1],c[b+2]);-1===a.indexOf(f)&&a.push(f)}return a},pixelize:function(a){if(!a)return this;var c=this.context.mozImageSmoothingEnabled,b=this.context.webkitImageSmoothingEnabled;this.context.mozImageSmoothingEnabled=!1;this.context.webkitImageSmoothingEnabled= +!1;a=this.canvas.width/(a||4)/this.canvas.width;var d=cq(this.canvas.width,this.canvas.height);d.drawImage(this.canvas,0,0,this.canvas.width,this.canvas.height,0,0,this.canvas.width*a|0,this.canvas.height*a|0);this.clear().drawImage(d.canvas,0,0,this.canvas.width*a|0,this.canvas.height*a|0,0,0,this.canvas.width,this.canvas.height);this.context.mozImageSmoothingEnabled=c;this.context.webkitImageSmoothingEnabled=b;return this},colorToMask:function(a,c){a=g.color(a).toArray();for(var b=this.context.getImageData(0, +0,this.canvas.width,this.canvas.height).data,d=[],f=0,e=b.length;f<e;f+=4)b[f+0]==a[0]&&b[f+1]==a[1]&&b[f+2]==a[2]?d.push(c||!1):d.push(!c);return d},grayscaleToMask:function(a){g.color(a).toArray();a=this.context.getImageData(0,0,this.canvas.width,this.canvas.height).data;for(var c=[],b=0,d=a.length;b<d;b+=4)c.push((a[b+0]+a[b+1]+a[b+2])/3|0);return c},grayscaleToAlpha:function(){for(var a=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),c=a.data,b=0,d=c.length;b<d;b+=4)c[b+3]= +(c[b+0]+c[b+1]+c[b+2])/3|0,c[b+0]=c[b+1]=c[b+2]=255;this.context.putImageData(a,0,0);return this},applyMask:function(a){for(var c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),b=c.data,d="boolean"===typeof a[0]?"bool":"byte",f=0,e=b.length;f<e;f+=4){var h=a[f/4];b[f+3]="bool"===d?255*h|0:h|0}this.context.putImageData(c,0,0);return this},fillMask:function(a){var c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),b=c.data,d="boolean"===typeof a[0]?"bool":"byte", +f=2===arguments.length?"normal":"gradient",e=g.color(arguments[1]);"gradient"===f&&(colorB=g.color(arguments[2]));for(var h=0,m=b.length;h<m;h+=4){var j=a[h/4];"byte"===d&&(j/=255);"normal"===f?j&&(b[h+0]=e[0]|0,b[h+1]=e[1]|0,b[h+2]=e[2]|0,b[h+3]=255*j|0):(b[h+0]=e[0]+(colorB[0]-e[0])*j|0,b[h+1]=e[1]+(colorB[1]-e[1])*j|0,b[h+2]=e[2]+(colorB[2]-e[2])*j|0,b[h+3]=255)}this.context.putImageData(c,0,0);return this},clear:function(a){a?(this.context.fillStyle=a,this.context.fillRect(0,0,this.canvas.width, +this.canvas.height)):this.context.clearRect(0,0,this.canvas.width,this.canvas.height);return this},clone:function(){var a=g.createCanvas(this.canvas.width,this.canvas.height);a.getContext("2d").drawImage(this.canvas,0,0);return g(a)},fillStyle:function(a){this.context.fillStyle=a;return this},strokeStyle:function(a){this.context.strokeStyle=a;return this},gradientText:function(a,c,b,d,f){var e=a.split(" "),h=2*this.font().match(/\d+/g)[0],g=0,j=0;if(d)for(var j=0,k=[""],n=0;n<e.length;n++){a=e[n]+ +" ";var l=this.context.measureText(a).width;g+l>d&&(k[++j]="",g=0);k[j]+=a;g+=l}else k=[a];for(n=0;n<k.length;n++){j=b+0.6*n*h|0;d=this.context.createLinearGradient(0,j,0,j+0.6*h|0);for(e=0;e<f.length;e+=2)d.addColorStop(f[e],f[e+1]);a=k[n];this.fillStyle(d).fillText(a,c,j)}return this},setHsl:function(){var a=1===arguments.length?arguments[0]:arguments,c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),b=c.data,d,f,e;e=[];d=[];for(var h=0,m=b.length;h<m;h+=4)e=g.rgbToHsl(b[h+0], +b[h+1],b[h+2]),d=null===a[0]?e[0]:g.limitValue(a[0],0,1),f=null===a[1]?e[1]:g.limitValue(a[1],0,1),e=null===a[2]?e[2]:g.limitValue(a[2],0,1),d=g.hslToRgb(d,f,e),b[h+0]=d[0],b[h+1]=d[1],b[h+2]=d[2];this.context.putImageData(c,0,0);return this},shiftHsl:function(){var a=1===arguments.length?arguments[0]:arguments,c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),b=c.data,d,f,e;e=[];d=[];for(var h=0,m=b.length;h<m;h+=4)e=g.rgbToHsl(b[h+0],b[h+1],b[h+2]),d=null===a[0]?e[0]:g.wrapValue(e[0]+ +a[0],0,1),f=null===a[1]?e[1]:g.limitValue(e[1]+a[1],0,1),e=null===a[2]?e[2]:g.limitValue(e[2]+a[2],0,1),d=g.hslToRgb(d,f,e),b[h+0]=d[0],b[h+1]=d[1],b[h+2]=d[2];this.context.putImageData(c,0,0);return this},replaceHue:function(a,c){var b=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),d=b.data,f,e=[];f=[];for(var h=0,m=d.length;h<m;h+=4)e=g.rgbToHsl(d[h+0],d[h+1],d[h+2]),f=0.05>Math.abs(e[0]-a)?g.wrapValue(c,0,1):e[0],f=g.hslToRgb(f,e[1],e[2]),d[h+0]=f[0],d[h+1]=f[1],d[h+2]=f[2]; +this.context.putImageData(b,0,0);return this},invert:function(){for(var a=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),c=a.data,b=0,d=c.length;b<d;b+=4)c[b+0]=255-c[b+0],c[b+1]=255-c[b+1],c[b+2]=255-c[b+2];this.context.putImageData(a,0,0);return this},roundRect:function(a,c,b,d,f){this.beginPath();this.moveTo(a+f,c);this.lineTo(a+b-f,c);this.quadraticCurveTo(a+b,c,a+b,c+f);this.lineTo(a+b,c+d-f);this.quadraticCurveTo(a+b,c+d,a+b-f,c+d);this.lineTo(a+f,c+d);this.quadraticCurveTo(a, +c+d,a,c+d-f);this.lineTo(a,c+f);this.quadraticCurveTo(a,c,a+f,c);this.closePath();return this},wrappedText:function(a,c,b,d,f){var e=a.split(" "),h=2*this.font().match(/\d+/g)[0],g=0,j=0;if(d){a=0;for(var k=[""],n=0;n<e.length;n++){var j=e[n]+" ",l=this.context.measureText(j).width;g+l>d&&(k[++a]="",g=0);k[a]+=j;g+=l}}else k=[a];for(n=0;n<k.length;n++)j=b+0.6*n*h|0,a=k[n],f&&f.call(this,c,b+j),this.fillText(a,c,j);return this},textBoundaries:function(a,c){var b=a.split(" "),d=2*this.font().match(/\d+/g)[0], +f=0;if(c)for(var e=0,h=[""],g=0;g<b.length;g++){var j=b[g]+" ",k=this.context.measureText(j).width;f+k>c&&(h[++e]="",f=0);h[e]+=j;f+=k}else h=[a],c=this.measureText(a).width;return{height:0.6*h.length*d|0,width:c}},paperBag:function(a,c,b,d,f,e){this.beginPath();this.moveTo(a,c);this.quadraticCurveTo(a+b/2|0,c+d*e|0,a+b,c);this.quadraticCurveTo(a+b-b*f|0,c+d/2|0,a+b,c+d);this.quadraticCurveTo(a+b/2|0,c+d-d*e|0,a,c+d);this.quadraticCurveTo(a+b*f|0,c+d/2|0,a,c)},borderImage:function(a,c,b,d,f,e,h,g, +j,k){this.drawImage(a,j,0,a.width-j-h,e,c+j,b,d-j-h,e);this.drawImage(a,j,a.height-g,a.width-j-h,g,c+j,b+f-g,d-j-h,g);this.drawImage(a,0,e,j,a.height-g-e,c,b+e,j,f-g-e);this.drawImage(a,a.width-h,e,h,a.height-g-e,c+d-h,b+e,h,f-g-e);this.drawImage(a,0,0,j,e,c,b,j,e);this.drawImage(a,a.width-h,0,h,e,c+d-h,b,h,e);this.drawImage(a,a.width-h,a.height-g,h,g,c+d-h,b+f-g,h,g);this.drawImage(a,0,a.height-g,j,g,c,b+f-g,j,g);k&&("string"===typeof k?this.fillStyle(k).fillRect(c+j,b+e,d-j-h,f-e-g):this.drawImage(a, +j,e,a.width-h-j,a.height-g-e,c+j,b+e,d-j-h,f-e-g))},convolve:function(a,c,b){"undefined"===typeof b&&(b=1);"undefined"===typeof c&&(c=1);for(var d=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),f=Math.sqrt(a.length)+0.5|0,e=f/2|0,h=d.data,m=d.width,d=d.height,j=g.createImageData(this.canvas.width,this.canvas.height),k=j.data,n=1;n<d-1;n++)for(var l=1;l<m-1;l++){for(var r=4*(n*m+l),z=0,p=0,q=0,w=0;w<f;w++)for(var x=0;x<f;x++){var s=n+w-e,t=l+x-e;0<=s&&(s<d&&0<=t&&t<m)&&(s=4*(s* +m+t),t=a[w*f+x]/b,z+=h[s+0]*t,p+=h[s+1]*t,q+=h[s+2]*t)}k[r+0]=g.mix(h[r+0],z,c);k[r+1]=g.mix(h[r+1],p,c);k[r+2]=g.mix(h[r+2],q,c);k[r+3]=h[r+3]}this.context.putImageData(j,0,0);return this},blur:function(a){return this.convolve([1,1,1,1,1,1,1,1,1],a,9)},gaussianBlur:function(a){return this.convolve([6.7E-7,2.292E-5,1.9117E-4,3.8771E-4,1.9117E-4,2.292E-5,6.7E-7,2.292E-5,7.8633E-4,0.00655965,0.01330373,0.00655965,7.8633E-4,2.292E-5,1.9117E-4,0.00655965,0.05472157,0.11098164,0.05472157,0.00655965,1.9117E-4, +3.8771E-4,0.01330373,0.11098164,0.22508352,0.11098164,0.01330373,3.8771E-4,1.9117E-4,0.00655965,0.05472157,0.11098164,0.05472157,0.00655965,1.9117E-4,2.292E-5,7.8633E-4,0.00655965,0.01330373,0.00655965,7.8633E-4,2.292E-5,6.7E-7,2.292E-5,1.9117E-4,3.8771E-4,1.9117E-4,2.292E-5,6.7E-7],a,1)},sharpen:function(a){return this.convolve([0,-1,0,-1,5,-1,0,-1,0],a)},threshold:function(a){for(var c=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),b=c.data,d,f,e,g=0;g<b.length;g+=4)d=b[g], +f=b[g+1],e=b[g+2],b[g]=b[g+1]=b[g+2]=0.2126*d+0.7152*f+0.0722*e>=a?255:0;this.context.putImageData(c,0,0);return this},sepia:function(){for(var a=this.context.getImageData(0,0,this.canvas.width,this.canvas.height),c=a.data,b=0;b<c.length;b+=4)c[b+0]=g.limitValue(0.393*c[b+0]+0.769*c[b+1]+0.189*c[b+2],0,255),c[b+1]=g.limitValue(0.349*c[b+0]+0.686*c[b+1]+0.168*c[b+2],0,255),c[b+2]=g.limitValue(0.272*c[b+0]+0.534*c[b+1]+0.131*c[b+2],0,255);this.context.putImageData(a,0,0);return this},measureText:function(){return this.context.measureText.apply(this.context, +arguments)},createRadialGradient:function(){return this.context.createRadialGradient.apply(this.context,arguments)},createLinearGradient:function(){return this.context.createLinearGradient.apply(this.context,arguments)},getImageData:function(){return this.context.getImageData.apply(this.context,arguments)},framework:function(a,c){c&&(this.tempContext=!0===c?a:c);for(var b in a)if(this[b])this[b](a[b],v,v);this.tempContext=null;return this},onStep:function(a,c){var b=this.tempContext||this,d=Date.now(); +this.timer=setInterval(function(){var c=Date.now()-d;d=Date.now();a.call(b,c,d)},c);return this},onRender:function(a){function c(){var f=Date.now()-d;d=Date.now();requestAnimationFrame(c);a.call(b,f,d)}var b=this.tempContext||this,d=Date.now();requestAnimationFrame(c);return this},onMouseMove:function(a){var c=this.tempContext||this;y?this.canvas.addEventListener("touchmove",function(b){b.preventDefault();b=g.mousePosition(b);a.call(c,b.x,b.y)}):this.canvas.addEventListener("mousemove",function(b){b= +g.mousePosition(b);a.call(c,b.x,b.y)});return this},onMouseDown:function(a){var c=this.tempContext||this;y?this.canvas.addEventListener("touchstart",function(b){var d=g.mousePosition(b);a.call(c,d.x,d.y,b.button)}):this.canvas.addEventListener("mousedown",function(b){var d=g.mousePosition(b);a.call(c,d.x,d.y,b.button)});return this},onMouseUp:function(a){var c=this.tempContext||this;y?this.canvas.addEventListener("touchend",function(b){var d=g.mousePosition(b);a.call(c,d.x,d.y,b.button)}):this.canvas.addEventListener("mouseup", +function(b){var d=g.mousePosition(b);a.call(c,d.x,d.y,b.button)});return this},onSwipe:function(a,c,b){function d(a){a.preventDefault();k=g.mousePosition(a);n=Date.now()}function f(a){a.preventDefault();p=g.mousePosition(a);q=Date.now()}function e(b){b.preventDefault();b=k.x-p.x;var c=k.y-p.y,d=Math.sqrt(b*b+c*c),e=q-n,f=v;d>l&&e<j&&(f=Math.abs(b)>Math.abs(c)?0<b?"left":"right":0<c?"up":"down",a.call(h,f))}var h=this.tempContext||this,l=c||35,j=b||350,k=0,n=0,p=0,q=0;this.canvas.addEventListener("touchstart", +function(a){d(a)});this.canvas.addEventListener("touchmove",function(a){f(a)});this.canvas.addEventListener("touchend",function(a){e(a)});this.canvas.addEventListener("mousedown",function(a){d(a)});this.canvas.addEventListener("mousemove",function(a){f(a)});this.canvas.addEventListener("mouseup",function(a){e(a)});return this},onKeyDown:function(a){document.addEventListener("keydown",function(c){c=48<=c.which&&90>=c.which?String.fromCharCode(c.which).toLowerCase():g.keycodes[c.which];a.call(self, +c)});return this},onKeyUp:function(a){document.addEventListener("keyup",function(c){c=48<=c.which&&90>=c.which?String.fromCharCode(c.which).toLowerCase():g.keycodes[c.which];a.call(self,c)});return this},onResize:function(a){var c=this;l.addEventListener("resize",function(){a.call(c,l.innerWidth,l.innerHeight)});a.call(c,l.innerWidth,l.innerHeight);return this},onDropImage:function(a){var c=this;document.addEventListener("drop",function(b){b.stopPropagation();b.preventDefault();b=b.dataTransfer.files[0]; +if(!/image/i.test(b.type))return!1;var d=new FileReader;d.onload=function(b){var d=new Image;d.onload=function(){a.call(c,this)};d.src=b.target.result};d.readAsDataURL(b)});document.addEventListener("dragover",function(a){a.preventDefault()});return this}};for(var u="arc arcTo beginPath bezierCurveTo clearRect clip closePath createImageData createLinearGradient createRadialGradient createPattern drawFocusRing drawImage fill fillRect fillText getImageData isPointInPath lineTo measureText moveTo putImageData quadraticCurveTo rect restore rotate save scale setTransform stroke strokeRect strokeText transform translate".split(" "), +q=0;q<u.length;q++){var p=u[q];g.Wrapper.prototype[p]||(g.Wrapper.prototype[p]=Function("this.context."+p+".apply(this.context, arguments); return this;"))}u="canvas fillStyle font globalAlpha globalCompositeOperation lineCap lineJoin lineWidth miterLimit shadowOffsetX shadowOffsetY shadowBlur shadowColor strokeStyle textAlign textBaseline".split(" ");for(q=0;q<u.length;q++)p=u[q],g.Wrapper.prototype[p]||(g.Wrapper.prototype[p]=Function("if(arguments.length) { this.context."+p+" = arguments[0]; return this; } else { return this.context."+ +p+"; }"));g.Color=function(){arguments.length&&this.parse(arguments)};g.Color.prototype={parse:function(a){"string"===typeof a[0]?(a=g.hexToRgb(a[0]),this[0]=a[0],this[1]=a[1],this[2]=a[2],this[3]=255):(this[0]=a[0],this[1]=a[1],this[2]=a[2],this[3]="undefined"===typeof a[3]?255:a[3])},toArray:function(){return[this[0],this[1],this[2],this[3]]},toRgb:function(){return"rgb("+this[0]+", "+this[1]+", "+this[2]+")"},toRgba:function(){return"rgb("+this[0]+", "+this[1]+", "+this[2]+", "+this[3]+")"},toHex:function(){return g.rgbToHex(this[0], +this[1],this[2])},toHsl:function(){return g.rgbToHsl(this[0],this[1],this[2])},toHsv:function(){return g.rgbToHsv(this[0],this[1],this[2])}};l.cq=l.CanvasQuery=g;"function"===typeof define&&define.amd&&define([],function(){return g})})(window);
\ No newline at end of file diff --git a/public/js/draw.js b/public/js/draw.js index 786b6b6..8bd82df 100644 --- a/public/js/draw.js +++ b/public/js/draw.js @@ -1,4 +1,5 @@ $(function(){ + if ($("#workspace").length == 0) return; var drawing = false; var color = colors.black; var brush = new Brush({ style: 'pencil', color: color, width: 10 }); @@ -60,11 +61,6 @@ $(function(){ } } - function Point(e, offset) { - this.x = e.pageX - offset.left; - this.y = e.pageY - offset.top; - } - }); function Brush (b) { @@ -94,3 +90,20 @@ function Brush (b) { ctx.putImageData(id, 0, 0); $("#drawing").append(canvas); } + +function Point(e, offset) { + this.x = e.pageX - offset.left; + this.y = e.pageY - offset.top; +} +Point.prototype.add = function(p) { + this.x += p.x; + this.y += p.y; +} +Point.prototype.subtract = function(p) { + this.x -= p.x; + this.y -= p.y; +} +Point.prototype.quantize = function(x, y) { + this.x = Math.floor( this.x / x ) * x; + this.y = Math.floor( this.y / y ) * y; +} |
