UNPKG

draw-image-editor

Version:
1,695 lines (1,516 loc) 1.1 MB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(require("vue")); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["FabricCanvas"] = factory(require("vue")); else root["FabricCanvas"] = factory(root["Vue"]); })((typeof self !== 'undefined' ? self : this), function(__WEBPACK_EXTERNAL_MODULE__8bbf__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "fb15"); /******/ }) /************************************************************************/ /******/ ({ /***/ 0: /***/ (function(module, exports) { /* (ignored) */ /***/ }), /***/ "0b9a": /***/ (function(module, exports, __webpack_require__) { (function(global) { // var fabric = global.fabric || (global.fabric = {}), // extend = fabric.util.object.extend, var clone = fabric.util.object.clone; // coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 }, supportsLineDash = fabric.StaticCanvas.supports("setLineDash"); if (fabric.WaveLine) { fabric.warn("fabric.WaveLine is already defined."); return; } fabric.WaveLine = fabric.util.createClass(fabric.Line, { type: "WaveLine", initialize(element, options) { options || (options = {}); this.callSuper("initialize", element, options); // Set default options this.set({ // hasBorders: false, // hasControls: false, }); }, _render(ctx) { // this.callSuper('_render', ctx); ctx.save(); const xDiff = this.x2 - this.x1; const yDiff = this.y2 - this.y1; const angle = Math.atan2(yDiff, xDiff); ctx.translate(xDiff / 2, yDiff / 2); ctx.rotate(angle); ctx.beginPath(); ctx.closePath(); ctx.fillStyle = this.stroke; ctx.strokeStyle = this.stroke; ctx.lineWidth = this.strokeWidth; ctx.fill(); ctx.restore(); const p = this.calcLinePoints(); const point = this.pointOnLine( this.point(p.x2, p.y2), this.point(p.x1, p.y1), 10 ); this.wavy( this.point(p.x1, p.y1), point, this.point(p.x2, p.y2), ctx ); ctx.stroke(); }, point(x, y) { return { x, y, }; }, wavy(from, to, endPoint, ctx) { let cx = 0, cy = 0, fx = from.x, fy = from.y, tx = to.x, ty = to.y, i = 0, step = 4, waveOffsetLength = 0, ang = Math.atan2(ty - fy, tx - fx), distance = Math.sqrt( (fx - tx) * (fx - tx) + (fy - ty) * (fy - ty) ), amplitude = -4, f = (Math.PI * distance) / 10; for (i; i <= distance; i += step) { waveOffsetLength = Math.sin((i / distance) * f) * amplitude; cx = from.x + Math.cos(ang) * i + Math.cos(ang - Math.PI / 2) * waveOffsetLength; cy = from.y + Math.sin(ang) * i + Math.sin(ang - Math.PI / 2) * waveOffsetLength; i > 0 ? ctx.lineTo(cx, cy) : ctx.moveTo(cx, cy); } ctx.lineTo(to.x, to.y); // ctx.lineTo(endPoint.x, endPoint.y); }, pointOnLine(point1, point2, dist) { const len = Math.sqrt( (point2.x - point1.x) * (point2.x - point1.x) + (point2.y - point1.y) * (point2.y - point1.y) ); const t = dist / len; let x3 = (1 - t) * point1.x + t * point2.x, y3 = (1 - t) * point1.y + t * point2.y; return new fabric.Point(x3, y3); }, toObject() { return fabric.util.object.extend(this.callSuper("toObject"), { customProps: this.customProps, }); }, }); fabric.WaveLine.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat( "x1 y1 x2 y2".split(" ") ); fabric.WaveLine.fromElement = function(element, callback) { var parsedAttributes = fabric.parseAttributes( element, fabric.WaveLine.ATTRIBUTE_NAMES ); parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.rx; parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.ry; callback(new fabric.WaveLine(parsedAttributes)); }; /* _FROM_SVG_END_ */ /** * Returns {@link fabric.Ellipse} instance from an object representation * @static * @memberOf fabric.Ellipse * @param {Object} object Object to create an instance from * @param {function} [callback] invoked with new instance as first argument * @return {fabric.Ellipse} */ // fabric.WaveLine.fromObject = function(object, callback) { // return fabric.WaveLine._fromObject("WaveLine", object, callback); // }; fabric.WaveLine.fromObject = function(object, callback) { function _callback(instance) { delete instance.points; callback && callback(instance); } var options = clone(object, true); options.points = [object.x1, object.y1, object.x2, object.y2]; fabric.Object._fromObject("WaveLine", options, _callback, "points"); }; })( true ? exports : undefined); // const { color = "#E34F51", lineWidth = 3, radius = 10 } = config; // y2 - y1 < 4 * radius && (y2 = y1 + 4 * radius); // var z1 = (y2 - y1 - 4 * radius) / 2; // ctx.beginPath(), // ctx.closePath(), // (ctx.lineWidth = lineWidth), // (ctx.strokeStyle = color), // ctx.arc(x1, y1 + radius, radius, 1.5 * Math.PI, 2 * Math.PI), // ctx.stroke(); // (ctx.strokeStyle = color), // (ctx.lineWidth = lineWidth), // ctx.beginPath(), // ctx.moveTo(x1 + radius, y1 + radius), // ctx.lineTo(x1 + radius, y1 + radius + z1), // ctx.stroke(), // ctx.beginPath(), // (ctx.lineWidth = lineWidth), // (ctx.strokeStyle = color), // ctx.arc( // x1 + 2 * radius, // y1 + z1 + radius, // radius, // 0.5 * Math.PI, // 1 * Math.PI // ), // ctx.stroke(), // ctx.beginPath(), // (ctx.lineWidth = lineWidth), // (ctx.strokeStyle = color), // ctx.arc( // x1 + 2 * radius, // y1 + z1 + 3 * radius, // radius, // 1 * Math.PI, // 1.5 * Math.PI // ), // ctx.stroke(), // (ctx.strokeStyle = color), // (ctx.lineWidth = lineWidth), // ctx.beginPath(), // ctx.moveTo(x1 + radius, y1 + z1 + 3 * radius), // ctx.lineTo(x1 + radius, y1 + 2 * z1 + 3 * radius), // ctx.stroke(), // ctx.beginPath(), // (ctx.lineWidth = lineWidth), // (ctx.strokeStyle = color), // ctx.arc( // x1, // y1 + 2 * z1 + 3 * radius, // radius, // 0 * Math.PI, // 0.5 * Math.PI // ), // ctx.stroke(); // if (y2 >= y1) { // topArc = [1.5 * Math.PI, 2 * Math.PI]; // topArrow = [0.5 * Math.PI, 1 * Math.PI]; // botArrow = [1 * Math.PI, 1.5 * Math.PI]; // botArc = [0 * Math.PI, 0.5 * Math.PI]; // } else { // topArc = [0 * Math.PI, 0.5 * Math.PI]; // botArc = [1.5 * Math.PI, 2 * Math.PI]; // topArrow = [1 * Math.PI, 1.5 * Math.PI]; // botArrow = [0.5 * Math.PI, 1 * Math.PI]; // } // radius = (y2 - y1) / radius > radius ? 10 : Math.abs((y2 - y1) / radius); /***/ }), /***/ 1: /***/ (function(module, exports) { /* (ignored) */ /***/ }), /***/ "1fb5": /***/ (function(module, exports, __webpack_require__) { "use strict"; exports.byteLength = byteLength exports.toByteArray = toByteArray exports.fromByteArray = fromByteArray var lookup = [] var revLookup = [] var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' for (var i = 0, len = code.length; i < len; ++i) { lookup[i] = code[i] revLookup[code.charCodeAt(i)] = i } // Support decoding URL-safe base64 strings, as Node.js does. // See: https://en.wikipedia.org/wiki/Base64#URL_applications revLookup['-'.charCodeAt(0)] = 62 revLookup['_'.charCodeAt(0)] = 63 function getLens (b64) { var len = b64.length if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } // Trim off extra bytes after placeholder bytes are found // See: https://github.com/beatgammit/base64-js/issues/42 var validLen = b64.indexOf('=') if (validLen === -1) validLen = len var placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4) return [validLen, placeHoldersLen] } // base64 is 4/3 + up to two characters of the original data function byteLength (b64) { var lens = getLens(b64) var validLen = lens[0] var placeHoldersLen = lens[1] return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } function _byteLength (b64, validLen, placeHoldersLen) { return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen } function toByteArray (b64) { var tmp var lens = getLens(b64) var validLen = lens[0] var placeHoldersLen = lens[1] var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) var curByte = 0 // if there are placeholders, only get up to the last complete 4 chars var len = placeHoldersLen > 0 ? validLen - 4 : validLen var i for (i = 0; i < len; i += 4) { tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] arr[curByte++] = (tmp >> 16) & 0xFF arr[curByte++] = (tmp >> 8) & 0xFF arr[curByte++] = tmp & 0xFF } if (placeHoldersLen === 2) { tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) arr[curByte++] = tmp & 0xFF } if (placeHoldersLen === 1) { tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) arr[curByte++] = (tmp >> 8) & 0xFF arr[curByte++] = tmp & 0xFF } return arr } function tripletToBase64 (num) { return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] } function encodeChunk (uint8, start, end) { var tmp var output = [] for (var i = start; i < end; i += 3) { tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF) output.push(tripletToBase64(tmp)) } return output.join('') } function fromByteArray (uint8) { var tmp var len = uint8.length var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes var parts = [] var maxChunkLength = 16383 // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { tmp = uint8[len - 1] parts.push( lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3F] + '==' ) } else if (extraBytes === 2) { tmp = (uint8[len - 2] << 8) + uint8[len - 1] parts.push( lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3F] + lookup[(tmp << 2) & 0x3F] + '=' ) } return parts.join('') } /***/ }), /***/ 2: /***/ (function(module, exports) { /* (ignored) */ /***/ }), /***/ "239c": /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; /* harmony import */ var _node_modules_mini_css_extract_plugin_dist_loader_js_ref_10_oneOf_1_0_node_modules_vue_cli_service_node_modules_css_loader_dist_cjs_js_ref_10_oneOf_1_1_node_modules_vue_cli_service_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_2_node_modules_less_loader_dist_cjs_js_ref_10_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_cli_service_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("c3af"); /* harmony import */ var _node_modules_mini_css_extract_plugin_dist_loader_js_ref_10_oneOf_1_0_node_modules_vue_cli_service_node_modules_css_loader_dist_cjs_js_ref_10_oneOf_1_1_node_modules_vue_cli_service_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_2_node_modules_less_loader_dist_cjs_js_ref_10_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_cli_service_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_mini_css_extract_plugin_dist_loader_js_ref_10_oneOf_1_0_node_modules_vue_cli_service_node_modules_css_loader_dist_cjs_js_ref_10_oneOf_1_1_node_modules_vue_cli_service_node_modules_vue_loader_lib_loaders_stylePostLoader_js_node_modules_postcss_loader_src_index_js_ref_10_oneOf_1_2_node_modules_less_loader_dist_cjs_js_ref_10_oneOf_1_3_node_modules_cache_loader_dist_cjs_js_ref_0_0_node_modules_vue_cli_service_node_modules_vue_loader_lib_index_js_vue_loader_options_index_vue_vue_type_style_index_0_lang_less___WEBPACK_IMPORTED_MODULE_0__); /* unused harmony reexport * */ /***/ }), /***/ "24aa": /***/ (function(module, exports) { var g; // This works in non-strict mode g = (function() { return this; })(); try { // This works if eval is allowed (see CSP) g = g || new Function("return this")(); } catch (e) { // This works if the window reference is available if (typeof window === "object") g = window; } // g can still be undefined, but nothing to do about it... // We return undefined, instead of nothing here, so it's // easier to handle this case. if(!global) { ...} module.exports = g; /***/ }), /***/ "2d70": /***/ (function(module, exports, __webpack_require__) { /* * @Author: your name * @Date: 2020-12-16 14:09:19 * @LastEditTime: 2020-12-18 23:30:43 * @LastEditors: Please set LastEditors * @Description: In User Settings Edit * @FilePath: /draw-image-editor/src/components/fabricCanvas/drawBomb.js */ (function(global) { // var fabric = global.fabric || (global.fabric = {}), // extend = fabric.util.object.extend, var clone = fabric.util.object.clone; // coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 }, // supportsLineDash = fabric.StaticCanvas.supports("setLineDash"); if (fabric.DrawBomb) { fabric.warn("fabric.DrawBomb is already defined."); return; } fabric.DrawBomb = fabric.util.createClass(fabric.Line, { type: "DrawBomb", initialize(element, options) { options || (options = {}); this.callSuper("initialize", element, options); // Set default options this.set({ // hasBorders: false, // hasControls: false, }); }, _render(ctx) { // this.callSuper('_render', ctx); // ctx.save(); const p = this.calcLinePoints(); const config = { color: this.stroke, lineWidth: this.strokeWidth, radius: this.radius, }; this.DrawBomb(ctx, p.x1, p.y1, p.x2, p.y2, config); }, DrawBomb(ctx, startx, starty, endx, endy, config) { let { color = "#E34F51", lineWidth = 3, radius = 3 } = config; if (startx > endx) { var pointX = startx - Math.abs(startx - endx) / 2; } else { var pointX = Math.abs(startx - endx) / 2 + startx; } if (starty > endy) { var pointY = starty - Math.abs(starty - endy) / 2; } else { var pointY = Math.abs(starty - endy) / 2 + starty; } var lineX = Math.abs(startx - endx) / 2; var lineY = Math.abs(starty - endy) / 2; ctx.beginPath(); ctx.closePath(); ctx.lineWidth = lineWidth; ctx.fillStyle = "rgba(0,0,0,0)"; ctx.strokeStyle = color; ctx.ellipse(pointX, pointY, lineX, lineY, 0, 0, 2 * Math.PI); ctx.stroke(); ctx.beginPath(); ctx.lineWidth = lineWidth; ctx.fillStyle = "rgba(0,0,0,0)"; ctx.strokeStyle = color; var ellipseX1 = startx + (endx - startx) / 2; var ellipseY1 = starty; // 第一条竖线 ctx.moveTo(ellipseX1 + 2, ellipseY1); ctx.quadraticCurveTo( Math.abs(ellipseX1), ellipseY1 - 7, ellipseX1 + 2, ellipseY1 - 6 ); ctx.stroke(); //第一个圆 ctx.beginPath(); ctx.arc(ellipseX1 + 5, ellipseY1 - 6, radius, 0, 2 * Math.PI); ctx.stroke(); // 第一个圆的圆边 ctx.beginPath(); ctx.moveTo(ellipseX1 + 2, ellipseY1 - 4); ctx.quadraticCurveTo( ellipseX1 - 3, ellipseY1 - 8, ellipseX1 + 3, ellipseY1 - 15 ); ctx.stroke(); //承接线 ctx.beginPath(); ctx.moveTo(ellipseX1 + 4, ellipseY1 - 13.5); ctx.quadraticCurveTo( ellipseX1 + 3, ellipseY1 - 18, ellipseX1 + 10, ellipseY1 - 17 ); ctx.stroke(); //第二个圆 ctx.beginPath(); ctx.arc( Math.abs(ellipseX1 + 11), ellipseY1 - 13, radius, 0, 2 * Math.PI ); ctx.stroke(); ctx.beginPath(); //第二个圆角 ctx.moveTo(Math.abs(ellipseX1 + 8), ellipseY1 - 15); ctx.quadraticCurveTo( Math.abs(ellipseX1 + 8), ellipseY1 - 23, Math.abs(ellipseX1 + 16), ellipseY1 - 19 ); ctx.stroke(); ctx.beginPath(); ctx.stroke(); }, }); fabric.DrawBomb.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat( "x1 y1 x2 y2".split(" ") ); fabric.DrawBomb.fromElement = function(element, callback) { var parsedAttributes = fabric.parseAttributes( element, fabric.DrawBomb.ATTRIBUTE_NAMES ); parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.rx; parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.ry; callback(new fabric.DrawBomb(parsedAttributes)); }; /* _FROM_SVG_END_ */ /** * Returns {@link fabric.DrawBomb} instance from an object representation * @static * @memberOf fabric.Ellipse * @param {Object} object Object to create an instance from * @param {function} [callback] invoked with new instance as first argument * @return {fabric.Ellipse} */ fabric.DrawBomb.fromObject = function(object, callback) { function _callback(instance) { delete instance.points; callback && callback(instance); } var options = clone(object, true); options.points = [object.x1, object.y1, object.x2, object.y2]; fabric.Object._fromObject("DrawBomb", options, _callback, "points"); }; })( true ? exports : undefined); /***/ }), /***/ "34f0": /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /***/ "4b5c": /***/ (function(module, exports, __webpack_require__) { (function(global) { // var fabric = global.fabric || (global.fabric = {}), // extend = fabric.util.object.extend, var clone = fabric.util.object.clone; // coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 }, // supportsLineDash = fabric.StaticCanvas.supports("setLineDash"); if (fabric.BracketLine) { fabric.warn("fabric.BracketLine is already defined."); return; } fabric.BracketLine = fabric.util.createClass(fabric.Line, { type: "BracketLine", initialize(element, options) { options || (options = {}); this.callSuper("initialize", element, options); // Set default options this.set({ // hasBorders: false, // hasControls: false, }); }, _render(ctx) { // this.callSuper('_render', ctx); // ctx.save(); const p = this.calcLinePoints(); const config = { color: this.stroke, lineWidth: this.strokeWidth, radius: this.radius, }; this.bracketLine(ctx, p.x1, p.y1, p.x2, p.y2, config); // this.bracketLine(ctx, this.x1, this.y1, this.x2, this.y2, config); }, bracketLine(ctx, x1, y1, x2, y2, config) { let { color = "#E34F51", lineWidth = 3, radius = 10 } = config; radius = (y2 - y1) / 5 > radius ? 10 : Math.abs((y2 - y1) / 5); var z1 = (y2 - y1 - 4 * radius) / 2; //> 0 ? (y2 - y1 - 4 * radius) / 2 : 0; ctx.beginPath(); ctx.closePath(); ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.arc(x1, y1 + radius, radius, 1.5 * Math.PI, 2 * Math.PI); ctx.stroke(); if (y2 > y1 + radius) { ctx.strokeStyle = color; ctx.lineWidth = lineWidth; ctx.beginPath(); ctx.moveTo(x1 + radius, y1 + radius); var topLineTo = z1 > 0 ? z1 : 0; ctx.lineTo(x1 + radius, y1 + radius + topLineTo); ctx.stroke(); ctx.beginPath(); ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.arc( x1 + 2 * radius, y1 + topLineTo + radius, radius, 0.5 * Math.PI, 1 * Math.PI ); ctx.stroke(); ctx.beginPath(); ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.arc( x1 + 2 * radius, y1 + topLineTo + 3 * radius, radius, 1 * Math.PI, 1.5 * Math.PI ); ctx.stroke(); ctx.strokeStyle = color; ctx.lineWidth = lineWidth; ctx.beginPath(); ctx.moveTo(x1 + radius, y1 + topLineTo + 3 * radius); ctx.lineTo(x1 + radius, y1 + 2 * topLineTo + 3 * radius); ctx.stroke(); ctx.beginPath(); ctx.lineWidth = lineWidth; ctx.strokeStyle = color; ctx.arc( x1, y1 + 2 * topLineTo + 3 * radius, radius, 0 * Math.PI, 0.5 * Math.PI ); ctx.stroke(); } }, }); fabric.BracketLine.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat( "x1 y1 x2 y2".split(" ") ); fabric.BracketLine.fromElement = function(element, callback) { var parsedAttributes = fabric.parseAttributes( element, fabric.BracketLine.ATTRIBUTE_NAMES ); parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.rx; parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.ry; callback(new fabric.BracketLine(parsedAttributes)); }; /* _FROM_SVG_END_ */ /** * Returns {@link fabric.BracketLine} instance from an object representation * @static * @memberOf fabric.Ellipse * @param {Object} object Object to create an instance from * @param {function} [callback] invoked with new instance as first argument * @return {fabric.Ellipse} */ fabric.BracketLine.fromObject = function(object, callback) { function _callback(instance) { delete instance.points; callback && callback(instance); } var options = clone(object, true); options.points = [object.x1, object.y1, object.x2, object.y2]; fabric.Object._fromObject("BracketLine", options, _callback, "points"); }; })( true ? exports : undefined); /***/ }), /***/ "63a0": /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /***/ "7173": /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /***/ "7a94": /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(Buffer) {/* build: `node build.js modules=ALL exclude=gestures,accessors requirejs minifier=uglifyjs` */ /*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */ var fabric = fabric || { version: '4.2.0' }; if (true) { exports.fabric = fabric; } /* _AMD_START_ */ else {} /* _AMD_END_ */ if (typeof document !== 'undefined' && typeof window !== 'undefined') { if (document instanceof (typeof HTMLDocument !== 'undefined' ? HTMLDocument : Document)) { fabric.document = document; } else { fabric.document = document.implementation.createHTMLDocument(''); } fabric.window = window; } else { // assume we're running under node.js when document/window are not present var jsdom = __webpack_require__(0); var virtualWindow = new jsdom.JSDOM( decodeURIComponent('%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E'), { features: { FetchExternalResources: ['img'] }, resources: 'usable' }).window; fabric.document = virtualWindow.document; fabric.jsdomImplForWrapper = __webpack_require__(1).implForWrapper; fabric.nodeCanvas = __webpack_require__(2).Canvas; fabric.window = virtualWindow; DOMParser = fabric.window.DOMParser; } /** * True when in environment that supports touch events * @type boolean */ fabric.isTouchSupported = 'ontouchstart' in fabric.window || 'ontouchstart' in fabric.document || (fabric.window && fabric.window.navigator && fabric.window.navigator.maxTouchPoints > 0); /** * True when in environment that's probably Node.js * @type boolean */ fabric.isLikelyNode = typeof Buffer !== 'undefined' && typeof window === 'undefined'; /* _FROM_SVG_START_ */ /** * Attributes parsed from all SVG elements * @type array */ fabric.SHARED_ATTRIBUTES = [ 'display', 'transform', 'fill', 'fill-opacity', 'fill-rule', 'opacity', 'stroke', 'stroke-dasharray', 'stroke-linecap', 'stroke-dashoffset', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke-width', 'id', 'paint-order', 'vector-effect', 'instantiated_by_use', 'clip-path', ]; /* _FROM_SVG_END_ */ /** * Pixel per Inch as a default value set to 96. Can be changed for more realistic conversion. */ fabric.DPI = 96; fabric.reNum = '(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:[eE][-+]?\\d+)?)'; fabric.commaWsp = '(?:\\s+,?\\s*|,\\s*)' fabric.rePathCommand = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:[eE][-+]?\d+)?)/ig; fabric.reNonWord = /[ \n\.,;!\?\-]/; fabric.fontPaths = { }; fabric.iMatrix = [1, 0, 0, 1, 0, 0]; fabric.svgNS = 'http://www.w3.org/2000/svg'; /** * Pixel limit for cache canvases. 1Mpx , 4Mpx should be fine. * @since 1.7.14 * @type Number * @default */ fabric.perfLimitSizeTotal = 2097152; /** * Pixel limit for cache canvases width or height. IE fixes the maximum at 5000 * @since 1.7.14 * @type Number * @default */ fabric.maxCacheSideLimit = 4096; /** * Lowest pixel limit for cache canvases, set at 256PX * @since 1.7.14 * @type Number * @default */ fabric.minCacheSideLimit = 256; /** * Cache Object for widths of chars in text rendering. */ fabric.charWidthsCache = { }; /** * if webgl is enabled and available, textureSize will determine the size * of the canvas backend * @since 2.0.0 * @type Number * @default */ fabric.textureSize = 2048; /** * When 'true', style information is not retained when copy/pasting text, making * pasted text use destination style. * Defaults to 'false'. * @type Boolean * @default */ fabric.disableStyleCopyPaste = false; /** * Enable webgl for filtering picture is available * A filtering backend will be initialized, this will both take memory and * time since a default 2048x2048 canvas will be created for the gl context * @since 2.0.0 * @type Boolean * @default */ fabric.enableGLFiltering = true; /** * Device Pixel Ratio * @see https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/SettingUptheCanvas/SettingUptheCanvas.html */ fabric.devicePixelRatio = fabric.window.devicePixelRatio || fabric.window.webkitDevicePixelRatio || fabric.window.mozDevicePixelRatio || 1; /** * Browser-specific constant to adjust CanvasRenderingContext2D.shadowBlur value, * which is unitless and not rendered equally across browsers. * * Values that work quite well (as of October 2017) are: * - Chrome: 1.5 * - Edge: 1.75 * - Firefox: 0.9 * - Safari: 0.95 * * @since 2.0.0 * @type Number * @default 1 */ fabric.browserShadowBlurConstant = 1; /** * This object contains the result of arc to beizer conversion for faster retrieving if the same arc needs to be converted again. * It was an internal variable, is accessible since version 2.3.4 */ fabric.arcToSegmentsCache = { }; /** * This object keeps the results of the boundsOfCurve calculation mapped by the joined arguments necessary to calculate it. * It does speed up calculation, if you parse and add always the same paths, but in case of heavy usage of freedrawing * you do not get any speed benefit and you get a big object in memory. * The object was a private variable before, while now is appended to the lib so that you have access to it and you * can eventually clear it. * It was an internal variable, is accessible since version 2.3.4 */ fabric.boundsOfCurveCache = { }; /** * If disabled boundsOfCurveCache is not used. For apps that make heavy usage of pencil drawing probably disabling it is better * @default true */ fabric.cachesBoundsOfCurve = true; /** * Skip performance testing of setupGLContext and force the use of putImageData that seems to be the one that works best on * Chrome + old hardware. if your users are experiencing empty images after filtering you may try to force this to true * this has to be set before instantiating the filtering backend ( before filtering the first image ) * @type Boolean * @default false */ fabric.forceGLPutImageData = false; fabric.initFilterBackend = function() { if (fabric.enableGLFiltering && fabric.isWebglSupported && fabric.isWebglSupported(fabric.textureSize)) { console.log('max texture size: ' + fabric.maxTextureSize); return (new fabric.WebglFilterBackend({ tileSize: fabric.textureSize })); } else if (fabric.Canvas2dFilterBackend) { return (new fabric.Canvas2dFilterBackend()); } }; if (typeof document !== 'undefined' && typeof window !== 'undefined') { // ensure globality even if entire library were function wrapped (as in Meteor.js packaging system) window.fabric = fabric; } (function() { /** * @private * @param {String} eventName * @param {Function} handler */ function _removeEventListener(eventName, handler) { if (!this.__eventListeners[eventName]) { return; } var eventListener = this.__eventListeners[eventName]; if (handler) { eventListener[eventListener.indexOf(handler)] = false; } else { fabric.util.array.fill(eventListener, false); } } /** * Observes specified event * @memberOf fabric.Observable * @alias on * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler}) * @param {Function} handler Function that receives a notification when an event of the specified type occurs * @return {Self} thisArg * @chainable */ function on(eventName, handler) { if (!this.__eventListeners) { this.__eventListeners = { }; } // one object with key/value pairs was passed if (arguments.length === 1) { for (var prop in eventName) { this.on(prop, eventName[prop]); } } else { if (!this.__eventListeners[eventName]) { this.__eventListeners[eventName] = []; } this.__eventListeners[eventName].push(handler); } return this; } /** * Stops event observing for a particular event handler. Calling this method * without arguments removes all handlers for all events * @memberOf fabric.Observable * @alias off * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler}) * @param {Function} handler Function to be deleted from EventListeners * @return {Self} thisArg * @chainable */ function off(eventName, handler) { if (!this.__eventListeners) { return this; } // remove all key/value pairs (event name -> event handler) if (arguments.length === 0) { for (eventName in this.__eventListeners) { _removeEventListener.call(this, eventName); } } // one object with key/value pairs was passed else if (arguments.length === 1 && typeof arguments[0] === 'object') { for (var prop in eventName) { _removeEventListener.call(this, prop, eventName[prop]); } } else { _removeEventListener.call(this, eventName, handler); } return this; } /** * Fires event with an optional options object * @memberOf fabric.Observable * @param {String} eventName Event name to fire * @param {Object} [options] Options object * @return {Self} thisArg * @chainable */ function fire(eventName, options) { if (!this.__eventListeners) { return this; } var listenersForEvent = this.__eventListeners[eventName]; if (!listenersForEvent) { return this; } for (var i = 0, len = listenersForEvent.length; i < len; i++) { listenersForEvent[i] && listenersForEvent[i].call(this, options || { }); } this.__eventListeners[eventName] = listenersForEvent.filter(function(value) { return value !== false; }); return this; } /** * @namespace fabric.Observable * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events} * @see {@link http://fabricjs.com/events|Events demo} */ fabric.Observable = { fire: fire, on: on, off: off, }; })(); /** * @namespace fabric.Collection */ fabric.Collection = { _objects: [], /** * Adds objects to collection, Canvas or Group, then renders canvas * (if `renderOnAddRemove` is not `false`). * in case of Group no changes to bounding box are made. * Objects should be instances of (or inherit from) fabric.Object * Use of this function is highly discouraged for groups. * you can add a bunch of objects with the add method but then you NEED * to run a addWithUpdate call for the Group class or position/bbox will be wrong. * @param {...fabric.Object} object Zero or more fabric instances * @return {Self} thisArg * @chainable */ add: function () { this._objects.push.apply(this._objects, arguments); if (this._onObjectAdded) { for (var i = 0, length = arguments.length; i < length; i++) { this._onObjectAdded(arguments[i]); } } this.renderOnAddRemove && this.requestRenderAll(); return this; }, /** * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`) * An object should be an instance of (or inherit from) fabric.Object * Use of this function is highly discouraged for groups. * you can add a bunch of objects with the insertAt method but then you NEED * to run a addWithUpdate call for the Group class or position/bbox will be wrong. * @param {Object} object Object to insert * @param {Number} index Index to insert object at * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs * @return {Self} thisArg * @chainable */ insertAt: function (object, index, nonSplicing) { var objects = this._objects; if (nonSplicing) { objects[index] = object; } else { objects.splice(index, 0, object); } this._onObjectAdded && this._onObjectAdded(object); this.renderOnAddRemove && this.requestRenderAll(); return this; }, /** * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`) * @param {...fabric.Object} object Zero or more fabric instances * @return {Self} thisArg * @chainable */ remove: function() { var objects = this._objects, index, somethingRemoved = false; for (var i = 0, length = arguments.length; i < length; i++) { index = objects.indexOf(arguments[i]); // only call onObjectRemoved if an object was actually removed if (index !== -1) { somethingRemoved = true; objects.splice(index, 1); this._onObjectRemoved && this._onObjectRemoved(arguments[i]); } } this.renderOnAddRemove && somethingRemoved && this.requestRenderAll(); return this; }, /** * Executes given function for each object in this group * @param {Function} callback * Callback invoked with current object as first argument, * index - as second and an array of all objects - as third. * Callback is invoked in a context of Global Object (e.g. `window`) * when no `context` argument is given * * @param {Object} context Context (aka thisObject) * @return {Self} thisArg * @chainable */ forEachObject: function(callback, context) { var objects = this.getObjects(); for (var i = 0, len = objects.length; i < len; i++) { callback.call(context, objects[i], i, objects); } return this; }, /** * Returns an array of children objects of this instance * Type parameter introduced in 1.3.10 * since 2.3.5 this method return always a COPY of the array; * @param {String} [type] When specified, only objects of this type are returned * @return {Array} */ getObjects: function(type) { if (typeof type === 'undefined') { return this._objects.concat(); } return this._objects.filter(function(o) { return o.type === type; }); }, /** * Returns object at specified index * @param {Number} index * @return {Self} thisArg */ item: function (index) { return this._objects[index]; }, /** * Returns true if collection contains no objects * @return {Boolean} true if collection is empty */ isEmpty: function () { return this._objects.length === 0; }, /** * Returns a size of a collection (i.e: length of an array containing its objects) * @return {Number} Collection size */ size: function() { return this._objects.length; }, /** * Returns true if collection contains an object * @param {Object} object Object to check against * @return {Boolean} `true` if collection contains an object */ contains: function(object) { return this._objects.indexOf(object) > -1; }, /** * Returns number representation of a collection complexity * @return {Number} complexity */ complexity: function () { return this._objects.reduce(function (memo, current) { memo += current.complexity ? current.complexity() : 0; return memo; }, 0); } }; /** * @namespace fabric.CommonMethods */ fabric.CommonMethods = { /** * Sets object's properties from options * @param {Object} [options] Options object */ _setOptions: function(options) { for (var prop in options) { this.set(prop, options[prop]); } }, /** * @private * @param {Object} [filler] Options object * @param {String} [property] property to set the Gradient to */ _initGradient: function(filler, property) { if (filler && filler.colorStops && !(filler instanceof fabric.Gradient)) { this.set(property, new fabric.Gradient(filler)); } }, /** * @private * @param {Object} [filler] Options object * @param {String} [property] property to set the Pattern to * @param {Function} [callback] callback to invoke after pattern load */ _initPattern: function(filler, property, callback) { if (filler && filler.source && !(filler instanceof fabric.Pattern)) { this.set(property, new fabric.Pattern(filler, callback)); } else { callback && callback(); } }, /** * @private */ _setObject: function(obj) { for (var prop in obj) { this._set(prop, obj[prop]); } }, /** * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`. * @param {String|Object} key Property name or object (if object, iterate over the object properties) * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one) * @return {fabric.Object} thisArg * @chainable */ set: function(key, value) { if (typeof key === 'object') { this._setObject(key); } else { this._set(key, value); } return this; }, _set: function(key, value) { this[key] = value; }, /** * Toggles specified property from `true` to `false` or from `false` to `true` * @param {String} property Property to toggle * @return {fabric.Object} thisArg * @chainable */ toggle: function(property) { var value = this.get(property); if (typeof value === 'boolean') { this.set(property, !value); } return this; }, /** * Basic getter * @param {String} property Property name * @return {*} value of a property */ get: function(property) { return this[property]; } }; (function(global) { var sqrt = Math.sqrt, atan2 = Math.atan2, pow = Math.pow, PiBy180 = Math.PI / 180, PiBy2 = Math.PI / 2; /** * @namespace fabric.util */ fabric.util = { /** * Calculate the cos of an angle, avoiding returning floats for known results * @static * @memberOf fabric.util * @param {Number} angle the angle in radians or in degree * @return {Number} */ cos: function(angle) { if (angle === 0) { return 1; } if (angle < 0) { // cos(a) = cos(-a) angle = -angle; } var angleSlice = angle / PiBy2; switch (angleSlice) { case 1: case 3: return 0; case 2: return -1; } return Math.cos(angle); }, /** * Calculate the sin of an angle, avoiding returning floats for known results * @static * @memberOf fabric.util * @param {Number} angle the angle in radians or in degree * @return {Number} */ sin: function(angle) { if (angle === 0) { return 0; } var angleSlice = angle / PiBy2, sign = 1; if (angle < 0) { // sin(-a) = -sin(a) sign = -1; } switch (angleSlice) { case 1: return sign; case 2: return 0; case 3: return -sign; } return Math.sin(angle); }, /** * Removes value from an array. * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf` * @static * @memberOf fabric.util * @param {Array} array * @param {*} value * @return {Array} original array */ removeFromArray: function(array, value) { var idx = array.indexOf(value); if (idx !== -1) { array.splice(idx, 1); } return array; }, /** * Returns random number between 2 specified ones. * @static * @memberOf fabric.util * @param {Number} min lower limit * @param {Number} max upper limit * @return {Number} random value (between min and max) */ getRandomInt: function(min, max) { return Math.floor(Math.random() * (max - min + 1)) + min; }, /** * Transforms degrees to radians. * @static * @memberOf fabric.util * @param {Number} degrees value in degrees * @return {Number} value in radians */ degreesToRadians: function(degrees) { return degrees * PiBy180; }, /** * Transforms radians to degrees. * @static * @memberOf fabric.util * @param {Number} radians value in radians * @return {Number} value in degrees */ radiansToDegrees: function(radians) { return radians / PiBy180; }, /** * Rotates `point` around `origin` with `radians` * @static * @memberOf fabric.util * @param {fabric.Point} point The point to rotate * @param {fabric.Point} origin The origin of the rotation * @param {Number} radians The radians of the angle for the rotation * @return {fabric.Point} The new rotated point */ rotatePoint: function(point, origin, radians) { point.subtractEquals(origin); var v = fabric.util.rotateVector(point, radians); return new fabric.Point(v.x, v.y).addEquals(origin); }, /** * Rotates `vector` with `radians` * @static * @memberOf fabric.util * @param {Object} vector The vector to rotate (x and y) * @param {Number} radians The radians of the angle for the rotation * @return {Object} The new rotated point */ rotateVector: function(vector, radians) { var sin = fabric.util.sin(radians), cos = fabric.util.cos(radians), rx = vector.x * cos - vector.y * sin, ry = vector.x * sin + vector.y * cos; return { x: rx, y: ry }; }, /** * Apply transform t to point p * @static * @memberOf fabric.util * @param {fabric.Point} p The point to transform * @param {Array} t The transform * @param {Boolean} [ignoreOffset] Indicates that the offset should not be applied * @return {fabric.Point} The transformed point */ transformPoint: function(p, t, ignoreOffset) { if (ignoreOffset) { return new fabric.Point( t[0] * p.x + t[2] * p.y, t[1] * p.x + t[3] * p.y ); } return new fabric.Point( t[0] * p.x + t[2] * p.y + t[4], t[1] * p.x + t[3] * p.y + t[5] ); }, /** * Returns coordinates of points's bounding rectangle (left, top, width, height) * @param {Array} points 4 points array * @param {Array} [transform] an array of 6 numbers representing a 2x3 transform matrix * @return {Object} Object with left, top, width, height properties */ makeBoundingBoxFromPoints: function(points, transform) { if (transform) { for (var i = 0; i < points.length; i++) { points[i] = fabric.util.transformPoint(points[i], transform); } } var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x], minX = fabric.util.array.min(xPoints), maxX = fabric.util.array.max(xPoints), width = maxX - minX, yPoints = [points[0].y, points[1].y, points[2].y, points[3].y], minY = fabric.util.array.min(yPoints), maxY = fabric.util.array.max(yPoints), height = maxY - minY; return { left: minX, top: minY, width: width, height: height }; }, /** * Invert transformation t * @static * @memberOf fabric.util * @param {Array} t The transform * @return {Array} The inverted transform */ invertTransform: function(t) { var a = 1 / (t[0] * t[3] - t[1] * t[2]), r = [a * t[3], -a * t[1], -a * t[2], a * t[0]], o = fabric.util.transformPoint({ x: t[4], y: t[5] }, r, true); r[4] = -o.x; r[5] = -o.y; return r; }, /** * A wrapper around Number#toFixed, which contrary to native method returns number, not string. * @static * @memberOf fabric.util * @param {Number|String} number number to operate on * @param {Number} fractionDigits number of fraction digits to "leave" * @return {Number} */ toFixed: function(number, fractionDigits) { return parseFloat(Number(number).toFixed(fractionDigits)); }, /** * Converts from attribute value to pixel value if applicable. * Returns converted pixels or original value not converted. * @param {Number|String} value number to operate on * @param {Number} fontSize * @retu