UNPKG

fabric

Version:

Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.

1 lines 31.3 kB
{"version":3,"file":"IText.min.mjs","sources":["../../../../src/shapes/IText/IText.ts"],"sourcesContent":["import { Canvas } from '../../canvas/Canvas';\nimport type { ITextEvents } from './ITextBehavior';\nimport { ITextClickBehavior } from './ITextClickBehavior';\nimport {\n ctrlKeysMapDown,\n ctrlKeysMapUp,\n keysMap,\n keysMapRtl,\n} from './constants';\nimport type { TClassProperties, TFiller, TOptions } from '../../typedefs';\nimport { classRegistry } from '../../ClassRegistry';\nimport type { SerializedTextProps, TextProps } from '../Text/Text';\nimport {\n JUSTIFY,\n JUSTIFY_CENTER,\n JUSTIFY_LEFT,\n JUSTIFY_RIGHT,\n} from '../Text/constants';\nimport { CENTER, FILL, LEFT, RIGHT } from '../../constants';\nimport type { ObjectToCanvasElementOptions } from '../Object/Object';\n\ntype CursorBoundaries = {\n left: number;\n top: number;\n leftOffset: number;\n topOffset: number;\n};\n\n// Declare IText protected properties to workaround TS\nconst protectedDefaultValues = {\n _selectionDirection: null,\n _reSpace: /\\s|\\r?\\n/,\n inCompositionMode: false,\n};\n\nexport const iTextDefaultValues: Partial<TClassProperties<IText>> = {\n selectionStart: 0,\n selectionEnd: 0,\n selectionColor: 'rgba(17,119,255,0.3)',\n isEditing: false,\n editable: true,\n editingBorderColor: 'rgba(102,153,255,0.25)',\n cursorWidth: 2,\n cursorColor: '',\n cursorDelay: 1000,\n cursorDuration: 600,\n caching: true,\n hiddenTextareaContainer: null,\n keysMap,\n keysMapRtl,\n ctrlKeysMapDown,\n ctrlKeysMapUp,\n ...protectedDefaultValues,\n};\n\n// @TODO this is not complete\ninterface UniqueITextProps {\n selectionStart: number;\n selectionEnd: number;\n}\n\nexport interface SerializedITextProps\n extends SerializedTextProps,\n UniqueITextProps {}\n\nexport interface ITextProps extends TextProps, UniqueITextProps {}\n\n/**\n * @fires changed\n * @fires selection:changed\n * @fires editing:entered\n * @fires editing:exited\n * @fires dragstart\n * @fires drag drag event firing on the drag source\n * @fires dragend\n * @fires copy\n * @fires cut\n * @fires paste\n *\n * #### Supported key combinations\n * ```\n * Move cursor: left, right, up, down\n * Select character: shift + left, shift + right\n * Select text vertically: shift + up, shift + down\n * Move cursor by word: alt + left, alt + right\n * Select words: shift + alt + left, shift + alt + right\n * Move cursor to line start/end: cmd + left, cmd + right or home, end\n * Select till start/end of line: cmd + shift + left, cmd + shift + right or shift + home, shift + end\n * Jump to start/end of text: cmd + up, cmd + down\n * Select till start/end of text: cmd + shift + up, cmd + shift + down or shift + pgUp, shift + pgDown\n * Delete character: backspace\n * Delete word: alt + backspace\n * Delete line: cmd + backspace\n * Forward delete: delete\n * Copy text: ctrl/cmd + c\n * Paste text: ctrl/cmd + v\n * Cut text: ctrl/cmd + x\n * Select entire text: ctrl/cmd + a\n * Quit editing tab or esc\n * ```\n *\n * #### Supported mouse/touch combination\n * ```\n * Position cursor: click/touch\n * Create selection: click/touch & drag\n * Create selection: click & shift + click\n * Select word: double click\n * Select line: triple click\n * ```\n */\nexport class IText<\n Props extends TOptions<ITextProps> = Partial<ITextProps>,\n SProps extends SerializedITextProps = SerializedITextProps,\n EventSpec extends ITextEvents = ITextEvents,\n >\n extends ITextClickBehavior<Props, SProps, EventSpec>\n implements UniqueITextProps\n{\n /**\n * Index where text selection starts (or where cursor is when there is no selection)\n * @type Number\n * @default\n */\n declare selectionStart: number;\n\n /**\n * Index where text selection ends\n * @type Number\n * @default\n */\n declare selectionEnd: number;\n\n declare compositionStart: number;\n\n declare compositionEnd: number;\n\n /**\n * Color of text selection\n * @type String\n * @default\n */\n declare selectionColor: string;\n\n /**\n * Indicates whether text is in editing mode\n * @type Boolean\n * @default\n */\n declare isEditing: boolean;\n\n /**\n * Indicates whether a text can be edited\n * @type Boolean\n * @default\n */\n declare editable: boolean;\n\n /**\n * Border color of text object while it's in editing mode\n * @type String\n * @default\n */\n declare editingBorderColor: string;\n\n /**\n * Width of cursor (in px)\n * @type Number\n * @default\n */\n declare cursorWidth: number;\n\n /**\n * Color of text cursor color in editing mode.\n * if not set (default) will take color from the text.\n * if set to a color value that fabric can understand, it will\n * be used instead of the color of the text at the current position.\n * @type String\n * @default\n */\n declare cursorColor: string;\n\n /**\n * Delay between cursor blink (in ms)\n * @type Number\n * @default\n */\n declare cursorDelay: number;\n\n /**\n * Duration of cursor fade in (in ms)\n * @type Number\n * @default\n */\n declare cursorDuration: number;\n\n declare compositionColor: string;\n\n /**\n * Indicates whether internal text char widths can be cached\n * @type Boolean\n * @default\n */\n declare caching: boolean;\n\n static ownDefaults = iTextDefaultValues;\n\n static getDefaults(): Record<string, any> {\n return { ...super.getDefaults(), ...IText.ownDefaults };\n }\n\n static type = 'IText';\n\n get type() {\n const type = super.type;\n // backward compatibility\n return type === 'itext' ? 'i-text' : type;\n }\n\n /**\n * Constructor\n * @param {String} text Text string\n * @param {Object} [options] Options object\n */\n constructor(text: string, options?: Props) {\n super(text, { ...IText.ownDefaults, ...options } as Props);\n this.initBehavior();\n }\n\n /**\n * While editing handle differently\n * @private\n * @param {string} key\n * @param {*} value\n */\n _set(key: string, value: any) {\n if (this.isEditing && this._savedProps && key in this._savedProps) {\n // @ts-expect-error irritating TS\n this._savedProps[key] = value;\n return this;\n }\n if (key === 'canvas') {\n this.canvas instanceof Canvas &&\n this.canvas.textEditingManager.remove(this);\n value instanceof Canvas && value.textEditingManager.add(this);\n }\n return super._set(key, value);\n }\n\n /**\n * Sets selection start (left boundary of a selection)\n * @param {Number} index Index to set selection start to\n */\n setSelectionStart(index: number) {\n index = Math.max(index, 0);\n this._updateAndFire('selectionStart', index);\n }\n\n /**\n * Sets selection end (right boundary of a selection)\n * @param {Number} index Index to set selection end to\n */\n setSelectionEnd(index: number) {\n index = Math.min(index, this.text.length);\n this._updateAndFire('selectionEnd', index);\n }\n\n /**\n * @private\n * @param {String} property 'selectionStart' or 'selectionEnd'\n * @param {Number} index new position of property\n */\n protected _updateAndFire(\n property: 'selectionStart' | 'selectionEnd',\n index: number,\n ) {\n if (this[property] !== index) {\n this._fireSelectionChanged();\n this[property] = index;\n }\n this._updateTextarea();\n }\n\n /**\n * Fires the even of selection changed\n * @private\n */\n _fireSelectionChanged() {\n this.fire('selection:changed');\n this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n }\n\n /**\n * Initialize text dimensions. Render all text on given context\n * or on a offscreen canvas to get the text width with measureText.\n * Updates this.width and this.height with the proper values.\n * Does not return dimensions.\n * @private\n */\n initDimensions() {\n this.isEditing && this.initDelayedCursor();\n super.initDimensions();\n }\n\n /**\n * Gets style of a current selection/cursor (at the start position)\n * if startIndex or endIndex are not provided, selectionStart or selectionEnd will be used.\n * @param {Number} startIndex Start index to get styles at\n * @param {Number} endIndex End index to get styles at, if not specified selectionEnd or startIndex + 1\n * @param {Boolean} [complete] get full style or not\n * @return {Array} styles an array with one, zero or more Style objects\n */\n getSelectionStyles(\n startIndex: number = this.selectionStart || 0,\n endIndex: number = this.selectionEnd,\n complete?: boolean,\n ) {\n return super.getSelectionStyles(startIndex, endIndex, complete);\n }\n\n /**\n * Sets style of a current selection, if no selection exist, do not set anything.\n * @param {Object} [styles] Styles object\n * @param {Number} [startIndex] Start index to get styles at\n * @param {Number} [endIndex] End index to get styles at, if not specified selectionEnd or startIndex + 1\n */\n setSelectionStyles(\n styles: object,\n startIndex: number = this.selectionStart || 0,\n endIndex: number = this.selectionEnd,\n ) {\n return super.setSelectionStyles(styles, startIndex, endIndex);\n }\n\n /**\n * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)\n * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n * @param {Boolean} [skipWrapping] consider the location for unwrapped lines. useful to manage styles.\n */\n get2DCursorLocation(\n selectionStart = this.selectionStart,\n skipWrapping?: boolean,\n ) {\n return super.get2DCursorLocation(selectionStart, skipWrapping);\n }\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n render(ctx: CanvasRenderingContext2D) {\n super.render(ctx);\n // clear the cursorOffsetCache, so we ensure to calculate once per renderCursor\n // the correct position but not at every cursor animation.\n this.cursorOffsetCache = {};\n this.renderCursorOrSelection();\n }\n\n /**\n * @override block cursor/selection logic while rendering the exported canvas\n * @todo this workaround should be replaced with a more robust solution\n */\n toCanvasElement(options?: ObjectToCanvasElementOptions): HTMLCanvasElement {\n const isEditing = this.isEditing;\n this.isEditing = false;\n const canvas = super.toCanvasElement(options);\n this.isEditing = isEditing;\n return canvas;\n }\n\n /**\n * Renders cursor or selection (depending on what exists)\n * it does on the contextTop. If contextTop is not available, do nothing.\n */\n renderCursorOrSelection() {\n if (!this.isEditing) {\n return;\n }\n const ctx = this.clearContextTop(true);\n if (!ctx) {\n return;\n }\n const boundaries = this._getCursorBoundaries();\n if (this.selectionStart === this.selectionEnd) {\n this.renderCursor(ctx, boundaries);\n } else {\n this.renderSelection(ctx, boundaries);\n }\n this.canvas!.contextTopDirty = true;\n ctx.restore();\n }\n\n /**\n * Returns cursor boundaries (left, top, leftOffset, topOffset)\n * left/top are left/top of entire text box\n * leftOffset/topOffset are offset from that left/top point of a text box\n * @private\n * @param {number} [index] index from start\n * @param {boolean} [skipCaching]\n */\n _getCursorBoundaries(\n index: number = this.selectionStart,\n skipCaching?: boolean,\n ): CursorBoundaries {\n const left = this._getLeftOffset(),\n top = this._getTopOffset(),\n offsets = this._getCursorBoundariesOffsets(index, skipCaching);\n return {\n left: left,\n top: top,\n leftOffset: offsets.left,\n topOffset: offsets.top,\n };\n }\n\n /**\n * Caches and returns cursor left/top offset relative to instance's center point\n * @private\n * @param {number} index index from start\n * @param {boolean} [skipCaching]\n */\n _getCursorBoundariesOffsets(\n index: number,\n skipCaching?: boolean,\n ): { left: number; top: number } {\n if (skipCaching) {\n return this.__getCursorBoundariesOffsets(index);\n }\n if (this.cursorOffsetCache && 'top' in this.cursorOffsetCache) {\n return this.cursorOffsetCache as { left: number; top: number };\n }\n return (this.cursorOffsetCache = this.__getCursorBoundariesOffsets(index));\n }\n\n /**\n * Calculates cursor left/top offset relative to instance's center point\n * @private\n * @param {number} index index from start\n */\n __getCursorBoundariesOffsets(index: number) {\n let topOffset = 0,\n leftOffset = 0;\n const { charIndex, lineIndex } = this.get2DCursorLocation(index);\n\n for (let i = 0; i < lineIndex; i++) {\n topOffset += this.getHeightOfLine(i);\n }\n const lineLeftOffset = this._getLineLeftOffset(lineIndex);\n const bound = this.__charBounds[lineIndex][charIndex];\n bound && (leftOffset = bound.left);\n if (\n this.charSpacing !== 0 &&\n charIndex === this._textLines[lineIndex].length\n ) {\n leftOffset -= this._getWidthOfCharSpacing();\n }\n const boundaries = {\n top: topOffset,\n left: lineLeftOffset + (leftOffset > 0 ? leftOffset : 0),\n };\n if (this.direction === 'rtl') {\n if (\n this.textAlign === RIGHT ||\n this.textAlign === JUSTIFY ||\n this.textAlign === JUSTIFY_RIGHT\n ) {\n boundaries.left *= -1;\n } else if (this.textAlign === LEFT || this.textAlign === JUSTIFY_LEFT) {\n boundaries.left = lineLeftOffset - (leftOffset > 0 ? leftOffset : 0);\n } else if (\n this.textAlign === CENTER ||\n this.textAlign === JUSTIFY_CENTER\n ) {\n boundaries.left = lineLeftOffset - (leftOffset > 0 ? leftOffset : 0);\n }\n }\n return boundaries;\n }\n\n /**\n * Renders cursor on context Top, outside the animation cycle, on request\n * Used for the drag/drop effect.\n * If contextTop is not available, do nothing.\n */\n renderCursorAt(selectionStart: number) {\n const boundaries = this._getCursorBoundaries(selectionStart, true);\n this._renderCursor(this.canvas!.contextTop, boundaries, selectionStart);\n }\n\n /**\n * Renders cursor\n * @param {Object} boundaries\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n renderCursor(ctx: CanvasRenderingContext2D, boundaries: CursorBoundaries) {\n this._renderCursor(ctx, boundaries, this.selectionStart);\n }\n\n _renderCursor(\n ctx: CanvasRenderingContext2D,\n boundaries: CursorBoundaries,\n selectionStart: number,\n ) {\n const cursorLocation = this.get2DCursorLocation(selectionStart),\n lineIndex = cursorLocation.lineIndex,\n charIndex =\n cursorLocation.charIndex > 0 ? cursorLocation.charIndex - 1 : 0,\n charHeight = this.getValueOfPropertyAt(lineIndex, charIndex, 'fontSize'),\n multiplier = this.getObjectScaling().x * this.canvas!.getZoom(),\n cursorWidth = this.cursorWidth / multiplier,\n dy = this.getValueOfPropertyAt(lineIndex, charIndex, 'deltaY'),\n topOffset =\n boundaries.topOffset +\n ((1 - this._fontSizeFraction) * this.getHeightOfLine(lineIndex)) /\n this.lineHeight -\n charHeight * (1 - this._fontSizeFraction);\n\n if (this.inCompositionMode) {\n // TODO: investigate why there isn't a return inside the if,\n // and why can't happen at the top of the function\n this.renderSelection(ctx, boundaries);\n }\n ctx.fillStyle =\n this.cursorColor ||\n (this.getValueOfPropertyAt(lineIndex, charIndex, FILL) as string);\n ctx.globalAlpha = this._currentCursorOpacity;\n ctx.fillRect(\n boundaries.left + boundaries.leftOffset - cursorWidth / 2,\n topOffset + boundaries.top + dy,\n cursorWidth,\n charHeight,\n );\n }\n\n /**\n * Renders text selection\n * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n renderSelection(ctx: CanvasRenderingContext2D, boundaries: CursorBoundaries) {\n const selection = {\n selectionStart: this.inCompositionMode\n ? this.hiddenTextarea!.selectionStart\n : this.selectionStart,\n selectionEnd: this.inCompositionMode\n ? this.hiddenTextarea!.selectionEnd\n : this.selectionEnd,\n };\n this._renderSelection(ctx, selection, boundaries);\n }\n\n /**\n * Renders drag start text selection\n */\n renderDragSourceEffect() {\n const dragStartSelection =\n this.draggableTextDelegate.getDragStartSelection()!;\n this._renderSelection(\n this.canvas!.contextTop,\n dragStartSelection,\n this._getCursorBoundaries(dragStartSelection.selectionStart, true),\n );\n }\n\n renderDropTargetEffect(e: DragEvent) {\n const dragSelection = this.getSelectionStartFromPointer(e);\n this.renderCursorAt(dragSelection);\n }\n\n /**\n * Renders text selection\n * @private\n * @param {{ selectionStart: number, selectionEnd: number }} selection\n * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n _renderSelection(\n ctx: CanvasRenderingContext2D,\n selection: { selectionStart: number; selectionEnd: number },\n boundaries: CursorBoundaries,\n ) {\n const selectionStart = selection.selectionStart,\n selectionEnd = selection.selectionEnd,\n isJustify = this.textAlign.includes(JUSTIFY),\n start = this.get2DCursorLocation(selectionStart),\n end = this.get2DCursorLocation(selectionEnd),\n startLine = start.lineIndex,\n endLine = end.lineIndex,\n startChar = start.charIndex < 0 ? 0 : start.charIndex,\n endChar = end.charIndex < 0 ? 0 : end.charIndex;\n\n for (let i = startLine; i <= endLine; i++) {\n const lineOffset = this._getLineLeftOffset(i) || 0;\n let lineHeight = this.getHeightOfLine(i),\n realLineHeight = 0,\n boxStart = 0,\n boxEnd = 0;\n\n if (i === startLine) {\n boxStart = this.__charBounds[startLine][startChar].left;\n }\n if (i >= startLine && i < endLine) {\n boxEnd =\n isJustify && !this.isEndOfWrapping(i)\n ? this.width\n : this.getLineWidth(i) || 5; // WTF is this 5?\n } else if (i === endLine) {\n if (endChar === 0) {\n boxEnd = this.__charBounds[endLine][endChar].left;\n } else {\n const charSpacing = this._getWidthOfCharSpacing();\n boxEnd =\n this.__charBounds[endLine][endChar - 1].left +\n this.__charBounds[endLine][endChar - 1].width -\n charSpacing;\n }\n }\n realLineHeight = lineHeight;\n if (this.lineHeight < 1 || (i === endLine && this.lineHeight > 1)) {\n lineHeight /= this.lineHeight;\n }\n let drawStart = boundaries.left + lineOffset + boxStart,\n drawHeight = lineHeight,\n extraTop = 0;\n const drawWidth = boxEnd - boxStart;\n if (this.inCompositionMode) {\n ctx.fillStyle = this.compositionColor || 'black';\n drawHeight = 1;\n extraTop = lineHeight;\n } else {\n ctx.fillStyle = this.selectionColor;\n }\n if (this.direction === 'rtl') {\n if (\n this.textAlign === RIGHT ||\n this.textAlign === JUSTIFY ||\n this.textAlign === JUSTIFY_RIGHT\n ) {\n drawStart = this.width - drawStart - drawWidth;\n } else if (this.textAlign === LEFT || this.textAlign === JUSTIFY_LEFT) {\n drawStart = boundaries.left + lineOffset - boxEnd;\n } else if (\n this.textAlign === CENTER ||\n this.textAlign === JUSTIFY_CENTER\n ) {\n drawStart = boundaries.left + lineOffset - boxEnd;\n }\n }\n ctx.fillRect(\n drawStart,\n boundaries.top + boundaries.topOffset + extraTop,\n drawWidth,\n drawHeight,\n );\n boundaries.topOffset += realLineHeight;\n }\n }\n\n /**\n * High level function to know the height of the cursor.\n * the currentChar is the one that precedes the cursor\n * Returns fontSize of char at the current cursor\n * Unused from the library, is for the end user\n * @return {Number} Character font size\n */\n getCurrentCharFontSize(): number {\n const cp = this._getCurrentCharIndex();\n return this.getValueOfPropertyAt(cp.l, cp.c, 'fontSize');\n }\n\n /**\n * High level function to know the color of the cursor.\n * the currentChar is the one that precedes the cursor\n * Returns color (fill) of char at the current cursor\n * if the text object has a pattern or gradient for filler, it will return that.\n * Unused by the library, is for the end user\n * @return {String | TFiller} Character color (fill)\n */\n getCurrentCharColor(): string | TFiller | null {\n const cp = this._getCurrentCharIndex();\n return this.getValueOfPropertyAt(cp.l, cp.c, FILL);\n }\n\n /**\n * Returns the cursor position for the getCurrent.. functions\n * @private\n */\n _getCurrentCharIndex() {\n const cursorPosition = this.get2DCursorLocation(this.selectionStart, true),\n charIndex =\n cursorPosition.charIndex > 0 ? cursorPosition.charIndex - 1 : 0;\n return { l: cursorPosition.lineIndex, c: charIndex };\n }\n\n dispose() {\n this._exitEditing();\n this.draggableTextDelegate.dispose();\n super.dispose();\n }\n}\n\nclassRegistry.setClass(IText);\n// legacy\nclassRegistry.setClass(IText, 'i-text');\n"],"names":["iTextDefaultValues","_objectSpread","selectionStart","selectionEnd","selectionColor","isEditing","editable","editingBorderColor","cursorWidth","cursorColor","cursorDelay","cursorDuration","caching","hiddenTextareaContainer","keysMap","keysMapRtl","ctrlKeysMapDown","ctrlKeysMapUp","_selectionDirection","_reSpace","inCompositionMode","IText","ITextClickBehavior","getDefaults","super","ownDefaults","type","constructor","text","options","this","initBehavior","_set","key","value","_savedProps","canvas","Canvas","textEditingManager","remove","add","setSelectionStart","index","Math","max","_updateAndFire","setSelectionEnd","min","length","property","_fireSelectionChanged","_updateTextarea","fire","target","initDimensions","initDelayedCursor","getSelectionStyles","startIndex","arguments","undefined","endIndex","complete","setSelectionStyles","styles","get2DCursorLocation","skipWrapping","render","ctx","cursorOffsetCache","renderCursorOrSelection","toCanvasElement","clearContextTop","boundaries","_getCursorBoundaries","renderCursor","renderSelection","contextTopDirty","restore","skipCaching","left","_getLeftOffset","top","_getTopOffset","offsets","_getCursorBoundariesOffsets","leftOffset","topOffset","__getCursorBoundariesOffsets","charIndex","lineIndex","i","getHeightOfLine","lineLeftOffset","_getLineLeftOffset","bound","__charBounds","charSpacing","_textLines","_getWidthOfCharSpacing","direction","textAlign","RIGHT","JUSTIFY","JUSTIFY_RIGHT","LEFT","JUSTIFY_LEFT","CENTER","JUSTIFY_CENTER","renderCursorAt","_renderCursor","contextTop","cursorLocation","charHeight","getValueOfPropertyAt","multiplier","getObjectScaling","x","getZoom","dy","_fontSizeFraction","lineHeight","fillStyle","FILL","globalAlpha","_currentCursorOpacity","fillRect","selection","hiddenTextarea","_renderSelection","renderDragSourceEffect","dragStartSelection","draggableTextDelegate","getDragStartSelection","renderDropTargetEffect","e","dragSelection","getSelectionStartFromPointer","isJustify","includes","start","end","startLine","endLine","startChar","endChar","lineOffset","realLineHeight","boxStart","boxEnd","isEndOfWrapping","width","getLineWidth","drawStart","drawHeight","extraTop","drawWidth","compositionColor","getCurrentCharFontSize","cp","_getCurrentCharIndex","l","c","getCurrentCharColor","cursorPosition","dispose","_exitEditing","_defineProperty","classRegistry","setClass"],"mappings":"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"}