From 653946c50c1d6d04c953decfd0873fd873bb04bf Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:14:31 +0200 Subject: [PATCH 01/67] svg --- src/parser/parseAttributes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/parseAttributes.ts b/src/parser/parseAttributes.ts index ae02a0e27ea..d17d4b60650 100644 --- a/src/parser/parseAttributes.ts +++ b/src/parser/parseAttributes.ts @@ -16,7 +16,7 @@ import { setStrokeFillOpacity } from './setStrokeFillOpacity'; * @param {Array} attributes Array of attributes to parse * @return {Object} object containing parsed attributes' names/values */ -export function parseAttributes(element, attributes, svgUid) { +export function parseAttributes(element, attributes, svgUid?: string) { if (!element) { return; } From b371499a478ce41e1ac60d1ce17c3e3c1bb571c4 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:14:40 +0200 Subject: [PATCH 02/67] SHARED_ATTRIBUTES --- HEADER.js | 28 ---------------------------- src/parser/attributes.ts | 25 +++++++++++++++++++++++++ src/parser/index.ts | 3 ++- 3 files changed, 27 insertions(+), 29 deletions(-) create mode 100644 src/parser/attributes.ts diff --git a/HEADER.js b/HEADER.js index 6aef6023249..8a59a9b5e1b 100644 --- a/HEADER.js +++ b/HEADER.js @@ -69,34 +69,6 @@ fabric.isTouchSupported = fabric.isLikelyNode = typeof Buffer !== 'undefined' && typeof window === 'undefined'; -/* _FROM_SVG_START_ */ -/** - * Attributes parsed from all SVG elements - * @type array - */ -fabric.SHARED_ATTRIBUTES = [ - 'display', - 'transform', - 'fill', - 'fill-opacity', - 'fill-rule', - 'opacity', - 'stroke', - 'stroke-dasharray', - 'stroke-linecap', - 'stroke-dashoffset', - 'stroke-linejoin', - 'stroke-miterlimit', - 'stroke-opacity', - 'stroke-width', - 'id', - 'paint-order', - 'vector-effect', - 'instantiated_by_use', - 'clip-path', -]; -/* _FROM_SVG_END_ */ - /** * @todo move to config when window is exported */ diff --git a/src/parser/attributes.ts b/src/parser/attributes.ts new file mode 100644 index 00000000000..f16412dcd5a --- /dev/null +++ b/src/parser/attributes.ts @@ -0,0 +1,25 @@ +/** + * Attributes parsed from all SVG elements + * @type array + */ +export const SHARED_ATTRIBUTES = [ + 'display', + 'transform', + 'fill', + 'fill-opacity', + 'fill-rule', + 'opacity', + 'stroke', + 'stroke-dasharray', + 'stroke-linecap', + 'stroke-dashoffset', + 'stroke-linejoin', + 'stroke-miterlimit', + 'stroke-opacity', + 'stroke-width', + 'id', + 'paint-order', + 'vector-effect', + 'instantiated_by_use', + 'clip-path', +]; diff --git a/src/parser/index.ts b/src/parser/index.ts index 18dffc9314f..02646cbfe65 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -1,5 +1,5 @@ -//@ts-nocheck import { fabric } from '../../HEADER'; +import { SHARED_ATTRIBUTES } from './attributes'; import { clipPaths, cssRules, gradientDefs } from './constants'; import { ElementsParser } from './elements_parser'; import { getCSSRules } from './getCSSRules'; @@ -15,6 +15,7 @@ import { parseSVGDocument } from './parseSVGDocument'; import { parseTransformAttribute } from './parseTransformAttribute'; Object.assign(fabric, { + SHARED_ATTRIBUTES, cssRules, gradientDefs, clipPaths, From a71cfc23d6d028600e490a13f20e8f335f9cc427 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:20:37 +0200 Subject: [PATCH 03/67] migrate --- src/shapes/circle.class.ts | 424 ++++++++++++++++++------------------- test/unit/circle.js | 2 +- 2 files changed, 211 insertions(+), 215 deletions(-) diff --git a/src/shapes/circle.class.ts b/src/shapes/circle.class.ts index 690b98db097..a65300c8099 100644 --- a/src/shapes/circle.class.ts +++ b/src/shapes/circle.class.ts @@ -1,232 +1,228 @@ -//@ts-nocheck import { fabric } from '../../HEADER'; +import { SHARED_ATTRIBUTES } from '../parser/attributes'; +import { parseAttributes } from '../parser/parseAttributes'; +import { cos } from '../util/misc/cos'; +import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; +import { sin } from '../util/misc/sin'; import { FabricObject } from './fabricObject.class'; -const degreesToRadians = fabric.util.degreesToRadians; - /** * Circle class * @class Circle * @extends fabric.Object * @see {@link Circle#initialize} for constructor definition */ -const Circle = fabric.util.createClass( - FabricObject, - /** @lends Circle.prototype */ { - /** - * List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged}) - * as well as for history (undo/redo) purposes - * @type Array - */ - stateProperties: FabricObject.prototype.stateProperties.concat( - 'radius', - 'startAngle', - 'endAngle' - ), - - /** - * Type of an object - * @type String - * @default - */ - type: 'circle', - - /** - * Radius of this circle - * @type Number - * @default - */ - radius: 0, - - /** - * degrees of start of the circle. - * probably will change to degrees in next major version - * @type Number 0 - 359 - * @default 0 - */ - startAngle: 0, - - /** - * End angle of the circle - * probably will change to degrees in next major version - * @type Number 1 - 360 - * @default 360 - */ - endAngle: 360, - - cacheProperties: FabricObject.prototype.cacheProperties.concat( - 'radius', - 'startAngle', - 'endAngle' - ), - - /** - * @private - * @param {String} key - * @param {*} value - * @return {Circle} thisArg - */ - _set: function (key, value) { - this.callSuper('_set', key, value); - - if (key === 'radius') { - this.setRadius(value); - } - - return this; - }, - - /** - * @private - * @param {CanvasRenderingContext2D} ctx context to render on - */ - _render: function (ctx) { - ctx.beginPath(); - ctx.arc( - 0, - 0, - this.radius, - degreesToRadians(this.startAngle), - degreesToRadians(this.endAngle), - false - ); - this._renderPaintInOrder(ctx); - }, - - /** - * Returns horizontal radius of an object (according to how an object is scaled) - * @return {Number} - */ - getRadiusX: function () { - return this.get('radius') * this.get('scaleX'); - }, - - /** - * Returns vertical radius of an object (according to how an object is scaled) - * @return {Number} - */ - getRadiusY: function () { - return this.get('radius') * this.get('scaleY'); - }, - - /** - * Sets radius of an object (and updates width accordingly) - * @return {Circle} thisArg - */ - setRadius: function (value) { - this.radius = value; - return this.set('width', value * 2).set('height', value * 2); - }, - - /** - * 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: function (propertiesToInclude) { - return this.callSuper( - 'toObject', - ['radius', 'startAngle', 'endAngle'].concat(propertiesToInclude) - ); - }, - - /* _TO_SVG_START_ */ - - /** - * Returns svg representation of an instance - * @return {Array} an array of strings with the specific svg representation - * of the instance - */ - _toSVG: function () { - const angle = (this.endAngle - this.startAngle) % 360; - - if (angle === 0) { - return [ - '\n', - ]; - } else { - const { radius } = this; - const start = degreesToRadians(this.startAngle), - end = degreesToRadians(this.endAngle), - startX = fabric.util.cos(start) * radius, - startY = fabric.util.sin(start) * radius, - endX = fabric.util.cos(end) * radius, - endY = fabric.util.sin(end) * radius, - largeFlag = angle > 180 ? '1' : '0'; - return [ - '\n', - ]; - } - }, - /* _TO_SVG_END_ */ +export class Circle extends FabricObject { + /** + * Radius of this circle + * @type Number + * @default + */ + radius: number; + + /** + * degrees of start of the circle. + * probably will change to degrees in next major version + * @type Number 0 - 359 + * @default 0 + */ + startAngle: number; + + /** + * End angle of the circle + * probably will change to degrees in next major version + * @type Number 1 - 360 + * @default 360 + */ + endAngle: number; + + /** + * @private + * @param {String} key + * @param {*} value + * @return {Circle} thisArg + */ + _set(key: string, value: any) { + super._set(key, value); + + if (key === 'radius') { + this.setRadius(value); + } + + return this; } -); -/* _FROM_SVG_START_ */ -/** - * List of attribute names to account for when parsing SVG element (used by {@link Circle.fromElement}) - * @static - * @memberOf Circle - * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement - */ -Circle.ATTRIBUTE_NAMES = ['cx', 'cy', 'r', ...fabric.SHARED_ATTRIBUTES]; - -/** - * Returns {@link Circle} instance from an SVG element - * @static - * @memberOf Circle - * @param {SVGElement} element Element to parse - * @param {Function} [callback] Options callback invoked after parsing is finished - * @param {Object} [options] Partial Circle object to default missing properties on the element. - * @throws {Error} If value of `r` attribute is missing or invalid - */ -Circle.fromElement = function (element, callback) { - const { - left = 0, - top = 0, - radius, - ...otherParsedAttributes - } = fabric.parseAttributes(element, Circle.ATTRIBUTE_NAMES); - - if (!radius || radius < 0) { - throw new Error( - 'value of `r` attribute is required and can not be negative' + /** + * @private + * @param {CanvasRenderingContext2D} ctx context to render on + */ + _render(ctx: CanvasRenderingContext2D) { + ctx.beginPath(); + ctx.arc( + 0, + 0, + this.radius, + degreesToRadians(this.startAngle), + degreesToRadians(this.endAngle), + false ); + this._renderPaintInOrder(ctx); } - // this probably requires to be fixed for default origins not being top/left. - callback( - new fabric.Circle({ - ...otherParsedAttributes, - radius, - left: left - radius, - top: top - radius, - }) - ); -}; + /** + * Returns horizontal radius of an object (according to how an object is scaled) + * @return {Number} + */ + getRadiusX(): number { + return this.get('radius') * this.get('scaleX'); + } -/* _FROM_SVG_END_ */ + /** + * Returns vertical radius of an object (according to how an object is scaled) + * @return {Number} + */ + getRadiusY(): number { + return this.get('radius') * this.get('scaleY'); + } -/** - * Returns {@link Circle} instance from an object representation - * @static - * @memberOf Circle - * @param {Object} object Object to create an instance from - * @returns {Promise} - */ -Circle.fromObject = (object) => FabricObject._fromObject(fabric.Circle, object); + /** + * Sets radius of an object (and updates width accordingly) + */ + setRadius(value: number) { + this.radius = value; + this.set({ width: value * 2, height: value * 2 }); + } + + /** + * 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(propertiesToInclude: (keyof this)[] = []): object { + return super.toObject([ + 'radius', + 'startAngle', + 'endAngle', + ...propertiesToInclude, + ]); + } + + /* _TO_SVG_START_ */ + + /** + * Returns svg representation of an instance + * @return {Array} an array of strings with the specific svg representation + * of the instance + */ + _toSVG(): (string | number)[] { + const angle = (this.endAngle - this.startAngle) % 360; + + if (angle === 0) { + return [ + '\n', + ]; + } else { + const { radius } = this; + const start = degreesToRadians(this.startAngle), + end = degreesToRadians(this.endAngle), + startX = cos(start) * radius, + startY = sin(start) * radius, + endX = cos(end) * radius, + endY = sin(end) * radius, + largeFlag = angle > 180 ? '1' : '0'; + return [ + '\n', + ]; + } + } + /* _TO_SVG_END_ */ + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by {@link Circle.fromElement}) + * @static + * @memberOf Circle + * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement + */ + static ATTRIBUTE_NAMES = ['cx', 'cy', 'r', ...SHARED_ATTRIBUTES]; + + /** + * Returns {@link Circle} instance from an SVG element + * @static + * @memberOf Circle + * @param {SVGElement} element Element to parse + * @param {Function} [callback] Options callback invoked after parsing is finished + * @param {Object} [options] Partial Circle object to default missing properties on the element. + * @throws {Error} If value of `r` attribute is missing or invalid + */ + static fromElement = function ( + element: SVGElement, + callback: (circle: Circle) => any + ) { + const { + left = 0, + top = 0, + radius, + ...otherParsedAttributes + } = parseAttributes(element, Circle.ATTRIBUTE_NAMES); + + if (!radius || radius < 0) { + throw new Error( + 'value of `r` attribute is required and can not be negative' + ); + } + + // this probably requires to be fixed for default origins not being top/left. + callback( + new Circle({ + ...otherParsedAttributes, + radius, + left: left - radius, + top: top - radius, + }) + ); + }; + + /* _FROM_SVG_END_ */ + + /** + * Returns {@link Circle} instance from an object representation + * @static + * @memberOf Circle + * @param {Object} object Object to create an instance from + * @returns {Promise} + */ + static fromObject = (object: object): Promise => + FabricObject._fromObject(Circle, object); +} + +Object.assign(Circle.prototype, { + type: 'circle', + radius: 0, + startAngle: 0, + endAngle: 360, + stateProperties: FabricObject.prototype.stateProperties.concat( + 'radius', + 'startAngle', + 'endAngle' + ), + cacheProperties: FabricObject.prototype.cacheProperties.concat( + 'radius', + 'startAngle', + 'endAngle' + ), +}); fabric.Circle = Circle; -export { Circle }; diff --git a/test/unit/circle.js b/test/unit/circle.js index b12575139dd..789a81ec506 100644 --- a/test/unit/circle.js +++ b/test/unit/circle.js @@ -56,7 +56,7 @@ assert.equal(circle.width, 20); assert.equal(circle.height, 20); - assert.equal(circle, circle.setRadius(20)); + circle.setRadius(20); assert.equal(circle.getRadiusX(), 20); assert.equal(circle.getRadiusY(), 20); From e169232e46d194729cfc95ee57a45eb1d3317fe2 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:24:04 +0200 Subject: [PATCH 04/67] Update circle.class.ts --- src/shapes/circle.class.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/shapes/circle.class.ts b/src/shapes/circle.class.ts index a65300c8099..f474820c6ae 100644 --- a/src/shapes/circle.class.ts +++ b/src/shapes/circle.class.ts @@ -6,12 +6,6 @@ import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; import { sin } from '../util/misc/sin'; import { FabricObject } from './fabricObject.class'; -/** - * Circle class - * @class Circle - * @extends fabric.Object - * @see {@link Circle#initialize} for constructor definition - */ export class Circle extends FabricObject { /** * Radius of this circle @@ -40,7 +34,6 @@ export class Circle extends FabricObject { * @private * @param {String} key * @param {*} value - * @return {Circle} thisArg */ _set(key: string, value: any) { super._set(key, value); From b0d03793c19361006dfde7bc1ebd0eb66187391a Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:26:36 +0200 Subject: [PATCH 05/67] Update circle.class.ts --- src/shapes/circle.class.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shapes/circle.class.ts b/src/shapes/circle.class.ts index f474820c6ae..dcef31c82ef 100644 --- a/src/shapes/circle.class.ts +++ b/src/shapes/circle.class.ts @@ -1,6 +1,7 @@ import { fabric } from '../../HEADER'; import { SHARED_ATTRIBUTES } from '../parser/attributes'; import { parseAttributes } from '../parser/parseAttributes'; +import { TClassProperties } from '../typedefs'; import { cos } from '../util/misc/cos'; import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; import { sin } from '../util/misc/sin'; @@ -201,7 +202,7 @@ export class Circle extends FabricObject { FabricObject._fromObject(Circle, object); } -Object.assign(Circle.prototype, { +export const defaultValues: Partial> = { type: 'circle', radius: 0, startAngle: 0, @@ -216,6 +217,8 @@ Object.assign(Circle.prototype, { 'startAngle', 'endAngle' ), -}); +}; + +Object.assign(Circle.prototype, defaultValues); fabric.Circle = Circle; From 4e7e4985b8765791d5753313d4e3cfa903806b85 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:29:49 +0200 Subject: [PATCH 06/67] defaults --- src/shapes/circle.class.ts | 9 +++++---- src/shapes/object.class.ts | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shapes/circle.class.ts b/src/shapes/circle.class.ts index dcef31c82ef..254cf359ccf 100644 --- a/src/shapes/circle.class.ts +++ b/src/shapes/circle.class.ts @@ -6,6 +6,7 @@ import { cos } from '../util/misc/cos'; import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; import { sin } from '../util/misc/sin'; import { FabricObject } from './fabricObject.class'; +import { fabricObjectDefaultValues } from './object.class'; export class Circle extends FabricObject { /** @@ -202,23 +203,23 @@ export class Circle extends FabricObject { FabricObject._fromObject(Circle, object); } -export const defaultValues: Partial> = { +export const circleDefaultValues: Partial> = { type: 'circle', radius: 0, startAngle: 0, endAngle: 360, - stateProperties: FabricObject.prototype.stateProperties.concat( + stateProperties: fabricObjectDefaultValues.stateProperties.concat( 'radius', 'startAngle', 'endAngle' ), - cacheProperties: FabricObject.prototype.cacheProperties.concat( + cacheProperties: fabricObjectDefaultValues.cacheProperties.concat( 'radius', 'startAngle', 'endAngle' ), }; -Object.assign(Circle.prototype, defaultValues); +Object.assign(Circle.prototype, circleDefaultValues); fabric.Circle = Circle; diff --git a/src/shapes/object.class.ts b/src/shapes/object.class.ts index ceeee9e14a7..2be5a720649 100644 --- a/src/shapes/object.class.ts +++ b/src/shapes/object.class.ts @@ -1991,7 +1991,7 @@ export class FabricObject extends ObjectGeometry { } } -const fabricObjectDefaultValues: TClassProperties = { +export const fabricObjectDefaultValues: TClassProperties = { type: 'object', originX: 'left', originY: 'top', From 403d791c9e07bfa387c4205fd2e4af17c8d63656 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:31:13 +0200 Subject: [PATCH 07/67] static --- src/shapes/circle.class.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/shapes/circle.class.ts b/src/shapes/circle.class.ts index 254cf359ccf..dfbb9c83cc1 100644 --- a/src/shapes/circle.class.ts +++ b/src/shapes/circle.class.ts @@ -162,10 +162,7 @@ export class Circle extends FabricObject { * @param {Object} [options] Partial Circle object to default missing properties on the element. * @throws {Error} If value of `r` attribute is missing or invalid */ - static fromElement = function ( - element: SVGElement, - callback: (circle: Circle) => any - ) { + static fromElement(element: SVGElement, callback: (circle: Circle) => any) { const { left = 0, top = 0, @@ -188,7 +185,7 @@ export class Circle extends FabricObject { top: top - radius, }) ); - }; + } /* _FROM_SVG_END_ */ @@ -199,8 +196,9 @@ export class Circle extends FabricObject { * @param {Object} object Object to create an instance from * @returns {Promise} */ - static fromObject = (object: object): Promise => - FabricObject._fromObject(Circle, object); + static fromObject(object: object): Promise { + return FabricObject._fromObject(Circle, object); + } } export const circleDefaultValues: Partial> = { From 575af883da4a1c5e4ac25645fb92cbd7a6a19966 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 10:33:05 +0200 Subject: [PATCH 08/67] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92517990158..d1d38a56c6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [next] +- chore(TS): migrate Circle [#8406](https://github.com/fabricjs/fabric.js/pull/8406) - chore(TS): convert Object interactivity mixin to its own class [#8401](https://github.com/fabricjs/fabric.js/pull/8401) - chore(TS): Convert controls e6/ts [#8400](https://github.com/fabricjs/fabric.js/pull/8400) - ci(): remove buggy changelog action in favor of `git diff` bash script + direct git how to merge `CHANGELOG.md` [#8309](https://github.com/fabricjs/fabric.js/pull/8346) From 8f64f7723e514e53cf3b5194d1d8b859f4f79db3 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 20:43:23 +0200 Subject: [PATCH 09/67] init --- src/shapes/polygon.class.ts | 86 ++---- src/shapes/polyline.class.ts | 578 +++++++++++++++++------------------ 2 files changed, 317 insertions(+), 347 deletions(-) diff --git a/src/shapes/polygon.class.ts b/src/shapes/polygon.class.ts index d388ad5d68c..d4fa9160fdd 100644 --- a/src/shapes/polygon.class.ts +++ b/src/shapes/polygon.class.ts @@ -1,77 +1,51 @@ -//@ts-nocheck - -import { projectStrokeOnPoints } from '../util/misc/projectStroke'; - -(function (global) { - var fabric = global.fabric || (global.fabric = {}); - +export class Polygon extends fabric.Polyline { /** - * Polygon class - * @class fabric.Polygon - * @extends fabric.Polyline - * @see {@link fabric.Polygon#initialize} for constructor definition + * @todo make this method protected when migrating */ - fabric.Polygon = fabric.util.createClass( - fabric.Polyline, - /** @lends fabric.Polygon.prototype */ { - /** - * Type of an object - * @type String - * @default - */ - type: 'polygon', - - /** - * @private - */ - _projectStrokeOnPoints: function () { - return projectStrokeOnPoints(this.points, this); - }, - - /** - * @private - * @param {CanvasRenderingContext2D} ctx Context to render on - */ - _render: function (ctx) { - if (!this.commonRender(ctx)) { - return; - } - ctx.closePath(); - this._renderPaintInOrder(ctx); - }, - } - ); + isOpen() { + return false; + } - /* _FROM_SVG_START_ */ /** - * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`) + * List of attribute names to account for when parsing SVG element (used by `Polygon.fromElement`) * @static - * @memberOf fabric.Polygon + * @memberOf Polygon * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement */ - fabric.Polygon.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(); + static ATTRIBUTE_NAMES = SHARED_ATTRIBUTES.concat(); /** - * Returns {@link fabric.Polygon} instance from an SVG element + * Returns {@link Polygon} instance from an SVG element * @static - * @memberOf fabric.Polygon + * @memberOf Polygon * @param {SVGElement} element Element to parse * @param {Function} callback callback function invoked after parsing * @param {Object} [options] Options object */ - fabric.Polygon.fromElement = fabric.Polyline.fromElementGenerator('Polygon'); - /* _FROM_SVG_END_ */ + static fromElement = fabric.Polyline.fromElementGenerator('Polygon'); /** - * Returns fabric.Polygon instance from an object representation + * Returns Polygon instance from an object representation * @static - * @memberOf fabric.Polygon + * @memberOf Polygon * @param {Object} object Object to create an instance from - * @returns {Promise} + * @returns {Promise} */ - fabric.Polygon.fromObject = function (object) { - return fabric.Object._fromObject(fabric.Polygon, object, { + static fromObject(object) { + return FabricObject._fromObject(Polygon, object, { extraParam: 'points', }); - }; -})(typeof exports !== 'undefined' ? exports : window); + } +} + +export const polygonDefaultValues: Partial> = { + type: 'polygon', +}; + +Object.assign(Polygon.prototype, polygonDefaultValues); +/** @todo TODO_JS_MIGRATION remove next line after refactoring build */ +fabric.Polygon = Polygon; + +/* _FROM_SVG_START_ */ + +/* _FROM_SVG_END_ */ diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index 6584e0348f0..9908d3e1a42 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -1,318 +1,292 @@ -//@ts-nocheck - +import { fabric } from '../../HEADER'; import { config } from '../config'; import { parseAttributes } from '../parser/parseAttributes'; import { parsePointsAttribute } from '../parser/parsePointsAttribute'; import { Point } from '../point.class'; +import { TClassProperties } from '../typedefs'; import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints'; import { projectStrokeOnPoints } from '../util/misc/projectStroke'; import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; +import { toFixed } from '../util/misc/toFixed'; +import { FabricObject } from './object.class'; -(function (global) { - var fabric = global.fabric || (global.fabric = {}), - extend = fabric.util.object.extend, - toFixed = fabric.util.toFixed; - +export class Polyline extends FabricObject { /** - * Polyline class - * @class fabric.Polyline - * @extends fabric.Object - * @see {@link fabric.Polyline#initialize} for constructor definition + * Points array + * @type Array + * @default */ - fabric.Polyline = fabric.util.createClass( - fabric.Object, - /** @lends fabric.Polyline.prototype */ { - /** - * Type of an object - * @type String - * @default - */ - type: 'polyline', - - /** - * Points array - * @type Array - * @default - */ - points: null, - - /** - * WARNING: Feature in progress - * Calculate the exact bounding box taking in account strokeWidth on acute angles - * this will be turned to true by default on fabric 6.0 - * maybe will be left in as an optimization since calculations may be slow - * @deprecated - * @type Boolean - * @default false - * @todo set default to true and remove flag and related logic - */ - exactBoundingBox: false, + points: Point[]; - initialized: false, - - cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'), + /** + * WARNING: Feature in progress + * Calculate the exact bounding box taking in account strokeWidth on acute angles + * this will be turned to true by default on fabric 6.0 + * maybe will be left in as an optimization since calculations may be slow + * @deprecated + * @type Boolean + * @default false + * @todo set default to true and remove flag and related logic + */ + exactBoundingBox: boolean; - /** - * A list of properties that if changed trigger a recalculation of dimensions - * @todo check if you really need to recalculate for all cases - */ - strokeBBoxAffectingProperties: [ - 'skewX', - 'skewY', - 'strokeLineCap', - 'strokeLineJoin', - 'strokeMiterLimit', - 'strokeWidth', - 'strokeUniform', - 'points', - ], + initialized: boolean; - /** - * Constructor - * @param {Array} points Array of points (where each point is an object with x and y) - * @param {Object} [options] Options object - * @return {fabric.Polyline} thisArg - * @example - * var poly = new fabric.Polyline([ - * { x: 10, y: 10 }, - * { x: 50, y: 30 }, - * { x: 40, y: 70 }, - * { x: 60, y: 50 }, - * { x: 100, y: 150 }, - * { x: 40, y: 100 } - * ], { - * stroke: 'red', - * left: 100, - * top: 100 - * }); - */ - initialize: function (points, options = {}) { - this.points = points || []; - this.callSuper('initialize', options); - this.initialized = true; - const bboxTL = this.setDimensions(); - const origin = this.translateToGivenOrigin( - new Point(options.left ?? bboxTL.x, options.top ?? bboxTL.y), - typeof options.left === 'number' ? this.originX : 'left', - typeof options.top === 'number' ? this.originY : 'top', - this.originX, - this.originY - ); - this.setPositionByOrigin(origin, this.originX, this.originY); - }, + /** + * A list of properties that if changed trigger a recalculation of dimensions + * @todo check if you really need to recalculate for all cases + */ + strokeBBoxAffectingProperties: (keyof this)[]; - /** - * @private - */ - _projectStrokeOnPoints: function () { - return projectStrokeOnPoints(this.points, this, true); - }, + /** + * Constructor + * @param {Array} points Array of points (where each point is an object with x and y) + * @param {Object} [options] Options object + * @return {Polyline} thisArg + * @example + * var poly = new Polyline([ + * { x: 10, y: 10 }, + * { x: 50, y: 30 }, + * { x: 40, y: 70 }, + * { x: 60, y: 50 }, + * { x: 100, y: 150 }, + * { x: 40, y: 100 } + * ], { + * stroke: 'red', + * left: 100, + * top: 100 + * }); + */ + constructor(points: Point[] = [], options = {}) { + super({ points, ...options }); + this.initialized = true; + const bboxTL = this.setDimensions(); + const origin = this.translateToGivenOrigin( + new Point(options.left ?? bboxTL.x, options.top ?? bboxTL.y), + typeof options.left === 'number' ? this.originX : 'left', + typeof options.top === 'number' ? this.originY : 'top', + this.originX, + this.originY + ); + this.setPositionByOrigin(origin, this.originX, this.originY); + } - /** - * Calculate the polygon bounding box - * @private - */ - _calcDimensions: function () { - const points = this.exactBoundingBox - ? this._projectStrokeOnPoints().map( - (projection) => projection.projectedPoint - ) - : this.points; - if (points.length === 0) { - return { - left: 0, - top: 0, - width: 0, - height: 0, - pathOffset: new Point(), - }; - } - const bbox = makeBoundingBoxFromPoints(points); - const bboxNoStroke = makeBoundingBoxFromPoints(this.points); - const offsetX = bbox.left + bbox.width / 2, - offsetY = bbox.top + bbox.height / 2; - const pathOffsetX = - offsetX - offsetY * Math.tan(degreesToRadians(this.skewX)); - const pathOffsetY = - offsetY - pathOffsetX * Math.tan(degreesToRadians(this.skewY)); - // TODO: remove next line - const legacyCorrection = - !this.fromSVG && !this.exactBoundingBox ? this.strokeWidth / 2 : 0; - return { - ...bbox, - left: bbox.left - legacyCorrection, - top: bbox.top - legacyCorrection, - pathOffset: new Point(pathOffsetX, pathOffsetY), - strokeOffset: new Point(bboxNoStroke.left, bboxNoStroke.top).subtract( - bbox.left, - bbox.top - ), - }; - }, + /** + * @private + */ + _projectStrokeOnPoints() { + return projectStrokeOnPoints(this.points, this, true); + } - /** - * @returns {Point} top left position of the bounding box, useful for complementary positioning - */ - setDimensions: function () { - const { left, top, width, height, pathOffset, strokeOffset } = - this._calcDimensions(); - this.set({ width, height, pathOffset, strokeOffset }); - return new Point(left, top); - }, + /** + * Calculate the polygon bounding box + * @private + */ + _calcDimensions() { + const points = this.exactBoundingBox + ? this._projectStrokeOnPoints().map( + (projection) => projection.projectedPoint + ) + : this.points; + if (points.length === 0) { + return { + left: 0, + top: 0, + width: 0, + height: 0, + pathOffset: new Point(), + }; + } + const bbox = makeBoundingBoxFromPoints(points); + const bboxNoStroke = makeBoundingBoxFromPoints(this.points); + const offsetX = bbox.left + bbox.width / 2, + offsetY = bbox.top + bbox.height / 2; + const pathOffsetX = + offsetX - offsetY * Math.tan(degreesToRadians(this.skewX)); + const pathOffsetY = + offsetY - pathOffsetX * Math.tan(degreesToRadians(this.skewY)); + // TODO: remove next line + const legacyCorrection = + !this.fromSVG && !this.exactBoundingBox ? this.strokeWidth / 2 : 0; + return { + ...bbox, + left: bbox.left - legacyCorrection, + top: bbox.top - legacyCorrection, + pathOffset: new Point(pathOffsetX, pathOffsetY), + strokeOffset: new Point(bboxNoStroke.left, bboxNoStroke.top).subtract( + bbox.left, + bbox.top + ), + }; + } - /** - * @override stroke is taken in account in size - */ - _getNonTransformedDimensions: function () { - return this.exactBoundingBox - ? new Point(this.width, this.height) - : this.callSuper('_getNonTransformedDimensions'); - }, + /** + * @returns {Point} top left position of the bounding box, useful for complementary positioning + */ + setDimensions() { + const { left, top, width, height, pathOffset, strokeOffset } = + this._calcDimensions(); + this.set({ width, height, pathOffset, strokeOffset }); + return new Point(left, top); + } - /** - * @override stroke and skewing are taken into account when projecting stroke on points, - * therefore we don't want the default calculation to account for skewing as well - * - * @private - */ - _getTransformedDimensions: function (options) { - return this.exactBoundingBox - ? this.callSuper('_getTransformedDimensions', { - ...(options || {}), - // disable stroke bbox calculations - strokeWidth: 0, - // disable skewing bbox calculations - skewX: 0, - skewY: 0, - }) - : this.callSuper('_getTransformedDimensions', options); - }, + /** + * @override stroke is taken in account in size + */ + _getNonTransformedDimensions() { + return this.exactBoundingBox + ? new Point(this.width, this.height) + : super._getNonTransformedDimensions(); + } - /** - * Recalculates dimensions when changing skew and scale - * @private - */ - _set: function (key, value) { - const changed = this.initialized && this[key] !== value; - const output = this.callSuper('_set', key, value); - if ( - changed && - (((key === 'scaleX' || key === 'scaleY') && - this.strokeUniform && - this.strokeBBoxAffectingProperties.includes('strokeUniform') && - this.strokeLineJoin !== 'round') || - this.strokeBBoxAffectingProperties.includes(key)) - ) { - this.setDimensions(); - } - return output; - }, + /** + * @override stroke and skewing are taken into account when projecting stroke on points, + * therefore we don't want the default calculation to account for skewing as well + * + * @private + */ + _getTransformedDimensions(options) { + return this.exactBoundingBox + ? super._getTransformedDimensions({ + ...(options || {}), + // disable stroke bbox calculations + strokeWidth: 0, + // disable skewing bbox calculations + skewX: 0, + skewY: 0, + }) + : super._getTransformedDimensions(options); + } - /** - * 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: function (propertiesToInclude) { - return extend(this.callSuper('toObject', propertiesToInclude), { - points: this.points.concat(), - }); - }, + /** + * Recalculates dimensions when changing skew and scale + * @private + */ + _set(key, value) { + const changed = this.initialized && this[key] !== value; + const output = super._set(key, value); + if ( + changed && + (((key === 'scaleX' || key === 'scaleY') && + this.strokeUniform && + this.strokeBBoxAffectingProperties.includes('strokeUniform') && + this.strokeLineJoin !== 'round') || + this.strokeBBoxAffectingProperties.includes(key)) + ) { + this.setDimensions(); + } + return output; + } - /* _TO_SVG_START_ */ - /** - * Returns svg representation of an instance - * @return {Array} an array of strings with the specific svg representation - * of the instance - */ - _toSVG: function () { - var points = [], - diffX = this.pathOffset.x, - diffY = this.pathOffset.y, - NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS; + /** + * 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(propertiesToInclude) { + return { + ...super.toObject(propertiesToInclude), + points: this.points.concat(), + }; + } - for (var i = 0, len = this.points.length; i < len; i++) { - points.push( - toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), - ',', - toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), - ' ' - ); - } - return [ - '<' + this.type + ' ', - 'COMMON_PARTS', - 'points="', - points.join(''), - '" />\n', - ]; - }, - /* _TO_SVG_END_ */ + /** + * Returns svg representation of an instance + * @return {Array} an array of strings with the specific svg representation + * of the instance + */ + _toSVG() { + var points = [], + diffX = this.pathOffset.x, + diffY = this.pathOffset.y, + NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS; - /** - * @private - * @param {CanvasRenderingContext2D} ctx Context to render on - */ - commonRender: function (ctx) { - var point, - len = this.points.length, - x = this.pathOffset.x, - y = this.pathOffset.y; + for (var i = 0, len = this.points.length; i < len; i++) { + points.push( + toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), + ',', + toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), + ' ' + ); + } + return [ + '<' + this.type + ' ', + 'COMMON_PARTS', + 'points="', + points.join(''), + '" />\n', + ]; + } - if (!len || isNaN(this.points[len - 1].y)) { - // do not draw if no points or odd points - // NaN comes from parseFloat of a empty string in parser - return false; - } - ctx.beginPath(); - ctx.moveTo(this.points[0].x - x, this.points[0].y - y); - for (var i = 0; i < len; i++) { - point = this.points[i]; - ctx.lineTo(point.x - x, point.y - y); - } - return true; - }, + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + commonRender(ctx) { + var point, + len = this.points.length, + x = this.pathOffset.x, + y = this.pathOffset.y; - /** - * @private - * @param {CanvasRenderingContext2D} ctx Context to render on - */ - _render: function (ctx) { - if (!this.commonRender(ctx)) { - return; - } - this._renderPaintInOrder(ctx); - }, + if (!len || isNaN(this.points[len - 1].y)) { + // do not draw if no points or odd points + // NaN comes from parseFloat of a empty string in parser + return false; + } + ctx.beginPath(); + ctx.moveTo(this.points[0].x - x, this.points[0].y - y); + for (var i = 0; i < len; i++) { + point = this.points[i]; + ctx.lineTo(point.x - x, point.y - y); + } + return true; + } - /** - * Returns complexity of an instance - * @return {Number} complexity of this instance - */ - complexity: function () { - return this.get('points').length; - }, + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _render(ctx) { + if (!this.commonRender(ctx)) { + return; } - ); + this._renderPaintInOrder(ctx); + } - /* _FROM_SVG_START_ */ /** - * List of attribute names to account for when parsing SVG element (used by {@link fabric.Polyline.fromElement}) + * Returns complexity of an instance + * @return {Number} complexity of this instance + */ + complexity() { + return this.get('points').length; + } + + /** + * List of attribute names to account for when parsing SVG element (used by {@link Polyline.fromElement}) * @static - * @memberOf fabric.Polyline + * @memberOf Polyline * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement */ - fabric.Polyline.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(); + static ATTRIBUTE_NAMES = [...SHARED_ATTRIBUTES]; + + static fromElement = Polyline.fromElementGenerator('Polyline'); /** - * Returns fabric.Polyline instance from an SVG element + * Returns Polyline instance from an SVG element * @static - * @memberOf fabric.Polyline + * @memberOf Polyline * @param {SVGElement} element Element to parser * @param {Function} callback callback function invoked after parsing * @param {Object} [options] Options object */ - fabric.Polyline.fromElementGenerator = function (_class) { - return function (element, callback, options = {}) { + static fromElementGenerator< + K extends { new (points: Point[], options: any): InstanceType } + >(klass: K) { + return function ( + element: SVGElement, + callback: (poly: InstanceType) => any, + options = {} + ) { if (!element) { return callback(null); } @@ -321,33 +295,55 @@ import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; // eslint-disable-next-line @typescript-eslint/no-unused-vars { left, top, ...parsedAttributes } = parseAttributes( element, - fabric[_class].ATTRIBUTE_NAMES + klass.ATTRIBUTE_NAMES ); callback( - new fabric[_class](points, { + new klass(points, { ...parsedAttributes, ...options, fromSVG: true, }) ); }; - }; - - fabric.Polyline.fromElement = - fabric.Polyline.fromElementGenerator('Polyline'); - - /* _FROM_SVG_END_ */ + } /** - * Returns fabric.Polyline instance from an object representation + * Returns Polyline instance from an object representation * @static - * @memberOf fabric.Polyline + * @memberOf Polyline * @param {Object} object Object to create an instance from - * @returns {Promise} + * @returns {Promise} */ - fabric.Polyline.fromObject = function (object) { - return fabric.Object._fromObject(fabric.Polyline, object, { + static fromObject(object) { + return FabricObject._fromObject(Polyline, object, { extraParam: 'points', }); - }; -})(typeof exports !== 'undefined' ? exports : window); + } +} + +export const polylineDefaultValues: Partial> = { + type: 'polyline', + points: [], + exactBoundingBox: false, + initialized: false, + cacheProperties: FabricObject.prototype.cacheProperties.concat('points'), + strokeBBoxAffectingProperties: [ + 'skewX', + 'skewY', + 'strokeLineCap', + 'strokeLineJoin', + 'strokeMiterLimit', + 'strokeWidth', + 'strokeUniform', + 'points', + ], +}; + +Object.assign(Polyline.prototype, polylineDefaultValues); + +/** @todo TODO_JS_MIGRATION remove next line after refactoring build */ +fabric.Polyline = Polyline; + +/* _FROM_SVG_START_ */ + +/* _FROM_SVG_END_ */ From ec4ac19c138d0b161c97c23fe1d6fe553228e656 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 31 Oct 2022 20:46:49 +0200 Subject: [PATCH 10/67] more --- src/shapes/polygon.class.ts | 18 ++++++++++++------ src/shapes/polyline.class.ts | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/shapes/polygon.class.ts b/src/shapes/polygon.class.ts index d4fa9160fdd..2815652eb44 100644 --- a/src/shapes/polygon.class.ts +++ b/src/shapes/polygon.class.ts @@ -1,4 +1,10 @@ -export class Polygon extends fabric.Polyline { +import { fabric } from '../../HEADER'; +import { SHARED_ATTRIBUTES } from '../parser/attributes'; +import { TClassProperties } from '../typedefs'; +import { FabricObject } from './object.class'; +import { Polyline } from './polyline.class'; + +export class Polygon extends Polyline { /** * @todo make this method protected when migrating */ @@ -6,6 +12,8 @@ export class Polygon extends fabric.Polyline { return false; } + /* _FROM_SVG_START_ */ + /** * List of attribute names to account for when parsing SVG element (used by `Polygon.fromElement`) * @static @@ -22,7 +30,9 @@ export class Polygon extends fabric.Polyline { * @param {Function} callback callback function invoked after parsing * @param {Object} [options] Options object */ - static fromElement = fabric.Polyline.fromElementGenerator('Polygon'); + static fromElement = Polyline.fromElementGenerator(Polygon); + + /* _FROM_SVG_END_ */ /** * Returns Polygon instance from an object representation @@ -45,7 +55,3 @@ export const polygonDefaultValues: Partial> = { Object.assign(Polygon.prototype, polygonDefaultValues); /** @todo TODO_JS_MIGRATION remove next line after refactoring build */ fabric.Polygon = Polygon; - -/* _FROM_SVG_START_ */ - -/* _FROM_SVG_END_ */ diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index 9908d3e1a42..e023bdaa212 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -1,5 +1,6 @@ import { fabric } from '../../HEADER'; import { config } from '../config'; +import { SHARED_ATTRIBUTES } from '../parser/attributes'; import { parseAttributes } from '../parser/parseAttributes'; import { parsePointsAttribute } from '../parser/parsePointsAttribute'; import { Point } from '../point.class'; @@ -269,7 +270,7 @@ export class Polyline extends FabricObject { */ static ATTRIBUTE_NAMES = [...SHARED_ATTRIBUTES]; - static fromElement = Polyline.fromElementGenerator('Polyline'); + static fromElement = Polyline.fromElementGenerator(Polyline); /** * Returns Polyline instance from an SVG element From 1c21ea14706975baa7836b255478e2dcb17feebe Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 22:15:02 +0200 Subject: [PATCH 11/67] m --- src/shapes/polygon.class.ts | 5 +---- src/shapes/polyline.class.ts | 41 ++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/shapes/polygon.class.ts b/src/shapes/polygon.class.ts index 2815652eb44..03b84e0c27c 100644 --- a/src/shapes/polygon.class.ts +++ b/src/shapes/polygon.class.ts @@ -5,10 +5,7 @@ import { FabricObject } from './object.class'; import { Polyline } from './polyline.class'; export class Polygon extends Polyline { - /** - * @todo make this method protected when migrating - */ - isOpen() { + protected isOpen() { return false; } diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index e023bdaa212..c4d13192c80 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -58,7 +58,7 @@ export class Polyline extends FabricObject { * top: 100 * }); */ - constructor(points: Point[] = [], options = {}) { + constructor(points: Point[] = [], options: object = {}): Polyline { super({ points, ...options }); this.initialized = true; const bboxTL = this.setDimensions(); @@ -72,11 +72,12 @@ export class Polyline extends FabricObject { this.setPositionByOrigin(origin, this.originX, this.originY); } - /** - * @private - */ - _projectStrokeOnPoints() { - return projectStrokeOnPoints(this.points, this, true); + protected isOpen() { + return true; + } + + private _projectStrokeOnPoints() { + return projectStrokeOnPoints(this.points, this, this.isOpen); } /** @@ -124,7 +125,7 @@ export class Polyline extends FabricObject { /** * @returns {Point} top left position of the bounding box, useful for complementary positioning */ - setDimensions() { + setDimensions(): Point { const { left, top, width, height, pathOffset, strokeOffset } = this._calcDimensions(); this.set({ width, height, pathOffset, strokeOffset }); @@ -184,7 +185,7 @@ export class Polyline extends FabricObject { * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output * @return {Object} Object representation of an instance */ - toObject(propertiesToInclude) { + toObject(propertiesToInclude: Array): object { return { ...super.toObject(propertiesToInclude), points: this.points.concat(), @@ -196,13 +197,13 @@ export class Polyline extends FabricObject { * @return {Array} an array of strings with the specific svg representation * of the instance */ - _toSVG() { - var points = [], + _toSVG(): Array { + const points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y, NUM_FRACTION_DIGITS = config.NUM_FRACTION_DIGITS; - for (var i = 0, len = this.points.length; i < len; i++) { + for (let i = 0, len = this.points.length; i < len; i++) { points.push( toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',', @@ -223,8 +224,8 @@ export class Polyline extends FabricObject { * @private * @param {CanvasRenderingContext2D} ctx Context to render on */ - commonRender(ctx) { - var point, + commonRender(ctx: CanvasRenderingContext2D) { + let point, len = this.points.length, x = this.pathOffset.x, y = this.pathOffset.y; @@ -236,7 +237,7 @@ export class Polyline extends FabricObject { } ctx.beginPath(); ctx.moveTo(this.points[0].x - x, this.points[0].y - y); - for (var i = 0; i < len; i++) { + for (let i = 0; i < len; i++) { point = this.points[i]; ctx.lineTo(point.x - x, point.y - y); } @@ -247,7 +248,7 @@ export class Polyline extends FabricObject { * @private * @param {CanvasRenderingContext2D} ctx Context to render on */ - _render(ctx) { + _render(ctx: CanvasRenderingContext2D) { if (!this.commonRender(ctx)) { return; } @@ -258,8 +259,8 @@ export class Polyline extends FabricObject { * Returns complexity of an instance * @return {Number} complexity of this instance */ - complexity() { - return this.get('points').length; + complexity(): number { + return this.points.length; } /** @@ -280,9 +281,7 @@ export class Polyline extends FabricObject { * @param {Function} callback callback function invoked after parsing * @param {Object} [options] Options object */ - static fromElementGenerator< - K extends { new (points: Point[], options: any): InstanceType } - >(klass: K) { + static fromElementGenerator(klass: K) { return function ( element: SVGElement, callback: (poly: InstanceType) => any, @@ -315,7 +314,7 @@ export class Polyline extends FabricObject { * @param {Object} object Object to create an instance from * @returns {Promise} */ - static fromObject(object) { + static fromObject(object: object): Promise { return FabricObject._fromObject(Polyline, object, { extraParam: 'points', }); From 4ba47fa5556ba27d952f281822147567ed1550e6 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 22:29:13 +0200 Subject: [PATCH 12/67] poly --- src/parser/parsePointsAttribute.ts | 15 +++++++-------- src/shapes/polyline.class.ts | 20 +++++++++++++------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/parser/parsePointsAttribute.ts b/src/parser/parsePointsAttribute.ts index 1ac59752231..636f4c6ac9c 100644 --- a/src/parser/parsePointsAttribute.ts +++ b/src/parser/parsePointsAttribute.ts @@ -1,5 +1,7 @@ //@ts-nocheck +import { Point } from '../point.class'; + /** * Parses "points" attribute, returning an array of values * @static @@ -17,15 +19,12 @@ export function parsePointsAttribute(points) { points = points.replace(/,/g, ' ').trim(); points = points.split(/\s+/); - let parsedPoints = [], - i, - len; + const parsedPoints: Point[] = []; - for (i = 0, len = points.length; i < len; i += 2) { - parsedPoints.push({ - x: parseFloat(points[i]), - y: parseFloat(points[i + 1]), - }); + for (let i = 0; i < points.length; i += 2) { + parsedPoints.push( + new Point(parseFloat(points[i]), parseFloat(points[i + 1])) + ); } // odd number of points is an error diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index c4d13192c80..41c24ff85f2 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -38,6 +38,8 @@ export class Polyline extends FabricObject { * @todo check if you really need to recalculate for all cases */ strokeBBoxAffectingProperties: (keyof this)[]; + fromSVG: boolean; + pathOffset: Point; /** * Constructor @@ -58,7 +60,7 @@ export class Polyline extends FabricObject { * top: 100 * }); */ - constructor(points: Point[] = [], options: object = {}): Polyline { + constructor(points: Point[] = [], options: any = {}) { super({ points, ...options }); this.initialized = true; const bboxTL = this.setDimensions(); @@ -116,8 +118,7 @@ export class Polyline extends FabricObject { top: bbox.top - legacyCorrection, pathOffset: new Point(pathOffsetX, pathOffsetY), strokeOffset: new Point(bboxNoStroke.left, bboxNoStroke.top).subtract( - bbox.left, - bbox.top + new Point(bbox.left, bbox.top) ), }; } @@ -197,7 +198,7 @@ export class Polyline extends FabricObject { * @return {Array} an array of strings with the specific svg representation * of the instance */ - _toSVG(): Array { + _toSVG() { const points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y, @@ -281,10 +282,15 @@ export class Polyline extends FabricObject { * @param {Function} callback callback function invoked after parsing * @param {Object} [options] Options object */ - static fromElementGenerator(klass: K) { + static fromElementGenerator< + T extends { + new (points: Point[], options: any): any; + ATTRIBUTE_NAMES: string[]; + } + >(klass: T) { return function ( element: SVGElement, - callback: (poly: InstanceType) => any, + callback: (poly: InstanceType) => any, options = {} ) { if (!element) { @@ -298,7 +304,7 @@ export class Polyline extends FabricObject { klass.ATTRIBUTE_NAMES ); callback( - new klass(points, { + new klass(points || [], { ...parsedAttributes, ...options, fromSVG: true, From c66798cfb7e65c98653f76c4645a649d293f25b4 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 22:30:14 +0200 Subject: [PATCH 13/67] Update polyline.class.ts --- src/shapes/polyline.class.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index 41c24ff85f2..a1fcbbecdc9 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -253,6 +253,7 @@ export class Polyline extends FabricObject { if (!this.commonRender(ctx)) { return; } + !this.isOpen() && ctx.closePath(); this._renderPaintInOrder(ctx); } From 63442ff41093e758de62a3d95c0dd29f92b5a13b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 22:43:16 +0200 Subject: [PATCH 14/67] more --- src/mixins/object_origin.mixin.ts | 4 ++-- src/shapes/object.class.ts | 6 +++--- src/shapes/polygon.class.ts | 11 +---------- src/shapes/polyline.class.ts | 16 ++++++++-------- 4 files changed, 14 insertions(+), 23 deletions(-) diff --git a/src/mixins/object_origin.mixin.ts b/src/mixins/object_origin.mixin.ts index 37ac9e11afe..f5b12cc465f 100644 --- a/src/mixins/object_origin.mixin.ts +++ b/src/mixins/object_origin.mixin.ts @@ -1,10 +1,10 @@ import { Point } from '../point.class'; import { transformPoint } from '../util/misc/matrix'; import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; -import { CommonMethods } from './shared_methods.mixin'; -import { TDegree, TOriginX, TOriginY } from '../typedefs'; import { Group } from '../shapes/group.class'; +import { TDegree, TOriginX, TOriginY } from '../typedefs'; import { sizeAfterTransform } from '../util/misc/objectTransforms'; +import { CommonMethods } from './shared_methods.mixin'; const originOffset = { left: -0.5, diff --git a/src/shapes/object.class.ts b/src/shapes/object.class.ts index 2be5a720649..52379133a1d 100644 --- a/src/shapes/object.class.ts +++ b/src/shapes/object.class.ts @@ -235,14 +235,14 @@ export class FabricObject extends ObjectGeometry { * @type String * @default butt */ - strokeLineCap: string; + strokeLineCap: CanvasLineCap; /** * Corner style of an object's stroke (one of "bevel", "round", "miter") * @type String * @default */ - strokeLineJoin: string; + strokeLineJoin: CanvasLineJoin; /** * Maximum miter length (used for strokeLineJoin = "miter") of an object's stroke @@ -1012,7 +1012,7 @@ export class FabricObject extends ObjectGeometry { * @param {*} value * @return {fabric.Object} thisArg */ - _set(key: string, value: any) { + _set(key: K, value: V) { const shouldConstrainValue = key === 'scaleX' || key === 'scaleY', isChanged = this[key] !== value; diff --git a/src/shapes/polygon.class.ts b/src/shapes/polygon.class.ts index 03b84e0c27c..f8ad577c8f0 100644 --- a/src/shapes/polygon.class.ts +++ b/src/shapes/polygon.class.ts @@ -1,5 +1,4 @@ import { fabric } from '../../HEADER'; -import { SHARED_ATTRIBUTES } from '../parser/attributes'; import { TClassProperties } from '../typedefs'; import { FabricObject } from './object.class'; import { Polyline } from './polyline.class'; @@ -11,14 +10,6 @@ export class Polygon extends Polyline { /* _FROM_SVG_START_ */ - /** - * List of attribute names to account for when parsing SVG element (used by `Polygon.fromElement`) - * @static - * @memberOf Polygon - * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement - */ - static ATTRIBUTE_NAMES = SHARED_ATTRIBUTES.concat(); - /** * Returns {@link Polygon} instance from an SVG element * @static @@ -38,7 +29,7 @@ export class Polygon extends Polyline { * @param {Object} object Object to create an instance from * @returns {Promise} */ - static fromObject(object) { + static fromObject(object: any) { return FabricObject._fromObject(Polygon, object, { extraParam: 'points', }); diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index a1fcbbecdc9..d6e98444c9a 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -79,7 +79,7 @@ export class Polyline extends FabricObject { } private _projectStrokeOnPoints() { - return projectStrokeOnPoints(this.points, this, this.isOpen); + return projectStrokeOnPoints(this.points, this, this.isOpen()); } /** @@ -99,6 +99,7 @@ export class Polyline extends FabricObject { width: 0, height: 0, pathOffset: new Point(), + strokeOffset: new Point(), }; } const bbox = makeBoundingBoxFromPoints(points); @@ -148,7 +149,7 @@ export class Polyline extends FabricObject { * * @private */ - _getTransformedDimensions(options) { + _getTransformedDimensions(options: any) { return this.exactBoundingBox ? super._getTransformedDimensions({ ...(options || {}), @@ -165,7 +166,7 @@ export class Polyline extends FabricObject { * Recalculates dimensions when changing skew and scale * @private */ - _set(key, value) { + _set(key: K, value: V) { const changed = this.initialized && this[key] !== value; const output = super._set(key, value); if ( @@ -186,7 +187,7 @@ export class Polyline extends FabricObject { * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output * @return {Object} Object representation of an instance */ - toObject(propertiesToInclude: Array): object { + toObject(propertiesToInclude: (keyof this)[]): object { return { ...super.toObject(propertiesToInclude), points: this.points.concat(), @@ -226,8 +227,7 @@ export class Polyline extends FabricObject { * @param {CanvasRenderingContext2D} ctx Context to render on */ commonRender(ctx: CanvasRenderingContext2D) { - let point, - len = this.points.length, + const len = this.points.length, x = this.pathOffset.x, y = this.pathOffset.y; @@ -239,7 +239,7 @@ export class Polyline extends FabricObject { ctx.beginPath(); ctx.moveTo(this.points[0].x - x, this.points[0].y - y); for (let i = 0; i < len; i++) { - point = this.points[i]; + const point = this.points[i]; ctx.lineTo(point.x - x, point.y - y); } return true; @@ -291,7 +291,7 @@ export class Polyline extends FabricObject { >(klass: T) { return function ( element: SVGElement, - callback: (poly: InstanceType) => any, + callback: (poly: InstanceType | null) => any, options = {} ) { if (!element) { From fd2afa64b9b644ff68cd6c9f8c392d0ee52fdd6a Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 22:48:26 +0200 Subject: [PATCH 15/67] unpleasant --- src/shapes/object.class.ts | 2 +- src/shapes/polyline.class.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shapes/object.class.ts b/src/shapes/object.class.ts index 52379133a1d..1a3ad04d2c6 100644 --- a/src/shapes/object.class.ts +++ b/src/shapes/object.class.ts @@ -1012,7 +1012,7 @@ export class FabricObject extends ObjectGeometry { * @param {*} value * @return {fabric.Object} thisArg */ - _set(key: K, value: V) { + _set(key: string, value: any) { const shouldConstrainValue = key === 'scaleX' || key === 'scaleY', isChanged = this[key] !== value; diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index d6e98444c9a..e5dc538f853 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -166,8 +166,8 @@ export class Polyline extends FabricObject { * Recalculates dimensions when changing skew and scale * @private */ - _set(key: K, value: V) { - const changed = this.initialized && this[key] !== value; + _set(key: string, value: any) { + const changed = this.initialized && this[key as keyof this] !== value; const output = super._set(key, value); if ( changed && @@ -175,7 +175,7 @@ export class Polyline extends FabricObject { this.strokeUniform && this.strokeBBoxAffectingProperties.includes('strokeUniform') && this.strokeLineJoin !== 'round') || - this.strokeBBoxAffectingProperties.includes(key)) + this.strokeBBoxAffectingProperties.includes(key as keyof this)) ) { this.setDimensions(); } From 4b6cc542c542d9bbc003de74ac141db89467b64d Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 22:51:38 +0200 Subject: [PATCH 16/67] imports --- src/shapes/polyline.class.ts | 5 +++-- test/unit/polygon.js | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index e5dc538f853..ab689747e1c 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -9,7 +9,8 @@ import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints'; import { projectStrokeOnPoints } from '../util/misc/projectStroke'; import { degreesToRadians } from '../util/misc/radiansDegreesConversion'; import { toFixed } from '../util/misc/toFixed'; -import { FabricObject } from './object.class'; +import { FabricObject } from './fabricObject.class'; +import { fabricObjectDefaultValues } from './object.class'; export class Polyline extends FabricObject { /** @@ -333,7 +334,7 @@ export const polylineDefaultValues: Partial> = { points: [], exactBoundingBox: false, initialized: false, - cacheProperties: FabricObject.prototype.cacheProperties.concat('points'), + cacheProperties: fabricObjectDefaultValues.cacheProperties.concat('points'), strokeBBoxAffectingProperties: [ 'skewX', 'skewY', diff --git a/test/unit/polygon.js b/test/unit/polygon.js index c91493341c9..bda87ead65a 100644 --- a/test/unit/polygon.js +++ b/test/unit/polygon.js @@ -58,6 +58,7 @@ var polygon = new fabric.Polygon(getPoints()); assert.ok(polygon instanceof fabric.Polygon); + assert.ok(polygon instanceof fabric.Polyline); assert.ok(polygon instanceof fabric.Object); assert.equal(polygon.type, 'polygon'); From 535fee06bb177a98b2cc6f63b290061d0eb2f8e3 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 22:54:22 +0200 Subject: [PATCH 17/67] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77fa33d7b28..bff53526c69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## [next] -- chore(TS): migrate Circle [#8406](https://github.com/fabricjs/fabric.js/pull/8406) +- chore(TS): migrate Polyline/Polygon [#8417](https://github.com/fabricjs/fabric.js/pull/8417) - chore(TS): migrate Ellipse [#8408](https://github.com/fabricjs/fabric.js/pull/8408) - chore(TS): migrate Triangle to TS [#8410](https://github.com/fabricjs/fabric.js/pull/8410) - chore(TS): migrate Circle to TS [#8406](https://github.com/fabricjs/fabric.js/pull/8406) From de8b31184f9a2ab680ba4e6be60fa6e24d8d09d9 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 23:03:10 +0200 Subject: [PATCH 18/67] more --- src/point.class.ts | 2 -- src/shapes/polyline.class.ts | 31 ++++++++++++------------------- test/unit/point.js | 1 - 3 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/point.class.ts b/src/point.class.ts index 530df68c9a0..5c201e80900 100644 --- a/src/point.class.ts +++ b/src/point.class.ts @@ -16,8 +16,6 @@ export class Point { y: number; - type = 'point'; - constructor(); constructor(x: number, y: number); constructor(point: IPoint); diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index ab689747e1c..964bcf975cd 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -39,9 +39,13 @@ export class Polyline extends FabricObject { * @todo check if you really need to recalculate for all cases */ strokeBBoxAffectingProperties: (keyof this)[]; + fromSVG: boolean; + pathOffset: Point; + strokeOffset: Point; + /** * Constructor * @param {Array} points Array of points (where each point is an object with x and y) @@ -227,7 +231,7 @@ export class Polyline extends FabricObject { * @private * @param {CanvasRenderingContext2D} ctx Context to render on */ - commonRender(ctx: CanvasRenderingContext2D) { + _render(ctx: CanvasRenderingContext2D) { const len = this.points.length, x = this.pathOffset.x, y = this.pathOffset.y; @@ -235,7 +239,7 @@ export class Polyline extends FabricObject { if (!len || isNaN(this.points[len - 1].y)) { // do not draw if no points or odd points // NaN comes from parseFloat of a empty string in parser - return false; + return; } ctx.beginPath(); ctx.moveTo(this.points[0].x - x, this.points[0].y - y); @@ -243,17 +247,6 @@ export class Polyline extends FabricObject { const point = this.points[i]; ctx.lineTo(point.x - x, point.y - y); } - return true; - } - - /** - * @private - * @param {CanvasRenderingContext2D} ctx Context to render on - */ - _render(ctx: CanvasRenderingContext2D) { - if (!this.commonRender(ctx)) { - return; - } !this.isOpen() && ctx.closePath(); this._renderPaintInOrder(ctx); } @@ -266,6 +259,8 @@ export class Polyline extends FabricObject { return this.points.length; } + /* _FROM_SVG_START_ */ + /** * List of attribute names to account for when parsing SVG element (used by {@link Polyline.fromElement}) * @static @@ -274,8 +269,6 @@ export class Polyline extends FabricObject { */ static ATTRIBUTE_NAMES = [...SHARED_ATTRIBUTES]; - static fromElement = Polyline.fromElementGenerator(Polyline); - /** * Returns Polyline instance from an SVG element * @static @@ -315,6 +308,10 @@ export class Polyline extends FabricObject { }; } + static fromElement = Polyline.fromElementGenerator(Polyline); + + /* _FROM_SVG_END_ */ + /** * Returns Polyline instance from an object representation * @static @@ -351,7 +348,3 @@ Object.assign(Polyline.prototype, polylineDefaultValues); /** @todo TODO_JS_MIGRATION remove next line after refactoring build */ fabric.Polyline = Polyline; - -/* _FROM_SVG_START_ */ - -/* _FROM_SVG_END_ */ diff --git a/test/unit/point.js b/test/unit/point.js index 0096de3d8b3..2384877d5ce 100644 --- a/test/unit/point.js +++ b/test/unit/point.js @@ -11,7 +11,6 @@ assert.ok(point instanceof fabric.Point); assert.ok(point.constructor === fabric.Point); assert.ok(typeof point.constructor === 'function'); - assert.equal(point.type, 'point'); assert.strictEqual(point.x, 0, 'constructor assign x value'); assert.strictEqual(point.y, 0, 'constructor assign y value'); From 66a14cc724184ed412676c5f6df6e25b7fa8d8b6 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 23:06:21 +0200 Subject: [PATCH 19/67] revert Point UT fail in deepEquals F it --- src/parser/parsePointsAttribute.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/parser/parsePointsAttribute.ts b/src/parser/parsePointsAttribute.ts index 636f4c6ac9c..1ac59752231 100644 --- a/src/parser/parsePointsAttribute.ts +++ b/src/parser/parsePointsAttribute.ts @@ -1,7 +1,5 @@ //@ts-nocheck -import { Point } from '../point.class'; - /** * Parses "points" attribute, returning an array of values * @static @@ -19,12 +17,15 @@ export function parsePointsAttribute(points) { points = points.replace(/,/g, ' ').trim(); points = points.split(/\s+/); - const parsedPoints: Point[] = []; + let parsedPoints = [], + i, + len; - for (let i = 0; i < points.length; i += 2) { - parsedPoints.push( - new Point(parseFloat(points[i]), parseFloat(points[i + 1])) - ); + for (i = 0, len = points.length; i < len; i += 2) { + parsedPoints.push({ + x: parseFloat(points[i]), + y: parseFloat(points[i + 1]), + }); } // odd number of points is an error From 65cfcd639722f5ac910baf34b585f2d8a259b94f Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 23:07:45 +0200 Subject: [PATCH 20/67] IPoint --- src/shapes/polyline.class.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index 964bcf975cd..e8a48c7a835 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -3,7 +3,7 @@ import { config } from '../config'; import { SHARED_ATTRIBUTES } from '../parser/attributes'; import { parseAttributes } from '../parser/parseAttributes'; import { parsePointsAttribute } from '../parser/parsePointsAttribute'; -import { Point } from '../point.class'; +import { IPoint, Point } from '../point.class'; import { TClassProperties } from '../typedefs'; import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints'; import { projectStrokeOnPoints } from '../util/misc/projectStroke'; @@ -18,7 +18,7 @@ export class Polyline extends FabricObject { * @type Array * @default */ - points: Point[]; + points: IPoint[]; /** * WARNING: Feature in progress @@ -65,7 +65,7 @@ export class Polyline extends FabricObject { * top: 100 * }); */ - constructor(points: Point[] = [], options: any = {}) { + constructor(points: IPoint[] = [], options: any = {}) { super({ points, ...options }); this.initialized = true; const bboxTL = this.setDimensions(); @@ -279,7 +279,7 @@ export class Polyline extends FabricObject { */ static fromElementGenerator< T extends { - new (points: Point[], options: any): any; + new (points: IPoint[], options: any): any; ATTRIBUTE_NAMES: string[]; } >(klass: T) { From 5681fce3bbbcb6f30cef49fd762c1ac5f6c8414d Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 23:19:58 +0200 Subject: [PATCH 21/67] refactor `fromElementGenerator` => `polyFromElement` --- src/shapes/polygon.class.ts | 10 ++++-- src/shapes/polyline.class.ts | 67 +++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 33 deletions(-) diff --git a/src/shapes/polygon.class.ts b/src/shapes/polygon.class.ts index f8ad577c8f0..e6762b59b9c 100644 --- a/src/shapes/polygon.class.ts +++ b/src/shapes/polygon.class.ts @@ -1,7 +1,7 @@ import { fabric } from '../../HEADER'; import { TClassProperties } from '../typedefs'; import { FabricObject } from './object.class'; -import { Polyline } from './polyline.class'; +import { polyFromElement, Polyline } from './polyline.class'; export class Polygon extends Polyline { protected isOpen() { @@ -18,7 +18,13 @@ export class Polygon extends Polyline { * @param {Function} callback callback function invoked after parsing * @param {Object} [options] Options object */ - static fromElement = Polyline.fromElementGenerator(Polygon); + static fromElement( + element: SVGElement, + callback: (poly: Polygon | null) => any, + options?: any + ) { + return polyFromElement(Polygon, element, callback, options); + } /* _FROM_SVG_END_ */ diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index e8a48c7a835..464df9ea96b 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -12,6 +12,36 @@ import { toFixed } from '../util/misc/toFixed'; import { FabricObject } from './fabricObject.class'; import { fabricObjectDefaultValues } from './object.class'; +export function polyFromElement< + T extends { + new (points: IPoint[], options: any): any; + ATTRIBUTE_NAMES: string[]; + } +>( + klass: T, + element: SVGElement, + callback: (poly: InstanceType | null) => any, + options = {} +) { + if (!element) { + return callback(null); + } + const points = parsePointsAttribute(element.getAttribute('points')), + // we omit left and top to instruct the constructor to position the object using the bbox + // eslint-disable-next-line @typescript-eslint/no-unused-vars + { left, top, ...parsedAttributes } = parseAttributes( + element, + klass.ATTRIBUTE_NAMES + ); + callback( + new klass(points || [], { + ...parsedAttributes, + ...options, + fromSVG: true, + }) + ); +} + export class Polyline extends FabricObject { /** * Points array @@ -277,39 +307,14 @@ export class Polyline extends FabricObject { * @param {Function} callback callback function invoked after parsing * @param {Object} [options] Options object */ - static fromElementGenerator< - T extends { - new (points: IPoint[], options: any): any; - ATTRIBUTE_NAMES: string[]; - } - >(klass: T) { - return function ( - element: SVGElement, - callback: (poly: InstanceType | null) => any, - options = {} - ) { - if (!element) { - return callback(null); - } - const points = parsePointsAttribute(element.getAttribute('points')), - // we omit left and top to instruct the constructor to position the object using the bbox - // eslint-disable-next-line @typescript-eslint/no-unused-vars - { left, top, ...parsedAttributes } = parseAttributes( - element, - klass.ATTRIBUTE_NAMES - ); - callback( - new klass(points || [], { - ...parsedAttributes, - ...options, - fromSVG: true, - }) - ); - }; + static fromElement( + element: SVGElement, + callback: (poly: Polyline | null) => any, + options?: any + ) { + return polyFromElement(Polyline, element, callback, options); } - static fromElement = Polyline.fromElementGenerator(Polyline); - /* _FROM_SVG_END_ */ /** From 1d18a151e03d001583dc671052afc08b5f29e12b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 23:21:23 +0200 Subject: [PATCH 22/67] Update polyline.class.ts --- src/shapes/polyline.class.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index 464df9ea96b..eb2e9e91c95 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -62,7 +62,7 @@ export class Polyline extends FabricObject { */ exactBoundingBox: boolean; - initialized: boolean; + private initialized: boolean; /** * A list of properties that if changed trigger a recalculation of dimensions From ce8660d77267b52138efb400604923ab33bc78f1 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 23:28:49 +0200 Subject: [PATCH 23/67] Update polyline.class.ts --- src/shapes/polyline.class.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index eb2e9e91c95..ad58bb1fbd2 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -62,7 +62,7 @@ export class Polyline extends FabricObject { */ exactBoundingBox: boolean; - private initialized: boolean; + private initialized: true | undefined; /** * A list of properties that if changed trigger a recalculation of dimensions @@ -335,7 +335,6 @@ export const polylineDefaultValues: Partial> = { type: 'polyline', points: [], exactBoundingBox: false, - initialized: false, cacheProperties: fabricObjectDefaultValues.cacheProperties.concat('points'), strokeBBoxAffectingProperties: [ 'skewX', From f6eb764b4fc20c2384911d6b82cff62661544c89 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 1 Nov 2022 23:35:20 +0200 Subject: [PATCH 24/67] remove default points --- src/shapes/polyline.class.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shapes/polyline.class.ts b/src/shapes/polyline.class.ts index ad58bb1fbd2..4cfa1133c52 100644 --- a/src/shapes/polyline.class.ts +++ b/src/shapes/polyline.class.ts @@ -333,7 +333,6 @@ export class Polyline extends FabricObject { export const polylineDefaultValues: Partial> = { type: 'polyline', - points: [], exactBoundingBox: false, cacheProperties: fabricObjectDefaultValues.cacheProperties.concat('points'), strokeBBoxAffectingProperties: [ From b5b5126bea0e95e116a2789313c320133483fe74 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 14:06:47 +0200 Subject: [PATCH 25/67] abstract methods + tidyup --- src/brushes/base_brush.class.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index 39eae1d1cff..7131d5e9c5b 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -1,7 +1,7 @@ import { fabric } from '../../HEADER'; import { Color } from '../color'; -import { Point } from '../point.class'; -import { Canvas, Shadow } from '../__types__'; +import type { Point } from '../point.class'; +import type { Canvas, Shadow } from '../__types__'; /** * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo} @@ -75,6 +75,11 @@ export abstract class BaseBrush { this.canvas = canvas; } + abstract _render(): void; + abstract onMouseDown(pointer: Point): void; + abstract onMouseMove(pointer: Point): void; + abstract onMouseUp(pointer: Point): void; + /** * Sets brush styles * @private @@ -100,6 +105,11 @@ export abstract class BaseBrush { ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]); } + protected needsFullRender() { + const color = new Color(this.color); + return color.getAlpha() < 1 || !!this.shadow; + } + /** * Sets brush shadow styles * @private @@ -120,11 +130,6 @@ export abstract class BaseBrush { ctx.shadowOffsetY = shadow.offsetY * zoom; } - protected needsFullRender() { - const color = new Color(this.color); - return color.getAlpha() < 1 || !!this.shadow; - } - /** * Removes brush shadow styles * @private From c536ecb53fcf50c7d8deed62faec0cf227ab4ffb Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 14:13:07 +0200 Subject: [PATCH 26/67] Update base_brush.class.ts --- src/brushes/base_brush.class.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index 7131d5e9c5b..6268f4164d6 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -1,8 +1,11 @@ import { fabric } from '../../HEADER'; import { Color } from '../color'; import type { Point } from '../point.class'; +import { TEvent } from '../typedefs'; import type { Canvas, Shadow } from '../__types__'; +type TBrushEventData = TEvent & { pointer: Point }; + /** * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo} */ @@ -76,9 +79,9 @@ export abstract class BaseBrush { } abstract _render(): void; - abstract onMouseDown(pointer: Point): void; - abstract onMouseMove(pointer: Point): void; - abstract onMouseUp(pointer: Point): void; + abstract onMouseDown(pointer: Point, ev: TBrushEventData): void; + abstract onMouseMove(pointer: Point, ev: TBrushEventData): void; + abstract onMouseUp(ev: TBrushEventData): void; /** * Sets brush styles From faf374ebf32e2450621652a9a34a3eaf214dbe1b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 14:14:29 +0200 Subject: [PATCH 27/67] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 228c17d831c..06013527c09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [next] +- chore(TS): BaseBrush abstract methods [#8428](https://github.com/fabricjs/fabric.js/pull/8428) - chore(TS): migrate Rect [#8411](https://github.com/fabricjs/fabric.js/pull/8411) - chore(TS): migrate Ellipse [#8408](https://github.com/fabricjs/fabric.js/pull/8408) - chore(TS): migrate Triangle to TS [#8410](https://github.com/fabricjs/fabric.js/pull/8410) From 2558035a155887fc40eb3ca133c865abed817f8b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 14:23:45 +0200 Subject: [PATCH 28/67] Update base_brush.class.ts --- src/brushes/base_brush.class.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index 6268f4164d6..2601fbe4ae1 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -81,7 +81,10 @@ export abstract class BaseBrush { abstract _render(): void; abstract onMouseDown(pointer: Point, ev: TBrushEventData): void; abstract onMouseMove(pointer: Point, ev: TBrushEventData): void; - abstract onMouseUp(ev: TBrushEventData): void; + /** + * @returns true if brush should continue blocking interaction + */ + abstract onMouseUp(ev: TBrushEventData): boolean | void; /** * Sets brush styles From 7576a6a901e1f6459b7a76366028d1f504a98468 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 16:23:50 +0200 Subject: [PATCH 29/67] feat(): PolyBrush --- src/brushes/PolyBrush.ts | 89 +++++++++++++++++++++++++++++++ src/brushes/index.ts | 1 + src/mixins/canvas_events.mixin.ts | 2 + 3 files changed, 92 insertions(+) create mode 100644 src/brushes/PolyBrush.ts diff --git a/src/brushes/PolyBrush.ts b/src/brushes/PolyBrush.ts new file mode 100644 index 00000000000..07175bd79a2 --- /dev/null +++ b/src/brushes/PolyBrush.ts @@ -0,0 +1,89 @@ +import { fabric } from '../../HEADER'; +import { Point } from '../point.class'; +import { Polygon } from '../shapes/polygon.class'; +import { Polyline } from '../shapes/polyline.class'; +import { BaseBrush } from './base_brush.class'; + +export class PolyBrush extends BaseBrush { + poly: Polyline | undefined; + builder = Polygon; + width = 5; + stroke = ''; + fill = ''; + + replacePoint(pointer: Point) { + const poly = this.poly!; + poly.points.pop(); + poly.points.push(pointer); + this._render(); + } + + private create(pointer: Point) { + this.poly = new this.builder([pointer, pointer], { + objectCaching: false, + canvas: this.canvas, + }); + this.setStyles(); + } + + setStyles() { + this.poly?.set({ + stroke: this.stroke || this.color, + fill: this.fill || this.color, + strokeWidth: this.width, + strokeLineCap: this.strokeLineCap, + strokeMiterLimit: this.strokeMiterLimit, + strokeLineJoin: this.strokeLineJoin, + strokeDashArray: this.strokeDashArray, + }); + } + + private finalize() { + // release interaction + this.canvas._isCurrentlyDrawing = false; + const poly = this.poly!; + // restore default value + poly.set('objectCaching', this.builder.prototype.objectCaching); + const pos = poly.setDimensions().scalarAdd(this.width / 2); + poly.setPositionByOrigin(pos, 'left', 'top'); + poly.setCoords(); + this.canvas.add(this.poly); + this.canvas.fire('path:created', { path: this.poly }); + this.canvas.clearContext(this.canvas.contextTop); + this.poly = undefined; + } + + _setBrushStyles() { + this.setStyles(); + } + + onMouseDown(pointer: Point) { + if (this.poly) { + this.poly.points.push(pointer); + } else { + this.create(pointer); + } + } + + onMouseMove(pointer: Point) { + this.replacePoint(pointer); + } + + onMouseUp({ pointer }: { pointer: Point }) { + this.replacePoint(pointer); + this.poly!.points.push(pointer); + return true; + } + + onDoubleClick(pointer: Point) { + this.replacePoint(pointer); + this.finalize(); + } + + _render(ctx = this.canvas.contextTop) { + this.canvas.clearContext(this.canvas.contextTop); + this.poly!.render(ctx); + } +} + +fabric.PolyBrush = PolyBrush; diff --git a/src/brushes/index.ts b/src/brushes/index.ts index 8d1edc86dc0..b4e73ac73d0 100644 --- a/src/brushes/index.ts +++ b/src/brushes/index.ts @@ -2,4 +2,5 @@ export * from './base_brush.class'; export * from './circle_brush.class'; export * from './pattern_brush.class'; export * from './pencil_brush.class'; +export * from './PolyBrush'; export * from './spray_brush.class'; diff --git a/src/mixins/canvas_events.mixin.ts b/src/mixins/canvas_events.mixin.ts index f0ab9d0d864..6b4a9650139 100644 --- a/src/mixins/canvas_events.mixin.ts +++ b/src/mixins/canvas_events.mixin.ts @@ -456,6 +456,8 @@ import { fireEvent } from '../util/fireEvent'; * @param {Event} e Event object fired on mousedown */ _onDoubleClick: function (e) { + this.freeDrawingBrush?.onDoubleClick && + this.freeDrawingBrush.onDoubleClick(this.getPointer(e)); this._cacheTransformEventData(e); this._handleEvent(e, 'dblclick'); this._resetTransformEventData(); From 6826935ac3eebd2ddc71d3dfd24d5bc0cf73654b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 16:47:23 +0200 Subject: [PATCH 30/67] Update PolyBrush.ts --- src/brushes/PolyBrush.ts | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/brushes/PolyBrush.ts b/src/brushes/PolyBrush.ts index 07175bd79a2..6585e198c06 100644 --- a/src/brushes/PolyBrush.ts +++ b/src/brushes/PolyBrush.ts @@ -2,6 +2,7 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Polygon } from '../shapes/polygon.class'; import { Polyline } from '../shapes/polyline.class'; +import { invertTransform } from '../util/misc/matrix'; import { BaseBrush } from './base_brush.class'; export class PolyBrush extends BaseBrush { @@ -11,15 +12,23 @@ export class PolyBrush extends BaseBrush { stroke = ''; fill = ''; + private normalizePointer(pointer: Point) { + return pointer.transform(this.canvas.viewportTransform, true); + } + + addPoint(pointer: Point) { + this.poly!.points.push(this.normalizePointer(pointer)); + } + replacePoint(pointer: Point) { - const poly = this.poly!; - poly.points.pop(); - poly.points.push(pointer); + this.poly!.points.pop(); + this.addPoint(pointer); this._render(); } private create(pointer: Point) { - this.poly = new this.builder([pointer, pointer], { + const p = this.normalizePointer(pointer); + this.poly = new this.builder([p, p], { objectCaching: false, canvas: this.canvas, }); @@ -41,7 +50,8 @@ export class PolyBrush extends BaseBrush { private finalize() { // release interaction this.canvas._isCurrentlyDrawing = false; - const poly = this.poly!; + const poly = this.poly; + if (!poly) return; // restore default value poly.set('objectCaching', this.builder.prototype.objectCaching); const pos = poly.setDimensions().scalarAdd(this.width / 2); @@ -59,7 +69,7 @@ export class PolyBrush extends BaseBrush { onMouseDown(pointer: Point) { if (this.poly) { - this.poly.points.push(pointer); + this.addPoint(pointer); } else { this.create(pointer); } @@ -71,18 +81,18 @@ export class PolyBrush extends BaseBrush { onMouseUp({ pointer }: { pointer: Point }) { this.replacePoint(pointer); - this.poly!.points.push(pointer); + this.addPoint(pointer); return true; } onDoubleClick(pointer: Point) { - this.replacePoint(pointer); + this.poly && this.replacePoint(pointer); this.finalize(); } _render(ctx = this.canvas.contextTop) { this.canvas.clearContext(this.canvas.contextTop); - this.poly!.render(ctx); + this.poly?.render(ctx); } } From ef485d5fd1954e32e46f68738840026178df6eaf Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 17:31:38 +0200 Subject: [PATCH 31/67] Update PolyBrush.ts --- src/brushes/PolyBrush.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/brushes/PolyBrush.ts b/src/brushes/PolyBrush.ts index 6585e198c06..771808e6347 100644 --- a/src/brushes/PolyBrush.ts +++ b/src/brushes/PolyBrush.ts @@ -2,37 +2,32 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Polygon } from '../shapes/polygon.class'; import { Polyline } from '../shapes/polyline.class'; -import { invertTransform } from '../util/misc/matrix'; import { BaseBrush } from './base_brush.class'; export class PolyBrush extends BaseBrush { poly: Polyline | undefined; builder = Polygon; - width = 5; stroke = ''; fill = ''; - private normalizePointer(pointer: Point) { - return pointer.transform(this.canvas.viewportTransform, true); + private addPoint(pointer: Point) { + this.poly!.points.push(pointer); } - addPoint(pointer: Point) { - this.poly!.points.push(this.normalizePointer(pointer)); - } - - replacePoint(pointer: Point) { + private replacePoint(pointer: Point) { this.poly!.points.pop(); this.addPoint(pointer); this._render(); } private create(pointer: Point) { - const p = this.normalizePointer(pointer); - this.poly = new this.builder([p, p], { + this.poly = new this.builder([], { objectCaching: false, canvas: this.canvas, }); this.setStyles(); + this.addPoint(pointer); + this.addPoint(pointer); } setStyles() { @@ -53,7 +48,7 @@ export class PolyBrush extends BaseBrush { const poly = this.poly; if (!poly) return; // restore default value - poly.set('objectCaching', this.builder.prototype.objectCaching); + poly.objectCaching = this.builder.prototype.objectCaching; const pos = poly.setDimensions().scalarAdd(this.width / 2); poly.setPositionByOrigin(pos, 'left', 'top'); poly.setCoords(); @@ -92,7 +87,12 @@ export class PolyBrush extends BaseBrush { _render(ctx = this.canvas.contextTop) { this.canvas.clearContext(this.canvas.contextTop); - this.poly?.render(ctx); + ctx.save(); + const t = this.canvas.viewportTransform; + const offset = new Point().transform(t); + ctx.transform(t[0], t[1], t[2], t[3], -offset.x, -offset.y); + this.poly!.render(ctx); + ctx.restore(); } } From 5e1f1fd3faf67455dcb180e707cf696c41498ef5 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 18:32:56 +0200 Subject: [PATCH 32/67] feat(): ShapeBrush --- src/brushes/PolyBrush.ts | 73 ++++++++--------------------------- src/brushes/ShapeBrush.ts | 81 +++++++++++++++++++++++++++++++++++++++ src/brushes/index.ts | 1 + 3 files changed, 99 insertions(+), 56 deletions(-) create mode 100644 src/brushes/ShapeBrush.ts diff --git a/src/brushes/PolyBrush.ts b/src/brushes/PolyBrush.ts index 771808e6347..576db14cdb6 100644 --- a/src/brushes/PolyBrush.ts +++ b/src/brushes/PolyBrush.ts @@ -2,71 +2,42 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Polygon } from '../shapes/polygon.class'; import { Polyline } from '../shapes/polyline.class'; -import { BaseBrush } from './base_brush.class'; +import { ShapeBrush } from './ShapeBrush'; -export class PolyBrush extends BaseBrush { - poly: Polyline | undefined; +export class PolyBrush extends ShapeBrush { builder = Polygon; - stroke = ''; - fill = ''; private addPoint(pointer: Point) { - this.poly!.points.push(pointer); + this.shape!.points.push(pointer); } private replacePoint(pointer: Point) { - this.poly!.points.pop(); + this.shape!.points.pop(); this.addPoint(pointer); this._render(); } - private create(pointer: Point) { - this.poly = new this.builder([], { - objectCaching: false, - canvas: this.canvas, - }); - this.setStyles(); - this.addPoint(pointer); - this.addPoint(pointer); + create() { + return new this.builder(); } - setStyles() { - this.poly?.set({ - stroke: this.stroke || this.color, - fill: this.fill || this.color, - strokeWidth: this.width, - strokeLineCap: this.strokeLineCap, - strokeMiterLimit: this.strokeMiterLimit, - strokeLineJoin: this.strokeLineJoin, - strokeDashArray: this.strokeDashArray, - }); - } - - private finalize() { + protected finalize() { // release interaction this.canvas._isCurrentlyDrawing = false; - const poly = this.poly; - if (!poly) return; - // restore default value - poly.objectCaching = this.builder.prototype.objectCaching; - const pos = poly.setDimensions().scalarAdd(this.width / 2); - poly.setPositionByOrigin(pos, 'left', 'top'); - poly.setCoords(); - this.canvas.add(this.poly); - this.canvas.fire('path:created', { path: this.poly }); - this.canvas.clearContext(this.canvas.contextTop); - this.poly = undefined; - } - - _setBrushStyles() { - this.setStyles(); + const shape = this.shape; + if (!shape) return; + const pos = shape.setDimensions().scalarAdd(this.width / 2); + shape.setPositionByOrigin(pos, 'left', 'top'); + super.finalize(); } onMouseDown(pointer: Point) { - if (this.poly) { + if (this.shape) { this.addPoint(pointer); } else { - this.create(pointer); + this.build(); + this.addPoint(pointer); + this.addPoint(pointer); } } @@ -81,19 +52,9 @@ export class PolyBrush extends BaseBrush { } onDoubleClick(pointer: Point) { - this.poly && this.replacePoint(pointer); + this.shape && this.replacePoint(pointer); this.finalize(); } - - _render(ctx = this.canvas.contextTop) { - this.canvas.clearContext(this.canvas.contextTop); - ctx.save(); - const t = this.canvas.viewportTransform; - const offset = new Point().transform(t); - ctx.transform(t[0], t[1], t[2], t[3], -offset.x, -offset.y); - this.poly!.render(ctx); - ctx.restore(); - } } fabric.PolyBrush = PolyBrush; diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/ShapeBrush.ts new file mode 100644 index 00000000000..a36cdbe3f35 --- /dev/null +++ b/src/brushes/ShapeBrush.ts @@ -0,0 +1,81 @@ +import { fabric } from '../../HEADER'; +import { Point } from '../point.class'; +import { FabricObject } from '../shapes/fabricObject.class'; +import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints'; +import { BaseBrush } from './base_brush.class'; + +export abstract class ShapeBrush extends BaseBrush { + shape: T | undefined; + stroke = ''; + fill = ''; + + private start: Point; + + abstract create(): T; + + protected build() { + this.shape = this.create(); + this.shape.set('canvas', this.canvas); + this.setStyles(); + } + + setStyles() { + this.shape?.set({ + stroke: this.stroke || this.color, + fill: this.fill || this.color, + strokeWidth: this.width, + strokeLineCap: this.strokeLineCap, + strokeMiterLimit: this.strokeMiterLimit, + strokeLineJoin: this.strokeLineJoin, + strokeDashArray: this.strokeDashArray, + }); + } + + private setBounds(a: Point, b: Point) { + const { left, top, width, height } = makeBoundingBoxFromPoints([a, b]); + this.shape!.set({ width, height }); + this.shape!.setPositionByOrigin(new Point(left, top), 'left', 'top'); + this._render(); + } + + protected finalize() { + const shape = this.shape; + if (!shape) return; + shape.setCoords(); + this.canvas.add(this.shape); + this.canvas.fire('path:created', { path: this.shape }); + this.canvas.clearContext(this.canvas.contextTop); + this.shape = undefined; + } + + _setBrushStyles() { + this.setStyles(); + } + + onMouseDown(pointer: Point) { + this.build(pointer); + this.start = pointer; + } + + onMouseMove(pointer: Point) { + this.setBounds(this.start, pointer); + } + + onMouseUp({ pointer }: { pointer: Point }) { + this.setBounds(this.start, pointer); + this.finalize(); + } + + _render(ctx = this.canvas.contextTop) { + this.canvas.clearContext(this.canvas.contextTop); + ctx.save(); + const t = this.canvas.viewportTransform; + const offset = new Point().transform(t); + ctx.transform(t[0], t[1], t[2], t[3], -offset.x, -offset.y); + this.shape!.transform(ctx); + this.shape!._render(ctx); + ctx.restore(); + } +} + +fabric.ShapeBrush = ShapeBrush; diff --git a/src/brushes/index.ts b/src/brushes/index.ts index b4e73ac73d0..9405add7da8 100644 --- a/src/brushes/index.ts +++ b/src/brushes/index.ts @@ -3,4 +3,5 @@ export * from './circle_brush.class'; export * from './pattern_brush.class'; export * from './pencil_brush.class'; export * from './PolyBrush'; +export * from './ShapeBrush'; export * from './spray_brush.class'; From a195dc56e0517b5cadb12d9610cb510b55821464 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 18:47:30 +0200 Subject: [PATCH 33/67] shape brush --- src/brushes/PolyBrush.ts | 4 +-- src/brushes/ShapeBrush.ts | 41 ++++++++++++++++++++++-- src/mixins/object_interactivity.mixin.ts | 2 +- src/shapes/rect.class.ts | 2 +- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/src/brushes/PolyBrush.ts b/src/brushes/PolyBrush.ts index 576db14cdb6..5cace5d6610 100644 --- a/src/brushes/PolyBrush.ts +++ b/src/brushes/PolyBrush.ts @@ -2,9 +2,9 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Polygon } from '../shapes/polygon.class'; import { Polyline } from '../shapes/polyline.class'; -import { ShapeBrush } from './ShapeBrush'; +import { ShapeBaseBrush } from './ShapeBrush'; -export class PolyBrush extends ShapeBrush { +export class PolyBrush extends ShapeBaseBrush { builder = Polygon; private addPoint(pointer: Point) { diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/ShapeBrush.ts index a36cdbe3f35..8fa400349e8 100644 --- a/src/brushes/ShapeBrush.ts +++ b/src/brushes/ShapeBrush.ts @@ -1,10 +1,13 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; +import { Circle } from '../shapes/circle.class'; +import { Ellipse } from '../shapes/ellipse.class'; import { FabricObject } from '../shapes/fabricObject.class'; +import { Rect } from '../shapes/rect.class'; import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints'; import { BaseBrush } from './base_brush.class'; -export abstract class ShapeBrush extends BaseBrush { +export abstract class ShapeBaseBrush extends BaseBrush { shape: T | undefined; stroke = ''; fill = ''; @@ -31,11 +34,10 @@ export abstract class ShapeBrush extends BaseBrush { }); } - private setBounds(a: Point, b: Point) { + protected setBounds(a: Point, b: Point) { const { left, top, width, height } = makeBoundingBoxFromPoints([a, b]); this.shape!.set({ width, height }); this.shape!.setPositionByOrigin(new Point(left, top), 'left', 'top'); - this._render(); } protected finalize() { @@ -59,6 +61,7 @@ export abstract class ShapeBrush extends BaseBrush { onMouseMove(pointer: Point) { this.setBounds(this.start, pointer); + this._render(); } onMouseUp({ pointer }: { pointer: Point }) { @@ -78,4 +81,36 @@ export abstract class ShapeBrush extends BaseBrush { } } +export class ShapeBrush extends ShapeBaseBrush { + builder = Rect; + create() { + return new this.builder(); + } +} + +export class CircleBrush extends ShapeBaseBrush { + create() { + return new Circle({}); + } + protected setBounds(a: Point, b: Point): void { + const { left, top, width, height } = makeBoundingBoxFromPoints([a, b]); + this.shape!.set({ radius: Math.max(width, height) / 2 }); + this.shape!.setPositionByOrigin(new Point(left, top), 'left', 'top'); + } +} + +export class EllipseBrush extends ShapeBaseBrush { + create() { + return new Ellipse({}); + } + protected setBounds(a: Point, b: Point): void { + const { left, top, width, height } = makeBoundingBoxFromPoints([a, b]); + this.shape!.set({ rx: width / 2, ry: height / 2 }); + this.shape!.setPositionByOrigin(new Point(left, top), 'left', 'top'); + } +} + +fabric.ShapeBaseBrush = ShapeBaseBrush; fabric.ShapeBrush = ShapeBrush; +fabric.CircleBrush = CircleBrush; +fabric.EllipseBrush = EllipseBrush; diff --git a/src/mixins/object_interactivity.mixin.ts b/src/mixins/object_interactivity.mixin.ts index dbd90e23ff2..325f61bc796 100644 --- a/src/mixins/object_interactivity.mixin.ts +++ b/src/mixins/object_interactivity.mixin.ts @@ -79,7 +79,7 @@ export class InteractiveFabricObject extends FabricObject { * Constructor * @param {Object} [options] Options object */ - constructor(options: Record) { + constructor(options?: Record) { super(options); } diff --git a/src/shapes/rect.class.ts b/src/shapes/rect.class.ts index 9de777e0455..6a4f84c2fb7 100644 --- a/src/shapes/rect.class.ts +++ b/src/shapes/rect.class.ts @@ -26,7 +26,7 @@ export class Rect extends FabricObject { * @param {Object} [options] Options object * @return {Object} thisArg */ - constructor(options: Record) { + constructor(options?: Record) { super(options); this._initRxRy(); } From 653ddbbe7721650c1c5e25da88532cb65022ea30 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 20:23:40 +0200 Subject: [PATCH 34/67] Update base_brush.class.ts --- src/brushes/base_brush.class.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index 2601fbe4ae1..e9beba7f59a 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -4,7 +4,7 @@ import type { Point } from '../point.class'; import { TEvent } from '../typedefs'; import type { Canvas, Shadow } from '../__types__'; -type TBrushEventData = TEvent & { pointer: Point }; +export type TBrushEventData = TEvent & { pointer: Point }; /** * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo} From be2e508e02febabc9c158860a82fa072b562c413 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 20:23:44 +0200 Subject: [PATCH 35/67] Update ShapeBrush.ts --- src/brushes/ShapeBrush.ts | 69 +++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 21 deletions(-) diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/ShapeBrush.ts index 8fa400349e8..a8689d1b2ef 100644 --- a/src/brushes/ShapeBrush.ts +++ b/src/brushes/ShapeBrush.ts @@ -4,13 +4,13 @@ import { Circle } from '../shapes/circle.class'; import { Ellipse } from '../shapes/ellipse.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { Rect } from '../shapes/rect.class'; -import { makeBoundingBoxFromPoints } from '../util/misc/boundingBoxFromPoints'; -import { BaseBrush } from './base_brush.class'; +import { BaseBrush, TBrushEventData } from './base_brush.class'; export abstract class ShapeBaseBrush extends BaseBrush { shape: T | undefined; stroke = ''; fill = ''; + centered = false; private start: Point; @@ -34,10 +34,21 @@ export abstract class ShapeBaseBrush extends BaseBrush { }); } - protected setBounds(a: Point, b: Point) { - const { left, top, width, height } = makeBoundingBoxFromPoints([a, b]); - this.shape!.set({ width, height }); - this.shape!.setPositionByOrigin(new Point(left, top), 'left', 'top'); + protected setBounds(a: Point, b: Point, ev: TBrushEventData) { + const v = b.subtract(a); + const shape = this.shape!; + if (this.centered) { + shape.set({ width: Math.abs(v.x) * 2, height: Math.abs(v.y) * 2 }); + shape.setPositionByOrigin(a, 0.5, 0.5); + } else { + shape.set({ width: Math.abs(v.x), height: Math.abs(v.y) }); + // keep a in place + shape.setPositionByOrigin( + a, + -Math.sign(v.x) * 0.5 + 0.5, + -Math.sign(v.y) * 0.5 + 0.5 + ); + } } protected finalize() { @@ -55,17 +66,17 @@ export abstract class ShapeBaseBrush extends BaseBrush { } onMouseDown(pointer: Point) { - this.build(pointer); + this.build(); this.start = pointer; } - onMouseMove(pointer: Point) { - this.setBounds(this.start, pointer); + onMouseMove(pointer: Point, ev: TBrushEventData) { + this.setBounds(this.start, pointer, ev); this._render(); } - onMouseUp({ pointer }: { pointer: Point }) { - this.setBounds(this.start, pointer); + onMouseUp(ev: TBrushEventData) { + this.setBounds(this.start, ev.pointer, ev); this.finalize(); } @@ -88,14 +99,25 @@ export class ShapeBrush extends ShapeBaseBrush { } } -export class CircleBrush extends ShapeBaseBrush { +export class CircleBrush1 extends ShapeBaseBrush { create() { - return new Circle({}); + return new Circle(); } protected setBounds(a: Point, b: Point): void { - const { left, top, width, height } = makeBoundingBoxFromPoints([a, b]); - this.shape!.set({ radius: Math.max(width, height) / 2 }); - this.shape!.setPositionByOrigin(new Point(left, top), 'left', 'top'); + const v = b.subtract(a); + const shape = this.shape!; + if (this.centered) { + shape.set({ radius: v.distanceFrom(new Point()) }); + shape.setPositionByOrigin(a, 0.5, 0.5); + } else { + shape.set({ radius: Math.max(Math.abs(v.x), Math.abs(v.y)) / 2 }); + // keep a in place + shape.setPositionByOrigin( + a, + -Math.sign(v.x) * 0.5 + 0.5, + -Math.sign(v.y) * 0.5 + 0.5 + ); + } } } @@ -103,14 +125,19 @@ export class EllipseBrush extends ShapeBaseBrush { create() { return new Ellipse({}); } - protected setBounds(a: Point, b: Point): void { - const { left, top, width, height } = makeBoundingBoxFromPoints([a, b]); - this.shape!.set({ rx: width / 2, ry: height / 2 }); - this.shape!.setPositionByOrigin(new Point(left, top), 'left', 'top'); + protected setBounds(a: Point, b: Point, ev: TBrushEventData) { + super.setBounds(a, b, ev); + const shape = this.shape!; + if (ev.e.shiftKey) { + const r = Math.max(shape.width, shape.height) / 2; + shape.set({ rx: r, ry: r }); + } else { + shape.set({ rx: shape.width / 2, ry: shape.height / 2 }); + } } } fabric.ShapeBaseBrush = ShapeBaseBrush; fabric.ShapeBrush = ShapeBrush; -fabric.CircleBrush = CircleBrush; +fabric.CircleBrush1 = CircleBrush1; fabric.EllipseBrush = EllipseBrush; From 3e8d0f63200247da36d49d04688b01a0c6b92d23 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 20:34:32 +0200 Subject: [PATCH 36/67] Update ellipse.class.ts --- src/shapes/ellipse.class.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shapes/ellipse.class.ts b/src/shapes/ellipse.class.ts index d98370ac055..fbfeb8e2ab2 100644 --- a/src/shapes/ellipse.class.ts +++ b/src/shapes/ellipse.class.ts @@ -26,7 +26,7 @@ export class Ellipse extends FabricObject { * @param {Object} [options] Options object * @return {Ellipse} thisArg */ - constructor(options: Record) { + constructor(options?: Record) { super(options); this.set('rx', (options && options.rx) || 0); this.set('ry', (options && options.ry) || 0); From b8f308e31ae3bdc2da5b0646fb8e4e3d5be5b4ac Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 20:34:42 +0200 Subject: [PATCH 37/67] Update ShapeBrush.ts --- src/brushes/ShapeBrush.ts | 52 +++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/ShapeBrush.ts index a8689d1b2ef..1c0f3c86d14 100644 --- a/src/brushes/ShapeBrush.ts +++ b/src/brushes/ShapeBrush.ts @@ -4,6 +4,7 @@ import { Circle } from '../shapes/circle.class'; import { Ellipse } from '../shapes/ellipse.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { Rect } from '../shapes/rect.class'; +import { ModifierKey } from '../typedefs'; import { BaseBrush, TBrushEventData } from './base_brush.class'; export abstract class ShapeBaseBrush extends BaseBrush { @@ -34,7 +35,7 @@ export abstract class ShapeBaseBrush extends BaseBrush { }); } - protected setBounds(a: Point, b: Point, ev: TBrushEventData) { + protected setBounds(a: Point, b: Point) { const v = b.subtract(a); const shape = this.shape!; if (this.centered) { @@ -70,13 +71,14 @@ export abstract class ShapeBaseBrush extends BaseBrush { this.start = pointer; } + // eslint-disable-next-line @typescript-eslint/no-unused-vars onMouseMove(pointer: Point, ev: TBrushEventData) { - this.setBounds(this.start, pointer, ev); + this.setBounds(this.start, pointer); this._render(); } onMouseUp(ev: TBrushEventData) { - this.setBounds(this.start, ev.pointer, ev); + this.setBounds(this.start, ev.pointer); this.finalize(); } @@ -99,36 +101,27 @@ export class ShapeBrush extends ShapeBaseBrush { } } -export class CircleBrush1 extends ShapeBaseBrush { +export class CircularShapeBrush extends ShapeBaseBrush { + /** + * The event modifier key that makes the brush draw a circle. + */ + modifierKey?: ModifierKey = 'shiftKey'; + + drawCircle?: boolean; + create() { - return new Circle(); + return new Ellipse(); } - protected setBounds(a: Point, b: Point): void { - const v = b.subtract(a); - const shape = this.shape!; - if (this.centered) { - shape.set({ radius: v.distanceFrom(new Point()) }); - shape.setPositionByOrigin(a, 0.5, 0.5); - } else { - shape.set({ radius: Math.max(Math.abs(v.x), Math.abs(v.y)) / 2 }); - // keep a in place - shape.setPositionByOrigin( - a, - -Math.sign(v.x) * 0.5 + 0.5, - -Math.sign(v.y) * 0.5 + 0.5 - ); - } - } -} -export class EllipseBrush extends ShapeBaseBrush { - create() { - return new Ellipse({}); + onMouseMove(pointer: Point, ev: TBrushEventData) { + this.drawCircle = this.modifierKey && ev.e[this.modifierKey]; + super.onMouseMove(pointer, ev); } - protected setBounds(a: Point, b: Point, ev: TBrushEventData) { - super.setBounds(a, b, ev); + + protected setBounds(a: Point, b: Point) { + super.setBounds(a, b); const shape = this.shape!; - if (ev.e.shiftKey) { + if (this.drawCircle) { const r = Math.max(shape.width, shape.height) / 2; shape.set({ rx: r, ry: r }); } else { @@ -139,5 +132,4 @@ export class EllipseBrush extends ShapeBaseBrush { fabric.ShapeBaseBrush = ShapeBaseBrush; fabric.ShapeBrush = ShapeBrush; -fabric.CircleBrush1 = CircleBrush1; -fabric.EllipseBrush = EllipseBrush; +fabric.CircularShapeBrush = CircularShapeBrush; From 2c78623fd617572b513ea8d2b71dcdeba3e2f873 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 21:03:17 +0200 Subject: [PATCH 38/67] circular shape brush sad naming --- src/brushes/CircularShapeBrush.ts | 53 +++++++++++++++++++++++++++++++ src/brushes/ShapeBrush.ts | 33 ------------------- src/brushes/index.ts | 1 + 3 files changed, 54 insertions(+), 33 deletions(-) create mode 100644 src/brushes/CircularShapeBrush.ts diff --git a/src/brushes/CircularShapeBrush.ts b/src/brushes/CircularShapeBrush.ts new file mode 100644 index 00000000000..3bce2803ff5 --- /dev/null +++ b/src/brushes/CircularShapeBrush.ts @@ -0,0 +1,53 @@ +import { fabric } from '../../HEADER'; +import { Point } from '../point.class'; +import { Ellipse } from '../shapes/ellipse.class'; +import { ModifierKey } from '../typedefs'; +import { TBrushEventData } from './base_brush.class'; +import { ShapeBaseBrush } from './ShapeBrush'; + +export class CircularShapeBrush extends ShapeBaseBrush { + /** + * The event modifier key that makes the brush draw a circle. + */ + modifierKey?: ModifierKey = 'shiftKey'; + + drawCircle?: boolean; + + create() { + return new Ellipse(); + } + + onMouseMove(pointer: Point, ev: TBrushEventData) { + this.drawCircle = this.modifierKey && ev.e[this.modifierKey]; + super.onMouseMove(pointer, ev); + } + + protected setBounds(a: Point, b: Point) { + const v = b.subtract(a); + const shape = this.shape!; + const d = new Point(Math.abs(v.x), Math.abs(v.y)); + // set radii + if (this.drawCircle) { + const r = this.centered + ? d.distanceFrom(new Point()) + : Math.max(d.x, d.y) / 2; + shape.set({ rx: r, ry: r }); + } else { + const { x: rx, y: ry } = this.centered ? d : d.scalarDivide(2); + shape.set({ rx, ry }); + } + // set position + if (this.centered) { + shape.setPositionByOrigin(a, 0.5, 0.5); + } else { + // keep a in place + shape.setPositionByOrigin( + a, + -Math.sign(v.x) * 0.5 + 0.5, + -Math.sign(v.y) * 0.5 + 0.5 + ); + } + } +} + +fabric.CircularShapeBrush = CircularShapeBrush; diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/ShapeBrush.ts index 1c0f3c86d14..5c23f03d006 100644 --- a/src/brushes/ShapeBrush.ts +++ b/src/brushes/ShapeBrush.ts @@ -1,10 +1,7 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; -import { Circle } from '../shapes/circle.class'; -import { Ellipse } from '../shapes/ellipse.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { Rect } from '../shapes/rect.class'; -import { ModifierKey } from '../typedefs'; import { BaseBrush, TBrushEventData } from './base_brush.class'; export abstract class ShapeBaseBrush extends BaseBrush { @@ -101,35 +98,5 @@ export class ShapeBrush extends ShapeBaseBrush { } } -export class CircularShapeBrush extends ShapeBaseBrush { - /** - * The event modifier key that makes the brush draw a circle. - */ - modifierKey?: ModifierKey = 'shiftKey'; - - drawCircle?: boolean; - - create() { - return new Ellipse(); - } - - onMouseMove(pointer: Point, ev: TBrushEventData) { - this.drawCircle = this.modifierKey && ev.e[this.modifierKey]; - super.onMouseMove(pointer, ev); - } - - protected setBounds(a: Point, b: Point) { - super.setBounds(a, b); - const shape = this.shape!; - if (this.drawCircle) { - const r = Math.max(shape.width, shape.height) / 2; - shape.set({ rx: r, ry: r }); - } else { - shape.set({ rx: shape.width / 2, ry: shape.height / 2 }); - } - } -} - fabric.ShapeBaseBrush = ShapeBaseBrush; fabric.ShapeBrush = ShapeBrush; -fabric.CircularShapeBrush = CircularShapeBrush; diff --git a/src/brushes/index.ts b/src/brushes/index.ts index 9405add7da8..57c4c3f165e 100644 --- a/src/brushes/index.ts +++ b/src/brushes/index.ts @@ -1,5 +1,6 @@ export * from './base_brush.class'; export * from './circle_brush.class'; +export * from './CircularShapeBrush'; export * from './pattern_brush.class'; export * from './pencil_brush.class'; export * from './PolyBrush'; From 5073ee7978dded019e5415b11e9a5c15019e6502 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 21:54:47 +0200 Subject: [PATCH 39/67] symmetric --- src/brushes/CircularShapeBrush.ts | 16 +--------------- src/brushes/ShapeBrush.ts | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/brushes/CircularShapeBrush.ts b/src/brushes/CircularShapeBrush.ts index 3bce2803ff5..836c70ce055 100644 --- a/src/brushes/CircularShapeBrush.ts +++ b/src/brushes/CircularShapeBrush.ts @@ -1,33 +1,19 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Ellipse } from '../shapes/ellipse.class'; -import { ModifierKey } from '../typedefs'; -import { TBrushEventData } from './base_brush.class'; import { ShapeBaseBrush } from './ShapeBrush'; export class CircularShapeBrush extends ShapeBaseBrush { - /** - * The event modifier key that makes the brush draw a circle. - */ - modifierKey?: ModifierKey = 'shiftKey'; - - drawCircle?: boolean; - create() { return new Ellipse(); } - onMouseMove(pointer: Point, ev: TBrushEventData) { - this.drawCircle = this.modifierKey && ev.e[this.modifierKey]; - super.onMouseMove(pointer, ev); - } - protected setBounds(a: Point, b: Point) { const v = b.subtract(a); const shape = this.shape!; const d = new Point(Math.abs(v.x), Math.abs(v.y)); // set radii - if (this.drawCircle) { + if (this.symmetric) { const r = this.centered ? d.distanceFrom(new Point()) : Math.max(d.x, d.y) / 2; diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/ShapeBrush.ts index 5c23f03d006..605d994a82c 100644 --- a/src/brushes/ShapeBrush.ts +++ b/src/brushes/ShapeBrush.ts @@ -2,6 +2,7 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { Rect } from '../shapes/rect.class'; +import { ModifierKey } from '../typedefs'; import { BaseBrush, TBrushEventData } from './base_brush.class'; export abstract class ShapeBaseBrush extends BaseBrush { @@ -9,6 +10,11 @@ export abstract class ShapeBaseBrush extends BaseBrush { stroke = ''; fill = ''; centered = false; + /** + * The event modifier key that makes the brush draw a circle. + */ + modifierKey?: ModifierKey = 'shiftKey'; + symmetric?: boolean; private start: Point; @@ -35,12 +41,20 @@ export abstract class ShapeBaseBrush extends BaseBrush { protected setBounds(a: Point, b: Point) { const v = b.subtract(a); const shape = this.shape!; + const d = new Point(Math.abs(v.x), Math.abs(v.y)); + // size + if (this.symmetric) { + const side = + (d.distanceFrom(new Point()) / Math.SQRT2) * (this.centered ? 2 : 1); + shape.set({ width: side, height: side }); + } else { + shape.set({ width: d.x, height: d.y }); + } + // position if (this.centered) { - shape.set({ width: Math.abs(v.x) * 2, height: Math.abs(v.y) * 2 }); shape.setPositionByOrigin(a, 0.5, 0.5); } else { - shape.set({ width: Math.abs(v.x), height: Math.abs(v.y) }); - // keep a in place + // keep a in place shape.setPositionByOrigin( a, -Math.sign(v.x) * 0.5 + 0.5, @@ -70,6 +84,7 @@ export abstract class ShapeBaseBrush extends BaseBrush { // eslint-disable-next-line @typescript-eslint/no-unused-vars onMouseMove(pointer: Point, ev: TBrushEventData) { + this.symmetric = this.modifierKey && ev.e[this.modifierKey]; this.setBounds(this.start, pointer); this._render(); } From f3dece5d142cbd8332414a3026d2f90caa9e0632 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 22:09:33 +0200 Subject: [PATCH 40/67] refactor --- src/brushes/CircularShapeBrush.ts | 8 ++- src/brushes/PolyBrush.ts | 2 +- src/brushes/ShapeBaseBrush.ts | 57 ++++++++++++++++++++++ src/brushes/ShapeBrush.ts | 81 +++++++++---------------------- 4 files changed, 83 insertions(+), 65 deletions(-) create mode 100644 src/brushes/ShapeBaseBrush.ts diff --git a/src/brushes/CircularShapeBrush.ts b/src/brushes/CircularShapeBrush.ts index 836c70ce055..1736c2ec72e 100644 --- a/src/brushes/CircularShapeBrush.ts +++ b/src/brushes/CircularShapeBrush.ts @@ -1,12 +1,10 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Ellipse } from '../shapes/ellipse.class'; -import { ShapeBaseBrush } from './ShapeBrush'; +import { ShapeBrush } from './ShapeBrush'; -export class CircularShapeBrush extends ShapeBaseBrush { - create() { - return new Ellipse(); - } +export class CircularShapeBrush extends ShapeBrush { + builder = Ellipse; protected setBounds(a: Point, b: Point) { const v = b.subtract(a); diff --git a/src/brushes/PolyBrush.ts b/src/brushes/PolyBrush.ts index 5cace5d6610..099d0e117b9 100644 --- a/src/brushes/PolyBrush.ts +++ b/src/brushes/PolyBrush.ts @@ -2,7 +2,7 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Polygon } from '../shapes/polygon.class'; import { Polyline } from '../shapes/polyline.class'; -import { ShapeBaseBrush } from './ShapeBrush'; +import { ShapeBaseBrush } from './ShapeBaseBrush'; export class PolyBrush extends ShapeBaseBrush { builder = Polygon; diff --git a/src/brushes/ShapeBaseBrush.ts b/src/brushes/ShapeBaseBrush.ts new file mode 100644 index 00000000000..60c6e90d346 --- /dev/null +++ b/src/brushes/ShapeBaseBrush.ts @@ -0,0 +1,57 @@ +import { fabric } from '../../HEADER'; +import { Point } from '../point.class'; +import { FabricObject } from '../shapes/fabricObject.class'; +import { BaseBrush } from './base_brush.class'; + +export abstract class ShapeBaseBrush extends BaseBrush { + shape: T | undefined; + stroke = ''; + fill = ''; + + abstract create(): T; + + protected build() { + this.shape = this.create(); + this.shape.set('canvas', this.canvas); + this.setStyles(); + } + + setStyles() { + this.shape?.set({ + stroke: this.stroke || this.color, + fill: this.fill || this.color, + strokeWidth: this.width, + strokeLineCap: this.strokeLineCap, + strokeMiterLimit: this.strokeMiterLimit, + strokeLineJoin: this.strokeLineJoin, + strokeDashArray: this.strokeDashArray, + }); + } + + protected finalize() { + const shape = this.shape; + if (!shape) return; + shape.setCoords(); + this.canvas.add(this.shape); + this.canvas.fire('path:created', { path: this.shape }); + this.canvas.clearContext(this.canvas.contextTop); + this.shape = undefined; + } + + _setBrushStyles() { + this.setStyles(); + } + + _render(ctx = this.canvas.contextTop) { + this.canvas.clearContext(this.canvas.contextTop); + ctx.save(); + const t = this.canvas.viewportTransform; + const offset = new Point().transform(t); + ctx.transform(t[0], t[1], t[2], t[3], -offset.x, -offset.y); + this.shape!.transform(ctx); + this.shape!._render(ctx); + ctx.restore(); + } +} + +fabric.ShapeBaseBrush = ShapeBaseBrush; diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/ShapeBrush.ts index 605d994a82c..a2f676334b3 100644 --- a/src/brushes/ShapeBrush.ts +++ b/src/brushes/ShapeBrush.ts @@ -3,39 +3,36 @@ import { Point } from '../point.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { Rect } from '../shapes/rect.class'; import { ModifierKey } from '../typedefs'; -import { BaseBrush, TBrushEventData } from './base_brush.class'; +import { TBrushEventData } from './base_brush.class'; +import { ShapeBaseBrush } from './ShapeBaseBrush'; -export abstract class ShapeBaseBrush extends BaseBrush { - shape: T | undefined; - stroke = ''; - fill = ''; +export class ShapeBrush< + T extends typeof FabricObject = typeof Rect +> extends ShapeBaseBrush> { + /** + * class to build shape from + */ + builder: T = Rect as unknown as T; + + /** + * set to `true` for the shape to be centered on mouse/touch down + */ centered = false; + /** - * The event modifier key that makes the brush draw a circle. + * The event modifier key that makes the brush symmetric. */ modifierKey?: ModifierKey = 'shiftKey'; - symmetric?: boolean; - - private start: Point; - abstract create(): T; + /** + * set to `true` for the shape to be symmetric + */ + symmetric?: boolean; - protected build() { - this.shape = this.create(); - this.shape.set('canvas', this.canvas); - this.setStyles(); - } + protected start: Point; - setStyles() { - this.shape?.set({ - stroke: this.stroke || this.color, - fill: this.fill || this.color, - strokeWidth: this.width, - strokeLineCap: this.strokeLineCap, - strokeMiterLimit: this.strokeMiterLimit, - strokeLineJoin: this.strokeLineJoin, - strokeDashArray: this.strokeDashArray, - }); + create() { + return new this.builder() as InstanceType; } protected setBounds(a: Point, b: Point) { @@ -63,26 +60,11 @@ export abstract class ShapeBaseBrush extends BaseBrush { } } - protected finalize() { - const shape = this.shape; - if (!shape) return; - shape.setCoords(); - this.canvas.add(this.shape); - this.canvas.fire('path:created', { path: this.shape }); - this.canvas.clearContext(this.canvas.contextTop); - this.shape = undefined; - } - - _setBrushStyles() { - this.setStyles(); - } - onMouseDown(pointer: Point) { this.build(); this.start = pointer; } - // eslint-disable-next-line @typescript-eslint/no-unused-vars onMouseMove(pointer: Point, ev: TBrushEventData) { this.symmetric = this.modifierKey && ev.e[this.modifierKey]; this.setBounds(this.start, pointer); @@ -93,25 +75,6 @@ export abstract class ShapeBaseBrush extends BaseBrush { this.setBounds(this.start, ev.pointer); this.finalize(); } - - _render(ctx = this.canvas.contextTop) { - this.canvas.clearContext(this.canvas.contextTop); - ctx.save(); - const t = this.canvas.viewportTransform; - const offset = new Point().transform(t); - ctx.transform(t[0], t[1], t[2], t[3], -offset.x, -offset.y); - this.shape!.transform(ctx); - this.shape!._render(ctx); - ctx.restore(); - } -} - -export class ShapeBrush extends ShapeBaseBrush { - builder = Rect; - create() { - return new this.builder(); - } } -fabric.ShapeBaseBrush = ShapeBaseBrush; fabric.ShapeBrush = ShapeBrush; From 4580f4145095ca84d4214b4079e7efa8184af51e Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 22:20:02 +0200 Subject: [PATCH 41/67] Update ShapeBaseBrush.ts --- src/brushes/ShapeBaseBrush.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/brushes/ShapeBaseBrush.ts b/src/brushes/ShapeBaseBrush.ts index 60c6e90d346..43e1d1edd6f 100644 --- a/src/brushes/ShapeBaseBrush.ts +++ b/src/brushes/ShapeBaseBrush.ts @@ -32,6 +32,7 @@ export abstract class ShapeBaseBrush extends BaseBrush { const shape = this.shape; if (!shape) return; shape.setCoords(); + this.canvas.fire('before:path:created', { path: this.shape }); this.canvas.add(this.shape); this.canvas.fire('path:created', { path: this.shape }); this.canvas.clearContext(this.canvas.contextTop); From 6ae1ea3da1da887343fa9a11980ef76f98874290 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 23:30:47 +0200 Subject: [PATCH 42/67] rename --- src/brushes/{CircularShapeBrush.ts => DrawOval.ts} | 6 +++--- src/brushes/{PolyBrush.ts => DrawPoly.ts} | 6 +++--- src/brushes/{ShapeBrush.ts => DrawShape.ts} | 8 ++++---- src/brushes/{ShapeBaseBrush.ts => DrawShapeBase.ts} | 4 ++-- src/brushes/index.ts | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) rename src/brushes/{CircularShapeBrush.ts => DrawOval.ts} (84%) rename src/brushes/{PolyBrush.ts => DrawPoly.ts} (89%) rename src/brushes/{ShapeBrush.ts => DrawShape.ts} (92%) rename src/brushes/{ShapeBaseBrush.ts => DrawShapeBase.ts} (92%) diff --git a/src/brushes/CircularShapeBrush.ts b/src/brushes/DrawOval.ts similarity index 84% rename from src/brushes/CircularShapeBrush.ts rename to src/brushes/DrawOval.ts index 1736c2ec72e..df26bf8fe44 100644 --- a/src/brushes/CircularShapeBrush.ts +++ b/src/brushes/DrawOval.ts @@ -1,9 +1,9 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Ellipse } from '../shapes/ellipse.class'; -import { ShapeBrush } from './ShapeBrush'; +import { DrawShape } from './DrawShape'; -export class CircularShapeBrush extends ShapeBrush { +export class DrawOval extends DrawShape { builder = Ellipse; protected setBounds(a: Point, b: Point) { @@ -34,4 +34,4 @@ export class CircularShapeBrush extends ShapeBrush { } } -fabric.CircularShapeBrush = CircularShapeBrush; +fabric.DrawOval = DrawOval; diff --git a/src/brushes/PolyBrush.ts b/src/brushes/DrawPoly.ts similarity index 89% rename from src/brushes/PolyBrush.ts rename to src/brushes/DrawPoly.ts index 099d0e117b9..851ba65ca58 100644 --- a/src/brushes/PolyBrush.ts +++ b/src/brushes/DrawPoly.ts @@ -2,9 +2,9 @@ import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Polygon } from '../shapes/polygon.class'; import { Polyline } from '../shapes/polyline.class'; -import { ShapeBaseBrush } from './ShapeBaseBrush'; +import { DrawShapeBase } from './DrawShapeBase'; -export class PolyBrush extends ShapeBaseBrush { +export class DrawPoly extends DrawShapeBase { builder = Polygon; private addPoint(pointer: Point) { @@ -57,4 +57,4 @@ export class PolyBrush extends ShapeBaseBrush { } } -fabric.PolyBrush = PolyBrush; +fabric.DrawPoly = DrawPoly; diff --git a/src/brushes/ShapeBrush.ts b/src/brushes/DrawShape.ts similarity index 92% rename from src/brushes/ShapeBrush.ts rename to src/brushes/DrawShape.ts index a2f676334b3..e59d4efe635 100644 --- a/src/brushes/ShapeBrush.ts +++ b/src/brushes/DrawShape.ts @@ -4,11 +4,11 @@ import { FabricObject } from '../shapes/fabricObject.class'; import { Rect } from '../shapes/rect.class'; import { ModifierKey } from '../typedefs'; import { TBrushEventData } from './base_brush.class'; -import { ShapeBaseBrush } from './ShapeBaseBrush'; +import { DrawShapeBase } from './DrawShapeBase'; -export class ShapeBrush< +export class DrawShape< T extends typeof FabricObject = typeof Rect -> extends ShapeBaseBrush> { +> extends DrawShapeBase> { /** * class to build shape from */ @@ -77,4 +77,4 @@ export class ShapeBrush< } } -fabric.ShapeBrush = ShapeBrush; +fabric.DrawShape = DrawShape; diff --git a/src/brushes/ShapeBaseBrush.ts b/src/brushes/DrawShapeBase.ts similarity index 92% rename from src/brushes/ShapeBaseBrush.ts rename to src/brushes/DrawShapeBase.ts index 43e1d1edd6f..4c54eb07202 100644 --- a/src/brushes/ShapeBaseBrush.ts +++ b/src/brushes/DrawShapeBase.ts @@ -3,7 +3,7 @@ import { Point } from '../point.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { BaseBrush } from './base_brush.class'; -export abstract class ShapeBaseBrush extends BaseBrush { +export abstract class DrawShapeBase extends BaseBrush { shape: T | undefined; stroke = ''; fill = ''; @@ -55,4 +55,4 @@ export abstract class ShapeBaseBrush extends BaseBrush { } } -fabric.ShapeBaseBrush = ShapeBaseBrush; +fabric.DrawShapeBase = DrawShapeBase; diff --git a/src/brushes/index.ts b/src/brushes/index.ts index 57c4c3f165e..4ebc69c6850 100644 --- a/src/brushes/index.ts +++ b/src/brushes/index.ts @@ -1,8 +1,8 @@ export * from './base_brush.class'; export * from './circle_brush.class'; -export * from './CircularShapeBrush'; +export * from './DrawOval'; +export * from './DrawPoly'; +export * from './DrawShape'; export * from './pattern_brush.class'; export * from './pencil_brush.class'; -export * from './PolyBrush'; -export * from './ShapeBrush'; export * from './spray_brush.class'; From 942cf90a77e685ab2429f5ed619a1d31eb85a1f9 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 23:32:38 +0200 Subject: [PATCH 43/67] Update DrawShapeBase.ts --- src/brushes/DrawShapeBase.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index 4c54eb07202..1a2a46aa933 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -1,4 +1,3 @@ -import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { BaseBrush } from './base_brush.class'; @@ -54,5 +53,3 @@ export abstract class DrawShapeBase extends BaseBrush { ctx.restore(); } } - -fabric.DrawShapeBase = DrawShapeBase; From 3bd0685b11bacb9df02a841a99dcbda7c47af026 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 23:35:18 +0200 Subject: [PATCH 44/67] Update DrawShapeBase.ts --- src/brushes/DrawShapeBase.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index 1a2a46aa933..220d144361f 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -2,6 +2,9 @@ import { Point } from '../point.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { BaseBrush } from './base_brush.class'; +/** + * Declarative shape drawing + */ export abstract class DrawShapeBase extends BaseBrush { shape: T | undefined; stroke = ''; From 62541fd482ebe50896eee7fe6f7ecbcd4851af3b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Mon, 7 Nov 2022 23:35:50 +0200 Subject: [PATCH 45/67] Update DrawShapeBase.ts --- src/brushes/DrawShapeBase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index 220d144361f..31f51e54da6 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -3,7 +3,7 @@ import { FabricObject } from '../shapes/fabricObject.class'; import { BaseBrush } from './base_brush.class'; /** - * Declarative shape drawing + * Declarative shape drawing using pointer events */ export abstract class DrawShapeBase extends BaseBrush { shape: T | undefined; From 4c28bbe1bc58486ae0c5a5e5ab600e2e0ef46031 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 22 Nov 2022 15:43:54 +0200 Subject: [PATCH 46/67] fix use `setBoundingBox` --- src/brushes/DrawPoly.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/brushes/DrawPoly.ts b/src/brushes/DrawPoly.ts index 851ba65ca58..55ee1ced846 100644 --- a/src/brushes/DrawPoly.ts +++ b/src/brushes/DrawPoly.ts @@ -26,8 +26,12 @@ export class DrawPoly extends DrawShapeBase { this.canvas._isCurrentlyDrawing = false; const shape = this.shape; if (!shape) return; - const pos = shape.setDimensions().scalarAdd(this.width / 2); - shape.setPositionByOrigin(pos, 'left', 'top'); + shape.setBoundingBox(true); + const r = this.width / 2; + shape.set({ + left: shape.left + r, + top: shape.top + r, + }); super.finalize(); } From 31cae7f0613fc6d87901c0168087c0b0c7122b53 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 22 Nov 2022 16:30:13 +0200 Subject: [PATCH 47/67] Create draw_shapes.js --- test/unit/draw_shapes.js | 153 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 test/unit/draw_shapes.js diff --git a/test/unit/draw_shapes.js b/test/unit/draw_shapes.js new file mode 100644 index 00000000000..adcb8cef3e8 --- /dev/null +++ b/test/unit/draw_shapes.js @@ -0,0 +1,153 @@ + let canvas; + QUnit.module('Draw Shapes', function (hooks) { + hooks.before(() => { + canvas = new fabric.Canvas(); + }); + hooks.afterEach(function() { + canvas.cancelRequestedRender(); + }); + hooks.after(() => { + canvas.dispose(); + }); + + [true, false].forEach((val) => { + QUnit.module(`enableRetinaScaling = ${val}`, (hooks) => { + hooks.beforeEach(function () { + canvas.enableRetinaScaling = val; + }); + hooks.afterEach(() => canvas.off()); + + function runShapeBrushTest(brush, assert, e = {}) { + var fireBeforePathCreatedEvent = false; + var firePathCreatedEvent = false; + var added = null; + canvas.on('before:path:created', function () { + fireBeforePathCreatedEvent = true; + }); + canvas.on('path:created', function (opt) { + firePathCreatedEvent = true; + added = opt.path; + }); + var pointer = canvas.getPointer({ clientX: 10, clientY: 10 }); + var pointer2 = canvas.getPointer({ clientX: 15, clientY: 15 }); + var pointer3 = canvas.getPointer({ clientX: 20, clientY: 25 }); + brush.onMouseDown(pointer, { e }); + brush.onMouseMove(pointer2, { e }); + brush.onMouseMove(pointer3, { e }); + brush.onMouseMove(pointer2, { e }); + brush.onMouseMove(pointer3, { e }); + brush.onMouseUp({ e, pointer: pointer3 }); + assert.equal(fireBeforePathCreatedEvent, true, 'before:path:created event is fired'); + assert.equal(firePathCreatedEvent, true, 'path:created event is fired'); + return added; + } + + QUnit.test('Draw Shape', function (assert) { + const brush = new fabric.DrawShape(canvas); + brush.width = 5; + const shape = runShapeBrushTest(brush, assert); + assert.ok(shape instanceof fabric.Rect, 'a rect is added'); + assert.equal(shape.strokeWidth, 5, 'should set width'); + assert.equal(shape.width, 10, 'should set width'); + assert.equal(shape.height, 15, 'should set height'); + assert.deepEqual( + shape.translateToOriginPoint(shape.getCenterPoint(), 'left', 'top'), + new fabric.Point(10, 10), + 'should preserve position from mousedown'); + }); + + QUnit.test('Draw Shape + symmetric', function (assert) { + const shape = runShapeBrushTest(new fabric.DrawShape(canvas), assert, { + shiftKey: true + }); + assert.equal(Math.round(shape.width), 13, 'should set width to height value'); + assert.equal(Math.round(shape.width), 13, 'should set height'); + assert.deepEqual( + shape.translateToOriginPoint(shape.getCenterPoint(), 'left', 'top'), + new fabric.Point(10, 10), + 'should preserve position from mousedown'); + }); + + QUnit.test('Draw Shape + centered', function (assert) { + const brush = new fabric.DrawShape(canvas); + brush.centered = true; + const shape = runShapeBrushTest(brush, assert); + assert.equal(shape.width, 10, 'should set width'); + assert.equal(shape.height, 15, 'should set height'); + assert.deepEqual(shape.getCenterPoint(), new fabric.Point(10, 10), 'should preserve position from mousedown'); + }); + + QUnit.test('Draw Shape + symmetric + centered', function (assert) { + const brush = new fabric.DrawShape(canvas); + brush.centered = true; + const shape = runShapeBrushTest(brush, assert, { + shiftKey: true + }); + assert.equal(Math.round(shape.width), 25, 'should set width'); + assert.equal(Math.round(shape.width), 25, 'should set height'); + assert.deepEqual(shape.getCenterPoint(), new fabric.Point(10, 10), 'should preserve position from mousedown'); + }); + + QUnit.test('Draw Oval', function (assert) { + const shape = runShapeBrushTest(new fabric.DrawOval(canvas), assert); + assert.equal(shape.rx, 5, 'should set rx'); + assert.equal(shape.ry, 7.5, 'should set ry'); + assert.equal(shape.width, 10, 'should set width'); + assert.equal(shape.height, 15, 'should set height'); + assert.deepEqual( + shape.translateToOriginPoint(shape.getCenterPoint(), 'left', 'top'), + new fabric.Point(10, 10), + 'should preserve position from mousedown'); + }); + + QUnit.test('Draw Oval + symmetric', function (assert) { + const shape = runShapeBrushTest(new fabric.DrawOval(canvas), assert, { + shiftKey: true + }); + assert.equal(shape.rx, 7.5, 'should set rx'); + assert.equal(shape.ry, 7.5, 'should set ry'); + assert.equal(shape.width, 15, 'should set width'); + assert.equal(shape.height, 15, 'should set height'); + assert.deepEqual( + shape.translateToOriginPoint(shape.getCenterPoint(), 'left', 'top'), + new fabric.Point(10, 10), + 'should preserve position from mousedown'); + }); + + [fabric.Polygon, fabric.Polyline].forEach(builder => { + QUnit.test(`Draw ${builder.name}`, function (assert) { + const brush = new fabric.DrawPoly(canvas); + brush.builder = builder; + const e = {}; + let fireBeforePathCreatedEvent = false; + let firePathCreatedEvent = false; + let poly = null; + canvas.on('before:path:created', function () { + fireBeforePathCreatedEvent = true; + }); + canvas.on('path:created', function (opt) { + firePathCreatedEvent = true; + poly = opt.path; + }); + const pointer = canvas.getPointer({ clientX: 10, clientY: 10 }); + const pointer2 = canvas.getPointer({ clientX: 15, clientY: 15 }); + const pointer3 = canvas.getPointer({ clientX: 20, clientY: 25 }); + brush.onMouseDown(pointer, { e }); + brush.onMouseMove(pointer3, { e }); + brush.onMouseUp({ e, pointer: pointer2 }); + brush.onMouseMove(pointer2, { e }); + brush.onDoubleClick(pointer3); + assert.equal(fireBeforePathCreatedEvent, true, 'before:path:created event is fired'); + assert.equal(firePathCreatedEvent, true, 'path:created event is fired'); + assert.ok(poly instanceof builder, `should create poly of type ${builder.name}`); + assert.deepEqual(poly.points, [pointer, pointer2, pointer3], 'should set points'); + assert.deepEqual( + poly.translateToOriginPoint(poly.getCenterPoint(), 'left', 'top'), + new fabric.Point(10, 10), + 'should preserve position from mousedown'); + }); + }); + }); + }); + }); + From 39bb29f099cf61f9e89dccebbea0f61b72bf1c75 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Tue, 22 Nov 2022 16:42:15 +0200 Subject: [PATCH 48/67] extensive tests! --- test/unit/draw_shapes.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/unit/draw_shapes.js b/test/unit/draw_shapes.js index adcb8cef3e8..2d5d982c967 100644 --- a/test/unit/draw_shapes.js +++ b/test/unit/draw_shapes.js @@ -100,6 +100,20 @@ 'should preserve position from mousedown'); }); + QUnit.test('Draw Oval + centered', function (assert) { + const brush = new fabric.DrawOval(canvas); + brush.centered = true; + const shape = runShapeBrushTest(brush, assert); + assert.equal(shape.rx, 10, 'should set rx'); + assert.equal(shape.ry, 15, 'should set ry'); + assert.equal(shape.width, 20, 'should set width'); + assert.equal(shape.height, 30, 'should set height'); + assert.deepEqual( + shape.getCenterPoint(), + new fabric.Point(10, 10), + 'should preserve position from mousedown'); + }); + QUnit.test('Draw Oval + symmetric', function (assert) { const shape = runShapeBrushTest(new fabric.DrawOval(canvas), assert, { shiftKey: true @@ -114,6 +128,22 @@ 'should preserve position from mousedown'); }); + QUnit.test('Draw Oval + centered + symmetric', function (assert) { + const brush = new fabric.DrawOval(canvas); + brush.centered = true; + const shape = runShapeBrushTest(brush, assert, { + shiftKey: true + }); + assert.equal(Math.round(shape.rx), 18, 'should set rx'); + assert.equal(Math.round(shape.ry), 18, 'should set ry'); + assert.equal(Math.round(shape.width), 36, 'should set width'); + assert.equal(Math.round(shape.height), 36, 'should set height'); + assert.deepEqual( + shape.getCenterPoint(), + new fabric.Point(10, 10), + 'should preserve position from mousedown'); + }); + [fabric.Polygon, fabric.Polyline].forEach(builder => { QUnit.test(`Draw ${builder.name}`, function (assert) { const brush = new fabric.DrawPoly(canvas); From 1e1db9ab5d4a9aa252014bc09238defbd38c220b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Wed, 23 Nov 2022 13:56:56 +0200 Subject: [PATCH 49/67] expose super class method `transform` --- src/brushes/DrawShapeBase.ts | 10 +++++++--- src/brushes/base_brush.class.ts | 9 +++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index 31f51e54da6..bc3134c6633 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -45,12 +45,16 @@ export abstract class DrawShapeBase extends BaseBrush { this.setStyles(); } - _render(ctx = this.canvas.contextTop) { - this.canvas.clearContext(this.canvas.contextTop); - ctx.save(); + transform(ctx: CanvasRenderingContext2D) { const t = this.canvas.viewportTransform; const offset = new Point().transform(t); ctx.transform(t[0], t[1], t[2], t[3], -offset.x, -offset.y); + } + + _render(ctx: CanvasRenderingContext2D = this.canvas.contextTop) { + this.canvas.clearContext(ctx); + ctx.save(); + this.transform(ctx); this.shape!.transform(ctx); this.shape!._render(ctx); ctx.restore(); diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index e9beba7f59a..df63145cc93 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -100,15 +100,16 @@ export abstract class BaseBrush { ctx.setLineDash(this.strokeDashArray || []); } + transform(ctx: CanvasRenderingContext2D) { + ctx.transform(...this.canvas.viewportTransform); + } + /** * Sets the transformation on given context - * @param {CanvasRenderingContext2D} ctx context to render on - * @private */ protected _saveAndTransform(ctx: CanvasRenderingContext2D) { - const v = this.canvas.viewportTransform; ctx.save(); - ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]); + this.transform(ctx); } protected needsFullRender() { From 6062754061fce6df689d0acc3c7875d44cb2cedd Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Wed, 23 Nov 2022 15:42:10 +0200 Subject: [PATCH 50/67] shadow --- src/brushes/DrawShapeBase.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index bc3134c6633..e7cbc0448a6 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -1,7 +1,11 @@ +import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { BaseBrush } from './base_brush.class'; +// TODO: remove transient +const { Shadow } = fabric; + /** * Declarative shape drawing using pointer events */ @@ -27,6 +31,7 @@ export abstract class DrawShapeBase extends BaseBrush { strokeMiterLimit: this.strokeMiterLimit, strokeLineJoin: this.strokeLineJoin, strokeDashArray: this.strokeDashArray, + shadow: this.shadow ? new Shadow(this.shadow) : undefined, }); } From 4ab566d434bc40b4db7cafecba8b1bde3d760f6f Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 27 Nov 2022 07:48:12 +0200 Subject: [PATCH 51/67] Update CHANGELOG.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cd6dcc514a..4b01d29a0bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ - chore(TS): migrate Polyline/Polygon [#8417](https://github.com/fabricjs/fabric.js/pull/8417) - chore(TS): BaseBrush abstract methods [#8428](https://github.com/fabricjs/fabric.js/pull/8428) -- chore(TS): BaseBrush abstract methods [#8428](https://github.com/fabricjs/fabric.js/pull/8428) - feat(): Add `createObjectDefaultControls` and `createTextboxDefaultControls` to create copies of control sets. [#8415](https://github.com/fabricjs/fabric.js/pull/8415) - fix(PatternBrush): `getPatternSrc`, rm `getPatternSrcFunction` [#8468](https://github.com/fabricjs/fabric.js/pull/8468) - chore(TS): more FabricObject typing [#8405](https://github.com/fabricjs/fabric.js/pull/8405) From 03e4150f7d7b128dbf4e96c0d5ce406de9a68dcf Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 27 Nov 2022 07:52:25 +0200 Subject: [PATCH 52/67] imports --- src/brushes/DrawShapeBase.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index e7cbc0448a6..96c8631fdf0 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -1,11 +1,8 @@ -import { fabric } from '../../HEADER'; import { Point } from '../point.class'; +import { Shadow } from '../shadow.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { BaseBrush } from './base_brush.class'; -// TODO: remove transient -const { Shadow } = fabric; - /** * Declarative shape drawing using pointer events */ From 6d182e01dd8aa156bbd50e83b3a335eded26c1fb Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 27 Nov 2022 07:53:40 +0200 Subject: [PATCH 53/67] fix merge artifact --- src/brushes/base_brush.class.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index 1cc6cc74537..6a2d38ba930 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -118,11 +118,6 @@ export abstract class BaseBrush { return color.getAlpha() < 1 || !!this.shadow; } - protected needsFullRender() { - const color = new Color(this.color); - return color.getAlpha() < 1 || !!this.shadow; - } - /** * Sets brush shadow styles * @private From c2676406ef84fd0107f8de90bd3c6342c828c6bf Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 27 Nov 2022 13:51:50 +0200 Subject: [PATCH 54/67] Update DrawShapeBase.ts --- src/brushes/DrawShapeBase.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index 96c8631fdf0..519b3acda8b 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -36,9 +36,9 @@ export abstract class DrawShapeBase extends BaseBrush { const shape = this.shape; if (!shape) return; shape.setCoords(); - this.canvas.fire('before:path:created', { path: this.shape }); + this.canvas.fire('before:path:created', { path: shape }); this.canvas.add(this.shape); - this.canvas.fire('path:created', { path: this.shape }); + this.canvas.fire('path:created', { path: shape }); this.canvas.clearContext(this.canvas.contextTop); this.shape = undefined; } From 211bfe7bc560f429547ee227e321ebc0f9bb8b2d Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 27 Nov 2022 13:55:44 +0200 Subject: [PATCH 55/67] imports/types --- src/brushes/DrawShape.ts | 4 ++-- src/brushes/base_brush.class.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/brushes/DrawShape.ts b/src/brushes/DrawShape.ts index e59d4efe635..849b1a0b9b0 100644 --- a/src/brushes/DrawShape.ts +++ b/src/brushes/DrawShape.ts @@ -1,13 +1,13 @@ import { fabric } from '../../HEADER'; +import { ModifierKey } from '../EventTypeDefs'; import { Point } from '../point.class'; import { FabricObject } from '../shapes/fabricObject.class'; import { Rect } from '../shapes/rect.class'; -import { ModifierKey } from '../typedefs'; import { TBrushEventData } from './base_brush.class'; import { DrawShapeBase } from './DrawShapeBase'; export class DrawShape< - T extends typeof FabricObject = typeof Rect + T extends typeof FabricObject = typeof Rect > extends DrawShapeBase> { /** * class to build shape from diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index 6a2d38ba930..1d7906a6ec0 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -5,7 +5,7 @@ import { TEvent } from '../EventTypeDefs'; import type { Shadow } from '../shadow.class'; import { Canvas } from '../__types__'; -type TBrushEventData = TEvent & { pointer: Point }; +export type TBrushEventData = TEvent & { pointer: Point }; /** * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo} From cafd0b3cfeaf73b72ca47923bcfaa92632a87404 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sun, 25 Dec 2022 09:36:35 +0200 Subject: [PATCH 56/67] fix(): imports after updating from master --- src/brushes/DrawShape.ts | 2 +- src/brushes/DrawShapeBase.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/brushes/DrawShape.ts b/src/brushes/DrawShape.ts index 849b1a0b9b0..4df28988d79 100644 --- a/src/brushes/DrawShape.ts +++ b/src/brushes/DrawShape.ts @@ -1,7 +1,7 @@ import { fabric } from '../../HEADER'; import { ModifierKey } from '../EventTypeDefs'; import { Point } from '../point.class'; -import { FabricObject } from '../shapes/fabricObject.class'; +import type { FabricObject } from '../shapes/Object/FabricObject'; import { Rect } from '../shapes/rect.class'; import { TBrushEventData } from './base_brush.class'; import { DrawShapeBase } from './DrawShapeBase'; diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index 519b3acda8b..d9c2b0d292c 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -1,6 +1,6 @@ import { Point } from '../point.class'; import { Shadow } from '../shadow.class'; -import { FabricObject } from '../shapes/fabricObject.class'; +import type { FabricObject } from '../shapes/Object/FabricObject'; import { BaseBrush } from './base_brush.class'; /** From f53a9218028c47e44dde4faaf47e7018bd45cbfc Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 30 Dec 2022 01:04:41 +0200 Subject: [PATCH 57/67] fix merge conflict --- src/brushes/base_brush.class.ts | 2 ++ src/canvas/canvas_events.ts | 9 +-------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index d33ca5119ed..5f68b67a791 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -86,6 +86,8 @@ export abstract class BaseBrush { * @returns true if brush should continue blocking interaction */ abstract onMouseUp(ev: TBrushEventData): boolean | void; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + onDoubleClick(pointer: Point) {} /** * Sets brush styles diff --git a/src/canvas/canvas_events.ts b/src/canvas/canvas_events.ts index 3174a84abc3..ecc8859c3c9 100644 --- a/src/canvas/canvas_events.ts +++ b/src/canvas/canvas_events.ts @@ -513,10 +513,6 @@ export class Canvas extends SelectableCanvas { this.fire('drop:after', options); } - /** - * @private - * @param {Event} e Event object fired on mousedown - */ private _onContextMenu(e: TPointerEvent): false { const options = this._simpleEventHandler('contextmenu:before', { e }); // TODO: this line is silly because the dev can subscribe to the event and prevent it themselves @@ -525,11 +521,8 @@ export class Canvas extends SelectableCanvas { return false; } - /** - * @private - * @param {Event} e Event object fired on mousedown - */ private _onDoubleClick(e: TPointerEvent) { + this.freeDrawingBrush?.onDoubleClick(this.getPointer(e)); this._cacheTransformEventData(e); this._handleEvent(e, 'dblclick'); this._resetTransformEventData(); From bae043bc97412b072542b5daf0c09b24816ef681 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 30 Dec 2022 01:06:42 +0200 Subject: [PATCH 58/67] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dbb9c56a3f..1c2b87a89c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ ## [next] -- chore(TS): migrate Polyline/Polygon [#8417](https://github.com/fabricjs/fabric.js/pull/8417) +- feat(): DrawShape, DrawOval, DrawPoly [#8430](https://github.com/fabricjs/fabric.js/pull/8430) - fix(Object Stacking): 🔙 refactor logic to support Group 🔝 - chore(TS): migrate Group/ActiveSelection [#8455](https://github.com/fabricjs/fabric.js/pull/8455) - chore(TS): Migrate smaller mixins to classes (dataurl and serialization ) [#8542](https://github.com/fabricjs/fabric.js/pull/8542) From c6f589613c75556e27dcc5013fd88eb933ff4f68 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 30 Dec 2022 01:09:06 +0200 Subject: [PATCH 59/67] Update base_brush.class.ts --- src/brushes/base_brush.class.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/brushes/base_brush.class.ts b/src/brushes/base_brush.class.ts index 5f68b67a791..fd6707be737 100644 --- a/src/brushes/base_brush.class.ts +++ b/src/brushes/base_brush.class.ts @@ -87,7 +87,9 @@ export abstract class BaseBrush { */ abstract onMouseUp(ev: TBrushEventData): boolean | void; // eslint-disable-next-line @typescript-eslint/no-unused-vars - onDoubleClick(pointer: Point) {} + onDoubleClick(pointer: Point) { + // noop + } /** * Sets brush styles From ea3c88be60ea38a728e1beb69866a41ea3c20422 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 30 Dec 2022 01:10:39 +0200 Subject: [PATCH 60/67] Update DrawShapeBase.ts --- src/brushes/DrawShapeBase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index d9c2b0d292c..c3d7f3ef6c9 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -37,7 +37,7 @@ export abstract class DrawShapeBase extends BaseBrush { if (!shape) return; shape.setCoords(); this.canvas.fire('before:path:created', { path: shape }); - this.canvas.add(this.shape); + this.canvas.add(shape); this.canvas.fire('path:created', { path: shape }); this.canvas.clearContext(this.canvas.contextTop); this.shape = undefined; From 62e94e548de3f55fd031a56cceded321cd397175 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 30 Dec 2022 01:12:30 +0200 Subject: [PATCH 61/67] Update canvas.class.ts --- src/canvas/canvas.class.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/canvas/canvas.class.ts b/src/canvas/canvas.class.ts index b49cba36201..0b88a5f573c 100644 --- a/src/canvas/canvas.class.ts +++ b/src/canvas/canvas.class.ts @@ -492,7 +492,7 @@ export class SelectableCanvas< contextTop: CanvasRenderingContext2D; wrapperEl: HTMLDivElement; cacheCanvasEl: HTMLCanvasElement; - protected _isCurrentlyDrawing: boolean; + _isCurrentlyDrawing: boolean; freeDrawingBrush?: BaseBrush; _activeObject?: FabricObject; _hasITextHandlers?: boolean; From d59f41d0eb2923b5dee9c3a411d5e3e3d2ef48bf Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 30 Dec 2022 07:27:42 +0200 Subject: [PATCH 62/67] better types --- src/brushes/DrawShape.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/brushes/DrawShape.ts b/src/brushes/DrawShape.ts index 4df28988d79..5212d6c5a57 100644 --- a/src/brushes/DrawShape.ts +++ b/src/brushes/DrawShape.ts @@ -3,16 +3,15 @@ import { ModifierKey } from '../EventTypeDefs'; import { Point } from '../point.class'; import type { FabricObject } from '../shapes/Object/FabricObject'; import { Rect } from '../shapes/rect.class'; +import { Constructor } from '../typedefs'; import { TBrushEventData } from './base_brush.class'; import { DrawShapeBase } from './DrawShapeBase'; -export class DrawShape< - T extends typeof FabricObject = typeof Rect -> extends DrawShapeBase> { +export class DrawShape extends DrawShapeBase { /** * class to build shape from */ - builder: T = Rect as unknown as T; + builder: Constructor = Rect as unknown as Constructor; /** * set to `true` for the shape to be centered on mouse/touch down @@ -32,7 +31,7 @@ export class DrawShape< protected start: Point; create() { - return new this.builder() as InstanceType; + return new this.builder(); } protected setBounds(a: Point, b: Point) { From 94c4a9e0c963ae96623b0fd100e68608c811ee77 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 30 Dec 2022 07:29:44 +0200 Subject: [PATCH 63/67] forgotten --- src/brushes/DrawOval.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/brushes/DrawOval.ts b/src/brushes/DrawOval.ts index df26bf8fe44..a858d5b6a2a 100644 --- a/src/brushes/DrawOval.ts +++ b/src/brushes/DrawOval.ts @@ -3,7 +3,7 @@ import { Point } from '../point.class'; import { Ellipse } from '../shapes/ellipse.class'; import { DrawShape } from './DrawShape'; -export class DrawOval extends DrawShape { +export class DrawOval extends DrawShape { builder = Ellipse; protected setBounds(a: Point, b: Point) { From 9093607e65819e485fd9921b1c3fbdf7bb54529f Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 6 Jan 2023 10:03:57 +0200 Subject: [PATCH 64/67] export --- index.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/index.js b/index.js index f496a21aacf..5061f6f8206 100644 --- a/index.js +++ b/index.js @@ -341,6 +341,10 @@ import { PencilBrush } from './src/brushes/pencil_brush.class'; import { CircleBrush } from './src/brushes/circle_brush.class'; import { SprayBrush } from './src/brushes/spray_brush.class'; import { PatternBrush } from './src/brushes/pattern_brush.class'; +import { DrawOval } from './src/brushes/DrawOval'; +import { DrawPoly } from './src/brushes/DrawPoly'; +import { DrawShape } from './src/brushes/DrawShape'; +import { DrawShapeBase } from './src/brushes/DrawShapeBase'; import { FabricObject as Object } from './src/shapes/Object/FabricObject'; import { Line } from './src/shapes/line.class'; import { Circle } from './src/shapes/circle.class'; @@ -397,6 +401,10 @@ const fabric = { CircleBrush, SprayBrush, PatternBrush, + DrawOval, + DrawPoly, + DrawShape, + DrawShapeBase, Object, Line, Circle, From e5dc0d2f16df5555f6b527cbc5cb265499a6792b Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Fri, 6 Jan 2023 10:06:30 +0200 Subject: [PATCH 65/67] cleanup --- src/brushes/DrawOval.ts | 3 --- src/brushes/DrawPoly.ts | 3 --- src/brushes/DrawShape.ts | 3 --- 3 files changed, 9 deletions(-) diff --git a/src/brushes/DrawOval.ts b/src/brushes/DrawOval.ts index a858d5b6a2a..fd6db5ebe3b 100644 --- a/src/brushes/DrawOval.ts +++ b/src/brushes/DrawOval.ts @@ -1,4 +1,3 @@ -import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Ellipse } from '../shapes/ellipse.class'; import { DrawShape } from './DrawShape'; @@ -33,5 +32,3 @@ export class DrawOval extends DrawShape { } } } - -fabric.DrawOval = DrawOval; diff --git a/src/brushes/DrawPoly.ts b/src/brushes/DrawPoly.ts index 55ee1ced846..ea9df6fc647 100644 --- a/src/brushes/DrawPoly.ts +++ b/src/brushes/DrawPoly.ts @@ -1,4 +1,3 @@ -import { fabric } from '../../HEADER'; import { Point } from '../point.class'; import { Polygon } from '../shapes/polygon.class'; import { Polyline } from '../shapes/polyline.class'; @@ -60,5 +59,3 @@ export class DrawPoly extends DrawShapeBase { this.finalize(); } } - -fabric.DrawPoly = DrawPoly; diff --git a/src/brushes/DrawShape.ts b/src/brushes/DrawShape.ts index 5212d6c5a57..81b97749c8a 100644 --- a/src/brushes/DrawShape.ts +++ b/src/brushes/DrawShape.ts @@ -1,4 +1,3 @@ -import { fabric } from '../../HEADER'; import { ModifierKey } from '../EventTypeDefs'; import { Point } from '../point.class'; import type { FabricObject } from '../shapes/Object/FabricObject'; @@ -75,5 +74,3 @@ export class DrawShape extends DrawShapeBase { this.finalize(); } } - -fabric.DrawShape = DrawShape; From d790f4b5d88fcbb34fe6ea0ad0fb97bab597b3cc Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 4 Feb 2023 09:40:59 +0200 Subject: [PATCH 66/67] Update CHANGELOG.md --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c8d3b56a94..dfbc17993c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,8 +3,6 @@ ## [next] - feat(): DrawShape, DrawOval, DrawPoly [#8430](https://github.com/fabricjs/fabric.js/pull/8430) -- fix(): `_initRetinaScaling` initializaing the scaling regardless of settings in Canvas. [#8565](https://github.com/fabricjs/fabric.js/pull/8565) -- fix(): regression of canvas migration with pointer and sendPointToPlane [#8563](https://github.com/fabricjs/fabric.js/pull/8563) - feat(): Node entry point [#8632](https://github.com/fabricjs/fabric.js/pull/8632) - chore(): Change import and export strategy [#8622](https://github.com/fabricjs/fabric.js/pull/8622) - chore(): rename files to modern style [#8621](https://github.com/fabricjs/fabric.js/pull/8621) From 8c0a4476ebecfb950a9c3d5195f2846cb7d281f0 Mon Sep 17 00:00:00 2001 From: ShaMan123 Date: Sat, 4 Feb 2023 10:23:12 +0200 Subject: [PATCH 67/67] fix imports, merge error --- src/brushes/DrawOval.ts | 4 ++-- src/brushes/DrawPoly.ts | 6 +++--- src/brushes/DrawShape.ts | 6 +++--- src/brushes/DrawShapeBase.ts | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/brushes/DrawOval.ts b/src/brushes/DrawOval.ts index fd6db5ebe3b..8d3d9a2d746 100644 --- a/src/brushes/DrawOval.ts +++ b/src/brushes/DrawOval.ts @@ -1,5 +1,5 @@ -import { Point } from '../point.class'; -import { Ellipse } from '../shapes/ellipse.class'; +import { Point } from '../Point'; +import { Ellipse } from '../shapes/Ellipse'; import { DrawShape } from './DrawShape'; export class DrawOval extends DrawShape { diff --git a/src/brushes/DrawPoly.ts b/src/brushes/DrawPoly.ts index ea9df6fc647..f765d637de1 100644 --- a/src/brushes/DrawPoly.ts +++ b/src/brushes/DrawPoly.ts @@ -1,6 +1,6 @@ -import { Point } from '../point.class'; -import { Polygon } from '../shapes/polygon.class'; -import { Polyline } from '../shapes/polyline.class'; +import { Point } from '../Point'; +import { Polygon } from '../shapes/Polygon'; +import { Polyline } from '../shapes/Polyline'; import { DrawShapeBase } from './DrawShapeBase'; export class DrawPoly extends DrawShapeBase { diff --git a/src/brushes/DrawShape.ts b/src/brushes/DrawShape.ts index 81b97749c8a..fa2b6b166ef 100644 --- a/src/brushes/DrawShape.ts +++ b/src/brushes/DrawShape.ts @@ -1,9 +1,9 @@ import { ModifierKey } from '../EventTypeDefs'; -import { Point } from '../point.class'; +import { Point } from '../Point'; import type { FabricObject } from '../shapes/Object/FabricObject'; -import { Rect } from '../shapes/rect.class'; +import { Rect } from '../shapes/Rect'; import { Constructor } from '../typedefs'; -import { TBrushEventData } from './base_brush.class'; +import { TBrushEventData } from './BaseBrush'; import { DrawShapeBase } from './DrawShapeBase'; export class DrawShape extends DrawShapeBase { diff --git a/src/brushes/DrawShapeBase.ts b/src/brushes/DrawShapeBase.ts index c3d7f3ef6c9..70eae99d0f9 100644 --- a/src/brushes/DrawShapeBase.ts +++ b/src/brushes/DrawShapeBase.ts @@ -1,7 +1,7 @@ -import { Point } from '../point.class'; -import { Shadow } from '../shadow.class'; +import { Point } from '../Point'; +import { Shadow } from '../Shadow'; import type { FabricObject } from '../shapes/Object/FabricObject'; -import { BaseBrush } from './base_brush.class'; +import { BaseBrush } from './BaseBrush'; /** * Declarative shape drawing using pointer events