mirror of
https://github.com/motion-canvas/motion-canvas.git
synced 2026-04-22 03:00:03 -04:00
feat(2d): add smooth corners and sharpness to rect (#310)
This commit is contained in:
@@ -5,17 +5,28 @@ import {
|
|||||||
} from '@motion-canvas/core/lib/types';
|
} from '@motion-canvas/core/lib/types';
|
||||||
import {Shape, ShapeProps} from './Shape';
|
import {Shape, ShapeProps} from './Shape';
|
||||||
import {drawRoundRect} from '../utils';
|
import {drawRoundRect} from '../utils';
|
||||||
|
import {initial, signal} from '../decorators';
|
||||||
import {spacingSignal} from '../decorators/spacingSignal';
|
import {spacingSignal} from '../decorators/spacingSignal';
|
||||||
import {SignalValue} from '@motion-canvas/core/lib/signals';
|
import {SignalValue, SimpleSignal} from '@motion-canvas/core/lib/signals';
|
||||||
|
|
||||||
export interface RectProps extends ShapeProps {
|
export interface RectProps extends ShapeProps {
|
||||||
radius?: SignalValue<PossibleSpacing>;
|
radius?: SignalValue<PossibleSpacing>;
|
||||||
|
smoothCorners?: SignalValue<boolean>;
|
||||||
|
cornerSharpness?: SignalValue<number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Rect extends Shape {
|
export class Rect extends Shape {
|
||||||
@spacingSignal('radius')
|
@spacingSignal('radius')
|
||||||
public declare readonly radius: SpacingSignal<this>;
|
public declare readonly radius: SpacingSignal<this>;
|
||||||
|
|
||||||
|
@initial(false)
|
||||||
|
@signal()
|
||||||
|
public declare readonly smoothCorners: SimpleSignal<boolean, this>;
|
||||||
|
|
||||||
|
@initial(0.6)
|
||||||
|
@signal()
|
||||||
|
public declare readonly cornerSharpness: SimpleSignal<number, this>;
|
||||||
|
|
||||||
public constructor(props: RectProps) {
|
public constructor(props: RectProps) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
@@ -23,8 +34,10 @@ export class Rect extends Shape {
|
|||||||
protected override getPath(): Path2D {
|
protected override getPath(): Path2D {
|
||||||
const path = new Path2D();
|
const path = new Path2D();
|
||||||
const radius = this.radius();
|
const radius = this.radius();
|
||||||
|
const smoothCorners = this.smoothCorners();
|
||||||
|
const cornerSharpness = this.cornerSharpness();
|
||||||
const rect = RectType.fromSizeCentered(this.size());
|
const rect = RectType.fromSizeCentered(this.size());
|
||||||
drawRoundRect(path, rect, radius);
|
drawRoundRect(path, rect, radius, smoothCorners, cornerSharpness);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -37,8 +50,10 @@ export class Rect extends Shape {
|
|||||||
const path = new Path2D();
|
const path = new Path2D();
|
||||||
const rippleSize = this.rippleSize();
|
const rippleSize = this.rippleSize();
|
||||||
const radius = this.radius().addScalar(rippleSize);
|
const radius = this.radius().addScalar(rippleSize);
|
||||||
|
const smoothCorners = this.smoothCorners();
|
||||||
|
const cornerSharpness = this.cornerSharpness();
|
||||||
const rect = RectType.fromSizeCentered(this.size()).expand(rippleSize);
|
const rect = RectType.fromSizeCentered(this.size()).expand(rippleSize);
|
||||||
drawRoundRect(path, rect, radius);
|
drawRoundRect(path, rect, radius, smoothCorners, cornerSharpness);
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ export function drawRoundRect(
|
|||||||
context: CanvasRenderingContext2D | Path2D,
|
context: CanvasRenderingContext2D | Path2D,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
radius: Spacing,
|
radius: Spacing,
|
||||||
|
smoothCorners: boolean,
|
||||||
|
cornerSharpness: number,
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
radius.top === 0 &&
|
radius.top === 0 &&
|
||||||
@@ -70,6 +72,56 @@ export function drawRoundRect(
|
|||||||
rect,
|
rect,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (smoothCorners) {
|
||||||
|
const sharpness = (radius: number): number => {
|
||||||
|
const val = radius * cornerSharpness;
|
||||||
|
return radius - val;
|
||||||
|
};
|
||||||
|
|
||||||
|
context.moveTo(rect.left + topLeft, rect.top);
|
||||||
|
context.lineTo(rect.right - topRight, rect.top);
|
||||||
|
|
||||||
|
context.bezierCurveTo(
|
||||||
|
rect.right - sharpness(topRight),
|
||||||
|
rect.top,
|
||||||
|
rect.right,
|
||||||
|
rect.top + sharpness(topRight),
|
||||||
|
rect.right,
|
||||||
|
rect.top + topRight,
|
||||||
|
);
|
||||||
|
context.lineTo(rect.right, rect.bottom - bottomRight);
|
||||||
|
|
||||||
|
context.bezierCurveTo(
|
||||||
|
rect.right,
|
||||||
|
rect.bottom - sharpness(bottomRight),
|
||||||
|
rect.right - sharpness(bottomRight),
|
||||||
|
rect.bottom,
|
||||||
|
rect.right - bottomRight,
|
||||||
|
rect.bottom,
|
||||||
|
);
|
||||||
|
context.lineTo(rect.left + bottomLeft, rect.bottom);
|
||||||
|
|
||||||
|
context.bezierCurveTo(
|
||||||
|
rect.left + sharpness(bottomLeft),
|
||||||
|
rect.bottom,
|
||||||
|
rect.left,
|
||||||
|
rect.bottom - sharpness(bottomLeft),
|
||||||
|
rect.left,
|
||||||
|
rect.bottom - bottomLeft,
|
||||||
|
);
|
||||||
|
context.lineTo(rect.left, rect.top + topLeft);
|
||||||
|
|
||||||
|
context.bezierCurveTo(
|
||||||
|
rect.left,
|
||||||
|
rect.top + sharpness(topLeft),
|
||||||
|
rect.left + sharpness(topLeft),
|
||||||
|
rect.top,
|
||||||
|
rect.left + topLeft,
|
||||||
|
rect.top,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
context.moveTo(rect.left + topLeft, rect.top);
|
context.moveTo(rect.left + topLeft, rect.top);
|
||||||
context.arcTo(rect.right, rect.top, rect.right, rect.bottom, topRight);
|
context.arcTo(rect.right, rect.top, rect.right, rect.bottom, topRight);
|
||||||
context.arcTo(rect.right, rect.bottom, rect.left, rect.bottom, bottomRight);
|
context.arcTo(rect.right, rect.bottom, rect.left, rect.bottom, bottomRight);
|
||||||
|
|||||||
Reference in New Issue
Block a user