Skip to content

Commit

Permalink
feat(Circle): Add counterclockwise parameter to Circle class (#9670)
Browse files Browse the repository at this point in the history
  • Loading branch information
lbordowitz authored Feb 25, 2024
1 parent b9b88bf commit 8d962d7
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 16 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
39 changes: 24 additions & 15 deletions src/shapes/Circle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<
Expand All @@ -60,6 +72,7 @@ export class Circle<
declare radius: number;
declare startAngle: number;
declare endAngle: number;
declare counterClockwise: boolean;

static type = 'Circle';

Expand Down Expand Up @@ -101,7 +114,7 @@ export class Circle<
this.radius,
degreesToRadians(this.startAngle),
degreesToRadians(this.endAngle),
false
this.counterClockwise
);
this._renderPaintInOrder(ctx);
}
Expand Down Expand Up @@ -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 [
`<path d="M ${startX} ${startY}`,
` A ${radius} ${radius}`,
' 0 ',
`${largeFlag} 1`,
` ${endX} ${endY}`,
'" ',
`<path d="M ${startX} ${startY} A ${radius} ${radius} 0 ${largeFlag} ${sweepFlag} ${endX} ${endY}" `,
'COMMON_PARTS',
' />\n',
];
Expand Down
11 changes: 10 additions & 1 deletion test/unit/circle.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
radius: 0,
startAngle: 0,
endAngle: 360,
counterClockwise: false,
skewX: 0,
skewY: 0,
strokeUniform: false
Expand Down Expand Up @@ -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, '<g transform=\"matrix(1 0 0 1 10.5 10.5)\" >\n<path d=\"M 10 0 A 10 10 0 0 1 -10 0\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;\" />\n</g>\n');
assert.equal(svgClipPath, '\t<path d=\"M 10 0 A 10 10 0 0 1 -10 0\" transform=\"matrix(1 0 0 1 10.5 10.5)\" />\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, '<g transform=\"matrix(1 0 0 1 10.5 10.5)\" >\n<path d=\"M 10 0 A 10 10 0 0 0 -10 0\" style=\"stroke: none; stroke-width: 1; stroke-dasharray: none; stroke-linecap: butt; stroke-dashoffset: 0; stroke-linejoin: miter; stroke-miterlimit: 4; fill: rgb(0,0,0); fill-rule: nonzero; opacity: 1;\" />\n</g>\n');
assert.equal(svgClipPath, '\t<path d=\"M 10 0 A 10 10 0 0 0 -10 0\" transform=\"matrix(1 0 0 1 10.5 10.5)\" />\n', 'half circle as clipPath');
});

QUnit.test('fromElement', function(assert) {
var done = assert.async();
assert.ok(typeof fabric.Circle.fromElement === 'function');
Expand Down

0 comments on commit 8d962d7

Please sign in to comment.