Skip to content
Merged

Dev #29

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 43 additions & 10 deletions apps/playground/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ import {
FillMode,
StrokeAlign,
StrokeStyle,
StrokeDashCap,
ShapeEffectDropShadow,
ShapeEffectInnerShadow,
ShapeEffectLayerBlur,
ShapeEffectBackgroundBlur,
} from "@flowscape-ui/core-sdk";

const container = document.querySelector<HTMLDivElement>("#app");
Expand Down Expand Up @@ -109,18 +112,43 @@ layerBackground.setImagePosition("50%", "50%");
// const groupNode = new NodeGroup(1000);

const rectNode = new NodeRect(1);
rectNode.setFillMode(FillMode.LinearGradient);
rectNode.setFill("linear-gradient(red, blue)");
rectNode.setFillMode(FillMode.Color);
rectNode.setFill("rgba(10, 20, 30, 0.5)");
rectNode.setStrokeWidth([5]);
rectNode.setStrokeAlign(StrokeAlign.Outside);
rectNode.setStrokeFill("white");
rectNode.setStrokeStyle(StrokeStyle.Dotted);
rectNode.setStrokeStyleProperties(
StrokeStyle.Dashed,
20,
10,
StrokeDashCap.Round,
);
// rectNode.setStrokeStyle(StrokeStyle.Dotted);
// rectNode.setStrokeStyleProperties(
// StrokeStyle.Dashed,
// 20,
// 10,
// StrokeDashCap.Round,
// );

const dropShadowEffect = new ShapeEffectDropShadow();
dropShadowEffect.setFill("#7C3AED");
dropShadowEffect.setOpacity(1);
dropShadowEffect.setOffset(10, 10);
dropShadowEffect.setBlur(0);
dropShadowEffect.setSpread(0);

const layerBlurEffect = new ShapeEffectLayerBlur();
layerBlurEffect.setBlur(100);

const innerShadow = new ShapeEffectInnerShadow();

innerShadow.setFill("#EF4444");
innerShadow.setOpacity(1);
innerShadow.setBlur(5);
innerShadow.setSpread(5);
innerShadow.setOffset(10, 10);

const backgroundBlurEffect = new ShapeEffectBackgroundBlur();
backgroundBlurEffect.setBlur(1);

rectNode.effectManager.add(innerShadow);
rectNode.effectManager.add(dropShadowEffect);
rectNode.effectManager.add(backgroundBlurEffect);

const rectNode2 = new NodeRect(20);
rectNode2.setPosition(-100, 0);
Expand Down Expand Up @@ -167,6 +195,7 @@ starNode.setStrokeFill("#1E3A8A");
starNode.setStrokeWidth([3]);
starNode.setRotation(12);
starNode.setSideCount(25);
starNode.effectManager.add(dropShadowEffect);

const pathNode = new NodePath(5);
pathNode.setPosition(440, 300);
Expand All @@ -180,6 +209,7 @@ pathNode.cubicTo({ x: 55, y: 10 }, { x: 165, y: 12 }, { x: 210, y: 80 });
pathNode.quadTo({ x: 240, y: 118 }, { x: 190, y: 150 });
pathNode.lineTo({ x: 55, y: 160 });
pathNode.closePath();
pathNode.effectManager.add(dropShadowEffect);

const lineNode = new NodeLine(6);
lineNode.setPosition(720, 320);
Expand All @@ -189,6 +219,7 @@ lineNode.setStrokeFill("#FCA5A5");
lineNode.setStrokeThickness(18);
lineNode.setLineCapStart(LineCap.Round);
lineNode.setLineCapEnd(LineCap.Square);
lineNode.effectManager.add(dropShadowEffect);

const textNode = new NodeText(7);
textNode.setPosition(700, 80);
Expand All @@ -208,6 +239,8 @@ textNode.setText(
"Precision tools for building\n" +
"interactive scene systems.",
);
textNode.effectManager.add(dropShadowEffect);
textNode.setStrokeFill("#FBBF24");

// groupNode.addChild(rectNode);
// groupNode.addChild(rectNode2);
Expand Down
16 changes: 15 additions & 1 deletion packages/engine/src/nodes/line/NodeLine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { EPSILON } from "../../core";
import type { Vector2 } from "../../core/transform";
import type { ID } from "../../core/types";
import { NodeType } from "../base";
import { ShapeBase, type ShapePathCommand } from "../shape";
import { ShapeBase, type ShapePathCommand, type StrokeWidth } from "../shape";
import { matrixInvert } from "../utils/matrix-invert";
import { LineCap, LineEnding, type INodeLine } from "./types";

