UNPKG

fabric

Version:

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

1 lines 15.8 kB
{"version":3,"file":"Line.mjs","sources":["../../../src/shapes/Line.ts"],"sourcesContent":["import { SHARED_ATTRIBUTES } from '../parser/attributes';\nimport { parseAttributes } from '../parser/parseAttributes';\nimport type { Abortable, TClassProperties, TOptions } from '../typedefs';\nimport { classRegistry } from '../ClassRegistry';\nimport { FabricObject, cacheProperties } from './Object/FabricObject';\nimport { Point } from '../Point';\nimport { isFiller } from '../util/typeAssertions';\nimport type { FabricObjectProps, SerializedObjectProps } from './Object/types';\nimport type { ObjectEvents } from '../EventTypeDefs';\nimport { makeBoundingBoxFromPoints } from '../util';\nimport { CENTER, LEFT, TOP } from '../constants';\nimport type { CSSRules } from '../parser/typedefs';\n\n// @TODO this code is terrible and Line should be a special case of polyline.\n\nconst coordProps = ['x1', 'x2', 'y1', 'y2'] as const;\n\ninterface UniqueLineProps {\n x1: number;\n x2: number;\n y1: number;\n y2: number;\n}\n\nexport interface SerializedLineProps\n extends SerializedObjectProps,\n UniqueLineProps {}\n\nexport class Line<\n Props extends TOptions<FabricObjectProps> = Partial<FabricObjectProps>,\n SProps extends SerializedLineProps = SerializedLineProps,\n EventSpec extends ObjectEvents = ObjectEvents,\n >\n extends FabricObject<Props, SProps, EventSpec>\n implements UniqueLineProps\n{\n /**\n * x value or first line edge\n * @type number\n * @default\n */\n declare x1: number;\n\n /**\n * y value or first line edge\n * @type number\n * @default\n */\n declare y1: number;\n\n /**\n * x value or second line edge\n * @type number\n * @default\n */\n declare x2: number;\n\n /**\n * y value or second line edge\n * @type number\n * @default\n */\n declare y2: number;\n\n static type = 'Line';\n\n static cacheProperties = [...cacheProperties, ...coordProps];\n /**\n * Constructor\n * @param {Array} [points] Array of points\n * @param {Object} [options] Options object\n * @return {Line} thisArg\n */\n constructor([x1, y1, x2, y2] = [0, 0, 0, 0], options: Partial<Props> = {}) {\n super();\n Object.assign(this, Line.ownDefaults);\n this.setOptions(options);\n this.x1 = x1;\n this.x2 = x2;\n this.y1 = y1;\n this.y2 = y2;\n this._setWidthHeight();\n const { left, top } = options;\n typeof left === 'number' && this.set(LEFT, left);\n typeof top === 'number' && this.set(TOP, top);\n }\n\n /**\n * @private\n * @param {Object} [options] Options\n */\n _setWidthHeight() {\n const { x1, y1, x2, y2 } = this;\n this.width = Math.abs(x2 - x1);\n this.height = Math.abs(y2 - y1);\n const { left, top, width, height } = makeBoundingBoxFromPoints([\n { x: x1, y: y1 },\n { x: x2, y: y2 },\n ]);\n const position = new Point(left + width / 2, top + height / 2);\n this.setPositionByOrigin(position, CENTER, CENTER);\n }\n\n /**\n * @private\n * @param {String} key\n * @param {*} value\n */\n _set(key: string, value: any) {\n super._set(key, value);\n if (coordProps.includes(key as keyof UniqueLineProps)) {\n // this doesn't make sense very much, since setting x1 when top or left\n // are already set, is just going to show a strange result since the\n // line will move way more than the developer expect.\n // in fabric5 it worked only when the line didn't have extra transformations,\n // in fabric6 too. With extra transform they behave bad in different ways.\n // This needs probably a good rework or a tutorial if you have to create a dynamic line\n this._setWidthHeight();\n }\n return this;\n }\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render(ctx: CanvasRenderingContext2D) {\n ctx.beginPath();\n\n const p = this.calcLinePoints();\n ctx.moveTo(p.x1, p.y1);\n ctx.lineTo(p.x2, p.y2);\n\n ctx.lineWidth = this.strokeWidth;\n\n // TODO: test this\n // make sure setting \"fill\" changes color of a line\n // (by copying fillStyle to strokeStyle, since line is stroked, not filled)\n const origStrokeStyle = ctx.strokeStyle;\n if (isFiller(this.stroke)) {\n ctx.strokeStyle = this.stroke.toLive(ctx)!;\n } else {\n ctx.strokeStyle = this.stroke ?? ctx.fillStyle;\n }\n this.stroke && this._renderStroke(ctx);\n ctx.strokeStyle = origStrokeStyle;\n }\n\n /**\n * This function is an helper for svg import. it returns the center of the object in the svg\n * untransformed coordinates\n * @private\n * @return {Point} center point from element coordinates\n */\n _findCenterFromElement(): Point {\n return new Point((this.x1 + this.x2) / 2, (this.y1 + this.y2) / 2);\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<\n T extends Omit<Props & TClassProperties<this>, keyof SProps>,\n K extends keyof T = never,\n >(propertiesToInclude: K[] = []): Pick<T, K> & SProps {\n return {\n ...super.toObject(propertiesToInclude),\n ...this.calcLinePoints(),\n };\n }\n\n /*\n * Calculate object dimensions from its properties\n * @private\n */\n _getNonTransformedDimensions(): Point {\n const dim = super._getNonTransformedDimensions();\n if (this.strokeLineCap === 'butt') {\n if (this.width === 0) {\n dim.y -= this.strokeWidth;\n }\n if (this.height === 0) {\n dim.x -= this.strokeWidth;\n }\n }\n return dim;\n }\n\n /**\n * Recalculates line points given width and height\n * Those points are simply placed around the center,\n * This is not useful outside internal render functions and svg output\n * Is not meant to be for the developer.\n * @private\n */\n calcLinePoints(): UniqueLineProps {\n const { x1: _x1, x2: _x2, y1: _y1, y2: _y2, width, height } = this;\n const xMult = _x1 <= _x2 ? -1 : 1,\n yMult = _y1 <= _y2 ? -1 : 1,\n x1 = (xMult * width) / 2,\n y1 = (yMult * height) / 2,\n x2 = (xMult * -width) / 2,\n y2 = (yMult * -height) / 2;\n\n return {\n x1,\n x2,\n y1,\n y2,\n };\n }\n\n /* _FROM_SVG_START_ */\n\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG() {\n const { x1, x2, y1, y2 } = this.calcLinePoints();\n return [\n '<line ',\n 'COMMON_PARTS',\n `x1=\"${x1}\" y1=\"${y1}\" x2=\"${x2}\" y2=\"${y2}\" />\\n`,\n ];\n }\n\n /**\n * List of attribute names to account for when parsing SVG element (used by {@link Line.fromElement})\n * @static\n * @memberOf Line\n * @see http://www.w3.org/TR/SVG/shapes.html#LineElement\n */\n static ATTRIBUTE_NAMES = SHARED_ATTRIBUTES.concat(coordProps);\n\n /**\n * Returns Line instance from an SVG element\n * @static\n * @memberOf Line\n * @param {HTMLElement} element Element to parse\n * @param {Object} [options] Options object\n * @param {Function} [callback] callback function invoked after parsing\n */\n static async fromElement(\n element: HTMLElement,\n options: Abortable,\n cssRules?: CSSRules,\n ) {\n const {\n x1 = 0,\n y1 = 0,\n x2 = 0,\n y2 = 0,\n ...parsedAttributes\n } = parseAttributes(element, this.ATTRIBUTE_NAMES, cssRules);\n return new this([x1, y1, x2, y2], parsedAttributes);\n }\n\n /* _FROM_SVG_END_ */\n\n /**\n * Returns Line instance from an object representation\n * @static\n * @memberOf Line\n * @param {Object} object Object to create an instance from\n * @returns {Promise<Line>}\n */\n static fromObject<T extends TOptions<SerializedLineProps>>({\n x1,\n y1,\n x2,\n y2,\n ...object\n }: T) {\n return this._fromObject<Line>(\n {\n ...object,\n points: [x1, y1, x2, y2],\n },\n {\n extraParam: 'points',\n },\n );\n }\n}\n\nclassRegistry.setClass(Line);\nclassRegistry.setSVGClass(Line);\n"],"names":["coordProps","Line","FabricObject","constructor","x1","y1","x2","y2","arguments","length","undefined","options","Object","assign","ownDefaults","setOptions","_setWidthHeight","left","top","set","LEFT","TOP","width","Math","abs","height","makeBoundingBoxFromPoints","x","y","position","Point","setPositionByOrigin","CENTER","_set","key","value","includes","_render","ctx","beginPath","p","calcLinePoints","moveTo","lineTo","lineWidth","strokeWidth","origStrokeStyle","strokeStyle","isFiller","stroke","toLive","_this$stroke","fillStyle","_renderStroke","_findCenterFromElement","toObject","propertiesToInclude","_objectSpread","_getNonTransformedDimensions","dim","strokeLineCap","_x1","_x2","_y1","_y2","xMult","yMult","_toSVG","concat","fromElement","element","cssRules","_parseAttributes","parseAttributes","ATTRIBUTE_NAMES","parsedAttributes","_objectWithoutProperties","_excluded","fromObject","_ref","object","_excluded2","_fromObject","points","extraParam","_defineProperty","cacheProperties","SHARED_ATTRIBUTES","classRegistry","setClass","setSVGClass"],"mappings":"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"}