From dfc9963eaefe7ea2af4426d5632c44fab7e821bc Mon Sep 17 00:00:00 2001 From: jakubfiala Date: Fri, 16 Nov 2018 12:22:22 +0000 Subject: [PATCH] build web version --- dist/atrament.min.js | 2 +- dist/atrament.min.js.map | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/atrament.min.js b/dist/atrament.min.js index 35392b6..d87f03c 100644 --- a/dist/atrament.min.js +++ b/dist/atrament.min.js @@ -1,2 +1,2 @@ -!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.atrament=e():t.atrament=e()}(this,function(){return function(t){function e(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return t[o].call(i.exports,i,i.exports,e),i.loaded=!0,i.exports}var n={};return e.m=t,e.c=n,e.p="",e(0)}([function(t,e,n){t.exports=n(1)},function(t,e,n){"use strict";t.exports=n(2)},function(t,e,n){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}function i(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);ethis._targetThickness?this._thickness-=.5:this._thickness=0&&v(w);)w-=4*h;w+=4*h,++x;for(var k=!1,b=!1;x++0&&(v(w-4)?k||(f.push([_-1,x]),k=!0):k&&(k=!1)),_=1?this.context.globalAlpha=1:this.context.globalAlpha=t/10}}],[{key:"lineDistance",value:function(t,e,n,o){var i=Math.pow(n-t,2),s=Math.pow(o-e,2);return Math.sqrt(i+s)}},{key:"hexToRgb",value:function(t){var e=t.match(/^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i);return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{key:"matchColor",value:function(t,e,n,o,i){return function(s){var r=t[s],a=t[s+1],c=t[s+2],h=t[s+3];return r===e&&a===n&&c===o&&h===i}}},{key:"colorPixel",value:function(e,n,o,s,r,a){var c=t.matchColor.apply(t,[e].concat(i(r)));return function(t){e[t]=n,e[t+1]=o,e[t+2]=s,e[t+3]=a,c(t+4)||(e[t+4]=.01*e[t+4]+.99*n,e[t+4+1]=.01*e[t+4+1]+.99*o,e[t+4+2]=.01*e[t+4+2]+.99*s,e[t+4+3]=.01*e[t+4+3]+.99*a),c(t-4)||(e[t-4]=.01*e[t-4]+.99*n,e[t-4+1]=.01*e[t-4+1]+.99*o,e[t-4+2]=.01*e[t-4+2]+.99*s,e[t-4+3]=.01*e[t-4+3]+.99*a)}}}]),t}();t.exports=r,t.exports.Atrament=u},function(t,e){"use strict";function n(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function o(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function t(t,e){for(var n=0;nthis._targetThickness?this._thickness-=.5:this._thickness=0&&v(w);)w-=4*h;w+=4*h,++x;for(var k=!1,b=!1;x++0&&(v(w-4)?k||(f.push([_-1,x]),k=!0):k&&(k=!1)),_=1?this.context.globalAlpha=1:this.context.globalAlpha=t/10}}],[{key:"lineDistance",value:function(t,e,n,i){var o=Math.pow(n-t,2),s=Math.pow(i-e,2);return Math.sqrt(o+s)}},{key:"hexToRgb",value:function(t){var e=t.match(/^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i);return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}},{key:"matchColor",value:function(t,e,n,i,o){return function(s){var r=t[s],a=t[s+1],c=t[s+2],h=t[s+3];return r===e&&a===n&&c===i&&h===o}}},{key:"colorPixel",value:function(e,n,i,s,r,a){var c=t.matchColor.apply(t,[e].concat(o(r)));return function(t){e[t]=n,e[t+1]=i,e[t+2]=s,e[t+3]=a,c(t+4)||(e[t+4]=.01*e[t+4]+.99*n,e[t+4+1]=.01*e[t+4+1]+.99*i,e[t+4+2]=.01*e[t+4+2]+.99*s,e[t+4+3]=.01*e[t+4+3]+.99*a),c(t-4)||(e[t-4]=.01*e[t-4]+.99*n,e[t-4+1]=.01*e[t-4+1]+.99*i,e[t-4+2]=.01*e[t-4+2]+.99*s,e[t-4+3]=.01*e[t-4+3]+.99*a)}}}]),t}();t.exports=r,t.exports.Atrament=u},function(t,e){"use strict";function n(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function i(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(e,"__esModule",{value:!0});var s=function(){function t(t,e){for(var n=0;n this._targetThickness) {\n\t this._thickness -= 0.5;\n\t } else if (this._thickness < this._targetThickness) {\n\t this._thickness += 0.5;\n\t }\n\t // set line width\n\t context.lineWidth = this._thickness;\n\t } else {\n\t // line width is equal to default weight\n\t context.lineWidth = this._weight;\n\t }\n\t\n\t // draw using quad interpolation\n\t context.quadraticCurveTo(mouse.px, mouse.py, mouse.x, mouse.y);\n\t context.stroke();\n\t\n\t // remember\n\t mouse.px = mouse.x;\n\t mouse.py = mouse.y;\n\t }\n\t }, {\n\t key: 'fireDirty',\n\t value: function fireDirty() {\n\t var event = document.createEvent('Event');\n\t event.initEvent('dirty', true, true);\n\t this.canvas.dispatchEvent(event);\n\t }\n\t }, {\n\t key: 'clear',\n\t value: function clear() {\n\t if (!this.dirty) {\n\t return;\n\t }\n\t\n\t this._dirty = false;\n\t this.fireDirty();\n\t\n\t // make sure we're in the right compositing mode, and erase everything\n\t if (this.context.globalCompositeOperation === 'destination-out') {\n\t this.mode = 'draw';\n\t this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n\t this.mode = 'erase';\n\t } else {\n\t this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n\t }\n\t }\n\t }, {\n\t key: 'toImage',\n\t value: function toImage() {\n\t return this.canvas.toDataURL();\n\t }\n\t }, {\n\t key: 'fill',\n\t value: function fill() {\n\t var _this2 = this;\n\t\n\t var mouse = this.mouse;\n\t var context = this.context;\n\t var startColor = Array.prototype.slice.call(context.getImageData(mouse.x, mouse.y, 1, 1).data, 0); // converting to Array because Safari 9\n\t\n\t if (!this._filling) {\n\t this.canvas.style.cursor = 'progress';\n\t this._filling = true;\n\t setTimeout(function () {\n\t _this2._floodFill(mouse.x, mouse.y, startColor);\n\t }, 100);\n\t } else {\n\t this._fillStack.push([mouse.x, mouse.y, startColor]);\n\t }\n\t }\n\t }, {\n\t key: '_floodFill',\n\t value: function _floodFill(_startX, _startY, startColor) {\n\t var _this3 = this;\n\t\n\t var context = this.context;\n\t var startX = Math.floor(_startX);\n\t var startY = Math.floor(_startY);\n\t var canvasWidth = context.canvas.width;\n\t var canvasHeight = context.canvas.height;\n\t var pixelStack = [[startX, startY]];\n\t // hex needs to be trasformed to rgb since colorLayer accepts RGB\n\t var fillColor = Atrament.hexToRgb(this.color);\n\t // Need to save current context with colors, we will update it\n\t var colorLayer = context.getImageData(0, 0, context.canvas.width, context.canvas.height);\n\t var alpha = Math.min(context.globalAlpha * 10 * 255, 255);\n\t var colorPixel = Atrament.colorPixel.apply(Atrament, [colorLayer.data].concat(_toConsumableArray(fillColor), [startColor, alpha]));\n\t var matchColor = Atrament.matchColor.apply(Atrament, [colorLayer.data].concat(_toConsumableArray(startColor)));\n\t var matchFillColor = Atrament.matchColor.apply(Atrament, [colorLayer.data].concat([].concat(_toConsumableArray(fillColor), [255])));\n\t\n\t // check if we're trying to fill with the same colour, if so, stop\n\t if (matchFillColor((startY * context.canvas.width + startX) * 4)) {\n\t this._filling = false;\n\t setTimeout(function () {\n\t _this3.canvas.style.cursor = 'crosshair';\n\t }, 100);\n\t return;\n\t }\n\t\n\t while (pixelStack.length) {\n\t var newPos = pixelStack.pop();\n\t var x = newPos[0];\n\t var y = newPos[1];\n\t\n\t var pixelPos = (y * canvasWidth + x) * 4;\n\t\n\t while (y-- >= 0 && matchColor(pixelPos)) {\n\t pixelPos -= canvasWidth * 4;\n\t }\n\t pixelPos += canvasWidth * 4;\n\t\n\t ++y;\n\t\n\t var reachLeft = false;\n\t var reachRight = false;\n\t\n\t while (y++ < canvasHeight - 1 && matchColor(pixelPos)) {\n\t colorPixel(pixelPos);\n\t\n\t if (x > 0) {\n\t if (matchColor(pixelPos - 4)) {\n\t if (!reachLeft) {\n\t pixelStack.push([x - 1, y]);\n\t reachLeft = true;\n\t }\n\t } else if (reachLeft) {\n\t reachLeft = false;\n\t }\n\t }\n\t\n\t if (x < canvasWidth - 1) {\n\t if (matchColor(pixelPos + 4)) {\n\t if (!reachRight) {\n\t pixelStack.push([x + 1, y]);\n\t reachRight = true;\n\t }\n\t } else if (reachRight) {\n\t reachRight = false;\n\t }\n\t }\n\t\n\t pixelPos += canvasWidth * 4;\n\t }\n\t }\n\t\n\t // Update context with filled bucket!\n\t context.putImageData(colorLayer, 0, 0);\n\t\n\t if (this._fillStack.length) {\n\t this._floodFill.apply(this, _toConsumableArray(this._fillStack.shift()));\n\t } else {\n\t this._filling = false;\n\t setTimeout(function () {\n\t _this3.canvas.style.cursor = 'crosshair';\n\t }, 100);\n\t }\n\t }\n\t }, {\n\t key: 'color',\n\t get: function get() {\n\t return this.context.strokeStyle;\n\t },\n\t set: function set(c) {\n\t if (typeof c !== 'string') throw new Error('wrong argument type');\n\t this.context.strokeStyle = c;\n\t }\n\t }, {\n\t key: 'weight',\n\t get: function get() {\n\t return this._weight;\n\t },\n\t set: function set(w) {\n\t if (typeof w !== 'number') throw new Error('wrong argument type');\n\t this._weight = w;\n\t this._thickness = w;\n\t this._targetThickness = w;\n\t this._maxWeight = w + this.WEIGHT_SPREAD;\n\t }\n\t }, {\n\t key: 'adaptiveStroke',\n\t get: function get() {\n\t return this._adaptive;\n\t },\n\t set: function set(s) {\n\t this._adaptive = !!s;\n\t }\n\t }, {\n\t key: 'mode',\n\t get: function get() {\n\t return this._mode;\n\t },\n\t set: function set(m) {\n\t if (typeof m !== 'string') throw new Error('wrong argument type');\n\t switch (m) {\n\t case 'erase':\n\t this._mode = 'erase';\n\t this.context.globalCompositeOperation = 'destination-out';\n\t break;\n\t case 'fill':\n\t this._mode = 'fill';\n\t this.context.globalCompositeOperation = 'source-over';\n\t break;\n\t default:\n\t this._mode = 'draw';\n\t this.context.globalCompositeOperation = 'source-over';\n\t break;\n\t }\n\t }\n\t }, {\n\t key: 'dirty',\n\t get: function get() {\n\t return !!this._dirty;\n\t }\n\t }, {\n\t key: 'smoothing',\n\t get: function get() {\n\t return this._smoothing === this.SMOOTHING_INIT;\n\t },\n\t set: function set(s) {\n\t if (typeof s !== 'boolean') throw new Error('wrong argument type');\n\t this._smoothing = s ? this.SMOOTHING_INIT : 0;\n\t }\n\t }, {\n\t key: 'opacity',\n\t set: function set(o) {\n\t if (typeof o !== 'number') throw new Error('wrong argument type');\n\t // now, we need to scale this, because our drawing method means we don't just get uniform transparency all over the drawn line.\n\t // so we scale it down a lot, meaning that it'll look nicely semi-transparent\n\t // unless opacity is 1, then we should go full on to 1\n\t if (o >= 1) this.context.globalAlpha = 1;else this.context.globalAlpha = o / 10;\n\t }\n\t }], [{\n\t key: 'lineDistance',\n\t value: function lineDistance(x1, y1, x2, y2) {\n\t // calculate euclidean distance between (x1, y1) and (x2, y2)\n\t var xs = Math.pow(x2 - x1, 2);\n\t var ys = Math.pow(y2 - y1, 2);\n\t return Math.sqrt(xs + ys);\n\t }\n\t }, {\n\t key: 'hexToRgb',\n\t value: function hexToRgb(hexColor) {\n\t // Since input type color provides hex and ImageData accepts RGB need to transform\n\t var m = hexColor.match(/^#?([\\da-f]{2})([\\da-f]{2})([\\da-f]{2})$/i);\n\t return [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)];\n\t }\n\t }, {\n\t key: 'matchColor',\n\t value: function matchColor(data, compR, compG, compB, compA) {\n\t return function (pixelPos) {\n\t // Pixel color equals comp color?\n\t var r = data[pixelPos];\n\t var g = data[pixelPos + 1];\n\t var b = data[pixelPos + 2];\n\t var a = data[pixelPos + 3];\n\t\n\t return r === compR && g === compG && b === compB && a === compA;\n\t };\n\t }\n\t }, {\n\t key: 'colorPixel',\n\t value: function colorPixel(data, fillR, fillG, fillB, startColor, alpha) {\n\t var matchColor = Atrament.matchColor.apply(Atrament, [data].concat(_toConsumableArray(startColor)));\n\t\n\t return function (pixelPos) {\n\t // Update fill color in matrix\n\t data[pixelPos] = fillR;\n\t data[pixelPos + 1] = fillG;\n\t data[pixelPos + 2] = fillB;\n\t data[pixelPos + 3] = alpha;\n\t\n\t if (!matchColor(pixelPos + 4)) {\n\t data[pixelPos + 4] = data[pixelPos + 4] * 0.01 + fillR * 0.99;\n\t data[pixelPos + 4 + 1] = data[pixelPos + 4 + 1] * 0.01 + fillG * 0.99;\n\t data[pixelPos + 4 + 2] = data[pixelPos + 4 + 2] * 0.01 + fillB * 0.99;\n\t data[pixelPos + 4 + 3] = data[pixelPos + 4 + 3] * 0.01 + alpha * 0.99;\n\t }\n\t\n\t if (!matchColor(pixelPos - 4)) {\n\t data[pixelPos - 4] = data[pixelPos - 4] * 0.01 + fillR * 0.99;\n\t data[pixelPos - 4 + 1] = data[pixelPos - 4 + 1] * 0.01 + fillG * 0.99;\n\t data[pixelPos - 4 + 2] = data[pixelPos - 4 + 2] * 0.01 + fillB * 0.99;\n\t data[pixelPos - 4 + 3] = data[pixelPos - 4 + 3] * 0.01 + alpha * 0.99;\n\t }\n\t };\n\t }\n\t }]);\n\t\n\t return Atrament;\n\t}();\n\t\n\t// for people who like functional programming\n\t\n\t\n\tfunction atrament(selector, width, height, color) {\n\t return new Atrament(selector, width, height, color);\n\t}\n\t\n\tmodule.exports = atrament;\n\tmodule.exports.Atrament = Atrament;\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports) {\n\n\t\"use strict\";\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\t\n\tvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\t\n\tfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\t\n\tfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\t\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\t\n\t// make a class for Point\n\tvar Point = function () {\n\t function Point(x, y) {\n\t _classCallCheck(this, Point);\n\t\n\t this._x = x;\n\t this._y = y;\n\t }\n\t\n\t _createClass(Point, [{\n\t key: \"set\",\n\t value: function set(x, y) {\n\t this._x = x;\n\t this._y = y;\n\t }\n\t }, {\n\t key: \"x\",\n\t get: function get() {\n\t return this._x;\n\t },\n\t set: function set(x) {\n\t this._x = x;\n\t }\n\t }, {\n\t key: \"y\",\n\t get: function get() {\n\t return this._y;\n\t },\n\t set: function set(y) {\n\t this._y = y;\n\t }\n\t }]);\n\t\n\t return Point;\n\t}();\n\t\n\t// make a class for the mouse data\n\t\n\t\n\tvar Mouse = function (_Point) {\n\t _inherits(Mouse, _Point);\n\t\n\t function Mouse() {\n\t _classCallCheck(this, Mouse);\n\t\n\t var _this = _possibleConstructorReturn(this, (Mouse.__proto__ || Object.getPrototypeOf(Mouse)).call(this, 0, 0));\n\t\n\t _this._down = false;\n\t _this._px = 0;\n\t _this._py = 0;\n\t return _this;\n\t }\n\t\n\t _createClass(Mouse, [{\n\t key: \"down\",\n\t get: function get() {\n\t return this._down;\n\t },\n\t set: function set(d) {\n\t this._down = d;\n\t }\n\t }, {\n\t key: \"x\",\n\t get: function get() {\n\t return this._x;\n\t },\n\t set: function set(x) {\n\t this._x = x;\n\t }\n\t }, {\n\t key: \"y\",\n\t get: function get() {\n\t return this._y;\n\t },\n\t set: function set(y) {\n\t this._y = y;\n\t }\n\t }, {\n\t key: \"px\",\n\t get: function get() {\n\t return this._px;\n\t },\n\t set: function set(px) {\n\t this._px = px;\n\t }\n\t }, {\n\t key: \"py\",\n\t get: function get() {\n\t return this._py;\n\t },\n\t set: function set(py) {\n\t this._py = py;\n\t }\n\t }]);\n\t\n\t return Mouse;\n\t}(Point);\n\t\n\texports.default = Mouse;\n\n/***/ })\n/******/ ])\n});\n;\n\n\n// WEBPACK FOOTER //\n// atrament.min.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 9899426b680185909fd3","module.exports = require('./src/atrament.js');\n\n\n\n// WEBPACK FOOTER //\n// ./index.js","import Mouse from './mouse.js';\n\nclass Atrament {\n constructor(selector, width, height, color) {\n if (!document) throw new Error('no DOM found');\n\n // get canvas element\n if (selector instanceof window.Node && selector.tagName === 'CANVAS') this.canvas = selector;\n else if (typeof selector === 'string') this.canvas = document.querySelector(selector);\n else throw new Error(`can't look for canvas based on '${selector}'`);\n if (!this.canvas) throw new Error('canvas not found');\n\n // set external canvas params\n this.canvas.width = width || 500;\n this.canvas.height = height || 500;\n this.canvas.style.cursor = 'crosshair';\n\n // create a mouse object\n this.mouse = new Mouse();\n\n // mousemove handler\n const mouseMove = e => {\n e.preventDefault();\n\n const rect = this.canvas.getBoundingClientRect();\n const position = e.changedTouches && e.changedTouches[0] || e;\n let x = position.offsetX;\n let y = position.offsetY;\n\n if (typeof x === 'undefined') {\n x = position.clientX - rect.left;\n }\n if (typeof y === 'undefined') {\n y = position.clientY - rect.top;\n }\n\n // draw if we should draw\n if (this.mouse.down) {\n this.draw(x, y);\n if (!this._dirty && (x !== this.mouse.x || y !== this.mouse.y)) {\n this._dirty = true;\n this.fireDirty();\n }\n }\n else {\n this.mouse.x = x;\n this.mouse.y = y;\n }\n };\n\n // mousedown handler\n const mouseDown = (mousePosition) => {\n mousePosition.preventDefault();\n // update position just in case\n mouseMove(mousePosition);\n\n // if we are filling - fill and return\n if (this._mode === 'fill') {\n this.fill();\n return;\n }\n\n // remember it\n this.mouse.px = this.mouse.x;\n this.mouse.py = this.mouse.y;\n // begin drawing\n this.mouse.down = true;\n this.context.beginPath();\n this.context.moveTo(this.mouse.px, this.mouse.py);\n };\n const mouseUp = () => {\n this.mouse.down = false;\n // stop drawing\n this.context.closePath();\n };\n\n // attach listeners\n this.canvas.addEventListener('mousemove', mouseMove);\n this.canvas.addEventListener('mousedown', mouseDown);\n document.addEventListener('mouseup', mouseUp);\n this.canvas.addEventListener('touchstart', mouseDown);\n this.canvas.addEventListener('touchend', mouseUp);\n this.canvas.addEventListener('touchmove', mouseMove);\n\n // helper for destroying Atrament (removing event listeners)\n this.destroy = () => {\n this.clear();\n this.canvas.removeEventListener('mousemove', mouseMove);\n this.canvas.removeEventListener('mousedown', mouseDown);\n document.removeEventListener('mouseup', mouseUp);\n this.canvas.removeEventListener('touchstart', mouseDown);\n this.canvas.removeEventListener('touchend', mouseUp);\n this.canvas.removeEventListener('touchmove', mouseMove);\n };\n\n // set internal canvas params\n this.context = this.canvas.getContext('2d');\n this.context.globalCompositeOperation = 'source-over';\n this.context.globalAlpha = 1;\n this.context.strokeStyle = color || 'rgba(0,0,0,1)';\n this.context.lineCap = 'round';\n this.context.lineJoin = 'round';\n this.context.translate(0.5, 0.5);\n\n this._filling = false;\n this._fillStack = [];\n\n // set drawing params\n this.SMOOTHING_INIT = 0.85;\n this.WEIGHT_SPREAD = 10;\n this._smoothing = this.SMOOTHING_INIT;\n this._maxWeight = 12;\n this._thickness = 2;\n this._targetThickness = 2;\n this._weight = 2;\n this._mode = 'draw';\n this._adaptive = true;\n }\n\n static lineDistance(x1, y1, x2, y2) {\n // calculate euclidean distance between (x1, y1) and (x2, y2)\n const xs = Math.pow(x2 - x1, 2);\n const ys = Math.pow(y2 - y1, 2);\n return Math.sqrt(xs + ys);\n }\n\n static hexToRgb(hexColor) {\n // Since input type color provides hex and ImageData accepts RGB need to transform\n const m = hexColor.match(/^#?([\\da-f]{2})([\\da-f]{2})([\\da-f]{2})$/i);\n return [\n parseInt(m[1], 16),\n parseInt(m[2], 16),\n parseInt(m[3], 16)\n ];\n }\n\n static matchColor(data, compR, compG, compB, compA) {\n return (pixelPos) => {\n // Pixel color equals comp color?\n const r = data[pixelPos];\n const g = data[pixelPos + 1];\n const b = data[pixelPos + 2];\n const a = data[pixelPos + 3];\n\n return (r === compR && g === compG && b === compB && a === compA);\n };\n }\n\n static colorPixel(data, fillR, fillG, fillB, startColor, alpha) {\n const matchColor = Atrament.matchColor(data, ...startColor);\n\n return (pixelPos) => {\n // Update fill color in matrix\n data[pixelPos] = fillR;\n data[pixelPos + 1] = fillG;\n data[pixelPos + 2] = fillB;\n data[pixelPos + 3] = alpha;\n\n if (!matchColor(pixelPos + 4)) {\n data[pixelPos + 4] = data[pixelPos + 4] * 0.01 + fillR * 0.99;\n data[pixelPos + 4 + 1] = data[pixelPos + 4 + 1] * 0.01 + fillG * 0.99;\n data[pixelPos + 4 + 2] = data[pixelPos + 4 + 2] * 0.01 + fillB * 0.99;\n data[pixelPos + 4 + 3] = data[pixelPos + 4 + 3] * 0.01 + alpha * 0.99;\n }\n\n if (!matchColor(pixelPos - 4)) {\n data[pixelPos - 4] = data[pixelPos - 4] * 0.01 + fillR * 0.99;\n data[pixelPos - 4 + 1] = data[pixelPos - 4 + 1] * 0.01 + fillG * 0.99;\n data[pixelPos - 4 + 2] = data[pixelPos - 4 + 2] * 0.01 + fillB * 0.99;\n data[pixelPos - 4 + 3] = data[pixelPos - 4 + 3] * 0.01 + alpha * 0.99;\n }\n };\n }\n\n draw(mX, mY) {\n const mouse = this.mouse;\n const context = this.context;\n\n // calculate distance from previous point\n const rawDist = Atrament.lineDistance(mX, mY, mouse.px, mouse.py);\n\n // now, here we scale the initial smoothing factor by the raw distance\n // this means that when the mouse moves fast, there is more smoothing\n // and when we're drawing small detailed stuff, we have more control\n // also we hard clip at 1\n const smoothingFactor = Math.min(0.87, this._smoothing + (rawDist - 60) / 3000);\n\n // calculate smoothed coordinates\n mouse.x = mX - (mX - mouse.px) * smoothingFactor;\n mouse.y = mY - (mY - mouse.py) * smoothingFactor;\n\n // recalculate distance from previous point, this time relative to the smoothed coords\n const dist = Atrament.lineDistance(mouse.x, mouse.y, mouse.px, mouse.py);\n\n if (this._adaptive) {\n // calculate target thickness based on the new distance\n this._targetThickness = (dist - 1) / (50 - 1) * (this._maxWeight - this._weight) + this._weight;\n // approach the target gradually\n if (this._thickness > this._targetThickness) {\n this._thickness -= 0.5;\n }\n else if (this._thickness < this._targetThickness) {\n this._thickness += 0.5;\n }\n // set line width\n context.lineWidth = this._thickness;\n }\n else {\n // line width is equal to default weight\n context.lineWidth = this._weight;\n }\n\n // draw using quad interpolation\n context.quadraticCurveTo(mouse.px, mouse.py, mouse.x, mouse.y);\n context.stroke();\n\n // remember\n mouse.px = mouse.x;\n mouse.py = mouse.y;\n }\n\n get color() {\n return this.context.strokeStyle;\n }\n\n set color(c) {\n if (typeof c !== 'string') throw new Error('wrong argument type');\n this.context.strokeStyle = c;\n }\n\n get weight() {\n return this._weight;\n }\n\n set weight(w) {\n if (typeof w !== 'number') throw new Error('wrong argument type');\n this._weight = w;\n this._thickness = w;\n this._targetThickness = w;\n this._maxWeight = w + this.WEIGHT_SPREAD;\n }\n\n get adaptiveStroke() {\n return this._adaptive;\n }\n\n set adaptiveStroke(s) {\n this._adaptive = !!s;\n }\n\n get mode() {\n return this._mode;\n }\n\n get dirty() {\n return !!this._dirty;\n }\n\n set mode(m) {\n if (typeof m !== 'string') throw new Error('wrong argument type');\n switch (m) {\n case 'erase':\n this._mode = 'erase';\n this.context.globalCompositeOperation = 'destination-out';\n break;\n case 'fill':\n this._mode = 'fill';\n this.context.globalCompositeOperation = 'source-over';\n break;\n default:\n this._mode = 'draw';\n this.context.globalCompositeOperation = 'source-over';\n break;\n }\n }\n\n get smoothing() {\n return this._smoothing === this.SMOOTHING_INIT;\n }\n\n set smoothing(s) {\n if (typeof s !== 'boolean') throw new Error('wrong argument type');\n this._smoothing = s ? this.SMOOTHING_INIT : 0;\n }\n\n set opacity(o) {\n if (typeof o !== 'number') throw new Error('wrong argument type');\n // now, we need to scale this, because our drawing method means we don't just get uniform transparency all over the drawn line.\n // so we scale it down a lot, meaning that it'll look nicely semi-transparent\n // unless opacity is 1, then we should go full on to 1\n if (o >= 1) this.context.globalAlpha = 1;\n else this.context.globalAlpha = o / 10;\n }\n\n fireDirty() {\n const event = document.createEvent('Event');\n event.initEvent('dirty', true, true);\n this.canvas.dispatchEvent(event);\n }\n\n clear() {\n if (!this.dirty) {\n return;\n }\n\n this._dirty = false;\n this.fireDirty();\n\n // make sure we're in the right compositing mode, and erase everything\n if (this.context.globalCompositeOperation === 'destination-out') {\n this.mode = 'draw';\n this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n this.mode = 'erase';\n }\n else {\n this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n }\n }\n\n toImage() {\n return this.canvas.toDataURL();\n }\n\n fill() {\n const mouse = this.mouse;\n const context = this.context;\n const startColor = Array.prototype.slice.call(context.getImageData(mouse.x, mouse.y, 1, 1).data, 0); // converting to Array because Safari 9\n\n if (!this._filling) {\n this.canvas.style.cursor = 'progress';\n this._filling = true;\n setTimeout(() => { this._floodFill(mouse.x, mouse.y, startColor); }, 100);\n }\n else {\n this._fillStack.push([\n mouse.x,\n mouse.y,\n startColor\n ]);\n }\n }\n\n _floodFill(_startX, _startY, startColor) {\n const context = this.context;\n const startX = Math.floor(_startX);\n const startY = Math.floor(_startY);\n const canvasWidth = context.canvas.width;\n const canvasHeight = context.canvas.height;\n const pixelStack = [[startX, startY]];\n // hex needs to be trasformed to rgb since colorLayer accepts RGB\n const fillColor = Atrament.hexToRgb(this.color);\n // Need to save current context with colors, we will update it\n const colorLayer = context.getImageData(0, 0, context.canvas.width, context.canvas.height);\n const alpha = Math.min(context.globalAlpha * 10 * 255, 255);\n const colorPixel = Atrament.colorPixel(colorLayer.data, ...fillColor, startColor, alpha);\n const matchColor = Atrament.matchColor(colorLayer.data, ...startColor);\n const matchFillColor = Atrament.matchColor(colorLayer.data, ...[...fillColor, 255]);\n\n // check if we're trying to fill with the same colour, if so, stop\n if (matchFillColor((startY * context.canvas.width + startX) * 4)) {\n this._filling = false;\n setTimeout(() => { this.canvas.style.cursor = 'crosshair'; }, 100);\n return;\n }\n\n while (pixelStack.length) {\n const newPos = pixelStack.pop();\n const x = newPos[0];\n let y = newPos[1];\n\n let pixelPos = (y * canvasWidth + x) * 4;\n\n while (y-- >= 0 && matchColor(pixelPos)) {\n pixelPos -= canvasWidth * 4;\n }\n pixelPos += canvasWidth * 4;\n\n ++y;\n\n let reachLeft = false;\n let reachRight = false;\n\n while (y++ < canvasHeight - 1 && matchColor(pixelPos)) {\n colorPixel(pixelPos);\n\n if (x > 0) {\n if (matchColor(pixelPos - 4)) {\n if (!reachLeft) {\n pixelStack.push([x - 1, y]);\n reachLeft = true;\n }\n }\n else if (reachLeft) {\n reachLeft = false;\n }\n }\n\n if (x < canvasWidth - 1) {\n if (matchColor(pixelPos + 4)) {\n if (!reachRight) {\n pixelStack.push([x + 1, y]);\n reachRight = true;\n }\n }\n else if (reachRight) {\n reachRight = false;\n }\n }\n\n pixelPos += canvasWidth * 4;\n }\n }\n\n // Update context with filled bucket!\n context.putImageData(colorLayer, 0, 0);\n\n if (this._fillStack.length) {\n this._floodFill(...this._fillStack.shift());\n }\n else {\n this._filling = false;\n setTimeout(() => { this.canvas.style.cursor = 'crosshair'; }, 100);\n }\n }\n}\n\n// for people who like functional programming\nfunction atrament(selector, width, height, color) {\n return new Atrament(selector, width, height, color);\n}\n\nmodule.exports = atrament;\nmodule.exports.Atrament = Atrament;\n\n\n\n// WEBPACK FOOTER //\n// ./src/atrament.js","// make a class for Point\nclass Point {\n constructor(x, y) {\n this._x = x;\n this._y = y;\n }\n\n get x() {\n return this._x;\n }\n\n get y() {\n return this._y;\n }\n\n set x(x) {\n this._x = x;\n }\n\n set y(y) {\n this._y = y;\n }\n\n set(x, y) {\n this._x = x;\n this._y = y;\n }\n}\n\n// make a class for the mouse data\nclass Mouse extends Point {\n constructor() {\n super(0, 0);\n this._down = false;\n this._px = 0;\n this._py = 0;\n }\n\n get down() {\n return this._down;\n }\n\n set down(d) {\n this._down = d;\n }\n\n get x() {\n return this._x;\n }\n\n get y() {\n return this._y;\n }\n\n set x(x) {\n this._x = x;\n }\n\n set y(y) {\n this._y = y;\n }\n\n get px() {\n return this._px;\n }\n\n get py() {\n return this._py;\n }\n\n set px(px) {\n this._px = px;\n }\n\n set py(py) {\n this._py = py;\n }\n\n}\n\nexport default Mouse;\n\n\n\n// WEBPACK FOOTER //\n// ./src/mouse.js"],"sourceRoot":""} +{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///atrament.min.js","webpack:///webpack/bootstrap d58c4ed1e2c6d5d8c29c","webpack:///./index.js","webpack:///./src/atrament.js","webpack:///./src/mouse.js"],"names":["root","factory","exports","module","define","amd","this","modules","__webpack_require__","moduleId","installedModules","id","loaded","call","m","c","p","_interopRequireDefault","obj","__esModule","default","_toConsumableArray","arr","Array","isArray","i","arr2","length","from","_classCallCheck","instance","Constructor","TypeError","atrament","selector","width","height","color","Atrament","_createClass","defineProperties","target","props","descriptor","enumerable","configurable","writable","Object","defineProperty","key","protoProps","staticProps","prototype","_mouse","_mouse2","_this","document","Error","window","Node","tagName","canvas","querySelector","style","cursor","mouse","Mouse","mouseMove","e","cancelable","preventDefault","rect","getBoundingClientRect","position","changedTouches","x","offsetX","y","offsetY","clientX","left","clientY","top","down","draw","_dirty","fireDirty","mouseDown","mousePosition","_mode","fill","px","py","context","beginPath","moveTo","mouseUp","closePath","addEventListener","destroy","clear","removeEventListener","getContext","globalCompositeOperation","globalAlpha","strokeStyle","lineCap","lineJoin","translate","_filling","_fillStack","SMOOTHING_INIT","WEIGHT_SPREAD","_smoothing","_maxWeight","_thickness","_targetThickness","_weight","_adaptive","value","mX","mY","rawDist","lineDistance","smoothingFactor","Math","min","dist","lineWidth","quadraticCurveTo","stroke","event","createEvent","initEvent","dispatchEvent","dirty","mode","clearRect","toDataURL","_this2","startColor","slice","getImageData","data","push","setTimeout","_floodFill","_startX","_startY","_this3","startX","floor","startY","canvasWidth","canvasHeight","pixelStack","fillColor","hexToRgb","colorLayer","alpha","colorPixel","apply","concat","matchColor","matchFillColor","newPos","pop","pixelPos","reachLeft","reachRight","putImageData","shift","get","set","w","s","o","x1","y1","x2","y2","xs","pow","ys","sqrt","hexColor","match","parseInt","compR","compG","compB","compA","r","g","b","a","fillR","fillG","fillB","_possibleConstructorReturn","self","ReferenceError","_inherits","subClass","superClass","create","constructor","setPrototypeOf","__proto__","Point","_x","_y","_Point","getPrototypeOf","_down","_px","_py","d"],"mappings":"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","file":"atrament.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"atrament\"] = factory();\n\telse\n\t\troot[\"atrament\"] = factory();\n})(this, function() {\nreturn \n\n\n// WEBPACK FOOTER //\n// webpack/universalModuleDefinition","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"atrament\"] = factory();\n\telse\n\t\troot[\"atrament\"] = factory();\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\tmodule.exports = __webpack_require__(1);\n\n\n/***/ }),\n/* 1 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tmodule.exports = __webpack_require__(2);\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\t\n\tvar _mouse = __webpack_require__(3);\n\t\n\tvar _mouse2 = _interopRequireDefault(_mouse);\n\t\n\tfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\t\n\tfunction _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }\n\t\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\t\n\tvar Atrament = function () {\n\t function Atrament(selector, width, height, color) {\n\t var _this = this;\n\t\n\t _classCallCheck(this, Atrament);\n\t\n\t if (!document) throw new Error('no DOM found');\n\t\n\t // get canvas element\n\t if (selector instanceof window.Node && selector.tagName === 'CANVAS') this.canvas = selector;else if (typeof selector === 'string') this.canvas = document.querySelector(selector);else throw new Error('can\\'t look for canvas based on \\'' + selector + '\\'');\n\t if (!this.canvas) throw new Error('canvas not found');\n\t\n\t // set external canvas params\n\t this.canvas.width = width || this.canvas.width;\n\t this.canvas.height = height || this.canvas.height;\n\t this.canvas.style.cursor = 'crosshair';\n\t\n\t // create a mouse object\n\t this.mouse = new _mouse2.default();\n\t\n\t // mousemove handler\n\t var mouseMove = function mouseMove(e) {\n\t if (e.cancelable) {\n\t e.preventDefault();\n\t }\n\t\n\t var rect = _this.canvas.getBoundingClientRect();\n\t var position = e.changedTouches && e.changedTouches[0] || e;\n\t var x = position.offsetX;\n\t var y = position.offsetY;\n\t\n\t if (typeof x === 'undefined') {\n\t x = position.clientX - rect.left;\n\t }\n\t if (typeof y === 'undefined') {\n\t y = position.clientY - rect.top;\n\t }\n\t\n\t // draw if we should draw\n\t if (_this.mouse.down) {\n\t _this.draw(x, y);\n\t if (!_this._dirty && (x !== _this.mouse.x || y !== _this.mouse.y)) {\n\t _this._dirty = true;\n\t _this.fireDirty();\n\t }\n\t } else {\n\t _this.mouse.x = x;\n\t _this.mouse.y = y;\n\t }\n\t };\n\t\n\t // mousedown handler\n\t var mouseDown = function mouseDown(mousePosition) {\n\t if (mousePosition.cancelable) {\n\t mousePosition.preventDefault();\n\t }\n\t // update position just in case\n\t mouseMove(mousePosition);\n\t\n\t // if we are filling - fill and return\n\t if (_this._mode === 'fill') {\n\t _this.fill();\n\t return;\n\t }\n\t\n\t // remember it\n\t _this.mouse.px = _this.mouse.x;\n\t _this.mouse.py = _this.mouse.y;\n\t // begin drawing\n\t _this.mouse.down = true;\n\t _this.context.beginPath();\n\t _this.context.moveTo(_this.mouse.px, _this.mouse.py);\n\t };\n\t var mouseUp = function mouseUp() {\n\t _this.mouse.down = false;\n\t // stop drawing\n\t _this.context.closePath();\n\t };\n\t\n\t // attach listeners\n\t this.canvas.addEventListener('mousemove', mouseMove);\n\t this.canvas.addEventListener('mousedown', mouseDown);\n\t document.addEventListener('mouseup', mouseUp);\n\t this.canvas.addEventListener('touchstart', mouseDown);\n\t this.canvas.addEventListener('touchend', mouseUp);\n\t this.canvas.addEventListener('touchmove', mouseMove);\n\t\n\t // helper for destroying Atrament (removing event listeners)\n\t this.destroy = function () {\n\t _this.clear();\n\t _this.canvas.removeEventListener('mousemove', mouseMove);\n\t _this.canvas.removeEventListener('mousedown', mouseDown);\n\t document.removeEventListener('mouseup', mouseUp);\n\t _this.canvas.removeEventListener('touchstart', mouseDown);\n\t _this.canvas.removeEventListener('touchend', mouseUp);\n\t _this.canvas.removeEventListener('touchmove', mouseMove);\n\t };\n\t\n\t // set internal canvas params\n\t this.context = this.canvas.getContext('2d');\n\t this.context.globalCompositeOperation = 'source-over';\n\t this.context.globalAlpha = 1;\n\t this.context.strokeStyle = color || 'rgba(0,0,0,1)';\n\t this.context.lineCap = 'round';\n\t this.context.lineJoin = 'round';\n\t this.context.translate(0.5, 0.5);\n\t\n\t this._filling = false;\n\t this._fillStack = [];\n\t\n\t // set drawing params\n\t this.SMOOTHING_INIT = 0.85;\n\t this.WEIGHT_SPREAD = 10;\n\t this._smoothing = this.SMOOTHING_INIT;\n\t this._maxWeight = 12;\n\t this._thickness = 2;\n\t this._targetThickness = 2;\n\t this._weight = 2;\n\t this._mode = 'draw';\n\t this._adaptive = true;\n\t }\n\t\n\t _createClass(Atrament, [{\n\t key: 'draw',\n\t value: function draw(mX, mY) {\n\t var mouse = this.mouse;\n\t var context = this.context;\n\t\n\t // calculate distance from previous point\n\t var rawDist = Atrament.lineDistance(mX, mY, mouse.px, mouse.py);\n\t\n\t // now, here we scale the initial smoothing factor by the raw distance\n\t // this means that when the mouse moves fast, there is more smoothing\n\t // and when we're drawing small detailed stuff, we have more control\n\t // also we hard clip at 1\n\t var smoothingFactor = Math.min(0.87, this._smoothing + (rawDist - 60) / 3000);\n\t\n\t // calculate smoothed coordinates\n\t mouse.x = mX - (mX - mouse.px) * smoothingFactor;\n\t mouse.y = mY - (mY - mouse.py) * smoothingFactor;\n\t\n\t // recalculate distance from previous point, this time relative to the smoothed coords\n\t var dist = Atrament.lineDistance(mouse.x, mouse.y, mouse.px, mouse.py);\n\t\n\t if (this._adaptive) {\n\t // calculate target thickness based on the new distance\n\t this._targetThickness = (dist - 1) / (50 - 1) * (this._maxWeight - this._weight) + this._weight;\n\t // approach the target gradually\n\t if (this._thickness > this._targetThickness) {\n\t this._thickness -= 0.5;\n\t } else if (this._thickness < this._targetThickness) {\n\t this._thickness += 0.5;\n\t }\n\t // set line width\n\t context.lineWidth = this._thickness;\n\t } else {\n\t // line width is equal to default weight\n\t context.lineWidth = this._weight;\n\t }\n\t\n\t // draw using quad interpolation\n\t context.quadraticCurveTo(mouse.px, mouse.py, mouse.x, mouse.y);\n\t context.stroke();\n\t\n\t // remember\n\t mouse.px = mouse.x;\n\t mouse.py = mouse.y;\n\t }\n\t }, {\n\t key: 'fireDirty',\n\t value: function fireDirty() {\n\t var event = document.createEvent('Event');\n\t event.initEvent('dirty', true, true);\n\t this.canvas.dispatchEvent(event);\n\t }\n\t }, {\n\t key: 'clear',\n\t value: function clear() {\n\t if (!this.dirty) {\n\t return;\n\t }\n\t\n\t this._dirty = false;\n\t this.fireDirty();\n\t\n\t // make sure we're in the right compositing mode, and erase everything\n\t if (this.context.globalCompositeOperation === 'destination-out') {\n\t this.mode = 'draw';\n\t this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n\t this.mode = 'erase';\n\t } else {\n\t this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n\t }\n\t }\n\t }, {\n\t key: 'toImage',\n\t value: function toImage() {\n\t return this.canvas.toDataURL();\n\t }\n\t }, {\n\t key: 'fill',\n\t value: function fill() {\n\t var _this2 = this;\n\t\n\t var mouse = this.mouse;\n\t var context = this.context;\n\t var startColor = Array.prototype.slice.call(context.getImageData(mouse.x, mouse.y, 1, 1).data, 0); // converting to Array because Safari 9\n\t\n\t if (!this._filling) {\n\t this.canvas.style.cursor = 'progress';\n\t this._filling = true;\n\t setTimeout(function () {\n\t _this2._floodFill(mouse.x, mouse.y, startColor);\n\t }, 100);\n\t } else {\n\t this._fillStack.push([mouse.x, mouse.y, startColor]);\n\t }\n\t }\n\t }, {\n\t key: '_floodFill',\n\t value: function _floodFill(_startX, _startY, startColor) {\n\t var _this3 = this;\n\t\n\t var context = this.context;\n\t var startX = Math.floor(_startX);\n\t var startY = Math.floor(_startY);\n\t var canvasWidth = context.canvas.width;\n\t var canvasHeight = context.canvas.height;\n\t var pixelStack = [[startX, startY]];\n\t // hex needs to be trasformed to rgb since colorLayer accepts RGB\n\t var fillColor = Atrament.hexToRgb(this.color);\n\t // Need to save current context with colors, we will update it\n\t var colorLayer = context.getImageData(0, 0, context.canvas.width, context.canvas.height);\n\t var alpha = Math.min(context.globalAlpha * 10 * 255, 255);\n\t var colorPixel = Atrament.colorPixel.apply(Atrament, [colorLayer.data].concat(_toConsumableArray(fillColor), [startColor, alpha]));\n\t var matchColor = Atrament.matchColor.apply(Atrament, [colorLayer.data].concat(_toConsumableArray(startColor)));\n\t var matchFillColor = Atrament.matchColor.apply(Atrament, [colorLayer.data].concat([].concat(_toConsumableArray(fillColor), [255])));\n\t\n\t // check if we're trying to fill with the same colour, if so, stop\n\t if (matchFillColor((startY * context.canvas.width + startX) * 4)) {\n\t this._filling = false;\n\t setTimeout(function () {\n\t _this3.canvas.style.cursor = 'crosshair';\n\t }, 100);\n\t return;\n\t }\n\t\n\t while (pixelStack.length) {\n\t var newPos = pixelStack.pop();\n\t var x = newPos[0];\n\t var y = newPos[1];\n\t\n\t var pixelPos = (y * canvasWidth + x) * 4;\n\t\n\t while (y-- >= 0 && matchColor(pixelPos)) {\n\t pixelPos -= canvasWidth * 4;\n\t }\n\t pixelPos += canvasWidth * 4;\n\t\n\t ++y;\n\t\n\t var reachLeft = false;\n\t var reachRight = false;\n\t\n\t while (y++ < canvasHeight - 1 && matchColor(pixelPos)) {\n\t colorPixel(pixelPos);\n\t\n\t if (x > 0) {\n\t if (matchColor(pixelPos - 4)) {\n\t if (!reachLeft) {\n\t pixelStack.push([x - 1, y]);\n\t reachLeft = true;\n\t }\n\t } else if (reachLeft) {\n\t reachLeft = false;\n\t }\n\t }\n\t\n\t if (x < canvasWidth - 1) {\n\t if (matchColor(pixelPos + 4)) {\n\t if (!reachRight) {\n\t pixelStack.push([x + 1, y]);\n\t reachRight = true;\n\t }\n\t } else if (reachRight) {\n\t reachRight = false;\n\t }\n\t }\n\t\n\t pixelPos += canvasWidth * 4;\n\t }\n\t }\n\t\n\t // Update context with filled bucket!\n\t context.putImageData(colorLayer, 0, 0);\n\t\n\t if (this._fillStack.length) {\n\t this._floodFill.apply(this, _toConsumableArray(this._fillStack.shift()));\n\t } else {\n\t this._filling = false;\n\t setTimeout(function () {\n\t _this3.canvas.style.cursor = 'crosshair';\n\t }, 100);\n\t }\n\t }\n\t }, {\n\t key: 'color',\n\t get: function get() {\n\t return this.context.strokeStyle;\n\t },\n\t set: function set(c) {\n\t if (typeof c !== 'string') throw new Error('wrong argument type');\n\t this.context.strokeStyle = c;\n\t }\n\t }, {\n\t key: 'weight',\n\t get: function get() {\n\t return this._weight;\n\t },\n\t set: function set(w) {\n\t if (typeof w !== 'number') throw new Error('wrong argument type');\n\t this._weight = w;\n\t this._thickness = w;\n\t this._targetThickness = w;\n\t this._maxWeight = w + this.WEIGHT_SPREAD;\n\t }\n\t }, {\n\t key: 'adaptiveStroke',\n\t get: function get() {\n\t return this._adaptive;\n\t },\n\t set: function set(s) {\n\t this._adaptive = !!s;\n\t }\n\t }, {\n\t key: 'mode',\n\t get: function get() {\n\t return this._mode;\n\t },\n\t set: function set(m) {\n\t if (typeof m !== 'string') throw new Error('wrong argument type');\n\t switch (m) {\n\t case 'erase':\n\t this._mode = 'erase';\n\t this.context.globalCompositeOperation = 'destination-out';\n\t break;\n\t case 'fill':\n\t this._mode = 'fill';\n\t this.context.globalCompositeOperation = 'source-over';\n\t break;\n\t default:\n\t this._mode = 'draw';\n\t this.context.globalCompositeOperation = 'source-over';\n\t break;\n\t }\n\t }\n\t }, {\n\t key: 'dirty',\n\t get: function get() {\n\t return !!this._dirty;\n\t }\n\t }, {\n\t key: 'smoothing',\n\t get: function get() {\n\t return this._smoothing === this.SMOOTHING_INIT;\n\t },\n\t set: function set(s) {\n\t if (typeof s !== 'boolean') throw new Error('wrong argument type');\n\t this._smoothing = s ? this.SMOOTHING_INIT : 0;\n\t }\n\t }, {\n\t key: 'opacity',\n\t set: function set(o) {\n\t if (typeof o !== 'number') throw new Error('wrong argument type');\n\t // now, we need to scale this, because our drawing method means we don't just get uniform transparency all over the drawn line.\n\t // so we scale it down a lot, meaning that it'll look nicely semi-transparent\n\t // unless opacity is 1, then we should go full on to 1\n\t if (o >= 1) this.context.globalAlpha = 1;else this.context.globalAlpha = o / 10;\n\t }\n\t }], [{\n\t key: 'lineDistance',\n\t value: function lineDistance(x1, y1, x2, y2) {\n\t // calculate euclidean distance between (x1, y1) and (x2, y2)\n\t var xs = Math.pow(x2 - x1, 2);\n\t var ys = Math.pow(y2 - y1, 2);\n\t return Math.sqrt(xs + ys);\n\t }\n\t }, {\n\t key: 'hexToRgb',\n\t value: function hexToRgb(hexColor) {\n\t // Since input type color provides hex and ImageData accepts RGB need to transform\n\t var m = hexColor.match(/^#?([\\da-f]{2})([\\da-f]{2})([\\da-f]{2})$/i);\n\t return [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16)];\n\t }\n\t }, {\n\t key: 'matchColor',\n\t value: function matchColor(data, compR, compG, compB, compA) {\n\t return function (pixelPos) {\n\t // Pixel color equals comp color?\n\t var r = data[pixelPos];\n\t var g = data[pixelPos + 1];\n\t var b = data[pixelPos + 2];\n\t var a = data[pixelPos + 3];\n\t\n\t return r === compR && g === compG && b === compB && a === compA;\n\t };\n\t }\n\t }, {\n\t key: 'colorPixel',\n\t value: function colorPixel(data, fillR, fillG, fillB, startColor, alpha) {\n\t var matchColor = Atrament.matchColor.apply(Atrament, [data].concat(_toConsumableArray(startColor)));\n\t\n\t return function (pixelPos) {\n\t // Update fill color in matrix\n\t data[pixelPos] = fillR;\n\t data[pixelPos + 1] = fillG;\n\t data[pixelPos + 2] = fillB;\n\t data[pixelPos + 3] = alpha;\n\t\n\t if (!matchColor(pixelPos + 4)) {\n\t data[pixelPos + 4] = data[pixelPos + 4] * 0.01 + fillR * 0.99;\n\t data[pixelPos + 4 + 1] = data[pixelPos + 4 + 1] * 0.01 + fillG * 0.99;\n\t data[pixelPos + 4 + 2] = data[pixelPos + 4 + 2] * 0.01 + fillB * 0.99;\n\t data[pixelPos + 4 + 3] = data[pixelPos + 4 + 3] * 0.01 + alpha * 0.99;\n\t }\n\t\n\t if (!matchColor(pixelPos - 4)) {\n\t data[pixelPos - 4] = data[pixelPos - 4] * 0.01 + fillR * 0.99;\n\t data[pixelPos - 4 + 1] = data[pixelPos - 4 + 1] * 0.01 + fillG * 0.99;\n\t data[pixelPos - 4 + 2] = data[pixelPos - 4 + 2] * 0.01 + fillB * 0.99;\n\t data[pixelPos - 4 + 3] = data[pixelPos - 4 + 3] * 0.01 + alpha * 0.99;\n\t }\n\t };\n\t }\n\t }]);\n\t\n\t return Atrament;\n\t}();\n\t\n\t// for people who like functional programming\n\t\n\t\n\tfunction atrament(selector, width, height, color) {\n\t return new Atrament(selector, width, height, color);\n\t}\n\t\n\tmodule.exports = atrament;\n\tmodule.exports.Atrament = Atrament;\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports) {\n\n\t\"use strict\";\n\t\n\tObject.defineProperty(exports, \"__esModule\", {\n\t value: true\n\t});\n\t\n\tvar _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();\n\t\n\tfunction _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return call && (typeof call === \"object\" || typeof call === \"function\") ? call : self; }\n\t\n\tfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function, not \" + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }\n\t\n\tfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\t\n\t// make a class for Point\n\tvar Point = function () {\n\t function Point(x, y) {\n\t _classCallCheck(this, Point);\n\t\n\t this._x = x;\n\t this._y = y;\n\t }\n\t\n\t _createClass(Point, [{\n\t key: \"set\",\n\t value: function set(x, y) {\n\t this._x = x;\n\t this._y = y;\n\t }\n\t }, {\n\t key: \"x\",\n\t get: function get() {\n\t return this._x;\n\t },\n\t set: function set(x) {\n\t this._x = x;\n\t }\n\t }, {\n\t key: \"y\",\n\t get: function get() {\n\t return this._y;\n\t },\n\t set: function set(y) {\n\t this._y = y;\n\t }\n\t }]);\n\t\n\t return Point;\n\t}();\n\t\n\t// make a class for the mouse data\n\t\n\t\n\tvar Mouse = function (_Point) {\n\t _inherits(Mouse, _Point);\n\t\n\t function Mouse() {\n\t _classCallCheck(this, Mouse);\n\t\n\t var _this = _possibleConstructorReturn(this, (Mouse.__proto__ || Object.getPrototypeOf(Mouse)).call(this, 0, 0));\n\t\n\t _this._down = false;\n\t _this._px = 0;\n\t _this._py = 0;\n\t return _this;\n\t }\n\t\n\t _createClass(Mouse, [{\n\t key: \"down\",\n\t get: function get() {\n\t return this._down;\n\t },\n\t set: function set(d) {\n\t this._down = d;\n\t }\n\t }, {\n\t key: \"x\",\n\t get: function get() {\n\t return this._x;\n\t },\n\t set: function set(x) {\n\t this._x = x;\n\t }\n\t }, {\n\t key: \"y\",\n\t get: function get() {\n\t return this._y;\n\t },\n\t set: function set(y) {\n\t this._y = y;\n\t }\n\t }, {\n\t key: \"px\",\n\t get: function get() {\n\t return this._px;\n\t },\n\t set: function set(px) {\n\t this._px = px;\n\t }\n\t }, {\n\t key: \"py\",\n\t get: function get() {\n\t return this._py;\n\t },\n\t set: function set(py) {\n\t this._py = py;\n\t }\n\t }]);\n\t\n\t return Mouse;\n\t}(Point);\n\t\n\texports.default = Mouse;\n\n/***/ })\n/******/ ])\n});\n;\n\n\n// WEBPACK FOOTER //\n// atrament.min.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap d58c4ed1e2c6d5d8c29c","module.exports = require('./src/atrament.js');\n\n\n\n// WEBPACK FOOTER //\n// ./index.js","import Mouse from './mouse.js';\n\nclass Atrament {\n constructor(selector, width, height, color) {\n if (!document) throw new Error('no DOM found');\n\n // get canvas element\n if (selector instanceof window.Node && selector.tagName === 'CANVAS') this.canvas = selector;\n else if (typeof selector === 'string') this.canvas = document.querySelector(selector);\n else throw new Error(`can't look for canvas based on '${selector}'`);\n if (!this.canvas) throw new Error('canvas not found');\n\n // set external canvas params\n this.canvas.width = width || this.canvas.width;\n this.canvas.height = height || this.canvas.height;\n this.canvas.style.cursor = 'crosshair';\n\n // create a mouse object\n this.mouse = new Mouse();\n\n // mousemove handler\n const mouseMove = e => {\n if (e.cancelable) {\n e.preventDefault();\n }\n\n const rect = this.canvas.getBoundingClientRect();\n const position = e.changedTouches && e.changedTouches[0] || e;\n let x = position.offsetX;\n let y = position.offsetY;\n\n if (typeof x === 'undefined') {\n x = position.clientX - rect.left;\n }\n if (typeof y === 'undefined') {\n y = position.clientY - rect.top;\n }\n\n // draw if we should draw\n if (this.mouse.down) {\n this.draw(x, y);\n if (!this._dirty && (x !== this.mouse.x || y !== this.mouse.y)) {\n this._dirty = true;\n this.fireDirty();\n }\n }\n else {\n this.mouse.x = x;\n this.mouse.y = y;\n }\n };\n\n // mousedown handler\n const mouseDown = (mousePosition) => {\n if (mousePosition.cancelable) {\n mousePosition.preventDefault();\n }\n // update position just in case\n mouseMove(mousePosition);\n\n // if we are filling - fill and return\n if (this._mode === 'fill') {\n this.fill();\n return;\n }\n\n // remember it\n this.mouse.px = this.mouse.x;\n this.mouse.py = this.mouse.y;\n // begin drawing\n this.mouse.down = true;\n this.context.beginPath();\n this.context.moveTo(this.mouse.px, this.mouse.py);\n };\n const mouseUp = () => {\n this.mouse.down = false;\n // stop drawing\n this.context.closePath();\n };\n\n // attach listeners\n this.canvas.addEventListener('mousemove', mouseMove);\n this.canvas.addEventListener('mousedown', mouseDown);\n document.addEventListener('mouseup', mouseUp);\n this.canvas.addEventListener('touchstart', mouseDown);\n this.canvas.addEventListener('touchend', mouseUp);\n this.canvas.addEventListener('touchmove', mouseMove);\n\n // helper for destroying Atrament (removing event listeners)\n this.destroy = () => {\n this.clear();\n this.canvas.removeEventListener('mousemove', mouseMove);\n this.canvas.removeEventListener('mousedown', mouseDown);\n document.removeEventListener('mouseup', mouseUp);\n this.canvas.removeEventListener('touchstart', mouseDown);\n this.canvas.removeEventListener('touchend', mouseUp);\n this.canvas.removeEventListener('touchmove', mouseMove);\n };\n\n // set internal canvas params\n this.context = this.canvas.getContext('2d');\n this.context.globalCompositeOperation = 'source-over';\n this.context.globalAlpha = 1;\n this.context.strokeStyle = color || 'rgba(0,0,0,1)';\n this.context.lineCap = 'round';\n this.context.lineJoin = 'round';\n this.context.translate(0.5, 0.5);\n\n this._filling = false;\n this._fillStack = [];\n\n // set drawing params\n this.SMOOTHING_INIT = 0.85;\n this.WEIGHT_SPREAD = 10;\n this._smoothing = this.SMOOTHING_INIT;\n this._maxWeight = 12;\n this._thickness = 2;\n this._targetThickness = 2;\n this._weight = 2;\n this._mode = 'draw';\n this._adaptive = true;\n }\n\n static lineDistance(x1, y1, x2, y2) {\n // calculate euclidean distance between (x1, y1) and (x2, y2)\n const xs = Math.pow(x2 - x1, 2);\n const ys = Math.pow(y2 - y1, 2);\n return Math.sqrt(xs + ys);\n }\n\n static hexToRgb(hexColor) {\n // Since input type color provides hex and ImageData accepts RGB need to transform\n const m = hexColor.match(/^#?([\\da-f]{2})([\\da-f]{2})([\\da-f]{2})$/i);\n return [\n parseInt(m[1], 16),\n parseInt(m[2], 16),\n parseInt(m[3], 16)\n ];\n }\n\n static matchColor(data, compR, compG, compB, compA) {\n return (pixelPos) => {\n // Pixel color equals comp color?\n const r = data[pixelPos];\n const g = data[pixelPos + 1];\n const b = data[pixelPos + 2];\n const a = data[pixelPos + 3];\n\n return (r === compR && g === compG && b === compB && a === compA);\n };\n }\n\n static colorPixel(data, fillR, fillG, fillB, startColor, alpha) {\n const matchColor = Atrament.matchColor(data, ...startColor);\n\n return (pixelPos) => {\n // Update fill color in matrix\n data[pixelPos] = fillR;\n data[pixelPos + 1] = fillG;\n data[pixelPos + 2] = fillB;\n data[pixelPos + 3] = alpha;\n\n if (!matchColor(pixelPos + 4)) {\n data[pixelPos + 4] = data[pixelPos + 4] * 0.01 + fillR * 0.99;\n data[pixelPos + 4 + 1] = data[pixelPos + 4 + 1] * 0.01 + fillG * 0.99;\n data[pixelPos + 4 + 2] = data[pixelPos + 4 + 2] * 0.01 + fillB * 0.99;\n data[pixelPos + 4 + 3] = data[pixelPos + 4 + 3] * 0.01 + alpha * 0.99;\n }\n\n if (!matchColor(pixelPos - 4)) {\n data[pixelPos - 4] = data[pixelPos - 4] * 0.01 + fillR * 0.99;\n data[pixelPos - 4 + 1] = data[pixelPos - 4 + 1] * 0.01 + fillG * 0.99;\n data[pixelPos - 4 + 2] = data[pixelPos - 4 + 2] * 0.01 + fillB * 0.99;\n data[pixelPos - 4 + 3] = data[pixelPos - 4 + 3] * 0.01 + alpha * 0.99;\n }\n };\n }\n\n draw(mX, mY) {\n const mouse = this.mouse;\n const context = this.context;\n\n // calculate distance from previous point\n const rawDist = Atrament.lineDistance(mX, mY, mouse.px, mouse.py);\n\n // now, here we scale the initial smoothing factor by the raw distance\n // this means that when the mouse moves fast, there is more smoothing\n // and when we're drawing small detailed stuff, we have more control\n // also we hard clip at 1\n const smoothingFactor = Math.min(0.87, this._smoothing + (rawDist - 60) / 3000);\n\n // calculate smoothed coordinates\n mouse.x = mX - (mX - mouse.px) * smoothingFactor;\n mouse.y = mY - (mY - mouse.py) * smoothingFactor;\n\n // recalculate distance from previous point, this time relative to the smoothed coords\n const dist = Atrament.lineDistance(mouse.x, mouse.y, mouse.px, mouse.py);\n\n if (this._adaptive) {\n // calculate target thickness based on the new distance\n this._targetThickness = (dist - 1) / (50 - 1) * (this._maxWeight - this._weight) + this._weight;\n // approach the target gradually\n if (this._thickness > this._targetThickness) {\n this._thickness -= 0.5;\n }\n else if (this._thickness < this._targetThickness) {\n this._thickness += 0.5;\n }\n // set line width\n context.lineWidth = this._thickness;\n }\n else {\n // line width is equal to default weight\n context.lineWidth = this._weight;\n }\n\n // draw using quad interpolation\n context.quadraticCurveTo(mouse.px, mouse.py, mouse.x, mouse.y);\n context.stroke();\n\n // remember\n mouse.px = mouse.x;\n mouse.py = mouse.y;\n }\n\n get color() {\n return this.context.strokeStyle;\n }\n\n set color(c) {\n if (typeof c !== 'string') throw new Error('wrong argument type');\n this.context.strokeStyle = c;\n }\n\n get weight() {\n return this._weight;\n }\n\n set weight(w) {\n if (typeof w !== 'number') throw new Error('wrong argument type');\n this._weight = w;\n this._thickness = w;\n this._targetThickness = w;\n this._maxWeight = w + this.WEIGHT_SPREAD;\n }\n\n get adaptiveStroke() {\n return this._adaptive;\n }\n\n set adaptiveStroke(s) {\n this._adaptive = !!s;\n }\n\n get mode() {\n return this._mode;\n }\n\n get dirty() {\n return !!this._dirty;\n }\n\n set mode(m) {\n if (typeof m !== 'string') throw new Error('wrong argument type');\n switch (m) {\n case 'erase':\n this._mode = 'erase';\n this.context.globalCompositeOperation = 'destination-out';\n break;\n case 'fill':\n this._mode = 'fill';\n this.context.globalCompositeOperation = 'source-over';\n break;\n default:\n this._mode = 'draw';\n this.context.globalCompositeOperation = 'source-over';\n break;\n }\n }\n\n get smoothing() {\n return this._smoothing === this.SMOOTHING_INIT;\n }\n\n set smoothing(s) {\n if (typeof s !== 'boolean') throw new Error('wrong argument type');\n this._smoothing = s ? this.SMOOTHING_INIT : 0;\n }\n\n set opacity(o) {\n if (typeof o !== 'number') throw new Error('wrong argument type');\n // now, we need to scale this, because our drawing method means we don't just get uniform transparency all over the drawn line.\n // so we scale it down a lot, meaning that it'll look nicely semi-transparent\n // unless opacity is 1, then we should go full on to 1\n if (o >= 1) this.context.globalAlpha = 1;\n else this.context.globalAlpha = o / 10;\n }\n\n fireDirty() {\n const event = document.createEvent('Event');\n event.initEvent('dirty', true, true);\n this.canvas.dispatchEvent(event);\n }\n\n clear() {\n if (!this.dirty) {\n return;\n }\n\n this._dirty = false;\n this.fireDirty();\n\n // make sure we're in the right compositing mode, and erase everything\n if (this.context.globalCompositeOperation === 'destination-out') {\n this.mode = 'draw';\n this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n this.mode = 'erase';\n }\n else {\n this.context.clearRect(-10, -10, this.canvas.width + 20, this.canvas.height + 20);\n }\n }\n\n toImage() {\n return this.canvas.toDataURL();\n }\n\n fill() {\n const mouse = this.mouse;\n const context = this.context;\n const startColor = Array.prototype.slice.call(context.getImageData(mouse.x, mouse.y, 1, 1).data, 0); // converting to Array because Safari 9\n\n if (!this._filling) {\n this.canvas.style.cursor = 'progress';\n this._filling = true;\n setTimeout(() => { this._floodFill(mouse.x, mouse.y, startColor); }, 100);\n }\n else {\n this._fillStack.push([\n mouse.x,\n mouse.y,\n startColor\n ]);\n }\n }\n\n _floodFill(_startX, _startY, startColor) {\n const context = this.context;\n const startX = Math.floor(_startX);\n const startY = Math.floor(_startY);\n const canvasWidth = context.canvas.width;\n const canvasHeight = context.canvas.height;\n const pixelStack = [[startX, startY]];\n // hex needs to be trasformed to rgb since colorLayer accepts RGB\n const fillColor = Atrament.hexToRgb(this.color);\n // Need to save current context with colors, we will update it\n const colorLayer = context.getImageData(0, 0, context.canvas.width, context.canvas.height);\n const alpha = Math.min(context.globalAlpha * 10 * 255, 255);\n const colorPixel = Atrament.colorPixel(colorLayer.data, ...fillColor, startColor, alpha);\n const matchColor = Atrament.matchColor(colorLayer.data, ...startColor);\n const matchFillColor = Atrament.matchColor(colorLayer.data, ...[...fillColor, 255]);\n\n // check if we're trying to fill with the same colour, if so, stop\n if (matchFillColor((startY * context.canvas.width + startX) * 4)) {\n this._filling = false;\n setTimeout(() => { this.canvas.style.cursor = 'crosshair'; }, 100);\n return;\n }\n\n while (pixelStack.length) {\n const newPos = pixelStack.pop();\n const x = newPos[0];\n let y = newPos[1];\n\n let pixelPos = (y * canvasWidth + x) * 4;\n\n while (y-- >= 0 && matchColor(pixelPos)) {\n pixelPos -= canvasWidth * 4;\n }\n pixelPos += canvasWidth * 4;\n\n ++y;\n\n let reachLeft = false;\n let reachRight = false;\n\n while (y++ < canvasHeight - 1 && matchColor(pixelPos)) {\n colorPixel(pixelPos);\n\n if (x > 0) {\n if (matchColor(pixelPos - 4)) {\n if (!reachLeft) {\n pixelStack.push([x - 1, y]);\n reachLeft = true;\n }\n }\n else if (reachLeft) {\n reachLeft = false;\n }\n }\n\n if (x < canvasWidth - 1) {\n if (matchColor(pixelPos + 4)) {\n if (!reachRight) {\n pixelStack.push([x + 1, y]);\n reachRight = true;\n }\n }\n else if (reachRight) {\n reachRight = false;\n }\n }\n\n pixelPos += canvasWidth * 4;\n }\n }\n\n // Update context with filled bucket!\n context.putImageData(colorLayer, 0, 0);\n\n if (this._fillStack.length) {\n this._floodFill(...this._fillStack.shift());\n }\n else {\n this._filling = false;\n setTimeout(() => { this.canvas.style.cursor = 'crosshair'; }, 100);\n }\n }\n}\n\n// for people who like functional programming\nfunction atrament(selector, width, height, color) {\n return new Atrament(selector, width, height, color);\n}\n\nmodule.exports = atrament;\nmodule.exports.Atrament = Atrament;\n\n\n\n// WEBPACK FOOTER //\n// ./src/atrament.js","// make a class for Point\nclass Point {\n constructor(x, y) {\n this._x = x;\n this._y = y;\n }\n\n get x() {\n return this._x;\n }\n\n get y() {\n return this._y;\n }\n\n set x(x) {\n this._x = x;\n }\n\n set y(y) {\n this._y = y;\n }\n\n set(x, y) {\n this._x = x;\n this._y = y;\n }\n}\n\n// make a class for the mouse data\nclass Mouse extends Point {\n constructor() {\n super(0, 0);\n this._down = false;\n this._px = 0;\n this._py = 0;\n }\n\n get down() {\n return this._down;\n }\n\n set down(d) {\n this._down = d;\n }\n\n get x() {\n return this._x;\n }\n\n get y() {\n return this._y;\n }\n\n set x(x) {\n this._x = x;\n }\n\n set y(y) {\n this._y = y;\n }\n\n get px() {\n return this._px;\n }\n\n get py() {\n return this._py;\n }\n\n set px(px) {\n this._px = px;\n }\n\n set py(py) {\n this._py = py;\n }\n\n}\n\nexport default Mouse;\n\n\n\n// WEBPACK FOOTER //\n// ./src/mouse.js"],"sourceRoot":""} \ No newline at end of file