fabric
Version:
Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.
714 lines • 25.2 kB
TypeScript
import type { ObjectEvents } from '../../EventTypeDefs';
import type { CompleteTextStyleDeclaration, TextStyle, TextStyleDeclaration } from './StyledText';
import { StyledText } from './StyledText';
import type { Abortable, TCacheCanvasDimensions, TClassProperties, TFiller, TOptions } from '../../typedefs';
import type { TextStyleArray } from '../../util/misc/textStyles';
import type { Path } from '../Path';
import type { FabricObjectProps, SerializedObjectProps } from '../Object/types';
import type { StylePropertiesType } from './constants';
import type { CSSRules } from '../../parser/typedefs';
export type TPathSide = 'left' | 'right';
export type TPathAlign = 'baseline' | 'center' | 'ascender' | 'descender';
export type TextLinesInfo = {
lines: string[];
graphemeLines: string[][];
graphemeText: string[];
_unwrappedLines: string[][];
};
/**
* Measure and return the info of a single grapheme.
* needs the the info of previous graphemes already filled
* Override to customize measuring
*/
export type GraphemeBBox = {
width: number;
height: number;
kernedWidth: number;
left: number;
deltaY: number;
renderLeft?: number;
renderTop?: number;
angle?: number;
};
interface UniqueTextProps {
charSpacing: number;
lineHeight: number;
fontSize: number;
fontWeight: string | number;
fontFamily: string;
fontStyle: string;
pathSide: TPathSide;
pathAlign: TPathAlign;
underline: boolean;
overline: boolean;
linethrough: boolean;
textAlign: string;
direction: CanvasDirection;
path?: Path;
textDecorationThickness: number;
}
export interface SerializedTextProps extends SerializedObjectProps, UniqueTextProps {
styles: TextStyleArray | TextStyle;
}
export interface TextProps extends FabricObjectProps, UniqueTextProps {
styles: TextStyle;
}
/**
* Text class
* @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text}
*/
export declare class FabricText<Props extends TOptions<TextProps> = Partial<TextProps>, SProps extends SerializedTextProps = SerializedTextProps, EventSpec extends ObjectEvents = ObjectEvents> extends StyledText<Props, SProps, EventSpec> implements UniqueTextProps {
/**
* Properties that requires a text layout recalculation when changed
* @type string[]
* @protected
*/
static textLayoutProperties: string[];
/**
* @private
*/
_reNewline: RegExp;
/**
* Use this regular expression to filter for whitespaces that is not a new line.
* Mostly used when text is 'justify' aligned.
* @private
*/
_reSpacesAndTabs: RegExp;
/**
* Use this regular expression to filter for whitespace that is not a new line.
* Mostly used when text is 'justify' aligned.
* @private
*/
_reSpaceAndTab: RegExp;
/**
* Use this regular expression to filter consecutive groups of non spaces.
* Mostly used when text is 'justify' aligned.
* @private
*/
_reWords: RegExp;
text: string;
/**
* Font size (in pixels)
* @type Number
* @default
*/
fontSize: number;
/**
* Font weight (e.g. bold, normal, 400, 600, 800)
* @type {(Number|String)}
* @default
*/
fontWeight: string | number;
/**
* Font family
* @type String
* @default
*/
fontFamily: string;
/**
* Text decoration underline.
* @type Boolean
* @default
*/
underline: boolean;
/**
* Text decoration overline.
* @type Boolean
* @default
*/
overline: boolean;
/**
* Text decoration linethrough.
* @type Boolean
* @default
*/
linethrough: boolean;
/**
* Text alignment. Possible values: "left", "center", "right", "justify",
* "justify-left", "justify-center" or "justify-right".
* @type String
* @default
*/
textAlign: string;
/**
* Font style . Possible values: "", "normal", "italic" or "oblique".
* @type String
* @default
*/
fontStyle: string;
/**
* Line height
* @type Number
* @default
*/
lineHeight: number;
/**
* Superscript schema object (minimum overlap)
*/
superscript: {
/**
* fontSize factor
* @default 0.6
*/
size: number;
/**
* baseline-shift factor (upwards)
* @default -0.35
*/
baseline: number;
};
/**
* Subscript schema object (minimum overlap)
*/
subscript: {
/**
* fontSize factor
* @default 0.6
*/
size: number;
/**
* baseline-shift factor (downwards)
* @default 0.11
*/
baseline: number;
};
/**
* Background color of text lines
* @type String
* @default
*/
textBackgroundColor: string;
styles: TextStyle;
/**
* Path that the text should follow.
* since 4.6.0 the path will be drawn automatically.
* if you want to make the path visible, give it a stroke and strokeWidth or fill value
* if you want it to be hidden, assign visible = false to the path.
* This feature is in BETA, and SVG import/export is not yet supported.
* @type Path
* @example
* const textPath = new Text('Text on a path', {
* top: 150,
* left: 150,
* textAlign: 'center',
* charSpacing: -50,
* path: new Path('M 0 0 C 50 -100 150 -100 200 0', {
* strokeWidth: 1,
* visible: false
* }),
* pathSide: 'left',
* pathStartOffset: 0
* });
* @default
*/
path?: Path;
/**
* The text decoration tickness for underline, overline and strikethrough
* The tickness is expressed in thousandths of fontSize ( em ).
* The original value was 1/15 that translates to 66.6667 thousandths.
* The choice of unit of measure is to align with charSpacing.
* You can slim the tickness without issues, while large underline or overline may end up
* outside the bounding box of the text. In order to fix that a bigger refactor of the code
* is needed and is out of scope for now. If you need such large overline on the first line
* of text or large underline on the last line of text, consider disabling caching as a
* workaround
* @default 66.667
*/
textDecorationThickness: number;
/**
* Offset amount for text path starting position
* Only used when text has a path
* @default
*/
pathStartOffset: number;
/**
* Which side of the path the text should be drawn on.
* Only used when text has a path
* @type {TPathSide} 'left|right'
* @default
*/
pathSide: TPathSide;
/**
* How text is aligned to the path. This property determines
* the perpendicular position of each character relative to the path.
* (one of "baseline", "center", "ascender", "descender")
* This feature is in BETA, and its behavior may change
* @type TPathAlign
* @default
*/
pathAlign: TPathAlign;
/**
* @private
*/
_fontSizeFraction: number;
/**
* @private
*/
offsets: {
underline: number;
linethrough: number;
overline: number;
};
/**
* Text Line proportion to font Size (in pixels)
* @type Number
* @default
*/
_fontSizeMult: number;
/**
* additional space between characters
* expressed in thousands of em unit
* @type Number
* @default
*/
charSpacing: number;
/**
* Baseline shift, styles only, keep at 0 for the main text object
* @type {Number}
* @default
*/
deltaY: number;
/**
* WARNING: EXPERIMENTAL. NOT SUPPORTED YET
* determine the direction of the text.
* This has to be set manually together with textAlign and originX for proper
* experience.
* some interesting link for the future
* https://www.w3.org/International/questions/qa-bidi-unicode-controls
* @since 4.5.0
* @type {CanvasDirection} 'ltr|rtl'
* @default
*/
direction: CanvasDirection;
/**
* contains characters bounding boxes
* This variable is considered to be protected.
* But for how mixins are implemented right now, we can't leave it private
* @protected
*/
__charBounds: GraphemeBBox[][];
/**
* use this size when measuring text. To avoid IE11 rounding errors
* @type {Number}
* @default
* @readonly
* @private
*/
CACHE_FONT_SIZE: number;
/**
* contains the min text width to avoid getting 0
* @type {Number}
* @default
*/
MIN_TEXT_WIDTH: number;
/**
* contains the the text of the object, divided in lines as they are displayed
* on screen. Wrapping will divide the text independently of line breaks
* @type {string[]}
* @default
*/
textLines: string[];
/**
* same as textlines, but each line is an array of graphemes as split by splitByGrapheme
* @type {string[]}
* @default
*/
_textLines: string[][];
_unwrappedTextLines: string[][];
_text: string[];
cursorWidth: number;
__lineHeights: number[];
__lineWidths: number[];
initialized?: true;
static cacheProperties: string[];
static ownDefaults: Partial<TClassProperties<FabricText<Partial<TextProps>, SerializedTextProps, ObjectEvents>>>;
static type: string;
static getDefaults(): Record<string, any>;
constructor(text: string, options?: Props);
/**
* If text has a path, it will add the extra information needed
* for path and text calculations
*/
setPathInfo(): void;
/**
* @private
* Divides text into lines of text and lines of graphemes.
*/
_splitText(): TextLinesInfo;
/**
* Initialize or update text dimensions.
* Updates this.width and this.height with the proper values.
* Does not return dimensions.
*/
initDimensions(): void;
/**
* Enlarge space boxes and shift the others
*/
enlargeSpaces(): void;
/**
* Detect if the text line is ended with an hard break
* text and itext do not have wrapping, return false
* @return {Boolean}
*/
isEndOfWrapping(lineIndex: number): boolean;
/**
* Detect if a line has a linebreak and so we need to account for it when moving
* and counting style.
* It return always 1 for text and Itext. Textbox has its own implementation
* @return Number
*/
missingNewlineOffset(lineIndex: number, skipWrapping?: boolean): 0 | 1;
/**
* Returns 2d representation (lineIndex and charIndex) of cursor
* @param {Number} selectionStart
* @param {Boolean} [skipWrapping] consider the location for unwrapped lines. useful to manage styles.
*/
get2DCursorLocation(selectionStart: number, skipWrapping?: boolean): {
lineIndex: number;
charIndex: number;
};
/**
* Returns string representation of an instance
* @return {String} String representation of text object
*/
toString(): string;
/**
* Return the dimension and the zoom level needed to create a cache canvas
* big enough to host the object to be cached.
* @private
* @param {Object} dim.x width of object to be cached
* @param {Object} dim.y height of object to be cached
* @return {Object}.width width of canvas
* @return {Object}.height height of canvas
* @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache
* @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache
*/
_getCacheCanvasDimensions(): TCacheCanvasDimensions;
/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_render(ctx: CanvasRenderingContext2D): void;
/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderText(ctx: CanvasRenderingContext2D): void;
/**
* Set the font parameter of the context with the object properties or with charStyle
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
* @param {Object} [charStyle] object with font style properties
* @param {String} [charStyle.fontFamily] Font Family
* @param {Number} [charStyle.fontSize] Font size in pixels. ( without px suffix )
* @param {String} [charStyle.fontWeight] Font weight
* @param {String} [charStyle.fontStyle] Font style (italic|normal)
*/
_setTextStyles(ctx: CanvasRenderingContext2D, charStyle?: any, forMeasuring?: boolean): void;
/**
* calculate and return the text Width measuring each line.
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
* @return {Number} Maximum width of Text object
*/
calcTextWidth(): number;
/**
* @private
* @param {String} method Method name ("fillText" or "strokeText")
* @param {CanvasRenderingContext2D} ctx Context to render on
* @param {String} line Text to render
* @param {Number} left Left position of text
* @param {Number} top Top position of text
* @param {Number} lineIndex Index of a line in a text
*/
_renderTextLine(method: 'fillText' | 'strokeText', ctx: CanvasRenderingContext2D, line: string[], left: number, top: number, lineIndex: number): void;
/**
* Renders the text background for lines, taking care of style
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderTextLinesBackground(ctx: CanvasRenderingContext2D): void;
/**
* measure and return the width of a single character.
* possibly overridden to accommodate different measure logic or
* to hook some external lib for character measurement
* @private
* @param {String} _char, char to be measured
* @param {Object} charStyle style of char to be measured
* @param {String} [previousChar] previous char
* @param {Object} [prevCharStyle] style of previous char
*/
_measureChar(_char: string, charStyle: CompleteTextStyleDeclaration, previousChar: string | undefined, prevCharStyle: CompleteTextStyleDeclaration | Record<string, never>): {
width: number;
kernedWidth: number;
};
/**
* Computes height of character at given position
* @param {Number} line the line index number
* @param {Number} _char the character index number
* @return {Number} fontSize of the character
*/
getHeightOfChar(line: number, _char: number): number;
/**
* measure a text line measuring all characters.
* @param {Number} lineIndex line number
*/
measureLine(lineIndex: number): {
width: number;
numOfSpaces: number;
};
/**
* measure every grapheme of a line, populating __charBounds
* @param {Number} lineIndex
* @return {Object} object.width total width of characters
* @return {Object} object.numOfSpaces length of chars that match this._reSpacesAndTabs
*/
_measureLine(lineIndex: number): {
width: number;
numOfSpaces: number;
};
/**
* Calculate the angle and the left,top position of the char that follow a path.
* It appends it to graphemeInfo to be reused later at rendering
* @private
* @param {Number} positionInPath to be measured
* @param {GraphemeBBox} graphemeInfo current grapheme box information
* @param {Object} startingPoint position of the point
*/
_setGraphemeOnPath(positionInPath: number, graphemeInfo: GraphemeBBox): void;
/**
*
* @param {String} grapheme to be measured
* @param {Number} lineIndex index of the line where the char is
* @param {Number} charIndex position in the line
* @param {String} [prevGrapheme] character preceding the one to be measured
* @returns {GraphemeBBox} grapheme bbox
*/
_getGraphemeBox(grapheme: string, lineIndex: number, charIndex: number, prevGrapheme?: string, skipLeft?: boolean): GraphemeBBox;
/**
* Calculate height of line at 'lineIndex'
* @param {Number} lineIndex index of line to calculate
* @return {Number}
*/
getHeightOfLine(lineIndex: number): number;
/**
* Calculate text box height
*/
calcTextHeight(): number;
/**
* @private
* @return {Number} Left offset
*/
_getLeftOffset(): number;
/**
* @private
* @return {Number} Top offset
*/
_getTopOffset(): number;
/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
* @param {String} method Method name ("fillText" or "strokeText")
*/
_renderTextCommon(ctx: CanvasRenderingContext2D, method: 'fillText' | 'strokeText'): void;
/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderTextFill(ctx: CanvasRenderingContext2D): void;
/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderTextStroke(ctx: CanvasRenderingContext2D): void;
/**
* @private
* @param {String} method fillText or strokeText.
* @param {CanvasRenderingContext2D} ctx Context to render on
* @param {Array} line Content of the line, splitted in an array by grapheme
* @param {Number} left
* @param {Number} top
* @param {Number} lineIndex
*/
_renderChars(method: 'fillText' | 'strokeText', ctx: CanvasRenderingContext2D, line: Array<any>, left: number, top: number, lineIndex: number): void;
/**
* This function try to patch the missing gradientTransform on canvas gradients.
* transforming a context to transform the gradient, is going to transform the stroke too.
* we want to transform the gradient but not the stroke operation, so we create
* a transformed gradient on a pattern and then we use the pattern instead of the gradient.
* this method has drawbacks: is slow, is in low resolution, needs a patch for when the size
* is limited.
* @private
* @param {TFiller} filler a fabric gradient instance
* @return {CanvasPattern} a pattern to use as fill/stroke style
*/
_applyPatternGradientTransformText(filler: TFiller): CanvasPattern;
handleFiller<T extends 'fill' | 'stroke'>(ctx: CanvasRenderingContext2D, property: `${T}Style`, filler: TFiller | string): {
offsetX: number;
offsetY: number;
};
/**
* This function prepare the canvas for a stroke style, and stroke and strokeWidth
* need to be sent in as defined
* @param {CanvasRenderingContext2D} ctx
* @param {CompleteTextStyleDeclaration} style with stroke and strokeWidth defined
* @returns
*/
_setStrokeStyles(ctx: CanvasRenderingContext2D, { stroke, strokeWidth, }: Pick<CompleteTextStyleDeclaration, 'stroke' | 'strokeWidth'>): {
offsetX: number;
offsetY: number;
};
/**
* This function prepare the canvas for a ill style, and fill
* need to be sent in as defined
* @param {CanvasRenderingContext2D} ctx
* @param {CompleteTextStyleDeclaration} style with ill defined
* @returns
*/
_setFillStyles(ctx: CanvasRenderingContext2D, { fill }: Pick<this, 'fill'>): {
offsetX: number;
offsetY: number;
};
/**
* @private
* @param {String} method
* @param {CanvasRenderingContext2D} ctx Context to render on
* @param {Number} lineIndex
* @param {Number} charIndex
* @param {String} _char
* @param {Number} left Left coordinate
* @param {Number} top Top coordinate
* @param {Number} lineHeight Height of the line
*/
_renderChar(method: 'fillText' | 'strokeText', ctx: CanvasRenderingContext2D, lineIndex: number, charIndex: number, _char: string, left: number, top: number): void;
/**
* Turns the character into a 'superior figure' (i.e. 'superscript')
* @param {Number} start selection start
* @param {Number} end selection end
*/
setSuperscript(start: number, end: number): void;
/**
* Turns the character into an 'inferior figure' (i.e. 'subscript')
* @param {Number} start selection start
* @param {Number} end selection end
*/
setSubscript(start: number, end: number): void;
/**
* Applies 'schema' at given position
* @private
* @param {Number} start selection start
* @param {Number} end selection end
* @param {Number} schema
*/
protected _setScript(start: number, end: number, schema: {
size: number;
baseline: number;
}): void;
/**
* @private
* @param {Number} lineIndex index text line
* @return {Number} Line left offset
*/
_getLineLeftOffset(lineIndex: number): number;
/**
* @private
*/
_clearCache(): void;
/**
* Measure a single line given its index. Used to calculate the initial
* text bounding box. The values are calculated and stored in __lineWidths cache.
* @private
* @param {Number} lineIndex line number
* @return {Number} Line width
*/
getLineWidth(lineIndex: number): number;
_getWidthOfCharSpacing(): number;
/**
* Retrieves the value of property at given character position
* @param {Number} lineIndex the line number
* @param {Number} charIndex the character number
* @param {String} property the property name
* @returns the value of 'property'
*/
getValueOfPropertyAt<T extends StylePropertiesType>(lineIndex: number, charIndex: number, property: T): this[T];
/**
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
_renderTextDecoration(ctx: CanvasRenderingContext2D, type: 'underline' | 'linethrough' | 'overline'): void;
/**
* return font declaration string for canvas context
* @param {Object} [styleObject] object
* @returns {String} font declaration formatted for canvas context.
*/
_getFontDeclaration({ fontFamily, fontStyle, fontWeight, fontSize, }?: Partial<Pick<TextStyleDeclaration, 'fontFamily' | 'fontStyle' | 'fontWeight' | 'fontSize'>>, forMeasuring?: boolean): string;
/**
* Renders text instance on a specified context
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
render(ctx: CanvasRenderingContext2D): void;
/**
* Override this method to customize grapheme splitting
* @todo the util `graphemeSplit` needs to be injectable in some way.
* is more comfortable to inject the correct util rather than having to override text
* in the middle of the prototype chain
* @param {string} value
* @returns {string[]} array of graphemes
*/
graphemeSplit(value: string): string[];
/**
* Returns the text as an array of lines.
* @param {String} text text to split
* @returns Lines in the text
*/
_splitTextIntoLines(text: string): TextLinesInfo;
/**
* Returns object representation of an instance
* @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output
* @return {Object} Object representation of an instance
*/
toObject<T extends Omit<Props & TClassProperties<this>, keyof SProps>, K extends keyof T = never>(propertiesToInclude?: K[]): Pick<T, K> & SProps;
set(key: string | any, value?: any): this;
/**
* Returns complexity of an instance
* @return {Number} complexity
*/
complexity(): number;
/**
* List of generic font families
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/font-family#generic-name
*/
static genericFonts: string[];
/**
* List of attribute names to account for when parsing SVG element (used by {@link FabricText.fromElement})
* @static
* @memberOf Text
* @see: http://www.w3.org/TR/SVG/text.html#TextElement
*/
static ATTRIBUTE_NAMES: string[];
/**
* Returns FabricText instance from an SVG element (<b>not yet implemented</b>)
* @static
* @memberOf Text
* @param {HTMLElement} element Element to parse
* @param {Object} [options] Options object
*/
static fromElement(element: HTMLElement, options: Abortable, cssRules?: CSSRules): Promise<FabricText<{
signal?: AbortSignal;
left: number;
top: number;
underline: boolean;
overline: boolean;
linethrough: boolean;
strokeWidth: number;
fontSize: number;
}, SerializedTextProps, ObjectEvents>>;
/**
* Returns FabricText instance from an object representation
* @param {Object} object plain js Object to create an instance from
* @returns {Promise<FabricText>}
*/
static fromObject<T extends TOptions<SerializedTextProps>, S extends FabricText>(object: T): Promise<S>;
}
export {};
//# sourceMappingURL=Text.d.ts.map