{"version":3,"file":"X_RectNotes.min.mjs","sources":["../../../../src/shapes/canvasx/X_RectNotes.ts"],"sourcesContent":["import { classRegistry } from '../../ClassRegistry';\nimport { X_Textbox as Textbox } from './X_Textbox';\nimport { createRectNotesDefaultControls } from '../../controls/X_commonControls';\nimport type {\n  TBBox,\n  TClassProperties,\n  TOriginX,\n  TOriginY,\n} from '../../typedefs';\nimport { Point } from '../../Point';\nimport { X_Connector } from './X_Connector';\n\n// this will be a separated effort\nexport const rectNotesDefaultValues: Partial<TClassProperties<RectNotes>> = {\n  minWidth: 20,\n  dynamicMinWidth: 2,\n\n  splitByGrapheme: true,\n  height: 138,\n  maxHeight: 138,\n\n  width: 230,\n  cornerStrokeColor: 'gray',\n  cornerStyle: 'circle',\n  cornerColor: 'white',\n  transparentCorners: false,\n};\n\n/**\n * Textbox class, based on IText, allows the user to resize the text rectangle\n * and wraps lines automatically. Textboxes have their Y scaling locked, the\n * user can only change width. Height is adjusted automatically based on the\n * wrapping of lines.\n */\n///@ts-ignore\nexport class RectNotes extends Textbox {\n  /**selectable\n   * Minimum width of textbox, in pixels.\n   * @type Number\n   * @default\n   */\n  declare minWidth: number;\n\n  declare locked: boolean;\n\n  declare verticalAlign: string;\n  declare originX: TOriginX;\n  declare originY: TOriginY;\n  declare width: number;\n  declare cornerStrokeColor: string;\n\n  declare cornerColor: string;\n  declare transparentCorners: boolean;\n  declare zIndex: number;\n  declare height: number;\n  declare maxHeight: number;\n  declare connectors: object[];\n  declare id: string;\n\n  public extendPropeties = [\n    'objType',\n    'whiteboardId',\n    'userId',\n    'timestamp',\n    'zIndex',\n    'locked',\n    'verticalAlign',\n    'lines',\n    'id',\n    'zIndex',\n    'relationship',\n    'emoj',\n    'userEmoji',\n  ];\n  /**\n   * Minimum calculated width of a textbox, in pixels.\n   * fixed to 2 so that an empty textbox cannot go to 0\n   * and is still selectable without text.\n   * @type Number\n   * @default\n   */\n  declare dynamicMinWidth: number;\n\n  /**\n   * Use this boolean property in order to split strings that have no white space concept.\n   * this is a cheap way to help with chinese/japanese\n   * @type Boolean\n   * @since 2.6.0\n   */\n  declare splitByGrapheme: boolean;\n\n  static textLayoutProperties = [...Textbox.textLayoutProperties, 'width'];\n\n  static ownDefaults: Record<string, any> = rectNotesDefaultValues;\n\n  static getDefaults() {\n    return {\n      ...super.getDefaults(),\n      controls: {\n        ...createRectNotesDefaultControls(),\n        // mr: { /* add your desired value here */ },\n      },\n      ...RectNotes.ownDefaults,\n    };\n  }\n  constructor(\n    text: string,\n    options: Partial<TClassProperties<RectNotes>> = {}\n  ) {\n    super(text, options);\n    this.initializeEvent();\n  }\n\n  findById(id: string) {\n    const canvas = this.canvas;\n    const obj: any = canvas\n      ?.getObjects()\n      .filter((widget: any) => widget.id === id);\n    if (obj.length === 0) return null;\n    return obj[0];\n  }\n\n  calculateControlPoint(boundingBox: TBBox, connectingPoint: Point): Point {\n    const left = boundingBox.left;\n    const top = boundingBox.top;\n    const width = boundingBox.width;\n    const height = boundingBox.height;\n\n    const right = left + width;\n    const bottom = top + height;\n\n    const connectingX = connectingPoint.x;\n    const connectingY = connectingPoint.y;\n\n    let controlX: number = 0;\n    let controlY: number = 0;\n\n    // Find the nearest border and calculate the control point outside the bounding box\n    const distances = [\n      { side: 'left', distance: Math.abs(connectingX - left) },\n      { side: 'right', distance: Math.abs(connectingX - right) },\n      { side: 'top', distance: Math.abs(connectingY - top) },\n      { side: 'bottom', distance: Math.abs(connectingY - bottom) },\n    ];\n\n    const nearestBorder = distances.reduce((min, current) =>\n      current.distance < min.distance ? current : min\n    );\n\n    switch (nearestBorder.side) {\n      case 'left':\n        controlX = left - 220;\n        controlY = connectingY;\n        break;\n      case 'right':\n        controlX = right + 220;\n        controlY = connectingY;\n        break;\n      case 'top':\n        controlX = connectingX;\n        controlY = top - 220;\n        break;\n      case 'bottom':\n        controlX = connectingX;\n        controlY = bottom + 220;\n        break;\n    }\n\n    return new Point(controlX, controlY);\n  }\n\n  updateConnector(point: any, connector: X_Connector, type: string) {\n    const controlPoint = this.calculateControlPoint(\n      this.getBoundingRect(),\n      new Point(point.x, point.y)\n    );\n\n    console.log(\n      'updateConnector: point:',\n      point,\n      'control point:',\n      controlPoint,\n      connector,\n      type\n    );\n    //if the connector is from the object, then the startpoint should be updated\n    //if the connector is to the object, then the endpoint should be updated\n\n    //recalculate the startpoint or endpoint of the connector, and also the ControlPoint\n    if (type === 'from') {\n      connector.update({\n        fromPoint: point,\n        control1: controlPoint,\n      });\n    }\n    if (type === 'to') {\n      connector.update({\n        toPoint: point,\n        control2: controlPoint,\n      });\n    }\n  }\n\n  moveOrScaleHandler(e: any) {\n    //if there is a connector, move the connector\n    if (this.connectors?.length === 0) return;\n    this.connectors?.forEach((connector: any) => {\n      const pointConnector = connector.point;\n\n      //get canvas point of the connector point\n      const point = new Point(pointConnector.x, pointConnector.y);\n      //@ts-ignore\n      const transformedPoint = this.transformPointToCanvas(point);\n\n      //use the connectorId to find the connector and then update the connector\n      //ts-ignore\n      const connectorObj = this.findById(connector.connectorId);\n\n      if (!connectorObj) return;\n      console.log('connectorObj', connectorObj);\n\n      if (this.id === connectorObj.fromId) {\n        this.updateConnector(transformedPoint, connectorObj, 'from');\n      }\n\n      if (this.id === connectorObj.toId) {\n        this.updateConnector(transformedPoint, connectorObj, 'to');\n      }\n    });\n  }\n\n  initializeEvent() {\n    this.on('moving', (e) => {\n      this.moveOrScaleHandler(e);\n    });\n\n    this.on('scaling', (e) => {\n      this.moveOrScaleHandler(e);\n    });\n  }\n\n  /**\n   * Unlike superclass's version of this function, Textbox does not update\n   * its width.\n   * @private\n   * @override\n   */\n  initDimensions() {\n    if (!this.initialized) {\n      return;\n    }\n    this.isEditing && this.initDelayedCursor();\n    this._clearCache();\n    // clear dynamicMinWidth as it will be different after we re-wrap line\n    this.dynamicMinWidth = 0;\n    // wrap lines\n    this._styleMap = this._generateStyleMap(this._splitText());\n    // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap\n    if (this.dynamicMinWidth > this.width) {\n      this.set('fontSize', this.fontSize - 2);\n      this._splitTextIntoLines(this.text);\n      return;\n    }\n    if (this.textAlign.indexOf('justify') !== -1) {\n      // once text is measured we need to make space fatter to make justified text.\n      this.enlargeSpaces();\n    }\n    // clear cache and re-calculate height\n    const height = this.calcTextHeight();\n    if (height > this.maxHeight && this.fontSize > 6) {\n      this.set('fontSize', this.fontSize - 2);\n      this._splitTextIntoLines(this.text);\n      return;\n    }\n    if (height > 130 && this.fontSize === 6) {\n      const prenum = 125 / height;\n      const newText = this.text.substring(0, this.text.length * prenum - 5);\n      this.set('text', newText + '...');\n    }\n    this.height = this.maxHeight;\n    return this.height;\n  }\n\n  /**\n   * Generate an object that translates the style object so that it is\n   * broken up by visual lines (new lines and automatic wrapping).\n   * The original text styles object is broken up by actual lines (new lines only),\n   * which is only sufficient for Text / IText\n   * @private\n   */\n  _generateStyleMap(textInfo: any) {\n    let realLineCount = 0;\n    let realLineCharCount = 0;\n    let charCount = 0;\n    const map: any = {};\n\n    for (let i = 0; i < textInfo.graphemeLines.length; i++) {\n      if (textInfo.graphemeText[charCount] === '\\n' && i > 0) {\n        realLineCharCount = 0;\n        charCount++;\n        realLineCount++;\n      } else if (\n        !this.splitByGrapheme &&\n        this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) &&\n        i > 0\n      ) {\n        // this case deals with space's that are removed from end of lines when wrapping\n        realLineCharCount++;\n        charCount++;\n      }\n\n      map[i] = {\n        line: realLineCount,\n        offset: realLineCharCount,\n      };\n\n      charCount += textInfo.graphemeLines[i].length;\n      realLineCharCount += textInfo.graphemeLines[i].length;\n    }\n\n    return map;\n  }\n\n  /**\n   * Returns true if object has a style property or has it on a specified line\n   * @param {Number} lineIndex\n   * @return {Boolean}\n   */\n  styleHas(property: any, lineIndex: number): boolean {\n    if (this._styleMap && !this.isWrapping) {\n      const map = this._styleMap[lineIndex];\n      if (map) {\n        lineIndex = map.line;\n      }\n    }\n    return super.styleHas(property, lineIndex);\n  }\n\n  // /**\n  //  * Returns true if object has no styling or no styling in a line\n  //  * @param {Number} lineIndex , lineIndex is on wrapped lines.\n  //  * @return {Boolean}\n  //  */\n  // isEmptyStyles(lineIndex: number): boolean {\n  //   if (!this.styles) {\n  //     return true;\n  //   }\n  //   let offset = 0,\n  //     nextLineIndex = lineIndex + 1,\n  //     nextOffset,\n  //     shouldLimit = false;\n  //   const map = this._styleMap[lineIndex],\n  //     mapNextLine = this._styleMap[lineIndex + 1];\n  //   if (map) {\n  //     lineIndex = map.line;\n  //     offset = map.offset;\n  //   }\n  //   if (mapNextLine) {\n  //     nextLineIndex = mapNextLine.line;\n  //     shouldLimit = nextLineIndex === lineIndex;\n  //     nextOffset = mapNextLine.offset;\n  //   }\n  //   const obj =\n  //     typeof lineIndex === 'undefined'\n  //       ? this.styles\n  //       : { line: this.styles[lineIndex] };\n  //   for (const p1 in obj) {\n  //     for (const p2 in obj[p1]) {\n  //       if (p2 >= offset && (!shouldLimit || p2 < nextOffset)) {\n  //         // eslint-disable-next-line no-unused-vars\n  //         for (const p3 in obj[p1][p2]) {\n  //           return false;\n  //         }\n  //       }\n  //     }\n  //   }\n  //   return true;\n  // }\n\n  // /**\n  //  * @param {Number} lineIndex\n  //  * @param {Number} charIndex\n  //  * @private\n  //  */\n  // _getStyleDeclaration(lineIndex: number, charIndex: number) {\n  //   if (this._styleMap && !this.isWrapping) {\n  //     const map = this._styleMap[lineIndex];\n  //     if (!map) {\n  //       return null;\n  //     }\n  //     lineIndex = map.line;\n  //     charIndex = map.offset + charIndex;\n  //   }\n  //   return super._getStyleDeclaration(lineIndex, charIndex);\n  // }\n\n  // /**\n  //  * @param {Number} lineIndex\n  //  * @param {Number} charIndex\n  //  * @param {Object} style\n  //  * @private\n  //  */\n  // _setStyleDeclaration(lineIndex: number, charIndex: number, style: object) {\n  //   const map = this._styleMap[lineIndex];\n  //   lineIndex = map.line;\n  //   charIndex = map.offset + charIndex;\n\n  //   this.styles[lineIndex][charIndex] = style;\n  // }\n\n  // /**\n  //  * @param {Number} lineIndex\n  //  * @param {Number} charIndex\n  //  * @private\n  //  */\n  // _deleteStyleDeclaration(lineIndex: number, charIndex: number) {\n  //   const map = this._styleMap[lineIndex];\n  //   lineIndex = map.line;\n  //   charIndex = map.offset + charIndex;\n  //   delete this.styles[lineIndex][charIndex];\n  // }\n\n  /**\n   * probably broken need a fix\n   * Returns the real style line that correspond to the wrapped lineIndex line\n   * Used just to verify if the line does exist or not.\n   * @param {Number} lineIndex\n   * @returns {Boolean} if the line exists or not\n   * @private\n   */\n  _getLineStyle(lineIndex: number): boolean {\n    const map = this._styleMap[lineIndex];\n    return !!this.styles[map.line];\n  }\n\n  /**\n   * Set the line style to an empty object so that is initialized\n   * @param {Number} lineIndex\n   * @param {Object} style\n   * @private\n   */\n  _setLineStyle(lineIndex: number) {\n    const map = this._styleMap[lineIndex];\n    this.styles[map.line] = {};\n  }\n\n  // /**\n  //  * Wraps text using the 'width' property of Textbox. First this function\n  //  * splits text on newlines, so we preserve newlines entered by the user.\n  //  * Then it wraps each line using the width of the Textbox by calling\n  //  * _wrapLine().\n  //  * @param {Array} lines The string array of text that is split into lines\n  //  * @param {Number} desiredWidth width you want to wrap to\n  //  * @returns {Array} Array of lines\n  //  */\n  // _wrapText(lines: Array<any>, desiredWidth: number): Array<any> {\n  //   const wrapped = [];\n  //   this.isWrapping = true;\n  //   for (let i = 0; i < lines.length; i++) {\n  //     wrapped.push(...this._wrapLine(lines[i], i, desiredWidth));\n  //   }\n  //   this.isWrapping = false;\n  //   return wrapped;\n  // }\n\n  // /**\n  //  * Helper function to measure a string of text, given its lineIndex and charIndex offset\n  //  * It gets called when charBounds are not available yet.\n  //  * Override if necessary\n  //  * Use with {@link Textbox#wordSplit}\n  //  *\n  //  * @param {CanvasRenderingContext2D} ctx\n  //  * @param {String} text\n  //  * @param {number} lineIndex\n  //  * @param {number} charOffset\n  //  * @returns {number}\n  //  */\n  // _measureWord(word, lineIndex: number, charOffset = 0): number {\n  //   let width = 0,\n  //     prevGrapheme;\n  //   const skipLeft = true;\n  //   for (let i = 0, len = word.length; i < len; i++) {\n  //     const box = this._getGraphemeBox(\n  //       word[i],\n  //       lineIndex,\n  //       i + charOffset,\n  //       prevGrapheme,\n  //       skipLeft\n  //     );\n  //     width += box.kernedWidth;\n  //     prevGrapheme = word[i];\n  //   }\n  //   return width;\n  // }\n\n  /**\n   * Override this method to customize word splitting\n   * Use with {@link Textbox#_measureWord}\n   * @param {string} value\n   * @returns {string[]} array of words\n   */\n  wordSplit(value: string): string[] {\n    return value.split(this._wordJoiners);\n  }\n\n  /**\n   * Wraps a line of text using the width of the Textbox and a context.\n   * @param {Array} line The grapheme array that represent the line\n   * @param {Number} lineIndex\n   * @param {Number} desiredWidth width you want to wrap the line to\n   * @param {Number} reservedSpace space to remove from wrapping for custom functionalities\n   * @returns {Array} Array of line(s) into which the given text is wrapped\n   * to.\n   */\n\n  graphemeSplitForRectNotes(textstring: string): string[] {\n    const graphemes = [];\n    const words = textstring.split(/\\b/);\n    for (let i = 0; i < words.length; i++) {\n      // 检查单词是否全为拉丁字母，长度不大于16\n      if (/^[a-zA-Z]{1,16}$/.test(words[i])) {\n        graphemes.push(words[i]);\n      } else {\n        for (let j = 0; j < words[i].length; j++) {\n          graphemes.push(words[i][j]);\n        }\n      }\n    }\n    return graphemes;\n  }\n\n  // _wrapLine(\n  //   _line: any,\n  //   lineIndex: number,\n  //   desiredWidth: number,\n  //   reservedSpace = 0\n  // ): Array<any> {\n  //   const additionalSpace = this._getWidthOfCharSpacing();\n  //   const splitByGrapheme = this.splitByGrapheme;\n  //   const graphemeLines = [];\n  //   const words = splitByGrapheme\n  //     ? this.graphemeSplitForRectNotes(_line)\n  //     : this.wordSplit(_line);\n  //   const infix = splitByGrapheme ? '' : ' ';\n\n  //   let lineWidth = 0,\n  //     line: any[] = [],\n  //     // spaces in different languages?\n  //     offset = 0,\n  //     infixWidth = 0,\n  //     largestWordWidth = 0,\n  //     lineJustStarted = true;\n  //   // fix a difference between split and graphemeSplit\n  //   if (words.length === 0) {\n  //     words.push([]);\n  //   }\n  //   desiredWidth -= reservedSpace;\n  //   // measure words\n  //   const data = words.map((word) => {\n  //     // if using splitByGrapheme words are already in graphemes.\n  //     word = splitByGrapheme ? word : this.graphemeSplitForRectNotes(word);\n  //     const width = this._measureWord(word, lineIndex, offset);\n  //     largestWordWidth = Math.max(width, largestWordWidth);\n  //     offset += word.length + 1;\n  //     return { word: word, width: width };\n  //   });\n  //   const maxWidth = Math.max(\n  //     desiredWidth,\n  //     largestWordWidth,\n  //     this.dynamicMinWidth\n  //   );\n  //   // layout words\n  //   offset = 0;\n  //   let i;\n  //   for (i = 0; i < words.length; i++) {\n  //     const word = data[i].word;\n  //     const wordWidth = data[i].width;\n  //     offset += word.length;\n\n  //     lineWidth += infixWidth + wordWidth - additionalSpace;\n  //     if (lineWidth > maxWidth && !lineJustStarted) {\n  //       graphemeLines.push(line);\n  //       line = [];\n  //       lineWidth = wordWidth;\n  //       lineJustStarted = true;\n  //     } else {\n  //       lineWidth += additionalSpace;\n  //     }\n\n  //     if (!lineJustStarted && !splitByGrapheme) {\n  //       line.push(infix);\n  //     }\n  //     if (word.length > 1) {\n  //       line = line.concat(word.split(''));\n  //     } else {\n  //       line = line.concat(word);\n  //     }\n\n  //     infixWidth = splitByGrapheme\n  //       ? 0\n  //       : this._measureWord([infix], lineIndex, offset);\n  //     offset++;\n  //     lineJustStarted = false;\n  //   }\n\n  //   i && graphemeLines.push(line);\n\n  //   if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {\n  //     this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;\n  //   }\n  //   return graphemeLines;\n  // }\n\n  /**\n   * Detect if the text line is ended with an hard break\n   * text and itext do not have wrapping, return false\n   * @param {Number} lineIndex text to split\n   * @return {Boolean}\n   */\n  isEndOfWrapping(lineIndex: number): boolean {\n    if (!this._styleMap[lineIndex + 1]) {\n      // is last line, return true;\n      return true;\n    }\n    if (this._styleMap[lineIndex + 1].line !== this._styleMap[lineIndex].line) {\n      // this is last line before a line break, return true;\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Detect if a line has a linebreak and so we need to account for it when moving\n   * and counting style.\n   * @return Number\n   */\n  missingNewlineOffset(lineIndex: number) {\n    if (this.splitByGrapheme) {\n      return this.isEndOfWrapping(lineIndex) ? 1 : 0;\n    }\n    return 1;\n  }\n\n  /**\n   * Gets lines of text to render in the Textbox. This function calculates\n   * text wrapping on the fly every time it is called.\n   * @param {String} text text to split\n   * @returns {Array} Array of lines in the Textbox.\n   * @override\n   */\n  _splitTextIntoLines(text: string) {\n    const newText = super._splitTextIntoLines(text),\n      graphemeLines = this._wrapText(newText.lines, this.width),\n      lines = new Array(graphemeLines.length);\n    for (let i = 0; i < graphemeLines.length; i++) {\n      lines[i] = graphemeLines[i].join('');\n    }\n    newText.lines = lines;\n    newText.graphemeLines = graphemeLines;\n    return newText;\n  }\n\n  getMinWidth() {\n    return Math.max(this.minWidth, this.dynamicMinWidth);\n  }\n\n  // _removeExtraneousStyles() {\n  //   const linesToKeep = {};\n  //   for (const prop in this._styleMap) {\n  //     if (this._textLines[prop]) {\n  //       linesToKeep[this._styleMap[prop].line] = 1;\n  //     }\n  //   }\n  //   for (const prop in this.styles) {\n  //     if (!linesToKeep[prop]) {\n  //       delete this.styles[prop];\n  //     }\n  //   }\n  // }\n\n  // /**\n  //  * Returns object representation of an instance\n  //  * @method toObject\n  //  * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n  //  * @return {Object} object representation of an instance\n  //  */\n  // toObject(propertiesToInclude: Array<any>): object {\n  //   return super.toObject(\n  //     [...this.extendPropeties, 'minWidth', 'splitByGrapheme'].concat(\n  //       propertiesToInclude\n  //     )\n  //   );\n  // }\n  /**boardx custom function */\n\n  /* caculate cusor positon in the middle of the textbox */\n  getCenteredTop(rectHeight: number) {\n    const textHeight = this.height;\n    return (rectHeight - textHeight) / 2;\n  }\n\n  _render(ctx: CanvasRenderingContext2D) {\n    const path: any = this.path;\n\n    path && !path.isNotVisible() && path._render(ctx);\n    this._setTextStyles(ctx);\n    this._renderTextLinesBackground(ctx);\n    this._renderTextDecoration(ctx, 'underline');\n    this._renderText(ctx);\n    this._renderTextDecoration(ctx, 'overline');\n    this._renderTextDecoration(ctx, 'linethrough');\n  }\n\n  _renderBackground(ctx: CanvasRenderingContext2D) {\n    if (!this.backgroundColor) {\n      return;\n    }\n    const dim = this._getNonTransformedDimensions();\n    ctx.fillStyle = this.backgroundColor;\n\n    // ctx.shadowBlur = 20;\n    // ctx.shadowOffsetX = 2 * this.scaleX * canvas.getZoom();\n    // ctx.shadowOffsetY = 6 * this.scaleY * canvas.getZoom();\n    // ctx.shadowColor = 'rgba(0,0,0,0.1)';\n    // ctx.shadowColor = 'rgba(0,0,0,1)';\n\n    ctx.fillRect(-dim.x / 2, -dim.y / 2, dim.x, dim.y);\n\n    // if there is background color no other shadows\n    // should be casted\n    // this._removeShadow(ctx);\n  }\n  _getTopOffset() {\n    return -this._getTotalLineHeights() / 2;\n  }\n  _getTotalLineHeights() {\n    return this._textLines.reduce(\n      (total, line, index) => total + this.getHeightOfLine(index),\n      0\n    );\n  }\n\n  _getTotalLineHeight() {\n    return this._textLines.reduce(\n      (total, _line, index) => total + this.getHeightOfLine(index),\n      0\n    );\n  }\n\n  _renderText(ctx: CanvasRenderingContext2D) {\n    ctx.shadowOffsetX = ctx.shadowOffsetY = ctx.shadowBlur = 0;\n    ctx.shadowColor = '';\n\n    if (this.paintFirst === 'stroke') {\n      this._renderTextStroke(ctx);\n      this._renderTextFill(ctx);\n    } else {\n      this._renderTextFill(ctx);\n      this._renderTextStroke(ctx);\n    }\n  }\n  drawRoundRectPath(\n    cxt: CanvasRenderingContext2D,\n    width: number,\n    height: number,\n    radius: number\n  ) {\n    cxt.beginPath();\n    //从右下角顺时针绘制，弧度从0到1/2PI\n    cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);\n\n    //矩形下边线\n    cxt.lineTo(radius, height);\n\n    //左下角圆弧，弧度从1/2PI到PI\n    cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);\n\n    //矩形左边线\n    cxt.lineTo(0, radius);\n\n    //左上角圆弧，弧度从PI到3/2PI\n    cxt.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);\n\n    //上边线\n    cxt.lineTo(width - radius, 0);\n\n    //右上角圆弧\n    cxt.arc(width - radius, radius, radius, (Math.PI * 3) / 2, Math.PI * 2);\n\n    //右边线\n    cxt.lineTo(width, height - radius);\n    cxt.closePath();\n  }\n}\n\nclassRegistry.setClass(RectNotes);\nclassRegistry.setSVGClass(RectNotes, 'RectNotes');\n"],"names":["rectNotesDefaultValues","minWidth","dynamicMinWidth","splitByGrapheme","height","maxHeight","width","cornerStrokeColor","cornerStyle","cornerColor","transparentCorners","RectNotes","Textbox","getDefaults","_objectSpread","super","controls","createRectNotesDefaultControls","ownDefaults","constructor","text","arguments","length","undefined","_defineProperty","this","initializeEvent","findById","id","canvas","obj","getObjects","filter","widget","calculateControlPoint","boundingBox","connectingPoint","left","top","right","bottom","connectingX","x","connectingY","y","controlX","controlY","side","distance","Math","abs","reduce","min","current","Point","updateConnector","point","connector","type","controlPoint","getBoundingRect","console","log","update","fromPoint","control1","toPoint","control2","moveOrScaleHandler","e","_this$connectors","_this$connectors2","connectors","forEach","pointConnector","transformedPoint","transformPointToCanvas","connectorObj","connectorId","fromId","toId","on","initDimensions","initialized","isEditing","initDelayedCursor","_clearCache","_styleMap","_generateStyleMap","_splitText","set","fontSize","_splitTextIntoLines","textAlign","indexOf","enlargeSpaces","calcTextHeight","prenum","newText","substring","textInfo","realLineCount","realLineCharCount","charCount","map","i","graphemeLines","graphemeText","_reSpaceAndTab","test","line","offset","styleHas","property","lineIndex","isWrapping","_getLineStyle","styles","_setLineStyle","wordSplit","value","split","_wordJoiners","graphemeSplitForRectNotes","textstring","graphemes","words","push","j","isEndOfWrapping","missingNewlineOffset","_wrapText","lines","Array","join","getMinWidth","max","getCenteredTop","rectHeight","_render","ctx","path","isNotVisible","_setTextStyles","_renderTextLinesBackground","_renderTextDecoration","_renderText","_renderBackground","backgroundColor","dim","_getNonTransformedDimensions","fillStyle","fillRect","_getTopOffset","_getTotalLineHeights","_textLines","total","index","getHeightOfLine","_getTotalLineHeight","_line","shadowOffsetX","shadowOffsetY","shadowBlur","shadowColor","paintFirst","_renderTextStroke","_renderTextFill","drawRoundRectPath","cxt","radius","beginPath","arc","PI","lineTo","closePath","textLayoutProperties","classRegistry","setClass","setSVGClass"],"mappings":"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"}