Expand All @@ -22,6 +22,7 @@ export class NodeLine extends ShapeBase implements INodeLine {
super(id, NodeType.Line, name ?? "Line");

this._thickness = 1;
super.setStrokeWidth([this._thickness]);
this._start = { x: 0, y: 0 };
this._end = { x: 100, y: 0 };
this._updateBounds();
Expand Down Expand Up @@ -68,11 +69,24 @@ export class NodeLine extends ShapeBase implements INodeLine {
}

public setStrokeThickness(value: number): void {
if (!Number.isFinite(value)) {
return;
}

const newValue = Math.max(0, value);
if (newValue === this._thickness) {
return;
}
this._thickness = newValue;
super.setStrokeWidth([newValue]);
}

public override getStrokeWidth(): StrokeWidth {
return [this._thickness];
}

public override setStrokeWidth(value: StrokeWidth): void {
this.setStrokeThickness(value[0] ?? 0);
}

/*********************************************************/
Expand Down
6 changes: 3 additions & 3 deletions packages/engine/src/nodes/shape/ShapeBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
type ConfigurableStrokeStyle,
type StrokeStyleShape,
} from "./types";
import { ShapeEffect } from "./effect";
import { ShapeEffectManager } from "./effect";
import type { Vector2 } from "../../core/transform/types";

export class ShapeBase extends NodeBase implements IShapeBase {
Expand All @@ -42,7 +42,7 @@ export class ShapeBase extends NodeBase implements IShapeBase {
"mesh-gradient(grid 2 2 method bilinear in oklab, vertex v00 0% 0% #F472B6, vertex v10 100% 0% #FBBF24, vertex v01 0% 100% #34D399, vertex v11 100% 100% #3B82F6, patch p00 v00 v10 v11 v01)",
};

public readonly effect: ShapeEffect;
public readonly effectManager: ShapeEffectManager;

private _cornerRadius: CornerRadius;
private _fillMode: FillMode;
Expand Down Expand Up @@ -86,7 +86,7 @@ export class ShapeBase extends NodeBase implements IShapeBase {
gap: 8,
};

this.effect = new ShapeEffect();
this.effectManager = new ShapeEffectManager();
}

/***********************************************************/
Expand Down
76 changes: 0 additions & 76 deletions packages/engine/src/nodes/shape/effect/ShapeEffect.ts

This file was deleted.

108 changes: 108 additions & 0 deletions packages/engine/src/nodes/shape/effect/ShapeEffectManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import type { IShapeEffect, IShapeEffectByType } from "./types";

export class ShapeEffectManager {
private readonly _effects: IShapeEffect[] = [];

public get(index: number): IShapeEffect | undefined {
return this._effects[index];
}

public getAll(): readonly IShapeEffect[] {
return [...this._effects];
}

public getByType<TType extends keyof IShapeEffectByType>(
type: TType,
): readonly IShapeEffectByType[TType][] {
return this._effects.filter(
(effect) => effect.type === type,
) as IShapeEffectByType[TType][];
}

public has(type: keyof IShapeEffectByType): boolean {
return this._effects.some((effect) => effect.type === type);
}

public add(effect: IShapeEffect): boolean {
if (this._effects.includes(effect)) {
return false;
}

this._effects.push(effect);
return true;
}

public remove(effect: IShapeEffect): boolean {
const index = this._effects.indexOf(effect);

if (index === -1) {
return false;
}

this._effects.splice(index, 1);
return true;
}

public removeAt(index: number): IShapeEffect | undefined {
if (
!Number.isInteger(index) ||
index < 0 ||
index >= this._effects.length
) {
return undefined;
}

const [effect] = this._effects.splice(index, 1);
return effect;
}

public removeByType(type: keyof IShapeEffectByType): number {
let removedCount = 0;

for (let index = this._effects.length - 1; index >= 0; index--) {
if (this._effects[index]?.type !== type) {
continue;
}

this._effects.splice(index, 1);
removedCount++;
}

return removedCount;
}

public move(fromIndex: number, toIndex: number): boolean {
if (
!Number.isInteger(fromIndex) ||
!Number.isInteger(toIndex) ||
fromIndex < 0 ||
toIndex < 0 ||
fromIndex >= this._effects.length ||
toIndex >= this._effects.length ||
fromIndex === toIndex
) {
return false;
}

const [effect] = this._effects.splice(fromIndex, 1);

if (!effect) {
return false;
}

this._effects.splice(toIndex, 0, effect);
return true;
}

public clear(): void {
this._effects.length = 0;
}

public setAll(effects: readonly IShapeEffect[]): void {
this.clear();

for (const effect of effects) {
this.add(effect);
}
}
}
Loading