86a784d0bbf9cf6ad64c5108dceea295.json 29.1 KB
{"ast":null,"code":"/**\r\n * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>\r\n * @fileoverview Image crop module (start cropping, end cropping)\r\n */\nimport snippet from 'tui-code-snippet';\nimport fabric from 'fabric';\nimport Component from '../interface/component';\nimport Cropzone from '../extension/cropzone';\nimport { keyCodes, componentNames, CROPZONE_DEFAULT_OPTIONS } from '../consts';\nimport { clamp, fixFloatingPoint } from '../util';\nconst MOUSE_MOVE_THRESHOLD = 10;\nconst DEFAULT_OPTION = {\n  presetRatio: null,\n  top: -10,\n  left: -10,\n  height: 1,\n  width: 1\n};\n/**\r\n * Cropper components\r\n * @param {Graphics} graphics - Graphics instance\r\n * @extends {Component}\r\n * @class Cropper\r\n * @ignore\r\n */\n\nclass Cropper extends Component {\n  constructor(graphics) {\n    super(componentNames.CROPPER, graphics);\n    /**\r\n     * Cropzone\r\n     * @type {Cropzone}\r\n     * @private\r\n     */\n\n    this._cropzone = null;\n    /**\r\n     * StartX of Cropzone\r\n     * @type {number}\r\n     * @private\r\n     */\n\n    this._startX = null;\n    /**\r\n     * StartY of Cropzone\r\n     * @type {number}\r\n     * @private\r\n     */\n\n    this._startY = null;\n    /**\r\n     * State whether shortcut key is pressed or not\r\n     * @type {boolean}\r\n     * @private\r\n     */\n\n    this._withShiftKey = false;\n    /**\r\n     * Listeners\r\n     * @type {object.<string, function>}\r\n     * @private\r\n     */\n\n    this._listeners = {\n      keydown: this._onKeyDown.bind(this),\n      keyup: this._onKeyUp.bind(this),\n      mousedown: this._onFabricMouseDown.bind(this),\n      mousemove: this._onFabricMouseMove.bind(this),\n      mouseup: this._onFabricMouseUp.bind(this)\n    };\n  }\n  /**\r\n   * Start cropping\r\n   */\n\n\n  start() {\n    if (this._cropzone) {\n      return;\n    }\n\n    const canvas = this.getCanvas();\n    canvas.forEachObject(obj => {\n      // {@link http://fabricjs.com/docs/fabric.Object.html#evented}\n      obj.evented = false;\n    });\n    this._cropzone = new Cropzone(canvas, snippet.extend({\n      left: 0,\n      top: 0,\n      width: 0.5,\n      height: 0.5,\n      strokeWidth: 0,\n      // {@link https://github.com/kangax/fabric.js/issues/2860}\n      cornerSize: 10,\n      cornerColor: 'black',\n      fill: 'transparent'\n    }, CROPZONE_DEFAULT_OPTIONS, this.graphics.cropSelectionStyle));\n    canvas.discardActiveObject();\n    canvas.add(this._cropzone);\n    canvas.on('mouse:down', this._listeners.mousedown);\n    canvas.selection = false;\n    canvas.defaultCursor = 'crosshair';\n    fabric.util.addListener(document, 'keydown', this._listeners.keydown);\n    fabric.util.addListener(document, 'keyup', this._listeners.keyup);\n  }\n  /**\r\n   * End cropping\r\n   */\n\n\n  end() {\n    const canvas = this.getCanvas();\n    const cropzone = this._cropzone;\n\n    if (!cropzone) {\n      return;\n    }\n\n    canvas.remove(cropzone);\n    canvas.selection = true;\n    canvas.defaultCursor = 'default';\n    canvas.off('mouse:down', this._listeners.mousedown);\n    canvas.forEachObject(obj => {\n      obj.evented = true;\n    });\n    this._cropzone = null;\n    fabric.util.removeListener(document, 'keydown', this._listeners.keydown);\n    fabric.util.removeListener(document, 'keyup', this._listeners.keyup);\n  }\n  /**\r\n   * Change cropzone visible\r\n   * @param {boolean} visible - cropzone visible state\r\n   */\n\n\n  changeVisibility(visible) {\n    if (this._cropzone) {\n      this._cropzone.set({\n        visible\n      });\n    }\n  }\n  /**\r\n   * onMousedown handler in fabric canvas\r\n   * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event\r\n   * @private\r\n   */\n\n\n  _onFabricMouseDown(fEvent) {\n    const canvas = this.getCanvas();\n\n    if (fEvent.target) {\n      return;\n    }\n\n    canvas.selection = false;\n    const coord = canvas.getPointer(fEvent.e);\n    this._startX = coord.x;\n    this._startY = coord.y;\n    canvas.on({\n      'mouse:move': this._listeners.mousemove,\n      'mouse:up': this._listeners.mouseup\n    });\n  }\n  /**\r\n   * onMousemove handler in fabric canvas\r\n   * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event\r\n   * @private\r\n   */\n\n\n  _onFabricMouseMove(fEvent) {\n    const canvas = this.getCanvas();\n    const pointer = canvas.getPointer(fEvent.e);\n    const {\n      x,\n      y\n    } = pointer;\n    const cropzone = this._cropzone;\n\n    if (Math.abs(x - this._startX) + Math.abs(y - this._startY) > MOUSE_MOVE_THRESHOLD) {\n      canvas.remove(cropzone);\n      cropzone.set(this._calcRectDimensionFromPoint(x, y));\n      canvas.add(cropzone);\n      canvas.setActiveObject(cropzone);\n    }\n  }\n  /**\r\n   * Get rect dimension setting from Canvas-Mouse-Position(x, y)\r\n   * @param {number} x - Canvas-Mouse-Position x\r\n   * @param {number} y - Canvas-Mouse-Position Y\r\n   * @returns {{left: number, top: number, width: number, height: number}}\r\n   * @private\r\n   */\n\n\n  _calcRectDimensionFromPoint(x, y) {\n    const canvas = this.getCanvas();\n    const canvasWidth = canvas.getWidth();\n    const canvasHeight = canvas.getHeight();\n    const startX = this._startX;\n    const startY = this._startY;\n    let left = clamp(x, 0, startX);\n    let top = clamp(y, 0, startY);\n    let width = clamp(x, startX, canvasWidth) - left; // (startX <= x(mouse) <= canvasWidth) - left\n\n    let height = clamp(y, startY, canvasHeight) - top; // (startY <= y(mouse) <= canvasHeight) - top\n\n    if (this._withShiftKey) {\n      // make fixed ratio cropzone\n      if (width > height) {\n        height = width;\n      } else if (height > width) {\n        width = height;\n      }\n\n      if (startX >= x) {\n        left = startX - width;\n      }\n\n      if (startY >= y) {\n        top = startY - height;\n      }\n    }\n\n    return {\n      left,\n      top,\n      width,\n      height\n    };\n  }\n  /**\r\n   * onMouseup handler in fabric canvas\r\n   * @private\r\n   */\n\n\n  _onFabricMouseUp() {\n    const cropzone = this._cropzone;\n    const listeners = this._listeners;\n    const canvas = this.getCanvas();\n    canvas.setActiveObject(cropzone);\n    canvas.off({\n      'mouse:move': listeners.mousemove,\n      'mouse:up': listeners.mouseup\n    });\n  }\n  /**\r\n   * Get cropped image data\r\n   * @param {Object} cropRect cropzone rect\r\n   *  @param {Number} cropRect.left left position\r\n   *  @param {Number} cropRect.top top position\r\n   *  @param {Number} cropRect.width width\r\n   *  @param {Number} cropRect.height height\r\n   * @returns {?{imageName: string, url: string}} cropped Image data\r\n   */\n\n\n  getCroppedImageData(cropRect) {\n    const canvas = this.getCanvas();\n    const containsCropzone = canvas.contains(this._cropzone);\n\n    if (!cropRect) {\n      return null;\n    }\n\n    if (containsCropzone) {\n      canvas.remove(this._cropzone);\n    }\n\n    const imageData = {\n      imageName: this.getImageName(),\n      url: canvas.toDataURL(cropRect)\n    };\n\n    if (containsCropzone) {\n      canvas.add(this._cropzone);\n    }\n\n    return imageData;\n  }\n  /**\r\n   * Get cropped rect\r\n   * @returns {Object} rect\r\n   */\n\n\n  getCropzoneRect() {\n    const cropzone = this._cropzone;\n\n    if (!cropzone.isValid()) {\n      return null;\n    }\n\n    return {\n      left: cropzone.left,\n      top: cropzone.top,\n      width: cropzone.width,\n      height: cropzone.height\n    };\n  }\n  /**\r\n   * Set a cropzone square\r\n   * @param {number} [presetRatio] - preset ratio\r\n   */\n\n\n  setCropzoneRect(presetRatio) {\n    const canvas = this.getCanvas();\n    const cropzone = this._cropzone;\n    canvas.discardActiveObject();\n    canvas.selection = false;\n    canvas.remove(cropzone);\n    cropzone.set(presetRatio ? this._getPresetPropertiesForCropSize(presetRatio) : DEFAULT_OPTION);\n    canvas.add(cropzone);\n    canvas.selection = true;\n\n    if (presetRatio) {\n      canvas.setActiveObject(cropzone);\n    }\n  }\n  /**\r\n   * get a cropzone square info\r\n   * @param {number} presetRatio - preset ratio\r\n   * @returns {{presetRatio: number, left: number, top: number, width: number, height: number}}\r\n   * @private\r\n   */\n\n\n  _getPresetPropertiesForCropSize(presetRatio) {\n    const canvas = this.getCanvas();\n    const originalWidth = canvas.getWidth();\n    const originalHeight = canvas.getHeight();\n    const standardSize = originalWidth >= originalHeight ? originalWidth : originalHeight;\n\n    const getScale = (value, orignalValue) => value > orignalValue ? orignalValue / value : 1;\n\n    let width = standardSize * presetRatio;\n    let height = standardSize;\n    const scaleWidth = getScale(width, originalWidth);\n    [width, height] = snippet.map([width, height], sizeValue => sizeValue * scaleWidth);\n    const scaleHeight = getScale(height, originalHeight);\n    [width, height] = snippet.map([width, height], sizeValue => fixFloatingPoint(sizeValue * scaleHeight));\n    return {\n      presetRatio,\n      top: (originalHeight - height) / 2,\n      left: (originalWidth - width) / 2,\n      width,\n      height\n    };\n  }\n  /**\r\n   * Keydown event handler\r\n   * @param {KeyboardEvent} e - Event object\r\n   * @private\r\n   */\n\n\n  _onKeyDown(e) {\n    if (e.keyCode === keyCodes.SHIFT) {\n      this._withShiftKey = true;\n    }\n  }\n  /**\r\n   * Keyup event handler\r\n   * @param {KeyboardEvent} e - Event object\r\n   * @private\r\n   */\n\n\n  _onKeyUp(e) {\n    if (e.keyCode === keyCodes.SHIFT) {\n      this._withShiftKey = false;\n    }\n  }\n\n}\n\nexport default Cropper;","map":{"version":3,"sources":["C:/Users/kkwan_000/Desktop/git/2017110269/minsung/src/js/component/cropper.js"],"names":["snippet","fabric","Component","Cropzone","keyCodes","componentNames","CROPZONE_DEFAULT_OPTIONS","clamp","fixFloatingPoint","MOUSE_MOVE_THRESHOLD","DEFAULT_OPTION","presetRatio","top","left","height","width","Cropper","constructor","graphics","CROPPER","_cropzone","_startX","_startY","_withShiftKey","_listeners","keydown","_onKeyDown","bind","keyup","_onKeyUp","mousedown","_onFabricMouseDown","mousemove","_onFabricMouseMove","mouseup","_onFabricMouseUp","start","canvas","getCanvas","forEachObject","obj","evented","extend","strokeWidth","cornerSize","cornerColor","fill","cropSelectionStyle","discardActiveObject","add","on","selection","defaultCursor","util","addListener","document","end","cropzone","remove","off","removeListener","changeVisibility","visible","set","fEvent","target","coord","getPointer","e","x","y","pointer","Math","abs","_calcRectDimensionFromPoint","setActiveObject","canvasWidth","getWidth","canvasHeight","getHeight","startX","startY","listeners","getCroppedImageData","cropRect","containsCropzone","contains","imageData","imageName","getImageName","url","toDataURL","getCropzoneRect","isValid","setCropzoneRect","_getPresetPropertiesForCropSize","originalWidth","originalHeight","standardSize","getScale","value","orignalValue","scaleWidth","map","sizeValue","scaleHeight","keyCode","SHIFT"],"mappings":"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","sourcesContent":["/**\r\n * @author NHN Ent. FE Development Team <dl_javascript@nhn.com>\r\n * @fileoverview Image crop module (start cropping, end cropping)\r\n */\r\nimport snippet from 'tui-code-snippet';\r\nimport fabric from 'fabric';\r\nimport Component from '../interface/component';\r\nimport Cropzone from '../extension/cropzone';\r\nimport { keyCodes, componentNames, CROPZONE_DEFAULT_OPTIONS } from '../consts';\r\nimport { clamp, fixFloatingPoint } from '../util';\r\n\r\nconst MOUSE_MOVE_THRESHOLD = 10;\r\nconst DEFAULT_OPTION = {\r\n  presetRatio: null,\r\n  top: -10,\r\n  left: -10,\r\n  height: 1,\r\n  width: 1,\r\n};\r\n\r\n/**\r\n * Cropper components\r\n * @param {Graphics} graphics - Graphics instance\r\n * @extends {Component}\r\n * @class Cropper\r\n * @ignore\r\n */\r\nclass Cropper extends Component {\r\n  constructor(graphics) {\r\n    super(componentNames.CROPPER, graphics);\r\n\r\n    /**\r\n     * Cropzone\r\n     * @type {Cropzone}\r\n     * @private\r\n     */\r\n    this._cropzone = null;\r\n\r\n    /**\r\n     * StartX of Cropzone\r\n     * @type {number}\r\n     * @private\r\n     */\r\n    this._startX = null;\r\n\r\n    /**\r\n     * StartY of Cropzone\r\n     * @type {number}\r\n     * @private\r\n     */\r\n    this._startY = null;\r\n\r\n    /**\r\n     * State whether shortcut key is pressed or not\r\n     * @type {boolean}\r\n     * @private\r\n     */\r\n    this._withShiftKey = false;\r\n\r\n    /**\r\n     * Listeners\r\n     * @type {object.<string, function>}\r\n     * @private\r\n     */\r\n    this._listeners = {\r\n      keydown: this._onKeyDown.bind(this),\r\n      keyup: this._onKeyUp.bind(this),\r\n      mousedown: this._onFabricMouseDown.bind(this),\r\n      mousemove: this._onFabricMouseMove.bind(this),\r\n      mouseup: this._onFabricMouseUp.bind(this),\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Start cropping\r\n   */\r\n  start() {\r\n    if (this._cropzone) {\r\n      return;\r\n    }\r\n    const canvas = this.getCanvas();\r\n\r\n    canvas.forEachObject((obj) => {\r\n      // {@link http://fabricjs.com/docs/fabric.Object.html#evented}\r\n      obj.evented = false;\r\n    });\r\n\r\n    this._cropzone = new Cropzone(\r\n      canvas,\r\n      snippet.extend(\r\n        {\r\n          left: 0,\r\n          top: 0,\r\n          width: 0.5,\r\n          height: 0.5,\r\n          strokeWidth: 0, // {@link https://github.com/kangax/fabric.js/issues/2860}\r\n          cornerSize: 10,\r\n          cornerColor: 'black',\r\n          fill: 'transparent',\r\n        },\r\n        CROPZONE_DEFAULT_OPTIONS,\r\n        this.graphics.cropSelectionStyle\r\n      )\r\n    );\r\n\r\n    canvas.discardActiveObject();\r\n    canvas.add(this._cropzone);\r\n    canvas.on('mouse:down', this._listeners.mousedown);\r\n    canvas.selection = false;\r\n    canvas.defaultCursor = 'crosshair';\r\n\r\n    fabric.util.addListener(document, 'keydown', this._listeners.keydown);\r\n    fabric.util.addListener(document, 'keyup', this._listeners.keyup);\r\n  }\r\n\r\n  /**\r\n   * End cropping\r\n   */\r\n  end() {\r\n    const canvas = this.getCanvas();\r\n    const cropzone = this._cropzone;\r\n\r\n    if (!cropzone) {\r\n      return;\r\n    }\r\n    canvas.remove(cropzone);\r\n    canvas.selection = true;\r\n    canvas.defaultCursor = 'default';\r\n    canvas.off('mouse:down', this._listeners.mousedown);\r\n    canvas.forEachObject((obj) => {\r\n      obj.evented = true;\r\n    });\r\n\r\n    this._cropzone = null;\r\n\r\n    fabric.util.removeListener(document, 'keydown', this._listeners.keydown);\r\n    fabric.util.removeListener(document, 'keyup', this._listeners.keyup);\r\n  }\r\n\r\n  /**\r\n   * Change cropzone visible\r\n   * @param {boolean} visible - cropzone visible state\r\n   */\r\n  changeVisibility(visible) {\r\n    if (this._cropzone) {\r\n      this._cropzone.set({ visible });\r\n    }\r\n  }\r\n\r\n  /**\r\n   * onMousedown handler in fabric canvas\r\n   * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event\r\n   * @private\r\n   */\r\n  _onFabricMouseDown(fEvent) {\r\n    const canvas = this.getCanvas();\r\n\r\n    if (fEvent.target) {\r\n      return;\r\n    }\r\n\r\n    canvas.selection = false;\r\n    const coord = canvas.getPointer(fEvent.e);\r\n\r\n    this._startX = coord.x;\r\n    this._startY = coord.y;\r\n\r\n    canvas.on({\r\n      'mouse:move': this._listeners.mousemove,\r\n      'mouse:up': this._listeners.mouseup,\r\n    });\r\n  }\r\n\r\n  /**\r\n   * onMousemove handler in fabric canvas\r\n   * @param {{target: fabric.Object, e: MouseEvent}} fEvent - Fabric event\r\n   * @private\r\n   */\r\n  _onFabricMouseMove(fEvent) {\r\n    const canvas = this.getCanvas();\r\n    const pointer = canvas.getPointer(fEvent.e);\r\n    const { x, y } = pointer;\r\n    const cropzone = this._cropzone;\r\n\r\n    if (Math.abs(x - this._startX) + Math.abs(y - this._startY) > MOUSE_MOVE_THRESHOLD) {\r\n      canvas.remove(cropzone);\r\n      cropzone.set(this._calcRectDimensionFromPoint(x, y));\r\n\r\n      canvas.add(cropzone);\r\n      canvas.setActiveObject(cropzone);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Get rect dimension setting from Canvas-Mouse-Position(x, y)\r\n   * @param {number} x - Canvas-Mouse-Position x\r\n   * @param {number} y - Canvas-Mouse-Position Y\r\n   * @returns {{left: number, top: number, width: number, height: number}}\r\n   * @private\r\n   */\r\n  _calcRectDimensionFromPoint(x, y) {\r\n    const canvas = this.getCanvas();\r\n    const canvasWidth = canvas.getWidth();\r\n    const canvasHeight = canvas.getHeight();\r\n    const startX = this._startX;\r\n    const startY = this._startY;\r\n    let left = clamp(x, 0, startX);\r\n    let top = clamp(y, 0, startY);\r\n    let width = clamp(x, startX, canvasWidth) - left; // (startX <= x(mouse) <= canvasWidth) - left\r\n    let height = clamp(y, startY, canvasHeight) - top; // (startY <= y(mouse) <= canvasHeight) - top\r\n\r\n    if (this._withShiftKey) {\r\n      // make fixed ratio cropzone\r\n      if (width > height) {\r\n        height = width;\r\n      } else if (height > width) {\r\n        width = height;\r\n      }\r\n\r\n      if (startX >= x) {\r\n        left = startX - width;\r\n      }\r\n\r\n      if (startY >= y) {\r\n        top = startY - height;\r\n      }\r\n    }\r\n\r\n    return {\r\n      left,\r\n      top,\r\n      width,\r\n      height,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * onMouseup handler in fabric canvas\r\n   * @private\r\n   */\r\n  _onFabricMouseUp() {\r\n    const cropzone = this._cropzone;\r\n    const listeners = this._listeners;\r\n    const canvas = this.getCanvas();\r\n\r\n    canvas.setActiveObject(cropzone);\r\n    canvas.off({\r\n      'mouse:move': listeners.mousemove,\r\n      'mouse:up': listeners.mouseup,\r\n    });\r\n  }\r\n\r\n  /**\r\n   * Get cropped image data\r\n   * @param {Object} cropRect cropzone rect\r\n   *  @param {Number} cropRect.left left position\r\n   *  @param {Number} cropRect.top top position\r\n   *  @param {Number} cropRect.width width\r\n   *  @param {Number} cropRect.height height\r\n   * @returns {?{imageName: string, url: string}} cropped Image data\r\n   */\r\n  getCroppedImageData(cropRect) {\r\n    const canvas = this.getCanvas();\r\n    const containsCropzone = canvas.contains(this._cropzone);\r\n    if (!cropRect) {\r\n      return null;\r\n    }\r\n\r\n    if (containsCropzone) {\r\n      canvas.remove(this._cropzone);\r\n    }\r\n\r\n    const imageData = {\r\n      imageName: this.getImageName(),\r\n      url: canvas.toDataURL(cropRect),\r\n    };\r\n\r\n    if (containsCropzone) {\r\n      canvas.add(this._cropzone);\r\n    }\r\n\r\n    return imageData;\r\n  }\r\n\r\n  /**\r\n   * Get cropped rect\r\n   * @returns {Object} rect\r\n   */\r\n  getCropzoneRect() {\r\n    const cropzone = this._cropzone;\r\n\r\n    if (!cropzone.isValid()) {\r\n      return null;\r\n    }\r\n\r\n    return {\r\n      left: cropzone.left,\r\n      top: cropzone.top,\r\n      width: cropzone.width,\r\n      height: cropzone.height,\r\n    };\r\n  }\r\n\r\n  /**\r\n   * Set a cropzone square\r\n   * @param {number} [presetRatio] - preset ratio\r\n   */\r\n  setCropzoneRect(presetRatio) {\r\n    const canvas = this.getCanvas();\r\n    const cropzone = this._cropzone;\r\n\r\n    canvas.discardActiveObject();\r\n    canvas.selection = false;\r\n    canvas.remove(cropzone);\r\n\r\n    cropzone.set(presetRatio ? this._getPresetPropertiesForCropSize(presetRatio) : DEFAULT_OPTION);\r\n\r\n    canvas.add(cropzone);\r\n    canvas.selection = true;\r\n\r\n    if (presetRatio) {\r\n      canvas.setActiveObject(cropzone);\r\n    }\r\n  }\r\n\r\n  /**\r\n   * get a cropzone square info\r\n   * @param {number} presetRatio - preset ratio\r\n   * @returns {{presetRatio: number, left: number, top: number, width: number, height: number}}\r\n   * @private\r\n   */\r\n  _getPresetPropertiesForCropSize(presetRatio) {\r\n    const canvas = this.getCanvas();\r\n    const originalWidth = canvas.getWidth();\r\n    const originalHeight = canvas.getHeight();\r\n\r\n    const standardSize = originalWidth >= originalHeight ? originalWidth : originalHeight;\r\n    const getScale = (value, orignalValue) => (value > orignalValue ? orignalValue / value : 1);\r\n\r\n    let width = standardSize * presetRatio;\r\n    let height = standardSize;\r\n\r\n    const scaleWidth = getScale(width, originalWidth);\r\n    [width, height] = snippet.map([width, height], (sizeValue) => sizeValue * scaleWidth);\r\n\r\n    const scaleHeight = getScale(height, originalHeight);\r\n    [width, height] = snippet.map([width, height], (sizeValue) =>\r\n      fixFloatingPoint(sizeValue * scaleHeight)\r\n    );\r\n\r\n    return {\r\n      presetRatio,\r\n      top: (originalHeight - height) / 2,\r\n      left: (originalWidth - width) / 2,\r\n      width,\r\n      height,\r\n    };\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  _onKeyDown(e) {\r\n    if (e.keyCode === keyCodes.SHIFT) {\r\n      this._withShiftKey = true;\r\n    }\r\n  }\r\n\r\n  /**\r\n   * Keyup event handler\r\n   * @param {KeyboardEvent} e - Event object\r\n   * @private\r\n   */\r\n  _onKeyUp(e) {\r\n    if (e.keyCode === keyCodes.SHIFT) {\r\n      this._withShiftKey = false;\r\n    }\r\n  }\r\n}\r\n\r\nexport default Cropper;\r\n"]},"metadata":{},"sourceType":"module"}