mirror of
https://github.com/motion-canvas/motion-canvas.git
synced 2026-01-11 14:57:56 -05:00
feat: add Grid node
This commit is contained in:
@@ -1,10 +1,50 @@
|
||||
import {Shape} from './Shape';
|
||||
import {Shape, ShapeProps} from './Shape';
|
||||
import {Signal, SignalValue} from '@motion-canvas/core/lib/utils';
|
||||
import {initial, property} from '../decorators';
|
||||
|
||||
export interface CircleProps extends ShapeProps {
|
||||
startAngle?: SignalValue<number>;
|
||||
endAngle?: SignalValue<number>;
|
||||
}
|
||||
|
||||
export class Circle extends Shape {
|
||||
@initial(0)
|
||||
@property()
|
||||
public declare readonly startAngle: Signal<number, this>;
|
||||
|
||||
@initial(360)
|
||||
@property()
|
||||
public declare readonly endAngle: Signal<number, this>;
|
||||
|
||||
public constructor(props: CircleProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
protected override getPath(): Path2D {
|
||||
const path = new Path2D();
|
||||
const start = (this.startAngle() / 180) * Math.PI;
|
||||
const end = (this.endAngle() / 180) * Math.PI;
|
||||
const {width, height} = this.computedSize();
|
||||
path.ellipse(0, 0, width / 2, height / 2, 0, 0, Math.PI * 2);
|
||||
path.ellipse(0, 0, width / 2, height / 2, 0, start, end);
|
||||
return path;
|
||||
}
|
||||
|
||||
protected override getRipplePath(): Path2D {
|
||||
const path = new Path2D();
|
||||
const rippleSize = this.rippleSize();
|
||||
const start = (this.startAngle() / 180) * Math.PI;
|
||||
const end = (this.endAngle() / 180) * Math.PI;
|
||||
const size = this.size();
|
||||
path.ellipse(
|
||||
0,
|
||||
0,
|
||||
size.x / 2 + rippleSize,
|
||||
size.y / 2 + rippleSize,
|
||||
0,
|
||||
start,
|
||||
end,
|
||||
);
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
44
packages/2d/src/components/Grid.ts
Normal file
44
packages/2d/src/components/Grid.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import {Shape, ShapeProps} from './Shape';
|
||||
import {SignalValue} from '@motion-canvas/core/lib/utils';
|
||||
import {PossibleVector2, Vector2} from '@motion-canvas/core/lib/types';
|
||||
import {initial, vector2Property, Vector2Property} from '../decorators';
|
||||
|
||||
export interface GridProps extends ShapeProps {
|
||||
spacing?: SignalValue<PossibleVector2>;
|
||||
}
|
||||
|
||||
export class Grid extends Shape {
|
||||
@initial(80)
|
||||
@vector2Property('spacing')
|
||||
public declare readonly spacing: Vector2Property<this>;
|
||||
|
||||
public constructor(props: GridProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
protected override drawShape(context: CanvasRenderingContext2D) {
|
||||
context.save();
|
||||
this.applyStyle(context);
|
||||
this.drawRipple(context);
|
||||
|
||||
const spacing = this.spacing();
|
||||
const size = this.computedSize().scale(0.5);
|
||||
const steps = size.div(spacing).floored;
|
||||
|
||||
for (let x = -steps.x; x <= steps.x; x++) {
|
||||
context.beginPath();
|
||||
context.moveTo(spacing.x * x, -size.height);
|
||||
context.lineTo(spacing.x * x, size.height);
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
for (let y = -steps.y; y <= steps.y; y++) {
|
||||
context.beginPath();
|
||||
context.moveTo(-size.width, spacing.y * y);
|
||||
context.lineTo(size.width, spacing.y * y);
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
context.restore();
|
||||
}
|
||||
}
|
||||
@@ -459,15 +459,24 @@ export class Layout extends Node {
|
||||
@computed()
|
||||
protected requestLayoutUpdate() {
|
||||
const parent = this.parentTransform();
|
||||
if (this.isLayoutRoot() || !parent) {
|
||||
this.view()?.element.append(this.element);
|
||||
if (this.appendedToView()) {
|
||||
parent?.requestFontUpdate();
|
||||
this.updateLayout();
|
||||
} else {
|
||||
parent.requestLayoutUpdate();
|
||||
parent!.requestLayoutUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
@computed()
|
||||
protected appendedToView() {
|
||||
const root = this.isLayoutRoot();
|
||||
if (root) {
|
||||
this.view()?.element.append(this.element);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply any new layout changes to this node and its children.
|
||||
*/
|
||||
|
||||
@@ -98,6 +98,7 @@ export abstract class Shape extends Layout {
|
||||
return super.getCacheRect().expand(this.lineWidth() / 2);
|
||||
}
|
||||
|
||||
@computed()
|
||||
protected getPath(): Path2D {
|
||||
return new Path2D();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export * from './Circle';
|
||||
export * from './Image';
|
||||
export * from './Grid';
|
||||
export * from './Layout';
|
||||
export * from './Line';
|
||||
export * from './Node';
|
||||
|
||||
@@ -222,7 +222,7 @@ export class Project {
|
||||
if (this.background) {
|
||||
this.context.save();
|
||||
this.context.fillStyle = this.background;
|
||||
this.context.fillRect(0, 0, this.width, this.height);
|
||||
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
this.context.restore();
|
||||
} else {
|
||||
this.context.clearRect(0, 0, this.width, this.height);
|
||||
|
||||
@@ -119,6 +119,10 @@ export class Vector2 implements Type {
|
||||
return new Vector2(-this.x, -this.y);
|
||||
}
|
||||
|
||||
public get floored(): Vector2 {
|
||||
return new Vector2(Math.floor(this.x), Math.floor(this.y));
|
||||
}
|
||||
|
||||
public get perpendicular(): Vector2 {
|
||||
return new Vector2(this.y, -this.x);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user