diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ef35a84b05..9d88a5fff89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## [next] +- feat(Circle): Add counterclockwise parameter to Circle class [#9670](https://github.com/fabricjs/fabric.js/pull/9670) + ## [6.0.0-beta19] - feat(LayoutManager): Expose objects registration [#9661](https://github.com/fabricjs/fabric.js/pull/9661) diff --git a/src/shapes/Circle.ts b/src/shapes/Circle.ts index cb233364800..87cfc79aa18 100644 --- a/src/shapes/Circle.ts +++ b/src/shapes/Circle.ts @@ -19,20 +19,26 @@ interface UniqueCircleProps { radius: number; /** - * degrees of start of the circle. - * probably will change to degrees in next major version - * @type Number 0 - 359 + * Angle for the start of the circle, in degrees. + * @type TDegree 0 - 359 * @default 0 */ startAngle: number; /** - * End angle of the circle - * probably will change to degrees in next major version - * @type Number 1 - 360 + * Angle for the end of the circle, in degrees + * @type TDegree 1 - 360 * @default 360 */ endAngle: number; + + /** + * Orientation for the direction of the circle. + * Setting to true will switch the arc of the circle to traverse from startAngle to endAngle in a counter-clockwise direction. + * Note: this will only change how the circle is drawn, and does not affect rotational transformation. + * @default false + */ + counterClockwise: boolean; } export interface SerializedCircleProps @@ -41,12 +47,18 @@ export interface SerializedCircleProps export interface CircleProps extends FabricObjectProps, UniqueCircleProps {} -const CIRCLE_PROPS = ['radius', 'startAngle', 'endAngle'] as const; +const CIRCLE_PROPS = [ + 'radius', + 'startAngle', + 'endAngle', + 'counterClockwise', +] as const; export const circleDefaultValues: UniqueCircleProps = { radius: 0, startAngle: 0, endAngle: 360, + counterClockwise: false, }; export class Circle< @@ -60,6 +72,7 @@ export class Circle< declare radius: number; declare startAngle: number; declare endAngle: number; + declare counterClockwise: boolean; static type = 'Circle'; @@ -101,7 +114,7 @@ export class Circle< this.radius, degreesToRadians(this.startAngle), degreesToRadians(this.endAngle), - false + this.counterClockwise ); this._renderPaintInOrder(ctx); } @@ -169,14 +182,10 @@ export class Circle< startY = sin(start) * radius, endX = cos(end) * radius, endY = sin(end) * radius, - largeFlag = angle > 180 ? '1' : '0'; + largeFlag = angle > 180 ? 1 : 0, + sweepFlag = this.counterClockwise ? 0 : 1; return [ - `\n', ]; diff --git a/test/unit/circle.js b/test/unit/circle.js index a68bf9543bc..632fb48bd67 100644 --- a/test/unit/circle.js +++ b/test/unit/circle.js @@ -117,6 +117,7 @@ radius: 0, startAngle: 0, endAngle: 360, + counterClockwise: false, skewX: 0, skewY: 0, strokeUniform: false @@ -159,13 +160,21 @@ }); QUnit.test('toSVG with half circle', function(assert) { - var circle = new fabric.Circle({ width: 100, height: 100, radius: 10, endAngle: fabric.util.radiansToDegrees(Math.PI) }); + var circle = new fabric.Circle({ width: 100, height: 100, radius: 10, endAngle: 180 }); var svg = circle.toSVG(); var svgClipPath = circle.toClipPathSVG(); assert.equal(svg, '\n\n\n'); assert.equal(svgClipPath, '\t\n', 'half circle as clipPath'); }); + QUnit.test('toSVG with counterclockwise half circle', function (assert) { + var circle = new fabric.Circle({ width: 100, height: 100, radius: 10, endAngle: 180, counterClockwise: true }); + var svg = circle.toSVG(); + var svgClipPath = circle.toClipPathSVG(); + assert.equal(svg, '\n\n\n'); + assert.equal(svgClipPath, '\t\n', 'half circle as clipPath'); + }); + QUnit.test('fromElement', function(assert) { var done = assert.async(); assert.ok(typeof fabric.Circle.fromElement === 'function');