426b9ec9511389d205e227563e0de944.json
131 KB
{"ast":null,"code":"/**\r\n * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>\r\n * @fileoverview Image-editor application class\r\n */\nimport snippet from 'tui-code-snippet';\nimport Invoker from './invoker';\nimport UI from './ui';\nimport action from './action';\nimport commandFactory from './factory/command';\nimport Graphics from './graphics';\nimport { sendHostName, Promise } from './util';\nimport { eventNames as events, commandNames as commands, keyCodes, rejectMessages } from './consts';\nimport { makeSelectionUndoData, makeSelectionUndoDatum } from './helper/selectionModifyHelper';\nconst {\n isUndefined,\n forEach,\n CustomEvents\n} = snippet;\nconst {\n MOUSE_DOWN,\n OBJECT_MOVED,\n OBJECT_SCALED,\n OBJECT_ACTIVATED,\n OBJECT_ROTATED,\n OBJECT_ADDED,\n OBJECT_MODIFIED,\n ADD_TEXT,\n ADD_OBJECT,\n TEXT_EDITING,\n TEXT_CHANGED,\n ICON_CREATE_RESIZE,\n ICON_CREATE_END,\n SELECTION_CLEARED,\n SELECTION_CREATED,\n ADD_OBJECT_AFTER\n} = events;\n/**\r\n * Image filter result\r\n * @typedef {object} FilterResult\r\n * @property {string} type - filter type like 'mask', 'Grayscale' and so on\r\n * @property {string} action - action type like 'add', 'remove'\r\n */\n\n/**\r\n * Flip status\r\n * @typedef {object} FlipStatus\r\n * @property {boolean} flipX - x axis\r\n * @property {boolean} flipY - y axis\r\n * @property {Number} angle - angle\r\n */\n\n/**\r\n * Rotation status\r\n * @typedef {Number} RotateStatus\r\n * @property {Number} angle - angle\r\n */\n\n/**\r\n * Old and new Size\r\n * @typedef {object} SizeChange\r\n * @property {Number} oldWidth - old width\r\n * @property {Number} oldHeight - old height\r\n * @property {Number} newWidth - new width\r\n * @property {Number} newHeight - new height\r\n */\n\n/**\r\n * @typedef {string} ErrorMsg - {string} error message\r\n */\n\n/**\r\n * @typedef {object} ObjectProps - graphics object properties\r\n * @property {number} id - object id\r\n * @property {string} type - object type\r\n * @property {string} text - text content\r\n * @property {(string | number)} left - Left\r\n * @property {(string | number)} top - Top\r\n * @property {(string | number)} width - Width\r\n * @property {(string | number)} height - Height\r\n * @property {string} fill - Color\r\n * @property {string} stroke - Stroke\r\n * @property {(string | number)} strokeWidth - StrokeWidth\r\n * @property {string} fontFamily - Font type for text\r\n * @property {number} fontSize - Font Size\r\n * @property {string} fontStyle - Type of inclination (normal / italic)\r\n * @property {string} fontWeight - Type of thicker or thinner looking (normal / bold)\r\n * @property {string} textAlign - Type of text align (left / center / right)\r\n * @property {string} textDecoration - Type of line (underline / line-through / overline)\r\n */\n\n/**\r\n * Shape filter option\r\n * @typedef {object.<string, number>} ShapeFilterOption\r\n */\n\n/**\r\n * Shape filter option\r\n * @typedef {object} ShapeFillOption - fill option of shape\r\n * @property {string} type - fill type ('color' or 'filter')\r\n * @property {Array.<ShapeFillFilterOption>} [filter] - {@link ShapeFilterOption} List.\r\n * only applies to filter types\r\n * (ex: \\[\\{pixelate: 20\\}, \\{blur: 0.3\\}\\])\r\n * @property {string} [color] - Shape foreground color (ex: '#fff', 'transparent')\r\n */\n\n/**\r\n * Image editor\r\n * @class\r\n * @param {string|HTMLElement} wrapper - Wrapper's element or selector\r\n * @param {Object} [options] - Canvas max width & height of css\r\n * @param {number} [options.includeUI] - Use the provided UI\r\n * @param {Object} [options.includeUI.loadImage] - Basic editing image\r\n * @param {string} options.includeUI.loadImage.path - image path\r\n * @param {string} options.includeUI.loadImage.name - image name\r\n * @param {Object} [options.includeUI.theme] - Theme object\r\n * @param {Array} [options.includeUI.menu] - It can be selected when only specific menu is used, Default values are \\['crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text', 'mask', 'filter'\\].\r\n * @param {string} [options.includeUI.initMenu] - The first menu to be selected and started.\r\n * @param {Object} [options.includeUI.uiSize] - ui size of editor\r\n * @param {string} options.includeUI.uiSize.width - width of ui\r\n * @param {string} options.includeUI.uiSize.height - height of ui\r\n * @param {string} [options.includeUI.menuBarPosition=bottom] - Menu bar position('top', 'bottom', 'left', 'right')\r\n * @param {number} options.cssMaxWidth - Canvas css-max-width\r\n * @param {number} options.cssMaxHeight - Canvas css-max-height\r\n * @param {Object} [options.selectionStyle] - selection style\r\n * @param {string} [options.selectionStyle.cornerStyle] - selection corner style\r\n * @param {number} [options.selectionStyle.cornerSize] - selection corner size\r\n * @param {string} [options.selectionStyle.cornerColor] - selection corner color\r\n * @param {string} [options.selectionStyle.cornerStrokeColor] = selection corner stroke color\r\n * @param {boolean} [options.selectionStyle.transparentCorners] - selection corner transparent\r\n * @param {number} [options.selectionStyle.lineWidth] - selection line width\r\n * @param {string} [options.selectionStyle.borderColor] - selection border color\r\n * @param {number} [options.selectionStyle.rotatingPointOffset] - selection rotating point length\r\n * @param {Boolean} [options.usageStatistics=true] - Let us know the hostname. If you don't want to send the hostname, please set to false.\r\n * @example\r\n * var ImageEditor = require('tui-image-editor');\r\n * var blackTheme = require('./js/theme/black-theme.js');\r\n * var instance = new ImageEditor(document.querySelector('#tui-image-editor'), {\r\n * includeUI: {\r\n * loadImage: {\r\n * path: 'img/sampleImage.jpg',\r\n * name: 'SampleImage'\r\n * },\r\n * theme: blackTheme, // or whiteTheme\r\n * menu: ['shape', 'filter'],\r\n * initMenu: 'filter',\r\n * uiSize: {\r\n * width: '1000px',\r\n * height: '700px'\r\n * },\r\n * menuBarPosition: 'bottom'\r\n * },\r\n * cssMaxWidth: 700,\r\n * cssMaxHeight: 500,\r\n * selectionStyle: {\r\n * cornerSize: 20,\r\n * rotatingPointOffset: 70\r\n * }\r\n * });\r\n */\n\nclass ImageEditor {\n constructor(wrapper, options) {\n options = snippet.extend({\n includeUI: false,\n usageStatistics: true\n }, options);\n this.mode = null;\n this.activeObjectId = null;\n /**\r\n * UI instance\r\n * @type {Ui}\r\n */\n\n if (options.includeUI) {\n const UIOption = options.includeUI;\n UIOption.usageStatistics = options.usageStatistics;\n this.ui = new UI(wrapper, UIOption, this.getActions());\n options = this.ui.setUiDefaultSelectionStyle(options);\n }\n /**\r\n * Invoker\r\n * @type {Invoker}\r\n * @private\r\n */\n\n\n this._invoker = new Invoker();\n /**\r\n * Graphics instance\r\n * @type {Graphics}\r\n * @private\r\n */\n\n this._graphics = new Graphics(this.ui ? this.ui.getEditorArea() : wrapper, {\n cssMaxWidth: options.cssMaxWidth,\n cssMaxHeight: options.cssMaxHeight\n });\n /**\r\n * Event handler list\r\n * @type {Object}\r\n * @private\r\n */\n\n this._handlers = {\n keydown: this._onKeyDown.bind(this),\n mousedown: this._onMouseDown.bind(this),\n objectActivated: this._onObjectActivated.bind(this),\n objectMoved: this._onObjectMoved.bind(this),\n objectScaled: this._onObjectScaled.bind(this),\n objectRotated: this._onObjectRotated.bind(this),\n objectAdded: this._onObjectAdded.bind(this),\n objectModified: this._onObjectModified.bind(this),\n createdPath: this._onCreatedPath,\n addText: this._onAddText.bind(this),\n addObject: this._onAddObject.bind(this),\n textEditing: this._onTextEditing.bind(this),\n textChanged: this._onTextChanged.bind(this),\n iconCreateResize: this._onIconCreateResize.bind(this),\n iconCreateEnd: this._onIconCreateEnd.bind(this),\n selectionCleared: this._selectionCleared.bind(this),\n selectionCreated: this._selectionCreated.bind(this)\n };\n\n this._attachInvokerEvents();\n\n this._attachGraphicsEvents();\n\n this._attachDomEvents();\n\n this._setSelectionStyle(options.selectionStyle, {\n applyCropSelectionStyle: options.applyCropSelectionStyle,\n applyGroupSelectionStyle: options.applyGroupSelectionStyle\n });\n\n if (options.usageStatistics) {\n sendHostName();\n }\n\n if (this.ui) {\n this.ui.initCanvas();\n this.setReAction();\n }\n\n fabric.enableGLFiltering = false;\n }\n /**\r\n * Set selection style by init option\r\n * @param {Object} selectionStyle - Selection styles\r\n * @param {Object} applyTargets - Selection apply targets\r\n * @param {boolean} applyCropSelectionStyle - whether apply with crop selection style or not\r\n * @param {boolean} applyGroupSelectionStyle - whether apply with group selection style or not\r\n * @private\r\n */\n\n\n _setSelectionStyle(selectionStyle, {\n applyCropSelectionStyle,\n applyGroupSelectionStyle\n }) {\n if (selectionStyle) {\n this._graphics.setSelectionStyle(selectionStyle);\n }\n\n if (applyCropSelectionStyle) {\n this._graphics.setCropSelectionStyle(selectionStyle);\n }\n\n if (applyGroupSelectionStyle) {\n this.on('selectionCreated', eventTarget => {\n if (eventTarget.type === 'activeSelection') {\n eventTarget.set(selectionStyle);\n }\n });\n }\n }\n /**\r\n * Attach invoker events\r\n * @private\r\n */\n\n\n _attachInvokerEvents() {\n const {\n UNDO_STACK_CHANGED,\n REDO_STACK_CHANGED\n } = events;\n /**\r\n * Undo stack changed event\r\n * @event ImageEditor#undoStackChanged\r\n * @param {Number} length - undo stack length\r\n * @example\r\n * imageEditor.on('undoStackChanged', function(length) {\r\n * console.log(length);\r\n * });\r\n */\n\n this._invoker.on(UNDO_STACK_CHANGED, this.fire.bind(this, UNDO_STACK_CHANGED));\n /**\r\n * Redo stack changed event\r\n * @event ImageEditor#redoStackChanged\r\n * @param {Number} length - redo stack length\r\n * @example\r\n * imageEditor.on('redoStackChanged', function(length) {\r\n * console.log(length);\r\n * });\r\n */\n\n\n this._invoker.on(REDO_STACK_CHANGED, this.fire.bind(this, REDO_STACK_CHANGED));\n }\n /**\r\n * Attach canvas events\r\n * @private\r\n */\n\n\n _attachGraphicsEvents() {\n this._graphics.on({\n [MOUSE_DOWN]: this._handlers.mousedown,\n [OBJECT_MOVED]: this._handlers.objectMoved,\n [OBJECT_SCALED]: this._handlers.objectScaled,\n [OBJECT_ROTATED]: this._handlers.objectRotated,\n [OBJECT_ACTIVATED]: this._handlers.objectActivated,\n [OBJECT_ADDED]: this._handlers.objectAdded,\n [OBJECT_MODIFIED]: this._handlers.objectModified,\n [ADD_TEXT]: this._handlers.addText,\n [ADD_OBJECT]: this._handlers.addObject,\n [TEXT_EDITING]: this._handlers.textEditing,\n [TEXT_CHANGED]: this._handlers.textChanged,\n [ICON_CREATE_RESIZE]: this._handlers.iconCreateResize,\n [ICON_CREATE_END]: this._handlers.iconCreateEnd,\n [SELECTION_CLEARED]: this._handlers.selectionCleared,\n [SELECTION_CREATED]: this._handlers.selectionCreated\n });\n }\n /**\r\n * Attach dom events\r\n * @private\r\n */\n\n\n _attachDomEvents() {\n // ImageEditor supports IE 9 higher\n document.addEventListener('keydown', this._handlers.keydown);\n }\n /**\r\n * Detach dom events\r\n * @private\r\n */\n\n\n _detachDomEvents() {\n // ImageEditor supports IE 9 higher\n document.removeEventListener('keydown', this._handlers.keydown);\n }\n /**\r\n * Keydown event handler\r\n * @param {KeyboardEvent} e - Event object\r\n * @private\r\n */\n\n /* eslint-disable complexity */\n\n\n _onKeyDown(e) {\n const {\n ctrlKey,\n keyCode,\n metaKey\n } = e;\n const isModifierKey = ctrlKey || metaKey;\n\n if (isModifierKey) {\n if (keyCode === keyCodes.C) {\n this._graphics.resetTargetObjectForCopyPaste();\n } else if (keyCode === keyCodes.V) {\n this._graphics.pasteObject();\n\n this.clearRedoStack();\n } else if (keyCode === keyCodes.Z) {\n // There is no error message on shortcut when it's empty\n this.undo()['catch'](() => {});\n } else if (keyCode === keyCodes.Y) {\n // There is no error message on shortcut when it's empty\n this.redo()['catch'](() => {});\n }\n }\n\n const isDeleteKey = keyCode === keyCodes.BACKSPACE || keyCode === keyCodes.DEL;\n\n const isRemoveReady = this._graphics.isReadyRemoveObject();\n\n if (isRemoveReady && isDeleteKey) {\n e.preventDefault();\n this.removeActiveObject();\n }\n }\n /**\r\n * Remove Active Object\r\n */\n\n\n removeActiveObject() {\n const activeObjectId = this._graphics.getActiveObjectIdForRemove();\n\n this.removeObject(activeObjectId);\n }\n /**\r\n * mouse down event handler\r\n * @param {Event} event - mouse down event\r\n * @param {Object} originPointer - origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @private\r\n */\n\n\n _onMouseDown(event, originPointer) {\n /**\r\n * The mouse down event with position x, y on canvas\r\n * @event ImageEditor#mousedown\r\n * @param {Object} event - browser mouse event object\r\n * @param {Object} originPointer origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @example\r\n * imageEditor.on('mousedown', function(event, originPointer) {\r\n * console.log(event);\r\n * console.log(originPointer);\r\n * if (imageEditor.hasFilter('colorFilter')) {\r\n * imageEditor.applyFilter('colorFilter', {\r\n * x: parseInt(originPointer.x, 10),\r\n * y: parseInt(originPointer.y, 10)\r\n * });\r\n * }\r\n * });\r\n */\n this.fire(events.MOUSE_DOWN, event, originPointer);\n }\n /**\r\n * Add a 'addObject' command\r\n * @param {Object} obj - Fabric object\r\n * @private\r\n */\n\n\n _pushAddObjectCommand(obj) {\n const command = commandFactory.create(commands.ADD_OBJECT, this._graphics, obj);\n\n this._invoker.pushUndoStack(command);\n }\n /**\r\n * Add a 'changeSelection' command\r\n * @param {fabric.Object} obj - selection object\r\n * @private\r\n */\n\n\n _pushModifyObjectCommand(obj) {\n const {\n type\n } = obj;\n const props = makeSelectionUndoData(obj, item => makeSelectionUndoDatum(this._graphics.getObjectId(item), item, type === 'activeSelection'));\n const command = commandFactory.create(commands.CHANGE_SELECTION, this._graphics, props);\n command.execute(this._graphics, props);\n\n this._invoker.pushUndoStack(command);\n }\n /**\r\n * 'objectActivated' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\n\n\n _onObjectActivated(props) {\n /**\r\n * The event when object is selected(aka activated).\r\n * @event ImageEditor#objectActivated\r\n * @param {ObjectProps} objectProps - object properties\r\n * @example\r\n * imageEditor.on('objectActivated', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * console.log(props.id);\r\n * });\r\n */\n this.fire(events.OBJECT_ACTIVATED, props);\n }\n /**\r\n * 'objectMoved' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\n\n\n _onObjectMoved(props) {\n /**\r\n * The event when object is moved\r\n * @event ImageEditor#objectMoved\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectMoved', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * });\r\n */\n this.fire(events.OBJECT_MOVED, props);\n }\n /**\r\n * 'objectScaled' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\n\n\n _onObjectScaled(props) {\n /**\r\n * The event when scale factor is changed\r\n * @event ImageEditor#objectScaled\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectScaled', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * });\r\n */\n this.fire(events.OBJECT_SCALED, props);\n }\n /**\r\n * 'objectRotated' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\n\n\n _onObjectRotated(props) {\n /**\r\n * The event when object angle is changed\r\n * @event ImageEditor#objectRotated\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectRotated', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * });\r\n */\n this.fire(events.OBJECT_ROTATED, props);\n }\n /**\r\n * Get current drawing mode\r\n * @returns {string}\r\n * @example\r\n * // Image editor drawing mode\r\n * //\r\n * // NORMAL: 'NORMAL'\r\n * // CROPPER: 'CROPPER'\r\n * // FREE_DRAWING: 'FREE_DRAWING'\r\n * // LINE_DRAWING: 'LINE_DRAWING'\r\n * // TEXT: 'TEXT'\r\n * //\r\n * if (imageEditor.getDrawingMode() === 'FREE_DRAWING') {\r\n * imageEditor.stopDrawingMode();\r\n * }\r\n */\n\n\n getDrawingMode() {\n return this._graphics.getDrawingMode();\n }\n /**\r\n * Clear all objects\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.clearObjects();\r\n */\n\n\n clearObjects() {\n return this.execute(commands.CLEAR_OBJECTS);\n }\n /**\r\n * Deactivate all objects\r\n * @example\r\n * imageEditor.deactivateAll();\r\n */\n\n\n deactivateAll() {\n this._graphics.deactivateAll();\n\n this._graphics.renderAll();\n }\n /**\r\n * discard selction\r\n * @example\r\n * imageEditor.discardSelection();\r\n */\n\n\n discardSelection() {\n this._graphics.discardSelection();\n }\n /**\r\n * selectable status change\r\n * @param {boolean} selectable - selctable status\r\n * @example\r\n * imageEditor.changeSelectableAll(false); // or true\r\n */\n\n\n changeSelectableAll(selectable) {\n this._graphics.changeSelectableAll(selectable);\n }\n /**\r\n * Invoke command\r\n * @param {String} commandName - Command name\r\n * @param {...*} args - Arguments for creating command\r\n * @returns {Promise}\r\n * @private\r\n */\n\n\n execute(commandName, ...args) {\n // Inject an Graphics instance as first parameter\n const theArgs = [this._graphics].concat(args);\n return this._invoker.execute(commandName, ...theArgs);\n }\n /**\r\n * Invoke command\r\n * @param {String} commandName - Command name\r\n * @param {...*} args - Arguments for creating command\r\n * @returns {Promise}\r\n * @private\r\n */\n\n\n executeSilent(commandName, ...args) {\n // Inject an Graphics instance as first parameter\n const theArgs = [this._graphics].concat(args);\n return this._invoker.executeSilent(commandName, ...theArgs);\n }\n /**\r\n * Undo\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.undo();\r\n */\n\n\n undo() {\n return this._invoker.undo();\n }\n /**\r\n * Redo\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.redo();\r\n */\n\n\n redo() {\n return this._invoker.redo();\n }\n /**\r\n * Load image from file\r\n * @param {File} imgFile - Image file\r\n * @param {string} [imageName] - imageName\r\n * @returns {Promise<SizeChange, ErrorMsg>}\r\n * @example\r\n * imageEditor.loadImageFromFile(file).then(result => {\r\n * console.log('old : ' + result.oldWidth + ', ' + result.oldHeight);\r\n * console.log('new : ' + result.newWidth + ', ' + result.newHeight);\r\n * });\r\n */\n\n\n loadImageFromFile(imgFile, imageName) {\n if (!imgFile) {\n return Promise.reject(rejectMessages.invalidParameters);\n }\n\n const imgUrl = URL.createObjectURL(imgFile);\n imageName = imageName || imgFile.name;\n return this.loadImageFromURL(imgUrl, imageName).then(value => {\n URL.revokeObjectURL(imgFile);\n return value;\n });\n }\n /**\r\n * Load image from url\r\n * @param {string} url - File url\r\n * @param {string} imageName - imageName\r\n * @returns {Promise<SizeChange, ErrorMsg>}\r\n * @example\r\n * imageEditor.loadImageFromURL('http://url/testImage.png', 'lena').then(result => {\r\n * console.log('old : ' + result.oldWidth + ', ' + result.oldHeight);\r\n * console.log('new : ' + result.newWidth + ', ' + result.newHeight);\r\n * });\r\n */\n\n\n loadImageFromURL(url, imageName) {\n if (!imageName || !url) {\n return Promise.reject(rejectMessages.invalidParameters);\n }\n\n return this.execute(commands.LOAD_IMAGE, imageName, url);\n }\n /**\r\n * Add image object on canvas\r\n * @param {string} imgUrl - Image url to make object\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.addImageObject('path/fileName.jpg').then(objectProps => {\r\n * console.log(ojectProps.id);\r\n * });\r\n */\n\n\n addImageObject(imgUrl) {\n if (!imgUrl) {\n return Promise.reject(rejectMessages.invalidParameters);\n }\n\n return this.execute(commands.ADD_IMAGE_OBJECT, imgUrl);\n }\n /**\r\n * Start a drawing mode. If the current mode is not 'NORMAL', 'stopDrawingMode()' will be called first.\r\n * @param {String} mode Can be one of <I>'CROPPER', 'FREE_DRAWING', 'LINE_DRAWING', 'TEXT', 'SHAPE'</I>\r\n * @param {Object} [option] parameters of drawing mode, it's available with 'FREE_DRAWING', 'LINE_DRAWING'\r\n * @param {Number} [option.width] brush width\r\n * @param {String} [option.color] brush color\r\n * @param {Object} [option.arrowType] arrow decorate\r\n * @param {string} [option.arrowType.tail] arrow decorate for tail. 'chevron' or 'triangle'\r\n * @param {string} [option.arrowType.head] arrow decorate for head. 'chevron' or 'triangle'\r\n * @returns {boolean} true if success or false\r\n * @example\r\n * imageEditor.startDrawingMode('FREE_DRAWING', {\r\n * width: 10,\r\n * color: 'rgba(255,0,0,0.5)'\r\n * });\r\n * imageEditor.startDrawingMode('LINE_DRAWING', {\r\n * width: 10,\r\n * color: 'rgba(255,0,0,0.5)',\r\n * arrowType: {\r\n * tail: 'chevron' // triangle\r\n * }\r\n * });\r\n *\r\n */\n\n\n startDrawingMode(mode, option) {\n return this._graphics.startDrawingMode(mode, option);\n }\n /**\r\n * Stop the current drawing mode and back to the 'NORMAL' mode\r\n * @example\r\n * imageEditor.stopDrawingMode();\r\n */\n\n\n stopDrawingMode() {\n this._graphics.stopDrawingMode();\n }\n /**\r\n * Crop this image with rect\r\n * @param {Object} rect crop rect\r\n * @param {Number} rect.left left position\r\n * @param {Number} rect.top top position\r\n * @param {Number} rect.width width\r\n * @param {Number} rect.height height\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.crop(imageEditor.getCropzoneRect());\r\n */\n\n\n crop(rect) {\n const data = this._graphics.getCroppedImageData(rect);\n\n if (!data) {\n return Promise.reject(rejectMessages.invalidParameters);\n }\n\n return this.loadImageFromURL(data.url, data.imageName);\n }\n /**\r\n * Get the cropping rect\r\n * @returns {Object} {{left: number, top: number, width: number, height: number}} rect\r\n */\n\n\n getCropzoneRect() {\n return this._graphics.getCropzoneRect();\n }\n /**\r\n * Set the cropping rect\r\n * @param {number} [mode] crop rect mode [1, 1.5, 1.3333333333333333, 1.25, 1.7777777777777777]\r\n */\n\n\n setCropzoneRect(mode) {\n this._graphics.setCropzoneRect(mode);\n }\n /**\r\n * Flip\r\n * @returns {Promise}\r\n * @param {string} type - 'flipX' or 'flipY' or 'reset'\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @private\r\n */\n\n\n _flip(type) {\n return this.execute(commands.FLIP_IMAGE, type);\n }\n /**\r\n * Flip x\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.flipX().then((status => {\r\n * console.log('flipX: ', status.flipX);\r\n * console.log('flipY: ', status.flipY);\r\n * console.log('angle: ', status.angle);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\n\n\n flipX() {\n return this._flip('flipX');\n }\n /**\r\n * Flip y\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.flipY().then(status => {\r\n * console.log('flipX: ', status.flipX);\r\n * console.log('flipY: ', status.flipY);\r\n * console.log('angle: ', status.angle);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\n\n\n flipY() {\n return this._flip('flipY');\n }\n /**\r\n * Reset flip\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.resetFlip().then(status => {\r\n * console.log('flipX: ', status.flipX);\r\n * console.log('flipY: ', status.flipY);\r\n * console.log('angle: ', status.angle);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });;\r\n */\n\n\n resetFlip() {\n return this._flip('reset');\n }\n /**\r\n * @param {string} type - 'rotate' or 'setAngle'\r\n * @param {number} angle - angle value (degree)\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<RotateStatus, ErrorMsg>}\r\n * @private\r\n */\n\n\n _rotate(type, angle, isSilent) {\n let result = null;\n\n if (isSilent) {\n result = this.executeSilent(commands.ROTATE_IMAGE, type, angle);\n } else {\n result = this.execute(commands.ROTATE_IMAGE, type, angle);\n }\n\n return result;\n }\n /**\r\n * Rotate image\r\n * @returns {Promise}\r\n * @param {number} angle - Additional angle to rotate image\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<RotateStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.rotate(10); // angle = 10\r\n * imageEditor.rotate(10); // angle = 20\r\n * imageEidtor.rotate(5); // angle = 5\r\n * imageEidtor.rotate(-95); // angle = -90\r\n * imageEditor.rotate(10).then(status => {\r\n * console.log('angle: ', status.angle);\r\n * })).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\n\n\n rotate(angle, isSilent) {\n return this._rotate('rotate', angle, isSilent);\n }\n /**\r\n * Set angle\r\n * @param {number} angle - Angle of image\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<RotateStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.setAngle(10); // angle = 10\r\n * imageEditor.rotate(10); // angle = 20\r\n * imageEidtor.setAngle(5); // angle = 5\r\n * imageEidtor.rotate(50); // angle = 55\r\n * imageEidtor.setAngle(-40); // angle = -40\r\n * imageEditor.setAngle(10).then(status => {\r\n * console.log('angle: ', status.angle);\r\n * })).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\n\n\n setAngle(angle, isSilent) {\n return this._rotate('setAngle', angle, isSilent);\n }\n /**\r\n * Set drawing brush\r\n * @param {Object} option brush option\r\n * @param {Number} option.width width\r\n * @param {String} option.color color like 'FFFFFF', 'rgba(0, 0, 0, 0.5)'\r\n * @example\r\n * imageEditor.startDrawingMode('FREE_DRAWING');\r\n * imageEditor.setBrush({\r\n * width: 12,\r\n * color: 'rgba(0, 0, 0, 0.5)'\r\n * });\r\n * imageEditor.setBrush({\r\n * width: 8,\r\n * color: 'FFFFFF'\r\n * });\r\n */\n\n\n setBrush(option) {\n this._graphics.setBrush(option);\n }\n /**\r\n * Set states of current drawing shape\r\n * @param {string} type - Shape type (ex: 'rect', 'circle', 'triangle')\r\n * @param {Object} [options] - Shape options\r\n * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or\r\n * Shape foreground color (ex: '#fff', 'transparent')\r\n * @param {string} [options.stoke] - Shape outline color\r\n * @param {number} [options.strokeWidth] - Shape outline width\r\n * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)\r\n * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)\r\n * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)\r\n * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)\r\n * @param {number} [options.isRegular] - Whether resizing shape has 1:1 ratio or not\r\n * @example\r\n * imageEditor.setDrawingShape('rect', {\r\n * fill: 'red',\r\n * width: 100,\r\n * height: 200\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('rect', {\r\n * fill: {\r\n * type: 'filter',\r\n * filter: [{blur: 0.3}, {pixelate: 20}]\r\n * },\r\n * width: 100,\r\n * height: 200\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('circle', {\r\n * fill: 'transparent',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('triangle', { // When resizing, the shape keep the 1:1 ratio\r\n * width: 1,\r\n * height: 1,\r\n * isRegular: true\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('circle', { // When resizing, the shape keep the 1:1 ratio\r\n * rx: 10,\r\n * ry: 10,\r\n * isRegular: true\r\n * });\r\n */\n\n\n setDrawingShape(type, options) {\n this._graphics.setDrawingShape(type, options);\n }\n\n setDrawingIcon(type, iconColor) {\n this._graphics.setIconStyle(type, iconColor);\n }\n /**\r\n * Add shape\r\n * @param {string} type - Shape type (ex: 'rect', 'circle', 'triangle')\r\n * @param {Object} options - Shape options\r\n * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or\r\n * Shape foreground color (ex: '#fff', 'transparent')\r\n * @param {string} [options.stroke] - Shape outline color\r\n * @param {number} [options.strokeWidth] - Shape outline width\r\n * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)\r\n * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)\r\n * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)\r\n * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)\r\n * @param {number} [options.left] - Shape x position\r\n * @param {number} [options.top] - Shape y position\r\n * @param {boolean} [options.isRegular] - Whether resizing shape has 1:1 ratio or not\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.addShape('rect', {\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * width: 100,\r\n * height: 200,\r\n * left: 10,\r\n * top: 10,\r\n * isRegular: true\r\n * });\r\n * @example\r\n * imageEditor.addShape('circle', {\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100,\r\n * isRegular: false\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n * @example\r\n * imageEditor.addShape('rect', {\r\n * fill: {\r\n * type: 'filter',\r\n * filter: [{blur: 0.3}, {pixelate: 20}]\r\n * },\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100,\r\n * isRegular: false\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n */\n\n\n addShape(type, options) {\n options = options || {};\n\n this._setPositions(options);\n\n return this.execute(commands.ADD_SHAPE, type, options);\n }\n /**\r\n * Change shape\r\n * @param {number} id - object id\r\n * @param {Object} options - Shape options\r\n * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or\r\n * Shape foreground color (ex: '#fff', 'transparent')\r\n * @param {string} [options.stroke] - Shape outline color\r\n * @param {number} [options.strokeWidth] - Shape outline width\r\n * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)\r\n * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)\r\n * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)\r\n * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)\r\n * @param {boolean} [options.isRegular] - Whether resizing shape has 1:1 ratio or not\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise}\r\n * @example\r\n * // call after selecting shape object on canvas\r\n * imageEditor.changeShape(id, { // change rectagle or triangle\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * width: 100,\r\n * height: 200\r\n * });\r\n * @example\r\n * // call after selecting shape object on canvas\r\n * imageEditor.changeShape(id, { // change circle\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100\r\n * });\r\n */\n\n\n changeShape(id, options, isSilent) {\n const executeMethodName = isSilent ? 'executeSilent' : 'execute';\n return this[executeMethodName](commands.CHANGE_SHAPE, id, options);\n }\n /**\r\n * Add text on image\r\n * @param {string} text - Initial input text\r\n * @param {Object} [options] Options for generating text\r\n * @param {Object} [options.styles] Initial styles\r\n * @param {string} [options.styles.fill] Color\r\n * @param {string} [options.styles.fontFamily] Font type for text\r\n * @param {number} [options.styles.fontSize] Size\r\n * @param {string} [options.styles.fontStyle] Type of inclination (normal / italic)\r\n * @param {string} [options.styles.fontWeight] Type of thicker or thinner looking (normal / bold)\r\n * @param {string} [options.styles.textAlign] Type of text align (left / center / right)\r\n * @param {string} [options.styles.textDecoration] Type of line (underline / line-through / overline)\r\n * @param {{x: number, y: number}} [options.position] - Initial position\r\n * @param {boolean} [options.autofocus] - text autofocus, default is true\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.addText('init text');\r\n * @example\r\n * imageEditor.addText('init text', {\r\n * styles: {\r\n * fill: '#000',\r\n * fontSize: 20,\r\n * fontWeight: 'bold'\r\n * },\r\n * position: {\r\n * x: 10,\r\n * y: 10\r\n * }\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n */\n\n\n addText(text, options) {\n text = text || '';\n options = options || {};\n return this.execute(commands.ADD_TEXT, text, options);\n }\n /**\r\n * Change contents of selected text object on image\r\n * @param {number} id - object id\r\n * @param {string} text - Changing text\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.changeText(id, 'change text');\r\n */\n\n\n changeText(id, text) {\n text = text || '';\n return this.execute(commands.CHANGE_TEXT, id, text);\n }\n /**\r\n * Set style\r\n * @param {number} id - object id\r\n * @param {Object} styleObj - text styles\r\n * @param {string} [styleObj.fill] Color\r\n * @param {string} [styleObj.fontFamily] Font type for text\r\n * @param {number} [styleObj.fontSize] Size\r\n * @param {string} [styleObj.fontStyle] Type of inclination (normal / italic)\r\n * @param {string} [styleObj.fontWeight] Type of thicker or thinner looking (normal / bold)\r\n * @param {string} [styleObj.textAlign] Type of text align (left / center / right)\r\n * @param {string} [styleObj.textDecoration] Type of line (underline / line-through / overline)\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.changeTextStyle(id, {\r\n * fontStyle: 'italic'\r\n * });\r\n */\n\n\n changeTextStyle(id, styleObj, isSilent) {\n const executeMethodName = isSilent ? 'executeSilent' : 'execute';\n return this[executeMethodName](commands.CHANGE_TEXT_STYLE, id, styleObj);\n }\n /**\r\n * change text mode\r\n * @param {string} type - change type\r\n * @private\r\n */\n\n\n _changeActivateMode(type) {\n if (type !== 'ICON' && this.getDrawingMode() !== type) {\n this.startDrawingMode(type);\n }\n }\n /**\r\n * 'textChanged' event handler\r\n * @param {Object} objectProps changed object properties\r\n * @private\r\n */\n\n\n _onTextChanged(objectProps) {\n this.changeText(objectProps.id, objectProps.text);\n }\n /**\r\n * 'iconCreateResize' event handler\r\n * @param {Object} originPointer origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @private\r\n */\n\n\n _onIconCreateResize(originPointer) {\n this.fire(events.ICON_CREATE_RESIZE, originPointer);\n }\n /**\r\n * 'iconCreateEnd' event handler\r\n * @param {Object} originPointer origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @private\r\n */\n\n\n _onIconCreateEnd(originPointer) {\n this.fire(events.ICON_CREATE_END, originPointer);\n }\n /**\r\n * 'textEditing' event handler\r\n * @private\r\n */\n\n\n _onTextEditing() {\n /**\r\n * The event which starts to edit text object\r\n * @event ImageEditor#textEditing\r\n * @example\r\n * imageEditor.on('textEditing', function() {\r\n * console.log('text editing');\r\n * });\r\n */\n this.fire(events.TEXT_EDITING);\n }\n /**\r\n * Mousedown event handler in case of 'TEXT' drawing mode\r\n * @param {fabric.Event} event - Current mousedown event object\r\n * @private\r\n */\n\n\n _onAddText(event) {\n /**\r\n * The event when 'TEXT' drawing mode is enabled and click non-object area.\r\n * @event ImageEditor#addText\r\n * @param {Object} pos\r\n * @param {Object} pos.originPosition - Current position on origin canvas\r\n * @param {Number} pos.originPosition.x - x\r\n * @param {Number} pos.originPosition.y - y\r\n * @param {Object} pos.clientPosition - Current position on client area\r\n * @param {Number} pos.clientPosition.x - x\r\n * @param {Number} pos.clientPosition.y - y\r\n * @example\r\n * imageEditor.on('addText', function(pos) {\r\n * console.log('text position on canvas: ' + pos.originPosition);\r\n * console.log('text position on brwoser: ' + pos.clientPosition);\r\n * });\r\n */\n this.fire(events.ADD_TEXT, {\n originPosition: event.originPosition,\n clientPosition: event.clientPosition\n });\n }\n /**\r\n * 'addObject' event handler\r\n * @param {Object} objectProps added object properties\r\n * @private\r\n */\n\n\n _onAddObject(objectProps) {\n const obj = this._graphics.getObject(objectProps.id);\n\n this._pushAddObjectCommand(obj);\n }\n /**\r\n * 'objectAdded' event handler\r\n * @param {Object} objectProps added object properties\r\n * @private\r\n */\n\n\n _onObjectAdded(objectProps) {\n /**\r\n * The event when object added\r\n * @event ImageEditor#objectAdded\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectAdded', function(props) {\r\n * console.log(props);\r\n * });\r\n */\n this.fire(OBJECT_ADDED, objectProps);\n /**\r\n * The event when object added (deprecated)\r\n * @event ImageEditor#addObjectAfter\r\n * @param {ObjectProps} props - object properties\r\n * @deprecated\r\n */\n\n this.fire(ADD_OBJECT_AFTER, objectProps);\n }\n /**\r\n * 'objectModified' event handler\r\n * @param {fabric.Object} obj - selection object\r\n * @private\r\n */\n\n\n _onObjectModified(obj) {\n this._pushModifyObjectCommand(obj);\n }\n /**\r\n * 'selectionCleared' event handler\r\n * @private\r\n */\n\n\n _selectionCleared() {\n this.fire(SELECTION_CLEARED);\n }\n /**\r\n * 'selectionCreated' event handler\r\n * @param {Object} eventTarget - Fabric object\r\n * @private\r\n */\n\n\n _selectionCreated(eventTarget) {\n this.fire(SELECTION_CREATED, eventTarget);\n }\n /**\r\n * Register custom icons\r\n * @param {{iconType: string, pathValue: string}} infos - Infos to register icons\r\n * @example\r\n * imageEditor.registerIcons({\r\n * customIcon: 'M 0 0 L 20 20 L 10 10 Z',\r\n * customArrow: 'M 60 0 L 120 60 H 90 L 75 45 V 180 H 45 V 45 L 30 60 H 0 Z'\r\n * });\r\n */\n\n\n registerIcons(infos) {\n this._graphics.registerPaths(infos);\n }\n /**\r\n * Change canvas cursor type\r\n * @param {string} cursorType - cursor type\r\n * @example\r\n * imageEditor.changeCursor('crosshair');\r\n */\n\n\n changeCursor(cursorType) {\n this._graphics.changeCursor(cursorType);\n }\n /**\r\n * Add icon on canvas\r\n * @param {string} type - Icon type ('arrow', 'cancel', custom icon name)\r\n * @param {Object} options - Icon options\r\n * @param {string} [options.fill] - Icon foreground color\r\n * @param {number} [options.left] - Icon x position\r\n * @param {number} [options.top] - Icon y position\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.addIcon('arrow'); // The position is center on canvas\r\n * @example\r\n * imageEditor.addIcon('arrow', {\r\n * left: 100,\r\n * top: 100\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n */\n\n\n addIcon(type, options) {\n options = options || {};\n\n this._setPositions(options);\n\n return this.execute(commands.ADD_ICON, type, options);\n }\n /**\r\n * Change icon color\r\n * @param {number} id - object id\r\n * @param {string} color - Color for icon\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.changeIconColor(id, '#000000');\r\n */\n\n\n changeIconColor(id, color) {\n return this.execute(commands.CHANGE_ICON_COLOR, id, color);\n }\n /**\r\n * Remove an object or group by id\r\n * @param {number} id - object id\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.removeObject(id);\r\n */\n\n\n removeObject(id) {\n return this.execute(commands.REMOVE_OBJECT, id);\n }\n /**\r\n * Whether it has the filter or not\r\n * @param {string} type - Filter type\r\n * @returns {boolean} true if it has the filter\r\n */\n\n\n hasFilter(type) {\n return this._graphics.hasFilter(type);\n }\n /**\r\n * Remove filter on canvas image\r\n * @param {string} type - Filter type\r\n * @returns {Promise<FilterResult, ErrorMsg>}\r\n * @example\r\n * imageEditor.removeFilter('Grayscale').then(obj => {\r\n * console.log('filterType: ', obj.type);\r\n * console.log('actType: ', obj.action);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\n\n\n removeFilter(type) {\n return this.execute(commands.REMOVE_FILTER, type);\n }\n /**\r\n * Apply filter on canvas image\r\n * @param {string} type - Filter type\r\n * @param {Object} options - Options to apply filter\r\n * @param {number} options.maskObjId - masking image object id\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<FilterResult, ErrorMsg>}\r\n * @example\r\n * imageEditor.applyFilter('Grayscale');\r\n * @example\r\n * imageEditor.applyFilter('mask', {maskObjId: id}).then(obj => {\r\n * console.log('filterType: ', obj.type);\r\n * console.log('actType: ', obj.action);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });;\r\n */\n\n\n applyFilter(type, options, isSilent) {\n const executeMethodName = isSilent ? 'executeSilent' : 'execute';\n return this[executeMethodName](commands.APPLY_FILTER, type, options);\n }\n /**\r\n * Get data url\r\n * @param {Object} options - options for toDataURL\r\n * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\r\n * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\r\n * @param {Number} [options.multiplier=1] Multiplier to scale by\r\n * @param {Number} [options.left] Cropping left offset. Introduced in fabric v1.2.14\r\n * @param {Number} [options.top] Cropping top offset. Introduced in fabric v1.2.14\r\n * @param {Number} [options.width] Cropping width. Introduced in fabric v1.2.14\r\n * @param {Number} [options.height] Cropping height. Introduced in fabric v1.2.14\r\n * @returns {string} A DOMString containing the requested data URI\r\n * @example\r\n * imgEl.src = imageEditor.toDataURL();\r\n *\r\n * imageEditor.loadImageFromURL(imageEditor.toDataURL(), 'FilterImage').then(() => {\r\n * imageEditor.addImageObject(imgUrl);\r\n * });\r\n */\n\n\n toDataURL(options) {\n return this._graphics.toDataURL(options);\n }\n /**\r\n * Get image name\r\n * @returns {string} image name\r\n * @example\r\n * console.log(imageEditor.getImageName());\r\n */\n\n\n getImageName() {\n return this._graphics.getImageName();\n }\n /**\r\n * Clear undoStack\r\n * @example\r\n * imageEditor.clearUndoStack();\r\n */\n\n\n clearUndoStack() {\n this._invoker.clearUndoStack();\n }\n /**\r\n * Clear redoStack\r\n * @example\r\n * imageEditor.clearRedoStack();\r\n */\n\n\n clearRedoStack() {\n this._invoker.clearRedoStack();\n }\n /**\r\n * Whehter the undo stack is empty or not\r\n * @returns {boolean}\r\n * imageEditor.isEmptyUndoStack();\r\n */\n\n\n isEmptyUndoStack() {\n return this._invoker.isEmptyUndoStack();\n }\n /**\r\n * Whehter the redo stack is empty or not\r\n * @returns {boolean}\r\n * imageEditor.isEmptyRedoStack();\r\n */\n\n\n isEmptyRedoStack() {\n return this._invoker.isEmptyRedoStack();\n }\n /**\r\n * Resize canvas dimension\r\n * @param {{width: number, height: number}} dimension - Max width & height\r\n * @returns {Promise}\r\n */\n\n\n resizeCanvasDimension(dimension) {\n if (!dimension) {\n return Promise.reject(rejectMessages.invalidParameters);\n }\n\n return this.execute(commands.RESIZE_CANVAS_DIMENSION, dimension);\n }\n /**\r\n * Destroy\r\n */\n\n\n destroy() {\n this.stopDrawingMode();\n\n this._detachDomEvents();\n\n this._graphics.destroy();\n\n this._graphics = null;\n\n if (this.ui) {\n this.ui.destroy();\n }\n\n forEach(this, (value, key) => {\n this[key] = null;\n }, this);\n }\n /**\r\n * Set position\r\n * @param {Object} options - Position options (left or top)\r\n * @private\r\n */\n\n\n _setPositions(options) {\n const centerPosition = this._graphics.getCenter();\n\n if (isUndefined(options.left)) {\n options.left = centerPosition.left;\n }\n\n if (isUndefined(options.top)) {\n options.top = centerPosition.top;\n }\n }\n /**\r\n * Set properties of active object\r\n * @param {number} id - object id\r\n * @param {Object} keyValue - key & value\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.setObjectProperties(id, {\r\n * left:100,\r\n * top:100,\r\n * width: 200,\r\n * height: 200,\r\n * opacity: 0.5\r\n * });\r\n */\n\n\n setObjectProperties(id, keyValue) {\n return this.execute(commands.SET_OBJECT_PROPERTIES, id, keyValue);\n }\n /**\r\n * Set properties of active object, Do not leave an invoke history.\r\n * @param {number} id - object id\r\n * @param {Object} keyValue - key & value\r\n * @example\r\n * imageEditor.setObjectPropertiesQuietly(id, {\r\n * left:100,\r\n * top:100,\r\n * width: 200,\r\n * height: 200,\r\n * opacity: 0.5\r\n * });\r\n */\n\n\n setObjectPropertiesQuietly(id, keyValue) {\n this._graphics.setObjectProperties(id, keyValue);\n }\n /**\r\n * Get properties of active object corresponding key\r\n * @param {number} id - object id\r\n * @param {Array<string>|ObjectProps|string} keys - property's key\r\n * @returns {ObjectProps} properties if id is valid or null\r\n * @example\r\n * var props = imageEditor.getObjectProperties(id, 'left');\r\n * console.log(props);\r\n * @example\r\n * var props = imageEditor.getObjectProperties(id, ['left', 'top', 'width', 'height']);\r\n * console.log(props);\r\n * @example\r\n * var props = imageEditor.getObjectProperties(id, {\r\n * left: null,\r\n * top: null,\r\n * width: null,\r\n * height: null,\r\n * opacity: null\r\n * });\r\n * console.log(props);\r\n */\n\n\n getObjectProperties(id, keys) {\n const object = this._graphics.getObject(id);\n\n if (!object) {\n return null;\n }\n\n return this._graphics.getObjectProperties(id, keys);\n }\n /**\r\n * Get the canvas size\r\n * @returns {Object} {{width: number, height: number}} canvas size\r\n * @example\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * console.log(canvasSize.width);\r\n * console.height(canvasSize.height);\r\n */\n\n\n getCanvasSize() {\n return this._graphics.getCanvasSize();\n }\n /**\r\n * Get object position by originX, originY\r\n * @param {number} id - object id\r\n * @param {string} originX - can be 'left', 'center', 'right'\r\n * @param {string} originY - can be 'top', 'center', 'bottom'\r\n * @returns {Object} {{x:number, y: number}} position by origin if id is valid, or null\r\n * @example\r\n * var position = imageEditor.getObjectPosition(id, 'left', 'top');\r\n * console.log(position);\r\n */\n\n\n getObjectPosition(id, originX, originY) {\n return this._graphics.getObjectPosition(id, originX, originY);\n }\n /**\r\n * Set object position by originX, originY\r\n * @param {number} id - object id\r\n * @param {Object} posInfo - position object\r\n * @param {number} posInfo.x - x position\r\n * @param {number} posInfo.y - y position\r\n * @param {string} posInfo.originX - can be 'left', 'center', 'right'\r\n * @param {string} posInfo.originY - can be 'top', 'center', 'bottom'\r\n * @returns {Promise}\r\n * @example\r\n * // align the object to 'left', 'top'\r\n * imageEditor.setObjectPosition(id, {\r\n * x: 0,\r\n * y: 0,\r\n * originX: 'left',\r\n * originY: 'top'\r\n * });\r\n * @example\r\n * // align the object to 'right', 'top'\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * imageEditor.setObjectPosition(id, {\r\n * x: canvasSize.width,\r\n * y: 0,\r\n * originX: 'right',\r\n * originY: 'top'\r\n * });\r\n * @example\r\n * // align the object to 'left', 'bottom'\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * imageEditor.setObjectPosition(id, {\r\n * x: 0,\r\n * y: canvasSize.height,\r\n * originX: 'left',\r\n * originY: 'bottom'\r\n * });\r\n * @example\r\n * // align the object to 'right', 'bottom'\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * imageEditor.setObjectPosition(id, {\r\n * x: canvasSize.width,\r\n * y: canvasSize.height,\r\n * originX: 'right',\r\n * originY: 'bottom'\r\n * });\r\n */\n\n\n setObjectPosition(id, posInfo) {\n return this.execute(commands.SET_OBJECT_POSITION, id, posInfo);\n }\n\n}\n\naction.mixin(ImageEditor);\nCustomEvents.mixin(ImageEditor);\nexport default ImageEditor;","map":{"version":3,"sources":["C:/Users/kkwan_000/Desktop/git/2017110269/minsung/src/js/imageEditor.js"],"names":["snippet","Invoker","UI","action","commandFactory","Graphics","sendHostName","Promise","eventNames","events","commandNames","commands","keyCodes","rejectMessages","makeSelectionUndoData","makeSelectionUndoDatum","isUndefined","forEach","CustomEvents","MOUSE_DOWN","OBJECT_MOVED","OBJECT_SCALED","OBJECT_ACTIVATED","OBJECT_ROTATED","OBJECT_ADDED","OBJECT_MODIFIED","ADD_TEXT","ADD_OBJECT","TEXT_EDITING","TEXT_CHANGED","ICON_CREATE_RESIZE","ICON_CREATE_END","SELECTION_CLEARED","SELECTION_CREATED","ADD_OBJECT_AFTER","ImageEditor","constructor","wrapper","options","extend","includeUI","usageStatistics","mode","activeObjectId","UIOption","ui","getActions","setUiDefaultSelectionStyle","_invoker","_graphics","getEditorArea","cssMaxWidth","cssMaxHeight","_handlers","keydown","_onKeyDown","bind","mousedown","_onMouseDown","objectActivated","_onObjectActivated","objectMoved","_onObjectMoved","objectScaled","_onObjectScaled","objectRotated","_onObjectRotated","objectAdded","_onObjectAdded","objectModified","_onObjectModified","createdPath","_onCreatedPath","addText","_onAddText","addObject","_onAddObject","textEditing","_onTextEditing","textChanged","_onTextChanged","iconCreateResize","_onIconCreateResize","iconCreateEnd","_onIconCreateEnd","selectionCleared","_selectionCleared","selectionCreated","_selectionCreated","_attachInvokerEvents","_attachGraphicsEvents","_attachDomEvents","_setSelectionStyle","selectionStyle","applyCropSelectionStyle","applyGroupSelectionStyle","initCanvas","setReAction","fabric","enableGLFiltering","setSelectionStyle","setCropSelectionStyle","on","eventTarget","type","set","UNDO_STACK_CHANGED","REDO_STACK_CHANGED","fire","document","addEventListener","_detachDomEvents","removeEventListener","e","ctrlKey","keyCode","metaKey","isModifierKey","C","resetTargetObjectForCopyPaste","V","pasteObject","clearRedoStack","Z","undo","Y","redo","isDeleteKey","BACKSPACE","DEL","isRemoveReady","isReadyRemoveObject","preventDefault","removeActiveObject","getActiveObjectIdForRemove","removeObject","event","originPointer","_pushAddObjectCommand","obj","command","create","pushUndoStack","_pushModifyObjectCommand","props","item","getObjectId","CHANGE_SELECTION","execute","getDrawingMode","clearObjects","CLEAR_OBJECTS","deactivateAll","renderAll","discardSelection","changeSelectableAll","selectable","commandName","args","theArgs","concat","executeSilent","loadImageFromFile","imgFile","imageName","reject","invalidParameters","imgUrl","URL","createObjectURL","name","loadImageFromURL","then","value","revokeObjectURL","url","LOAD_IMAGE","addImageObject","ADD_IMAGE_OBJECT","startDrawingMode","option","stopDrawingMode","crop","rect","data","getCroppedImageData","getCropzoneRect","setCropzoneRect","_flip","FLIP_IMAGE","flipX","flipY","resetFlip","_rotate","angle","isSilent","result","ROTATE_IMAGE","rotate","setAngle","setBrush","setDrawingShape","setDrawingIcon","iconColor","setIconStyle","addShape","_setPositions","ADD_SHAPE","changeShape","id","executeMethodName","CHANGE_SHAPE","text","changeText","CHANGE_TEXT","changeTextStyle","styleObj","CHANGE_TEXT_STYLE","_changeActivateMode","objectProps","originPosition","clientPosition","getObject","registerIcons","infos","registerPaths","changeCursor","cursorType","addIcon","ADD_ICON","changeIconColor","color","CHANGE_ICON_COLOR","REMOVE_OBJECT","hasFilter","removeFilter","REMOVE_FILTER","applyFilter","APPLY_FILTER","toDataURL","getImageName","clearUndoStack","isEmptyUndoStack","isEmptyRedoStack","resizeCanvasDimension","dimension","RESIZE_CANVAS_DIMENSION","destroy","key","centerPosition","getCenter","left","top","setObjectProperties","keyValue","SET_OBJECT_PROPERTIES","setObjectPropertiesQuietly","getObjectProperties","keys","object","getCanvasSize","getObjectPosition","originX","originY","setObjectPosition","posInfo","SET_OBJECT_POSITION","mixin"],"mappings":"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M,GAAG,IAAb;;AACA,QAAID,QAAJ,EAAc;AACZC,MAAAA,MAAM,GAAG,KAAKnC,aAAL,CAAmBtJ,QAAQ,CAAC0L,YAA5B,EAA0C7F,IAA1C,EAAgD0F,KAAhD,CAAT;AACD,KAFD,MAEO;AACLE,MAAAA,MAAM,GAAG,KAAKhD,OAAL,CAAazI,QAAQ,CAAC0L,YAAtB,EAAoC7F,IAApC,EAA0C0F,KAA1C,CAAT;AACD;;AAED,WAAOE,MAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEE,EAAAA,MAAM,CAACJ,KAAD,EAAQC,QAAR,EAAkB;AACtB,WAAO,KAAKF,OAAL,CAAa,QAAb,EAAuBC,KAAvB,EAA8BC,QAA9B,CAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEI,EAAAA,QAAQ,CAACL,KAAD,EAAQC,QAAR,EAAkB;AACxB,WAAO,KAAKF,OAAL,CAAa,UAAb,EAAyBC,KAAzB,EAAgCC,QAAhC,CAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEK,EAAAA,QAAQ,CAACpB,MAAD,EAAS;AACf,SAAKnI,SAAL,CAAeuJ,QAAf,CAAwBpB,MAAxB;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEqB,EAAAA,eAAe,CAACjG,IAAD,EAAOlE,OAAP,EAAgB;AAC7B,SAAKW,SAAL,CAAewJ,eAAf,CAA+BjG,IAA/B,EAAqClE,OAArC;AACD;;AAEDoK,EAAAA,cAAc,CAAClG,IAAD,EAAOmG,SAAP,EAAkB;AAC9B,SAAK1J,SAAL,CAAe2J,YAAf,CAA4BpG,IAA5B,EAAkCmG,SAAlC;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEE,EAAAA,QAAQ,CAACrG,IAAD,EAAOlE,OAAP,EAAgB;AACtBA,IAAAA,OAAO,GAAGA,OAAO,IAAI,EAArB;;AAEA,SAAKwK,aAAL,CAAmBxK,OAAnB;;AAEA,WAAO,KAAK8G,OAAL,CAAazI,QAAQ,CAACoM,SAAtB,EAAiCvG,IAAjC,EAAuClE,OAAvC,CAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACE0K,EAAAA,WAAW,CAACC,EAAD,EAAK3K,OAAL,EAAc6J,QAAd,EAAwB;AACjC,UAAMe,iBAAiB,GAAGf,QAAQ,GAAG,eAAH,GAAqB,SAAvD;AAEA,WAAO,KAAKe,iBAAL,EAAwBvM,QAAQ,CAACwM,YAAjC,EAA+CF,EAA/C,EAAmD3K,OAAnD,CAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEmC,EAAAA,OAAO,CAAC2I,IAAD,EAAO9K,OAAP,EAAgB;AACrB8K,IAAAA,IAAI,GAAGA,IAAI,IAAI,EAAf;AACA9K,IAAAA,OAA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ACF;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEE,EAAAA,aAAa,GAAG;AACd,WAAO,KAAKnN,SAAL,CAAemN,aAAf,EAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEC,EAAAA,iBAAiB,CAACpD,EAAD,EAAKqD,OAAL,EAAcC,OAAd,EAAuB;AACtC,WAAO,KAAKtN,SAAL,CAAeoN,iBAAf,CAAiCpD,EAAjC,EAAqCqD,OAArC,EAA8CC,OAA9C,CAAP;AACD;AAED;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACEC,EAAAA,iBAAiB,CAACvD,EAAD,EAAKwD,OAAL,EAAc;AAC7B,WAAO,KAAKrH,OAAL,CAAazI,QAAQ,CAAC+P,mBAAtB,EAA2CzD,EAA3C,EAA+CwD,OAA/C,CAAP;AACD;;AAh+Ce;;AAm+ClBtQ,MAAM,CAACwQ,KAAP,CAAaxO,WAAb;AACAjB,YAAY,CAACyP,KAAb,CAAmBxO,WAAnB;AAEA,eAAeA,WAAf","sourcesContent":["/**\r\n * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>\r\n * @fileoverview Image-editor application class\r\n */\r\nimport snippet from 'tui-code-snippet';\r\nimport Invoker from './invoker';\r\nimport UI from './ui';\r\nimport action from './action';\r\nimport commandFactory from './factory/command';\r\nimport Graphics from './graphics';\r\nimport { sendHostName, Promise } from './util';\r\nimport { eventNames as events, commandNames as commands, keyCodes, rejectMessages } from './consts';\r\nimport { makeSelectionUndoData, makeSelectionUndoDatum } from './helper/selectionModifyHelper';\r\n\r\nconst { isUndefined, forEach, CustomEvents } = snippet;\r\n\r\nconst {\r\n MOUSE_DOWN,\r\n OBJECT_MOVED,\r\n OBJECT_SCALED,\r\n OBJECT_ACTIVATED,\r\n OBJECT_ROTATED,\r\n OBJECT_ADDED,\r\n OBJECT_MODIFIED,\r\n ADD_TEXT,\r\n ADD_OBJECT,\r\n TEXT_EDITING,\r\n TEXT_CHANGED,\r\n ICON_CREATE_RESIZE,\r\n ICON_CREATE_END,\r\n SELECTION_CLEARED,\r\n SELECTION_CREATED,\r\n ADD_OBJECT_AFTER,\r\n} = events;\r\n\r\n/**\r\n * Image filter result\r\n * @typedef {object} FilterResult\r\n * @property {string} type - filter type like 'mask', 'Grayscale' and so on\r\n * @property {string} action - action type like 'add', 'remove'\r\n */\r\n\r\n/**\r\n * Flip status\r\n * @typedef {object} FlipStatus\r\n * @property {boolean} flipX - x axis\r\n * @property {boolean} flipY - y axis\r\n * @property {Number} angle - angle\r\n */\r\n/**\r\n * Rotation status\r\n * @typedef {Number} RotateStatus\r\n * @property {Number} angle - angle\r\n */\r\n\r\n/**\r\n * Old and new Size\r\n * @typedef {object} SizeChange\r\n * @property {Number} oldWidth - old width\r\n * @property {Number} oldHeight - old height\r\n * @property {Number} newWidth - new width\r\n * @property {Number} newHeight - new height\r\n */\r\n\r\n/**\r\n * @typedef {string} ErrorMsg - {string} error message\r\n */\r\n\r\n/**\r\n * @typedef {object} ObjectProps - graphics object properties\r\n * @property {number} id - object id\r\n * @property {string} type - object type\r\n * @property {string} text - text content\r\n * @property {(string | number)} left - Left\r\n * @property {(string | number)} top - Top\r\n * @property {(string | number)} width - Width\r\n * @property {(string | number)} height - Height\r\n * @property {string} fill - Color\r\n * @property {string} stroke - Stroke\r\n * @property {(string | number)} strokeWidth - StrokeWidth\r\n * @property {string} fontFamily - Font type for text\r\n * @property {number} fontSize - Font Size\r\n * @property {string} fontStyle - Type of inclination (normal / italic)\r\n * @property {string} fontWeight - Type of thicker or thinner looking (normal / bold)\r\n * @property {string} textAlign - Type of text align (left / center / right)\r\n * @property {string} textDecoration - Type of line (underline / line-through / overline)\r\n */\r\n\r\n/**\r\n * Shape filter option\r\n * @typedef {object.<string, number>} ShapeFilterOption\r\n */\r\n\r\n/**\r\n * Shape filter option\r\n * @typedef {object} ShapeFillOption - fill option of shape\r\n * @property {string} type - fill type ('color' or 'filter')\r\n * @property {Array.<ShapeFillFilterOption>} [filter] - {@link ShapeFilterOption} List.\r\n * only applies to filter types\r\n * (ex: \\[\\{pixelate: 20\\}, \\{blur: 0.3\\}\\])\r\n * @property {string} [color] - Shape foreground color (ex: '#fff', 'transparent')\r\n */\r\n\r\n/**\r\n * Image editor\r\n * @class\r\n * @param {string|HTMLElement} wrapper - Wrapper's element or selector\r\n * @param {Object} [options] - Canvas max width & height of css\r\n * @param {number} [options.includeUI] - Use the provided UI\r\n * @param {Object} [options.includeUI.loadImage] - Basic editing image\r\n * @param {string} options.includeUI.loadImage.path - image path\r\n * @param {string} options.includeUI.loadImage.name - image name\r\n * @param {Object} [options.includeUI.theme] - Theme object\r\n * @param {Array} [options.includeUI.menu] - It can be selected when only specific menu is used, Default values are \\['crop', 'flip', 'rotate', 'draw', 'shape', 'icon', 'text', 'mask', 'filter'\\].\r\n * @param {string} [options.includeUI.initMenu] - The first menu to be selected and started.\r\n * @param {Object} [options.includeUI.uiSize] - ui size of editor\r\n * @param {string} options.includeUI.uiSize.width - width of ui\r\n * @param {string} options.includeUI.uiSize.height - height of ui\r\n * @param {string} [options.includeUI.menuBarPosition=bottom] - Menu bar position('top', 'bottom', 'left', 'right')\r\n * @param {number} options.cssMaxWidth - Canvas css-max-width\r\n * @param {number} options.cssMaxHeight - Canvas css-max-height\r\n * @param {Object} [options.selectionStyle] - selection style\r\n * @param {string} [options.selectionStyle.cornerStyle] - selection corner style\r\n * @param {number} [options.selectionStyle.cornerSize] - selection corner size\r\n * @param {string} [options.selectionStyle.cornerColor] - selection corner color\r\n * @param {string} [options.selectionStyle.cornerStrokeColor] = selection corner stroke color\r\n * @param {boolean} [options.selectionStyle.transparentCorners] - selection corner transparent\r\n * @param {number} [options.selectionStyle.lineWidth] - selection line width\r\n * @param {string} [options.selectionStyle.borderColor] - selection border color\r\n * @param {number} [options.selectionStyle.rotatingPointOffset] - selection rotating point length\r\n * @param {Boolean} [options.usageStatistics=true] - Let us know the hostname. If you don't want to send the hostname, please set to false.\r\n * @example\r\n * var ImageEditor = require('tui-image-editor');\r\n * var blackTheme = require('./js/theme/black-theme.js');\r\n * var instance = new ImageEditor(document.querySelector('#tui-image-editor'), {\r\n * includeUI: {\r\n * loadImage: {\r\n * path: 'img/sampleImage.jpg',\r\n * name: 'SampleImage'\r\n * },\r\n * theme: blackTheme, // or whiteTheme\r\n * menu: ['shape', 'filter'],\r\n * initMenu: 'filter',\r\n * uiSize: {\r\n * width: '1000px',\r\n * height: '700px'\r\n * },\r\n * menuBarPosition: 'bottom'\r\n * },\r\n * cssMaxWidth: 700,\r\n * cssMaxHeight: 500,\r\n * selectionStyle: {\r\n * cornerSize: 20,\r\n * rotatingPointOffset: 70\r\n * }\r\n * });\r\n */\r\nclass ImageEditor {\r\n constructor(wrapper, options) {\r\n options = snippet.extend(\r\n {\r\n includeUI: false,\r\n usageStatistics: true,\r\n },\r\n options\r\n );\r\n\r\n this.mode = null;\r\n\r\n this.activeObjectId = null;\r\n\r\n /**\r\n * UI instance\r\n * @type {Ui}\r\n */\r\n if (options.includeUI) {\r\n const UIOption = options.includeUI;\r\n UIOption.usageStatistics = options.usageStatistics;\r\n\r\n this.ui = new UI(wrapper, UIOption, this.getActions());\r\n options = this.ui.setUiDefaultSelectionStyle(options);\r\n }\r\n\r\n /**\r\n * Invoker\r\n * @type {Invoker}\r\n * @private\r\n */\r\n this._invoker = new Invoker();\r\n\r\n /**\r\n * Graphics instance\r\n * @type {Graphics}\r\n * @private\r\n */\r\n this._graphics = new Graphics(this.ui ? this.ui.getEditorArea() : wrapper, {\r\n cssMaxWidth: options.cssMaxWidth,\r\n cssMaxHeight: options.cssMaxHeight,\r\n });\r\n\r\n /**\r\n * Event handler list\r\n * @type {Object}\r\n * @private\r\n */\r\n this._handlers = {\r\n keydown: this._onKeyDown.bind(this),\r\n mousedown: this._onMouseDown.bind(this),\r\n objectActivated: this._onObjectActivated.bind(this),\r\n objectMoved: this._onObjectMoved.bind(this),\r\n objectScaled: this._onObjectScaled.bind(this),\r\n objectRotated: this._onObjectRotated.bind(this),\r\n objectAdded: this._onObjectAdded.bind(this),\r\n objectModified: this._onObjectModified.bind(this),\r\n createdPath: this._onCreatedPath,\r\n addText: this._onAddText.bind(this),\r\n addObject: this._onAddObject.bind(this),\r\n textEditing: this._onTextEditing.bind(this),\r\n textChanged: this._onTextChanged.bind(this),\r\n iconCreateResize: this._onIconCreateResize.bind(this),\r\n iconCreateEnd: this._onIconCreateEnd.bind(this),\r\n selectionCleared: this._selectionCleared.bind(this),\r\n selectionCreated: this._selectionCreated.bind(this),\r\n };\r\n\r\n this._attachInvokerEvents();\r\n this._attachGraphicsEvents();\r\n this._attachDomEvents();\r\n this._setSelectionStyle(options.selectionStyle, {\r\n applyCropSelectionStyle: options.applyCropSelectionStyle,\r\n applyGroupSelectionStyle: options.applyGroupSelectionStyle,\r\n });\r\n\r\n if (options.usageStatistics) {\r\n sendHostName();\r\n }\r\n\r\n if (this.ui) {\r\n this.ui.initCanvas();\r\n this.setReAction();\r\n }\r\n fabric.enableGLFiltering = false;\r\n }\r\n\r\n /**\r\n * Set selection style by init option\r\n * @param {Object} selectionStyle - Selection styles\r\n * @param {Object} applyTargets - Selection apply targets\r\n * @param {boolean} applyCropSelectionStyle - whether apply with crop selection style or not\r\n * @param {boolean} applyGroupSelectionStyle - whether apply with group selection style or not\r\n * @private\r\n */\r\n _setSelectionStyle(selectionStyle, { applyCropSelectionStyle, applyGroupSelectionStyle }) {\r\n if (selectionStyle) {\r\n this._graphics.setSelectionStyle(selectionStyle);\r\n }\r\n\r\n if (applyCropSelectionStyle) {\r\n this._graphics.setCropSelectionStyle(selectionStyle);\r\n }\r\n\r\n if (applyGroupSelectionStyle) {\r\n this.on('selectionCreated', (eventTarget) => {\r\n if (eventTarget.type === 'activeSelection') {\r\n eventTarget.set(selectionStyle);\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Attach invoker events\r\n * @private\r\n */\r\n _attachInvokerEvents() {\r\n const { UNDO_STACK_CHANGED, REDO_STACK_CHANGED } = events;\r\n\r\n /**\r\n * Undo stack changed event\r\n * @event ImageEditor#undoStackChanged\r\n * @param {Number} length - undo stack length\r\n * @example\r\n * imageEditor.on('undoStackChanged', function(length) {\r\n * console.log(length);\r\n * });\r\n */\r\n this._invoker.on(UNDO_STACK_CHANGED, this.fire.bind(this, UNDO_STACK_CHANGED));\r\n /**\r\n * Redo stack changed event\r\n * @event ImageEditor#redoStackChanged\r\n * @param {Number} length - redo stack length\r\n * @example\r\n * imageEditor.on('redoStackChanged', function(length) {\r\n * console.log(length);\r\n * });\r\n */\r\n this._invoker.on(REDO_STACK_CHANGED, this.fire.bind(this, REDO_STACK_CHANGED));\r\n }\r\n\r\n /**\r\n * Attach canvas events\r\n * @private\r\n */\r\n _attachGraphicsEvents() {\r\n this._graphics.on({\r\n [MOUSE_DOWN]: this._handlers.mousedown,\r\n [OBJECT_MOVED]: this._handlers.objectMoved,\r\n [OBJECT_SCALED]: this._handlers.objectScaled,\r\n [OBJECT_ROTATED]: this._handlers.objectRotated,\r\n [OBJECT_ACTIVATED]: this._handlers.objectActivated,\r\n [OBJECT_ADDED]: this._handlers.objectAdded,\r\n [OBJECT_MODIFIED]: this._handlers.objectModified,\r\n [ADD_TEXT]: this._handlers.addText,\r\n [ADD_OBJECT]: this._handlers.addObject,\r\n [TEXT_EDITING]: this._handlers.textEditing,\r\n [TEXT_CHANGED]: this._handlers.textChanged,\r\n [ICON_CREATE_RESIZE]: this._handlers.iconCreateResize,\r\n [ICON_CREATE_END]: this._handlers.iconCreateEnd,\r\n [SELECTION_CLEARED]: this._handlers.selectionCleared,\r\n [SELECTION_CREATED]: this._handlers.selectionCreated,\r\n });\r\n }\r\n\r\n /**\r\n * Attach dom events\r\n * @private\r\n */\r\n _attachDomEvents() {\r\n // ImageEditor supports IE 9 higher\r\n document.addEventListener('keydown', this._handlers.keydown);\r\n }\r\n\r\n /**\r\n * Detach dom events\r\n * @private\r\n */\r\n _detachDomEvents() {\r\n // ImageEditor supports IE 9 higher\r\n document.removeEventListener('keydown', this._handlers.keydown);\r\n }\r\n\r\n /**\r\n * Keydown event handler\r\n * @param {KeyboardEvent} e - Event object\r\n * @private\r\n */\r\n /* eslint-disable complexity */\r\n _onKeyDown(e) {\r\n const { ctrlKey, keyCode, metaKey } = e;\r\n const isModifierKey = ctrlKey || metaKey;\r\n\r\n if (isModifierKey) {\r\n if (keyCode === keyCodes.C) {\r\n this._graphics.resetTargetObjectForCopyPaste();\r\n } else if (keyCode === keyCodes.V) {\r\n this._graphics.pasteObject();\r\n this.clearRedoStack();\r\n } else if (keyCode === keyCodes.Z) {\r\n // There is no error message on shortcut when it's empty\r\n this.undo()['catch'](() => {});\r\n } else if (keyCode === keyCodes.Y) {\r\n // There is no error message on shortcut when it's empty\r\n this.redo()['catch'](() => {});\r\n }\r\n }\r\n\r\n const isDeleteKey = keyCode === keyCodes.BACKSPACE || keyCode === keyCodes.DEL;\r\n const isRemoveReady = this._graphics.isReadyRemoveObject();\r\n\r\n if (isRemoveReady && isDeleteKey) {\r\n e.preventDefault();\r\n this.removeActiveObject();\r\n }\r\n }\r\n\r\n /**\r\n * Remove Active Object\r\n */\r\n removeActiveObject() {\r\n const activeObjectId = this._graphics.getActiveObjectIdForRemove();\r\n\r\n this.removeObject(activeObjectId);\r\n }\r\n\r\n /**\r\n * mouse down event handler\r\n * @param {Event} event - mouse down event\r\n * @param {Object} originPointer - origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @private\r\n */\r\n _onMouseDown(event, originPointer) {\r\n /**\r\n * The mouse down event with position x, y on canvas\r\n * @event ImageEditor#mousedown\r\n * @param {Object} event - browser mouse event object\r\n * @param {Object} originPointer origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @example\r\n * imageEditor.on('mousedown', function(event, originPointer) {\r\n * console.log(event);\r\n * console.log(originPointer);\r\n * if (imageEditor.hasFilter('colorFilter')) {\r\n * imageEditor.applyFilter('colorFilter', {\r\n * x: parseInt(originPointer.x, 10),\r\n * y: parseInt(originPointer.y, 10)\r\n * });\r\n * }\r\n * });\r\n */\r\n\r\n this.fire(events.MOUSE_DOWN, event, originPointer);\r\n }\r\n\r\n /**\r\n * Add a 'addObject' command\r\n * @param {Object} obj - Fabric object\r\n * @private\r\n */\r\n _pushAddObjectCommand(obj) {\r\n const command = commandFactory.create(commands.ADD_OBJECT, this._graphics, obj);\r\n this._invoker.pushUndoStack(command);\r\n }\r\n\r\n /**\r\n * Add a 'changeSelection' command\r\n * @param {fabric.Object} obj - selection object\r\n * @private\r\n */\r\n _pushModifyObjectCommand(obj) {\r\n const { type } = obj;\r\n const props = makeSelectionUndoData(obj, (item) =>\r\n makeSelectionUndoDatum(this._graphics.getObjectId(item), item, type === 'activeSelection')\r\n );\r\n const command = commandFactory.create(commands.CHANGE_SELECTION, this._graphics, props);\r\n command.execute(this._graphics, props);\r\n\r\n this._invoker.pushUndoStack(command);\r\n }\r\n\r\n /**\r\n * 'objectActivated' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\r\n _onObjectActivated(props) {\r\n /**\r\n * The event when object is selected(aka activated).\r\n * @event ImageEditor#objectActivated\r\n * @param {ObjectProps} objectProps - object properties\r\n * @example\r\n * imageEditor.on('objectActivated', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * console.log(props.id);\r\n * });\r\n */\r\n this.fire(events.OBJECT_ACTIVATED, props);\r\n }\r\n\r\n /**\r\n * 'objectMoved' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\r\n _onObjectMoved(props) {\r\n /**\r\n * The event when object is moved\r\n * @event ImageEditor#objectMoved\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectMoved', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * });\r\n */\r\n this.fire(events.OBJECT_MOVED, props);\r\n }\r\n\r\n /**\r\n * 'objectScaled' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\r\n _onObjectScaled(props) {\r\n /**\r\n * The event when scale factor is changed\r\n * @event ImageEditor#objectScaled\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectScaled', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * });\r\n */\r\n this.fire(events.OBJECT_SCALED, props);\r\n }\r\n\r\n /**\r\n * 'objectRotated' event handler\r\n * @param {ObjectProps} props - object properties\r\n * @private\r\n */\r\n _onObjectRotated(props) {\r\n /**\r\n * The event when object angle is changed\r\n * @event ImageEditor#objectRotated\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectRotated', function(props) {\r\n * console.log(props);\r\n * console.log(props.type);\r\n * });\r\n */\r\n this.fire(events.OBJECT_ROTATED, props);\r\n }\r\n\r\n /**\r\n * Get current drawing mode\r\n * @returns {string}\r\n * @example\r\n * // Image editor drawing mode\r\n * //\r\n * // NORMAL: 'NORMAL'\r\n * // CROPPER: 'CROPPER'\r\n * // FREE_DRAWING: 'FREE_DRAWING'\r\n * // LINE_DRAWING: 'LINE_DRAWING'\r\n * // TEXT: 'TEXT'\r\n * //\r\n * if (imageEditor.getDrawingMode() === 'FREE_DRAWING') {\r\n * imageEditor.stopDrawingMode();\r\n * }\r\n */\r\n getDrawingMode() {\r\n return this._graphics.getDrawingMode();\r\n }\r\n\r\n /**\r\n * Clear all objects\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.clearObjects();\r\n */\r\n clearObjects() {\r\n return this.execute(commands.CLEAR_OBJECTS);\r\n }\r\n\r\n /**\r\n * Deactivate all objects\r\n * @example\r\n * imageEditor.deactivateAll();\r\n */\r\n deactivateAll() {\r\n this._graphics.deactivateAll();\r\n this._graphics.renderAll();\r\n }\r\n\r\n /**\r\n * discard selction\r\n * @example\r\n * imageEditor.discardSelection();\r\n */\r\n discardSelection() {\r\n this._graphics.discardSelection();\r\n }\r\n\r\n /**\r\n * selectable status change\r\n * @param {boolean} selectable - selctable status\r\n * @example\r\n * imageEditor.changeSelectableAll(false); // or true\r\n */\r\n changeSelectableAll(selectable) {\r\n this._graphics.changeSelectableAll(selectable);\r\n }\r\n\r\n /**\r\n * Invoke command\r\n * @param {String} commandName - Command name\r\n * @param {...*} args - Arguments for creating command\r\n * @returns {Promise}\r\n * @private\r\n */\r\n execute(commandName, ...args) {\r\n // Inject an Graphics instance as first parameter\r\n const theArgs = [this._graphics].concat(args);\r\n\r\n return this._invoker.execute(commandName, ...theArgs);\r\n }\r\n\r\n /**\r\n * Invoke command\r\n * @param {String} commandName - Command name\r\n * @param {...*} args - Arguments for creating command\r\n * @returns {Promise}\r\n * @private\r\n */\r\n executeSilent(commandName, ...args) {\r\n // Inject an Graphics instance as first parameter\r\n const theArgs = [this._graphics].concat(args);\r\n\r\n return this._invoker.executeSilent(commandName, ...theArgs);\r\n }\r\n\r\n /**\r\n * Undo\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.undo();\r\n */\r\n undo() {\r\n return this._invoker.undo();\r\n }\r\n\r\n /**\r\n * Redo\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.redo();\r\n */\r\n redo() {\r\n return this._invoker.redo();\r\n }\r\n\r\n /**\r\n * Load image from file\r\n * @param {File} imgFile - Image file\r\n * @param {string} [imageName] - imageName\r\n * @returns {Promise<SizeChange, ErrorMsg>}\r\n * @example\r\n * imageEditor.loadImageFromFile(file).then(result => {\r\n * console.log('old : ' + result.oldWidth + ', ' + result.oldHeight);\r\n * console.log('new : ' + result.newWidth + ', ' + result.newHeight);\r\n * });\r\n */\r\n loadImageFromFile(imgFile, imageName) {\r\n if (!imgFile) {\r\n return Promise.reject(rejectMessages.invalidParameters);\r\n }\r\n\r\n const imgUrl = URL.createObjectURL(imgFile);\r\n imageName = imageName || imgFile.name;\r\n\r\n return this.loadImageFromURL(imgUrl, imageName).then((value) => {\r\n URL.revokeObjectURL(imgFile);\r\n\r\n return value;\r\n });\r\n }\r\n\r\n /**\r\n * Load image from url\r\n * @param {string} url - File url\r\n * @param {string} imageName - imageName\r\n * @returns {Promise<SizeChange, ErrorMsg>}\r\n * @example\r\n * imageEditor.loadImageFromURL('http://url/testImage.png', 'lena').then(result => {\r\n * console.log('old : ' + result.oldWidth + ', ' + result.oldHeight);\r\n * console.log('new : ' + result.newWidth + ', ' + result.newHeight);\r\n * });\r\n */\r\n loadImageFromURL(url, imageName) {\r\n if (!imageName || !url) {\r\n return Promise.reject(rejectMessages.invalidParameters);\r\n }\r\n\r\n return this.execute(commands.LOAD_IMAGE, imageName, url);\r\n }\r\n\r\n /**\r\n * Add image object on canvas\r\n * @param {string} imgUrl - Image url to make object\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.addImageObject('path/fileName.jpg').then(objectProps => {\r\n * console.log(ojectProps.id);\r\n * });\r\n */\r\n addImageObject(imgUrl) {\r\n if (!imgUrl) {\r\n return Promise.reject(rejectMessages.invalidParameters);\r\n }\r\n\r\n return this.execute(commands.ADD_IMAGE_OBJECT, imgUrl);\r\n }\r\n\r\n /**\r\n * Start a drawing mode. If the current mode is not 'NORMAL', 'stopDrawingMode()' will be called first.\r\n * @param {String} mode Can be one of <I>'CROPPER', 'FREE_DRAWING', 'LINE_DRAWING', 'TEXT', 'SHAPE'</I>\r\n * @param {Object} [option] parameters of drawing mode, it's available with 'FREE_DRAWING', 'LINE_DRAWING'\r\n * @param {Number} [option.width] brush width\r\n * @param {String} [option.color] brush color\r\n * @param {Object} [option.arrowType] arrow decorate\r\n * @param {string} [option.arrowType.tail] arrow decorate for tail. 'chevron' or 'triangle'\r\n * @param {string} [option.arrowType.head] arrow decorate for head. 'chevron' or 'triangle'\r\n * @returns {boolean} true if success or false\r\n * @example\r\n * imageEditor.startDrawingMode('FREE_DRAWING', {\r\n * width: 10,\r\n * color: 'rgba(255,0,0,0.5)'\r\n * });\r\n * imageEditor.startDrawingMode('LINE_DRAWING', {\r\n * width: 10,\r\n * color: 'rgba(255,0,0,0.5)',\r\n * arrowType: {\r\n * tail: 'chevron' // triangle\r\n * }\r\n * });\r\n *\r\n */\r\n startDrawingMode(mode, option) {\r\n return this._graphics.startDrawingMode(mode, option);\r\n }\r\n\r\n /**\r\n * Stop the current drawing mode and back to the 'NORMAL' mode\r\n * @example\r\n * imageEditor.stopDrawingMode();\r\n */\r\n stopDrawingMode() {\r\n this._graphics.stopDrawingMode();\r\n }\r\n\r\n /**\r\n * Crop this image with rect\r\n * @param {Object} rect crop rect\r\n * @param {Number} rect.left left position\r\n * @param {Number} rect.top top position\r\n * @param {Number} rect.width width\r\n * @param {Number} rect.height height\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.crop(imageEditor.getCropzoneRect());\r\n */\r\n crop(rect) {\r\n const data = this._graphics.getCroppedImageData(rect);\r\n if (!data) {\r\n return Promise.reject(rejectMessages.invalidParameters);\r\n }\r\n\r\n return this.loadImageFromURL(data.url, data.imageName);\r\n }\r\n\r\n /**\r\n * Get the cropping rect\r\n * @returns {Object} {{left: number, top: number, width: number, height: number}} rect\r\n */\r\n getCropzoneRect() {\r\n return this._graphics.getCropzoneRect();\r\n }\r\n\r\n /**\r\n * Set the cropping rect\r\n * @param {number} [mode] crop rect mode [1, 1.5, 1.3333333333333333, 1.25, 1.7777777777777777]\r\n */\r\n setCropzoneRect(mode) {\r\n this._graphics.setCropzoneRect(mode);\r\n }\r\n\r\n /**\r\n * Flip\r\n * @returns {Promise}\r\n * @param {string} type - 'flipX' or 'flipY' or 'reset'\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @private\r\n */\r\n _flip(type) {\r\n return this.execute(commands.FLIP_IMAGE, type);\r\n }\r\n\r\n /**\r\n * Flip x\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.flipX().then((status => {\r\n * console.log('flipX: ', status.flipX);\r\n * console.log('flipY: ', status.flipY);\r\n * console.log('angle: ', status.angle);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\r\n flipX() {\r\n return this._flip('flipX');\r\n }\r\n\r\n /**\r\n * Flip y\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.flipY().then(status => {\r\n * console.log('flipX: ', status.flipX);\r\n * console.log('flipY: ', status.flipY);\r\n * console.log('angle: ', status.angle);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\r\n flipY() {\r\n return this._flip('flipY');\r\n }\r\n\r\n /**\r\n * Reset flip\r\n * @returns {Promise<FlipStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.resetFlip().then(status => {\r\n * console.log('flipX: ', status.flipX);\r\n * console.log('flipY: ', status.flipY);\r\n * console.log('angle: ', status.angle);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });;\r\n */\r\n resetFlip() {\r\n return this._flip('reset');\r\n }\r\n\r\n /**\r\n * @param {string} type - 'rotate' or 'setAngle'\r\n * @param {number} angle - angle value (degree)\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<RotateStatus, ErrorMsg>}\r\n * @private\r\n */\r\n _rotate(type, angle, isSilent) {\r\n let result = null;\r\n if (isSilent) {\r\n result = this.executeSilent(commands.ROTATE_IMAGE, type, angle);\r\n } else {\r\n result = this.execute(commands.ROTATE_IMAGE, type, angle);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n /**\r\n * Rotate image\r\n * @returns {Promise}\r\n * @param {number} angle - Additional angle to rotate image\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<RotateStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.rotate(10); // angle = 10\r\n * imageEditor.rotate(10); // angle = 20\r\n * imageEidtor.rotate(5); // angle = 5\r\n * imageEidtor.rotate(-95); // angle = -90\r\n * imageEditor.rotate(10).then(status => {\r\n * console.log('angle: ', status.angle);\r\n * })).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\r\n rotate(angle, isSilent) {\r\n return this._rotate('rotate', angle, isSilent);\r\n }\r\n\r\n /**\r\n * Set angle\r\n * @param {number} angle - Angle of image\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<RotateStatus, ErrorMsg>}\r\n * @example\r\n * imageEditor.setAngle(10); // angle = 10\r\n * imageEditor.rotate(10); // angle = 20\r\n * imageEidtor.setAngle(5); // angle = 5\r\n * imageEidtor.rotate(50); // angle = 55\r\n * imageEidtor.setAngle(-40); // angle = -40\r\n * imageEditor.setAngle(10).then(status => {\r\n * console.log('angle: ', status.angle);\r\n * })).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\r\n setAngle(angle, isSilent) {\r\n return this._rotate('setAngle', angle, isSilent);\r\n }\r\n\r\n /**\r\n * Set drawing brush\r\n * @param {Object} option brush option\r\n * @param {Number} option.width width\r\n * @param {String} option.color color like 'FFFFFF', 'rgba(0, 0, 0, 0.5)'\r\n * @example\r\n * imageEditor.startDrawingMode('FREE_DRAWING');\r\n * imageEditor.setBrush({\r\n * width: 12,\r\n * color: 'rgba(0, 0, 0, 0.5)'\r\n * });\r\n * imageEditor.setBrush({\r\n * width: 8,\r\n * color: 'FFFFFF'\r\n * });\r\n */\r\n setBrush(option) {\r\n this._graphics.setBrush(option);\r\n }\r\n\r\n /**\r\n * Set states of current drawing shape\r\n * @param {string} type - Shape type (ex: 'rect', 'circle', 'triangle')\r\n * @param {Object} [options] - Shape options\r\n * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or\r\n * Shape foreground color (ex: '#fff', 'transparent')\r\n * @param {string} [options.stoke] - Shape outline color\r\n * @param {number} [options.strokeWidth] - Shape outline width\r\n * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)\r\n * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)\r\n * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)\r\n * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)\r\n * @param {number} [options.isRegular] - Whether resizing shape has 1:1 ratio or not\r\n * @example\r\n * imageEditor.setDrawingShape('rect', {\r\n * fill: 'red',\r\n * width: 100,\r\n * height: 200\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('rect', {\r\n * fill: {\r\n * type: 'filter',\r\n * filter: [{blur: 0.3}, {pixelate: 20}]\r\n * },\r\n * width: 100,\r\n * height: 200\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('circle', {\r\n * fill: 'transparent',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('triangle', { // When resizing, the shape keep the 1:1 ratio\r\n * width: 1,\r\n * height: 1,\r\n * isRegular: true\r\n * });\r\n * @example\r\n * imageEditor.setDrawingShape('circle', { // When resizing, the shape keep the 1:1 ratio\r\n * rx: 10,\r\n * ry: 10,\r\n * isRegular: true\r\n * });\r\n */\r\n setDrawingShape(type, options) {\r\n this._graphics.setDrawingShape(type, options);\r\n }\r\n\r\n setDrawingIcon(type, iconColor) {\r\n this._graphics.setIconStyle(type, iconColor);\r\n }\r\n\r\n /**\r\n * Add shape\r\n * @param {string} type - Shape type (ex: 'rect', 'circle', 'triangle')\r\n * @param {Object} options - Shape options\r\n * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or\r\n * Shape foreground color (ex: '#fff', 'transparent')\r\n * @param {string} [options.stroke] - Shape outline color\r\n * @param {number} [options.strokeWidth] - Shape outline width\r\n * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)\r\n * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)\r\n * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)\r\n * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)\r\n * @param {number} [options.left] - Shape x position\r\n * @param {number} [options.top] - Shape y position\r\n * @param {boolean} [options.isRegular] - Whether resizing shape has 1:1 ratio or not\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.addShape('rect', {\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * width: 100,\r\n * height: 200,\r\n * left: 10,\r\n * top: 10,\r\n * isRegular: true\r\n * });\r\n * @example\r\n * imageEditor.addShape('circle', {\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100,\r\n * isRegular: false\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n * @example\r\n * imageEditor.addShape('rect', {\r\n * fill: {\r\n * type: 'filter',\r\n * filter: [{blur: 0.3}, {pixelate: 20}]\r\n * },\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100,\r\n * isRegular: false\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n */\r\n addShape(type, options) {\r\n options = options || {};\r\n\r\n this._setPositions(options);\r\n\r\n return this.execute(commands.ADD_SHAPE, type, options);\r\n }\r\n\r\n /**\r\n * Change shape\r\n * @param {number} id - object id\r\n * @param {Object} options - Shape options\r\n * @param {(ShapeFillOption | string)} [options.fill] - {@link ShapeFillOption} or\r\n * Shape foreground color (ex: '#fff', 'transparent')\r\n * @param {string} [options.stroke] - Shape outline color\r\n * @param {number} [options.strokeWidth] - Shape outline width\r\n * @param {number} [options.width] - Width value (When type option is 'rect', this options can use)\r\n * @param {number} [options.height] - Height value (When type option is 'rect', this options can use)\r\n * @param {number} [options.rx] - Radius x value (When type option is 'circle', this options can use)\r\n * @param {number} [options.ry] - Radius y value (When type option is 'circle', this options can use)\r\n * @param {boolean} [options.isRegular] - Whether resizing shape has 1:1 ratio or not\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise}\r\n * @example\r\n * // call after selecting shape object on canvas\r\n * imageEditor.changeShape(id, { // change rectagle or triangle\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * width: 100,\r\n * height: 200\r\n * });\r\n * @example\r\n * // call after selecting shape object on canvas\r\n * imageEditor.changeShape(id, { // change circle\r\n * fill: 'red',\r\n * stroke: 'blue',\r\n * strokeWidth: 3,\r\n * rx: 10,\r\n * ry: 100\r\n * });\r\n */\r\n changeShape(id, options, isSilent) {\r\n const executeMethodName = isSilent ? 'executeSilent' : 'execute';\r\n\r\n return this[executeMethodName](commands.CHANGE_SHAPE, id, options);\r\n }\r\n\r\n /**\r\n * Add text on image\r\n * @param {string} text - Initial input text\r\n * @param {Object} [options] Options for generating text\r\n * @param {Object} [options.styles] Initial styles\r\n * @param {string} [options.styles.fill] Color\r\n * @param {string} [options.styles.fontFamily] Font type for text\r\n * @param {number} [options.styles.fontSize] Size\r\n * @param {string} [options.styles.fontStyle] Type of inclination (normal / italic)\r\n * @param {string} [options.styles.fontWeight] Type of thicker or thinner looking (normal / bold)\r\n * @param {string} [options.styles.textAlign] Type of text align (left / center / right)\r\n * @param {string} [options.styles.textDecoration] Type of line (underline / line-through / overline)\r\n * @param {{x: number, y: number}} [options.position] - Initial position\r\n * @param {boolean} [options.autofocus] - text autofocus, default is true\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.addText('init text');\r\n * @example\r\n * imageEditor.addText('init text', {\r\n * styles: {\r\n * fill: '#000',\r\n * fontSize: 20,\r\n * fontWeight: 'bold'\r\n * },\r\n * position: {\r\n * x: 10,\r\n * y: 10\r\n * }\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n */\r\n addText(text, options) {\r\n text = text || '';\r\n options = options || {};\r\n\r\n return this.execute(commands.ADD_TEXT, text, options);\r\n }\r\n\r\n /**\r\n * Change contents of selected text object on image\r\n * @param {number} id - object id\r\n * @param {string} text - Changing text\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.changeText(id, 'change text');\r\n */\r\n changeText(id, text) {\r\n text = text || '';\r\n\r\n return this.execute(commands.CHANGE_TEXT, id, text);\r\n }\r\n\r\n /**\r\n * Set style\r\n * @param {number} id - object id\r\n * @param {Object} styleObj - text styles\r\n * @param {string} [styleObj.fill] Color\r\n * @param {string} [styleObj.fontFamily] Font type for text\r\n * @param {number} [styleObj.fontSize] Size\r\n * @param {string} [styleObj.fontStyle] Type of inclination (normal / italic)\r\n * @param {string} [styleObj.fontWeight] Type of thicker or thinner looking (normal / bold)\r\n * @param {string} [styleObj.textAlign] Type of text align (left / center / right)\r\n * @param {string} [styleObj.textDecoration] Type of line (underline / line-through / overline)\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.changeTextStyle(id, {\r\n * fontStyle: 'italic'\r\n * });\r\n */\r\n changeTextStyle(id, styleObj, isSilent) {\r\n const executeMethodName = isSilent ? 'executeSilent' : 'execute';\r\n\r\n return this[executeMethodName](commands.CHANGE_TEXT_STYLE, id, styleObj);\r\n }\r\n\r\n /**\r\n * change text mode\r\n * @param {string} type - change type\r\n * @private\r\n */\r\n _changeActivateMode(type) {\r\n if (type !== 'ICON' && this.getDrawingMode() !== type) {\r\n this.startDrawingMode(type);\r\n }\r\n }\r\n\r\n /**\r\n * 'textChanged' event handler\r\n * @param {Object} objectProps changed object properties\r\n * @private\r\n */\r\n _onTextChanged(objectProps) {\r\n this.changeText(objectProps.id, objectProps.text);\r\n }\r\n\r\n /**\r\n * 'iconCreateResize' event handler\r\n * @param {Object} originPointer origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @private\r\n */\r\n _onIconCreateResize(originPointer) {\r\n this.fire(events.ICON_CREATE_RESIZE, originPointer);\r\n }\r\n\r\n /**\r\n * 'iconCreateEnd' event handler\r\n * @param {Object} originPointer origin pointer\r\n * @param {Number} originPointer.x x position\r\n * @param {Number} originPointer.y y position\r\n * @private\r\n */\r\n _onIconCreateEnd(originPointer) {\r\n this.fire(events.ICON_CREATE_END, originPointer);\r\n }\r\n\r\n /**\r\n * 'textEditing' event handler\r\n * @private\r\n */\r\n _onTextEditing() {\r\n /**\r\n * The event which starts to edit text object\r\n * @event ImageEditor#textEditing\r\n * @example\r\n * imageEditor.on('textEditing', function() {\r\n * console.log('text editing');\r\n * });\r\n */\r\n this.fire(events.TEXT_EDITING);\r\n }\r\n\r\n /**\r\n * Mousedown event handler in case of 'TEXT' drawing mode\r\n * @param {fabric.Event} event - Current mousedown event object\r\n * @private\r\n */\r\n _onAddText(event) {\r\n /**\r\n * The event when 'TEXT' drawing mode is enabled and click non-object area.\r\n * @event ImageEditor#addText\r\n * @param {Object} pos\r\n * @param {Object} pos.originPosition - Current position on origin canvas\r\n * @param {Number} pos.originPosition.x - x\r\n * @param {Number} pos.originPosition.y - y\r\n * @param {Object} pos.clientPosition - Current position on client area\r\n * @param {Number} pos.clientPosition.x - x\r\n * @param {Number} pos.clientPosition.y - y\r\n * @example\r\n * imageEditor.on('addText', function(pos) {\r\n * console.log('text position on canvas: ' + pos.originPosition);\r\n * console.log('text position on brwoser: ' + pos.clientPosition);\r\n * });\r\n */\r\n this.fire(events.ADD_TEXT, {\r\n originPosition: event.originPosition,\r\n clientPosition: event.clientPosition,\r\n });\r\n }\r\n\r\n /**\r\n * 'addObject' event handler\r\n * @param {Object} objectProps added object properties\r\n * @private\r\n */\r\n _onAddObject(objectProps) {\r\n const obj = this._graphics.getObject(objectProps.id);\r\n this._pushAddObjectCommand(obj);\r\n }\r\n\r\n /**\r\n * 'objectAdded' event handler\r\n * @param {Object} objectProps added object properties\r\n * @private\r\n */\r\n _onObjectAdded(objectProps) {\r\n /**\r\n * The event when object added\r\n * @event ImageEditor#objectAdded\r\n * @param {ObjectProps} props - object properties\r\n * @example\r\n * imageEditor.on('objectAdded', function(props) {\r\n * console.log(props);\r\n * });\r\n */\r\n this.fire(OBJECT_ADDED, objectProps);\r\n\r\n /**\r\n * The event when object added (deprecated)\r\n * @event ImageEditor#addObjectAfter\r\n * @param {ObjectProps} props - object properties\r\n * @deprecated\r\n */\r\n this.fire(ADD_OBJECT_AFTER, objectProps);\r\n }\r\n\r\n /**\r\n * 'objectModified' event handler\r\n * @param {fabric.Object} obj - selection object\r\n * @private\r\n */\r\n _onObjectModified(obj) {\r\n this._pushModifyObjectCommand(obj);\r\n }\r\n\r\n /**\r\n * 'selectionCleared' event handler\r\n * @private\r\n */\r\n _selectionCleared() {\r\n this.fire(SELECTION_CLEARED);\r\n }\r\n\r\n /**\r\n * 'selectionCreated' event handler\r\n * @param {Object} eventTarget - Fabric object\r\n * @private\r\n */\r\n _selectionCreated(eventTarget) {\r\n this.fire(SELECTION_CREATED, eventTarget);\r\n }\r\n\r\n /**\r\n * Register custom icons\r\n * @param {{iconType: string, pathValue: string}} infos - Infos to register icons\r\n * @example\r\n * imageEditor.registerIcons({\r\n * customIcon: 'M 0 0 L 20 20 L 10 10 Z',\r\n * customArrow: 'M 60 0 L 120 60 H 90 L 75 45 V 180 H 45 V 45 L 30 60 H 0 Z'\r\n * });\r\n */\r\n registerIcons(infos) {\r\n this._graphics.registerPaths(infos);\r\n }\r\n\r\n /**\r\n * Change canvas cursor type\r\n * @param {string} cursorType - cursor type\r\n * @example\r\n * imageEditor.changeCursor('crosshair');\r\n */\r\n changeCursor(cursorType) {\r\n this._graphics.changeCursor(cursorType);\r\n }\r\n\r\n /**\r\n * Add icon on canvas\r\n * @param {string} type - Icon type ('arrow', 'cancel', custom icon name)\r\n * @param {Object} options - Icon options\r\n * @param {string} [options.fill] - Icon foreground color\r\n * @param {number} [options.left] - Icon x position\r\n * @param {number} [options.top] - Icon y position\r\n * @returns {Promise<ObjectProps, ErrorMsg>}\r\n * @example\r\n * imageEditor.addIcon('arrow'); // The position is center on canvas\r\n * @example\r\n * imageEditor.addIcon('arrow', {\r\n * left: 100,\r\n * top: 100\r\n * }).then(objectProps => {\r\n * console.log(objectProps.id);\r\n * });\r\n */\r\n addIcon(type, options) {\r\n options = options || {};\r\n\r\n this._setPositions(options);\r\n\r\n return this.execute(commands.ADD_ICON, type, options);\r\n }\r\n\r\n /**\r\n * Change icon color\r\n * @param {number} id - object id\r\n * @param {string} color - Color for icon\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.changeIconColor(id, '#000000');\r\n */\r\n changeIconColor(id, color) {\r\n return this.execute(commands.CHANGE_ICON_COLOR, id, color);\r\n }\r\n\r\n /**\r\n * Remove an object or group by id\r\n * @param {number} id - object id\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.removeObject(id);\r\n */\r\n removeObject(id) {\r\n return this.execute(commands.REMOVE_OBJECT, id);\r\n }\r\n\r\n /**\r\n * Whether it has the filter or not\r\n * @param {string} type - Filter type\r\n * @returns {boolean} true if it has the filter\r\n */\r\n hasFilter(type) {\r\n return this._graphics.hasFilter(type);\r\n }\r\n\r\n /**\r\n * Remove filter on canvas image\r\n * @param {string} type - Filter type\r\n * @returns {Promise<FilterResult, ErrorMsg>}\r\n * @example\r\n * imageEditor.removeFilter('Grayscale').then(obj => {\r\n * console.log('filterType: ', obj.type);\r\n * console.log('actType: ', obj.action);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });\r\n */\r\n removeFilter(type) {\r\n return this.execute(commands.REMOVE_FILTER, type);\r\n }\r\n\r\n /**\r\n * Apply filter on canvas image\r\n * @param {string} type - Filter type\r\n * @param {Object} options - Options to apply filter\r\n * @param {number} options.maskObjId - masking image object id\r\n * @param {boolean} isSilent - is silent execution or not\r\n * @returns {Promise<FilterResult, ErrorMsg>}\r\n * @example\r\n * imageEditor.applyFilter('Grayscale');\r\n * @example\r\n * imageEditor.applyFilter('mask', {maskObjId: id}).then(obj => {\r\n * console.log('filterType: ', obj.type);\r\n * console.log('actType: ', obj.action);\r\n * }).catch(message => {\r\n * console.log('error: ', message);\r\n * });;\r\n */\r\n applyFilter(type, options, isSilent) {\r\n const executeMethodName = isSilent ? 'executeSilent' : 'execute';\r\n\r\n return this[executeMethodName](commands.APPLY_FILTER, type, options);\r\n }\r\n\r\n /**\r\n * Get data url\r\n * @param {Object} options - options for toDataURL\r\n * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\r\n * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\r\n * @param {Number} [options.multiplier=1] Multiplier to scale by\r\n * @param {Number} [options.left] Cropping left offset. Introduced in fabric v1.2.14\r\n * @param {Number} [options.top] Cropping top offset. Introduced in fabric v1.2.14\r\n * @param {Number} [options.width] Cropping width. Introduced in fabric v1.2.14\r\n * @param {Number} [options.height] Cropping height. Introduced in fabric v1.2.14\r\n * @returns {string} A DOMString containing the requested data URI\r\n * @example\r\n * imgEl.src = imageEditor.toDataURL();\r\n *\r\n * imageEditor.loadImageFromURL(imageEditor.toDataURL(), 'FilterImage').then(() => {\r\n * imageEditor.addImageObject(imgUrl);\r\n * });\r\n */\r\n toDataURL(options) {\r\n return this._graphics.toDataURL(options);\r\n }\r\n\r\n /**\r\n * Get image name\r\n * @returns {string} image name\r\n * @example\r\n * console.log(imageEditor.getImageName());\r\n */\r\n getImageName() {\r\n return this._graphics.getImageName();\r\n }\r\n\r\n /**\r\n * Clear undoStack\r\n * @example\r\n * imageEditor.clearUndoStack();\r\n */\r\n clearUndoStack() {\r\n this._invoker.clearUndoStack();\r\n }\r\n\r\n /**\r\n * Clear redoStack\r\n * @example\r\n * imageEditor.clearRedoStack();\r\n */\r\n clearRedoStack() {\r\n this._invoker.clearRedoStack();\r\n }\r\n\r\n /**\r\n * Whehter the undo stack is empty or not\r\n * @returns {boolean}\r\n * imageEditor.isEmptyUndoStack();\r\n */\r\n isEmptyUndoStack() {\r\n return this._invoker.isEmptyUndoStack();\r\n }\r\n\r\n /**\r\n * Whehter the redo stack is empty or not\r\n * @returns {boolean}\r\n * imageEditor.isEmptyRedoStack();\r\n */\r\n isEmptyRedoStack() {\r\n return this._invoker.isEmptyRedoStack();\r\n }\r\n\r\n /**\r\n * Resize canvas dimension\r\n * @param {{width: number, height: number}} dimension - Max width & height\r\n * @returns {Promise}\r\n */\r\n resizeCanvasDimension(dimension) {\r\n if (!dimension) {\r\n return Promise.reject(rejectMessages.invalidParameters);\r\n }\r\n\r\n return this.execute(commands.RESIZE_CANVAS_DIMENSION, dimension);\r\n }\r\n\r\n /**\r\n * Destroy\r\n */\r\n destroy() {\r\n this.stopDrawingMode();\r\n this._detachDomEvents();\r\n this._graphics.destroy();\r\n this._graphics = null;\r\n\r\n if (this.ui) {\r\n this.ui.destroy();\r\n }\r\n\r\n forEach(\r\n this,\r\n (value, key) => {\r\n this[key] = null;\r\n },\r\n this\r\n );\r\n }\r\n\r\n /**\r\n * Set position\r\n * @param {Object} options - Position options (left or top)\r\n * @private\r\n */\r\n _setPositions(options) {\r\n const centerPosition = this._graphics.getCenter();\r\n\r\n if (isUndefined(options.left)) {\r\n options.left = centerPosition.left;\r\n }\r\n\r\n if (isUndefined(options.top)) {\r\n options.top = centerPosition.top;\r\n }\r\n }\r\n\r\n /**\r\n * Set properties of active object\r\n * @param {number} id - object id\r\n * @param {Object} keyValue - key & value\r\n * @returns {Promise}\r\n * @example\r\n * imageEditor.setObjectProperties(id, {\r\n * left:100,\r\n * top:100,\r\n * width: 200,\r\n * height: 200,\r\n * opacity: 0.5\r\n * });\r\n */\r\n setObjectProperties(id, keyValue) {\r\n return this.execute(commands.SET_OBJECT_PROPERTIES, id, keyValue);\r\n }\r\n\r\n /**\r\n * Set properties of active object, Do not leave an invoke history.\r\n * @param {number} id - object id\r\n * @param {Object} keyValue - key & value\r\n * @example\r\n * imageEditor.setObjectPropertiesQuietly(id, {\r\n * left:100,\r\n * top:100,\r\n * width: 200,\r\n * height: 200,\r\n * opacity: 0.5\r\n * });\r\n */\r\n setObjectPropertiesQuietly(id, keyValue) {\r\n this._graphics.setObjectProperties(id, keyValue);\r\n }\r\n\r\n /**\r\n * Get properties of active object corresponding key\r\n * @param {number} id - object id\r\n * @param {Array<string>|ObjectProps|string} keys - property's key\r\n * @returns {ObjectProps} properties if id is valid or null\r\n * @example\r\n * var props = imageEditor.getObjectProperties(id, 'left');\r\n * console.log(props);\r\n * @example\r\n * var props = imageEditor.getObjectProperties(id, ['left', 'top', 'width', 'height']);\r\n * console.log(props);\r\n * @example\r\n * var props = imageEditor.getObjectProperties(id, {\r\n * left: null,\r\n * top: null,\r\n * width: null,\r\n * height: null,\r\n * opacity: null\r\n * });\r\n * console.log(props);\r\n */\r\n getObjectProperties(id, keys) {\r\n const object = this._graphics.getObject(id);\r\n if (!object) {\r\n return null;\r\n }\r\n\r\n return this._graphics.getObjectProperties(id, keys);\r\n }\r\n\r\n /**\r\n * Get the canvas size\r\n * @returns {Object} {{width: number, height: number}} canvas size\r\n * @example\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * console.log(canvasSize.width);\r\n * console.height(canvasSize.height);\r\n */\r\n getCanvasSize() {\r\n return this._graphics.getCanvasSize();\r\n }\r\n\r\n /**\r\n * Get object position by originX, originY\r\n * @param {number} id - object id\r\n * @param {string} originX - can be 'left', 'center', 'right'\r\n * @param {string} originY - can be 'top', 'center', 'bottom'\r\n * @returns {Object} {{x:number, y: number}} position by origin if id is valid, or null\r\n * @example\r\n * var position = imageEditor.getObjectPosition(id, 'left', 'top');\r\n * console.log(position);\r\n */\r\n getObjectPosition(id, originX, originY) {\r\n return this._graphics.getObjectPosition(id, originX, originY);\r\n }\r\n\r\n /**\r\n * Set object position by originX, originY\r\n * @param {number} id - object id\r\n * @param {Object} posInfo - position object\r\n * @param {number} posInfo.x - x position\r\n * @param {number} posInfo.y - y position\r\n * @param {string} posInfo.originX - can be 'left', 'center', 'right'\r\n * @param {string} posInfo.originY - can be 'top', 'center', 'bottom'\r\n * @returns {Promise}\r\n * @example\r\n * // align the object to 'left', 'top'\r\n * imageEditor.setObjectPosition(id, {\r\n * x: 0,\r\n * y: 0,\r\n * originX: 'left',\r\n * originY: 'top'\r\n * });\r\n * @example\r\n * // align the object to 'right', 'top'\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * imageEditor.setObjectPosition(id, {\r\n * x: canvasSize.width,\r\n * y: 0,\r\n * originX: 'right',\r\n * originY: 'top'\r\n * });\r\n * @example\r\n * // align the object to 'left', 'bottom'\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * imageEditor.setObjectPosition(id, {\r\n * x: 0,\r\n * y: canvasSize.height,\r\n * originX: 'left',\r\n * originY: 'bottom'\r\n * });\r\n * @example\r\n * // align the object to 'right', 'bottom'\r\n * var canvasSize = imageEditor.getCanvasSize();\r\n * imageEditor.setObjectPosition(id, {\r\n * x: canvasSize.width,\r\n * y: canvasSize.height,\r\n * originX: 'right',\r\n * originY: 'bottom'\r\n * });\r\n */\r\n setObjectPosition(id, posInfo) {\r\n return this.execute(commands.SET_OBJECT_POSITION, id, posInfo);\r\n }\r\n}\r\n\r\naction.mixin(ImageEditor);\r\nCustomEvents.mixin(ImageEditor);\r\n\r\nexport default ImageEditor;\r\n"]},"metadata":{},"sourceType":"module"}