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');