@flighthq/shape 0.3.0-next.1566.dcdf1d3 → 0.3.0-next.1584.a68fe91
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contract.d.ts +2 -0
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js +2 -0
- package/dist/contract.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/morphShape.d.ts +8 -0
- package/dist/morphShape.d.ts.map +1 -0
- package/dist/morphShape.js +48 -0
- package/dist/morphShape.js.map +1 -0
- package/dist/morphShapeAnimation.d.ts +5 -0
- package/dist/morphShapeAnimation.d.ts.map +1 -0
- package/dist/morphShapeAnimation.js +27 -0
- package/dist/morphShapeAnimation.js.map +1 -0
- package/package.json +8 -7
- package/src/morphShape.test.ts +161 -0
- package/src/morphShapeAnimation.test.ts +120 -0
package/dist/contract.d.ts
CHANGED
package/dist/contract.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
|
package/dist/contract.js
CHANGED
package/dist/contract.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC;AACxB,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { PathCommand, appendShapeArc, appendShapeArcTo, appendShapeBeginTextureFill, appendShapeBeginFill, appendShapeBeginGradientFill, appendShapeCircle, appendShapeCubicCurveTo, appendShapeCurveTo, appendShapeDrawTriangles, appendShapeEllipse, appendShapeEndFill, appendShapeGeometryCommand, appendShapeLineTextureStyle, appendShapeLineGradientStyle, appendShapeLineStyle, appendShapeLineTo, appendShapeMoveTo, appendShapePath, appendShapePolygon, appendShapePolyline, appendShapeRectangle, appendShapeRoundRectangle, appendShapeRoundRectangleVarying, clearShapeCommands, computeShapeLocalBoundsRectangle, copyShapeCommands, createScale9Shape, createShape, enableShapeHitTesting, getPathCommandOperandCount, getShapeBounds, getShapeCommandCount, getShapeFillRegions, getShapeStrokeRegions, getShapeStrokeOutlineRegions, hasNonSolidShapeFill, hasNonSolidShapeStroke, hasShapeFill, hitTestShapeCommandPoint, isShapeEmpty, registerShapeHitTestCommand, } from './contract';
|
|
1
|
+
export { PathCommand, applyAnimationClipToMorphShape, applyMorphShapeAnimationSample, appendMorphShapePath, appendShapeArc, appendShapeArcTo, appendShapeBeginTextureFill, appendShapeBeginFill, appendShapeBeginGradientFill, appendShapeCircle, appendShapeCubicCurveTo, appendShapeCurveTo, appendShapeDrawTriangles, appendShapeEllipse, appendShapeEndFill, appendShapeGeometryCommand, appendShapeLineTextureStyle, appendShapeLineGradientStyle, appendShapeLineStyle, appendShapeLineTo, appendShapeMoveTo, appendShapePath, appendShapePolygon, appendShapePolyline, appendShapeRectangle, appendShapeRoundRectangle, appendShapeRoundRectangleVarying, clearShapeCommands, computeShapeLocalBoundsRectangle, copyShapeCommands, createMorphShape, createMorphShapeAnimationTarget, createScale9Shape, createShape, enableShapeHitTesting, getPathCommandOperandCount, getShapeBounds, getShapeCommandCount, getShapeFillRegions, getShapeStrokeRegions, getShapeStrokeOutlineRegions, hasNonSolidShapeFill, hasNonSolidShapeStroke, hasShapeFill, hitTestShapeCommandPoint, isShapeEmpty, registerShapeHitTestCommand, setMorphShapeProgress, } from './contract';
|
|
2
2
|
export * from './scale9ShapeCommands';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,EAC5B,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC5B,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,gCAAgC,EAChC,kBAAkB,EAClB,gCAAgC,EAChC,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,oBAAoB,EACpB,sBAAsB,EACtB,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,8BAA8B,EAC9B,8BAA8B,EAC9B,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,EAC5B,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC5B,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,gCAAgC,EAChC,kBAAkB,EAClB,gCAAgC,EAChC,iBAAiB,EACjB,gBAAgB,EAChB,+BAA+B,EAC/B,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,oBAAoB,EACpB,sBAAsB,EACtB,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,cAAc,uBAAuB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { PathCommand, appendShapeArc, appendShapeArcTo, appendShapeBeginTextureFill, appendShapeBeginFill, appendShapeBeginGradientFill, appendShapeCircle, appendShapeCubicCurveTo, appendShapeCurveTo, appendShapeDrawTriangles, appendShapeEllipse, appendShapeEndFill, appendShapeGeometryCommand, appendShapeLineTextureStyle, appendShapeLineGradientStyle, appendShapeLineStyle, appendShapeLineTo, appendShapeMoveTo, appendShapePath, appendShapePolygon, appendShapePolyline, appendShapeRectangle, appendShapeRoundRectangle, appendShapeRoundRectangleVarying, clearShapeCommands, computeShapeLocalBoundsRectangle, copyShapeCommands, createScale9Shape, createShape, enableShapeHitTesting, getPathCommandOperandCount, getShapeBounds, getShapeCommandCount, getShapeFillRegions, getShapeStrokeRegions, getShapeStrokeOutlineRegions, hasNonSolidShapeFill, hasNonSolidShapeStroke, hasShapeFill, hitTestShapeCommandPoint, isShapeEmpty, registerShapeHitTestCommand, } from './contract';
|
|
1
|
+
export { PathCommand, applyAnimationClipToMorphShape, applyMorphShapeAnimationSample, appendMorphShapePath, appendShapeArc, appendShapeArcTo, appendShapeBeginTextureFill, appendShapeBeginFill, appendShapeBeginGradientFill, appendShapeCircle, appendShapeCubicCurveTo, appendShapeCurveTo, appendShapeDrawTriangles, appendShapeEllipse, appendShapeEndFill, appendShapeGeometryCommand, appendShapeLineTextureStyle, appendShapeLineGradientStyle, appendShapeLineStyle, appendShapeLineTo, appendShapeMoveTo, appendShapePath, appendShapePolygon, appendShapePolyline, appendShapeRectangle, appendShapeRoundRectangle, appendShapeRoundRectangleVarying, clearShapeCommands, computeShapeLocalBoundsRectangle, copyShapeCommands, createMorphShape, createMorphShapeAnimationTarget, createScale9Shape, createShape, enableShapeHitTesting, getPathCommandOperandCount, getShapeBounds, getShapeCommandCount, getShapeFillRegions, getShapeStrokeRegions, getShapeStrokeOutlineRegions, hasNonSolidShapeFill, hasNonSolidShapeStroke, hasShapeFill, hitTestShapeCommandPoint, isShapeEmpty, registerShapeHitTestCommand, setMorphShapeProgress, } from './contract';
|
|
2
2
|
export * from './scale9ShapeCommands';
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,EAC5B,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC5B,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,gCAAgC,EAChC,kBAAkB,EAClB,gCAAgC,EAChC,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,oBAAoB,EACpB,sBAAsB,EACtB,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,2BAA2B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,EACX,8BAA8B,EAC9B,8BAA8B,EAC9B,oBAAoB,EACpB,cAAc,EACd,gBAAgB,EAChB,2BAA2B,EAC3B,oBAAoB,EACpB,4BAA4B,EAC5B,iBAAiB,EACjB,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,0BAA0B,EAC1B,2BAA2B,EAC3B,4BAA4B,EAC5B,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,yBAAyB,EACzB,gCAAgC,EAChC,kBAAkB,EAClB,gCAAgC,EAChC,iBAAiB,EACjB,gBAAgB,EAChB,+BAA+B,EAC/B,iBAAiB,EACjB,WAAW,EACX,qBAAqB,EACrB,0BAA0B,EAC1B,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,qBAAqB,EACrB,4BAA4B,EAC5B,oBAAoB,EACpB,sBAAsB,EACtB,YAAY,EACZ,wBAAwB,EACxB,YAAY,EACZ,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,YAAY,CAAC;AACpB,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MorphShape, MorphShapeData, MorphShapeRuntime, PartialNode, PathMorph } from '@flighthq/types/contract';
|
|
2
|
+
export declare function appendMorphShapePath(shape: MorphShape): void;
|
|
3
|
+
export declare function createMorphShape(morph: Readonly<PathMorph>, obj?: Readonly<PartialNode<MorphShape>>): MorphShape;
|
|
4
|
+
export declare function createMorphShapeData(morph: Readonly<PathMorph>, data?: Readonly<Partial<MorphShapeData>>): MorphShapeData;
|
|
5
|
+
export declare function createMorphShapeRuntime(): MorphShapeRuntime;
|
|
6
|
+
export declare function getMorphShapeRuntime(source: Readonly<MorphShape>): Readonly<MorphShapeRuntime>;
|
|
7
|
+
export declare function setMorphShapeProgress(shape: MorphShape, progress: number): void;
|
|
8
|
+
//# sourceMappingURL=morphShape.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"morphShape.d.ts","sourceRoot":"","sources":["../src/morphShape.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAStH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAG5D;AAMD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC,GAAG,UAAU,CAOhH;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,EAC1B,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,GACvC,cAAc,CAUhB;AAED,wBAAgB,uBAAuB,IAAI,iBAAiB,CAE3D;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAE9F;AAKD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAK/E"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { invalidateContent } from '@flighthq/node/contract';
|
|
2
|
+
import { createPath, samplePathMorph } from '@flighthq/path/contract';
|
|
3
|
+
import { createNode2D, getNode2DRuntime } from '@flighthq/scene2d/contract';
|
|
4
|
+
import { MorphShapeKind } from '@flighthq/types/contract';
|
|
5
|
+
import { createShapeRuntime } from './shape';
|
|
6
|
+
import { appendShapePath } from './shapeCommands';
|
|
7
|
+
// Adds the MorphShape's stable sampled path at the current point in its retained command stream. This
|
|
8
|
+
// composes with the ordinary beginFill/lineStyle/endFill commands: callers author styling exactly as
|
|
9
|
+
// they do for Shape, then insert the live morph geometry wherever it belongs.
|
|
10
|
+
export function appendMorphShapePath(shape) {
|
|
11
|
+
const path = shape.data.path;
|
|
12
|
+
appendShapePath(shape, path.commands, path.data, path.winding);
|
|
13
|
+
}
|
|
14
|
+
// Creates a retained MorphShape entity around a prepared path morph. The command stream starts empty,
|
|
15
|
+
// like createShape; use appendMorphShapePath after the desired fill/stroke commands. Playback is
|
|
16
|
+
// intentionally absent—animation/timeline code drives setMorphShapeProgress explicitly. Backends expose
|
|
17
|
+
// their default MorphShape renderer as an explicit alias of their Shape command-stream renderer.
|
|
18
|
+
export function createMorphShape(morph, obj) {
|
|
19
|
+
return createNode2D(MorphShapeKind, obj, (data) => createMorphShapeData(morph, data), createMorphShapeRuntime);
|
|
20
|
+
}
|
|
21
|
+
export function createMorphShapeData(morph, data) {
|
|
22
|
+
const progress = data?.progress ?? 0;
|
|
23
|
+
const path = createPath(morph.winding);
|
|
24
|
+
samplePathMorph(path, morph, progress);
|
|
25
|
+
return {
|
|
26
|
+
commands: data?.commands ?? [],
|
|
27
|
+
morph,
|
|
28
|
+
path,
|
|
29
|
+
progress,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export function createMorphShapeRuntime() {
|
|
33
|
+
return createShapeRuntime();
|
|
34
|
+
}
|
|
35
|
+
export function getMorphShapeRuntime(source) {
|
|
36
|
+
return getNode2DRuntime(source);
|
|
37
|
+
}
|
|
38
|
+
// Samples changed progress into the stable Path arrays retained by drawPath commands, then invalidates
|
|
39
|
+
// Shape content so bounds and every backend rebuild from the new coordinates. Reapplying the same value
|
|
40
|
+
// is a no-op; progress remains unclamped to preserve the path layer's deliberate easing-overshoot contract.
|
|
41
|
+
export function setMorphShapeProgress(shape, progress) {
|
|
42
|
+
if (shape.data.progress === progress)
|
|
43
|
+
return;
|
|
44
|
+
shape.data.progress = progress;
|
|
45
|
+
samplePathMorph(shape.data.path, shape.data.morph, progress);
|
|
46
|
+
invalidateContent(shape);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=morphShape.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"morphShape.js","sourceRoot":"","sources":["../src/morphShape.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAE5E,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,sGAAsG;AACtG,qGAAqG;AACrG,8EAA8E;AAC9E,MAAM,UAAU,oBAAoB,CAAC,KAAiB;IACpD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;IAC7B,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,sGAAsG;AACtG,iGAAiG;AACjG,wGAAwG;AACxG,iGAAiG;AACjG,MAAM,UAAU,gBAAgB,CAAC,KAA0B,EAAE,GAAuC;IAClG,OAAO,YAAY,CACjB,cAAc,EACd,GAAG,EACH,CAAC,IAAI,EAAE,EAAE,CAAC,oBAAoB,CAAC,KAAK,EAAE,IAAI,CAAC,EAC3C,uBAAuB,CACV,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAClC,KAA0B,EAC1B,IAAwC;IAExC,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;IACvC,OAAO;QACL,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,EAAE;QAC9B,KAAK;QACL,IAAI;QACJ,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,OAAO,kBAAkB,EAAuB,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAA4B;IAC/D,OAAO,gBAAgB,CAAC,MAAM,CAAsB,CAAC;AACvD,CAAC;AAED,uGAAuG;AACvG,wGAAwG;AACxG,4GAA4G;AAC5G,MAAM,UAAU,qBAAqB,CAAC,KAAiB,EAAE,QAAgB;IACvE,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO;IAC7C,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC/B,eAAe,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAC7D,iBAAiB,CAAC,KAAK,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AnimationChannel, AnimationClip, MorphShape, MorphShapeAnimationTarget } from '@flighthq/types/contract';
|
|
2
|
+
export declare function applyAnimationClipToMorphShape(clip: Readonly<AnimationClip>, time: number): void;
|
|
3
|
+
export declare function applyMorphShapeAnimationSample(sampled: Readonly<ArrayLike<number>>, channel: Readonly<AnimationChannel>): boolean;
|
|
4
|
+
export declare function createMorphShapeAnimationTarget(shape: MorphShape): MorphShapeAnimationTarget;
|
|
5
|
+
//# sourceMappingURL=morphShapeAnimation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"morphShapeAnimation.d.ts","sourceRoot":"","sources":["../src/morphShapeAnimation.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,UAAU,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAOvH,wBAAgB,8BAA8B,CAAC,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAEhG;AAID,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,QAAQ,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,EACpC,OAAO,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAClC,OAAO,CAOT;AAID,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,UAAU,GAAG,yBAAyB,CAE5F"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { sampleAnimationClip } from '@flighthq/animation/contract';
|
|
2
|
+
import { MorphShapeKind } from '@flighthq/types/contract';
|
|
3
|
+
import { setMorphShapeProgress } from './morphShape';
|
|
4
|
+
// Samples every channel at `time` and applies the channels carrying MorphShapeAnimationTarget refs.
|
|
5
|
+
// Foreign targets are ignored, so one clip may compose MorphShape progress with other domain sinks.
|
|
6
|
+
export function applyAnimationClipToMorphShape(clip, time) {
|
|
7
|
+
sampleAnimationClip(morphShapeAnimationScratch, clip, time, applyMorphShapeAnimationSample);
|
|
8
|
+
}
|
|
9
|
+
// Allocation-free visitor shared by clip, crossfade, blend-tree, state-machine, and layer-stack
|
|
10
|
+
// samplers. Returns whether the channel carried a valid MorphShape animation target.
|
|
11
|
+
export function applyMorphShapeAnimationSample(sampled, channel) {
|
|
12
|
+
const target = channel.targetRef;
|
|
13
|
+
if (target === null || typeof target !== 'object' || target.shape === undefined)
|
|
14
|
+
return false;
|
|
15
|
+
const shape = target.shape;
|
|
16
|
+
if (shape === null || typeof shape !== 'object' || shape.kind !== MorphShapeKind)
|
|
17
|
+
return false;
|
|
18
|
+
setMorphShapeProgress(shape, sampled[0]);
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
// Allocates one stable binding descriptor. Keep and reuse this identity when multiple animation
|
|
22
|
+
// controllers should recognize their MorphShape progress channels as the same target.
|
|
23
|
+
export function createMorphShapeAnimationTarget(shape) {
|
|
24
|
+
return { shape };
|
|
25
|
+
}
|
|
26
|
+
const morphShapeAnimationScratch = [0];
|
|
27
|
+
//# sourceMappingURL=morphShapeAnimation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"morphShapeAnimation.js","sourceRoot":"","sources":["../src/morphShapeAnimation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAE1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,oGAAoG;AACpG,oGAAoG;AACpG,MAAM,UAAU,8BAA8B,CAAC,IAA6B,EAAE,IAAY;IACxF,mBAAmB,CAAC,0BAA0B,EAAE,IAAI,EAAE,IAAI,EAAE,8BAA8B,CAAC,CAAC;AAC9F,CAAC;AAED,gGAAgG;AAChG,qFAAqF;AACrF,MAAM,UAAU,8BAA8B,CAC5C,OAAoC,EACpC,OAAmC;IAEnC,MAAM,MAAM,GAAG,OAAO,CAAC,SAA6C,CAAC;IACrE,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,KAAK,CAAC;IAC9F,MAAM,KAAK,GAAG,MAAM,CAAC,KAA0B,CAAC;IAChD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO,KAAK,CAAC;IAC/F,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACzC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gGAAgG;AAChG,sFAAsF;AACtF,MAAM,UAAU,+BAA+B,CAAC,KAAiB;IAC/D,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED,MAAM,0BAA0B,GAAa,CAAC,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/shape",
|
|
3
|
-
"version": "0.3.0-next.
|
|
3
|
+
"version": "0.3.0-next.1584.a68fe91",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/flighthq/flight.git",
|
|
@@ -36,15 +36,16 @@
|
|
|
36
36
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@flighthq/
|
|
40
|
-
"@flighthq/
|
|
41
|
-
"@flighthq/
|
|
42
|
-
"@flighthq/
|
|
43
|
-
"@flighthq/
|
|
39
|
+
"@flighthq/animation": "0.3.0-next.1584.a68fe91",
|
|
40
|
+
"@flighthq/scene2d": "0.3.0-next.1584.a68fe91",
|
|
41
|
+
"@flighthq/geometry": "0.3.0-next.1584.a68fe91",
|
|
42
|
+
"@flighthq/node": "0.3.0-next.1584.a68fe91",
|
|
43
|
+
"@flighthq/path": "0.3.0-next.1584.a68fe91",
|
|
44
|
+
"@flighthq/types": "0.3.0-next.1584.a68fe91"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
47
|
"typescript": "^5.3.0"
|
|
47
48
|
},
|
|
48
|
-
"description": "Vector Shape display
|
|
49
|
+
"description": "Vector Shape and MorphShape display nodes: retained drawing commands, path morphing, scale-9, and hit testing",
|
|
49
50
|
"sideEffects": false
|
|
50
51
|
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { createRectangle } from '@flighthq/geometry/contract';
|
|
2
|
+
import { getNodeLocalContentRevision } from '@flighthq/node/contract';
|
|
3
|
+
import { appendPathLineTo, appendPathMoveTo, createPath, createPathMorph } from '@flighthq/path/contract';
|
|
4
|
+
import type { PathMorph, ShapeCommandToken } from '@flighthq/types/contract';
|
|
5
|
+
import { MorphShapeKind } from '@flighthq/types/contract';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
appendMorphShapePath,
|
|
9
|
+
createMorphShape,
|
|
10
|
+
createMorphShapeData,
|
|
11
|
+
createMorphShapeRuntime,
|
|
12
|
+
getMorphShapeRuntime,
|
|
13
|
+
setMorphShapeProgress,
|
|
14
|
+
} from './morphShape';
|
|
15
|
+
import { getShapeBounds } from './shape';
|
|
16
|
+
import { appendShapeBeginFill, appendShapeEndFill } from './shapeCommands';
|
|
17
|
+
|
|
18
|
+
describe('appendMorphShapePath', () => {
|
|
19
|
+
it('inserts the live path between ordinary Shape styling commands', () => {
|
|
20
|
+
const shape = createMorphShape(createTestMorph());
|
|
21
|
+
appendShapeBeginFill(shape, 0x336699, 0.75);
|
|
22
|
+
|
|
23
|
+
appendMorphShapePath(shape);
|
|
24
|
+
appendShapeEndFill(shape);
|
|
25
|
+
|
|
26
|
+
expect(shape.data.commands).toStrictEqual([
|
|
27
|
+
'beginFill',
|
|
28
|
+
2,
|
|
29
|
+
0x336699,
|
|
30
|
+
0.75,
|
|
31
|
+
'drawPath',
|
|
32
|
+
3,
|
|
33
|
+
shape.data.path.commands,
|
|
34
|
+
shape.data.path.data,
|
|
35
|
+
'nonZero',
|
|
36
|
+
'endFill',
|
|
37
|
+
0,
|
|
38
|
+
]);
|
|
39
|
+
expect(shape.data.commands[6]).toBe(shape.data.path.commands);
|
|
40
|
+
expect(shape.data.commands[7]).toBe(shape.data.path.data);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
describe('createMorphShape', () => {
|
|
45
|
+
it('creates a distinct MorphShape over the prepared start sample', () => {
|
|
46
|
+
const morph = createTestMorph();
|
|
47
|
+
|
|
48
|
+
const shape = createMorphShape(morph);
|
|
49
|
+
|
|
50
|
+
expect(shape.kind).toBe(MorphShapeKind);
|
|
51
|
+
expect(shape.data.commands).toStrictEqual([]);
|
|
52
|
+
expect(shape.data.morph).toBe(morph);
|
|
53
|
+
expect(shape.data.path.commands).toStrictEqual(morph.commands);
|
|
54
|
+
expect(shape.data.path.data).toStrictEqual(morph.startData);
|
|
55
|
+
expect(shape.data.progress).toBe(0);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('uses initial progress and a provided command buffer', () => {
|
|
59
|
+
const commands: ShapeCommandToken[] = ['beginFill', 2, 0xff0000, 1];
|
|
60
|
+
|
|
61
|
+
const shape = createMorphShape(createTestMorph(), { data: { commands, progress: 0.5 } });
|
|
62
|
+
|
|
63
|
+
expect(shape.data.commands).toBe(commands);
|
|
64
|
+
expect(shape.data.path.data).toStrictEqual([5, 10, 10, 10, 15, 10, 20, 10]);
|
|
65
|
+
expect(shape.data.progress).toBe(0.5);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('owns a distinct sampled path for each retained shape', () => {
|
|
69
|
+
const morph = createTestMorph();
|
|
70
|
+
|
|
71
|
+
const a = createMorphShape(morph);
|
|
72
|
+
const b = createMorphShape(morph);
|
|
73
|
+
|
|
74
|
+
expect(a).not.toBe(b);
|
|
75
|
+
expect(a.data.path).not.toBe(b.data.path);
|
|
76
|
+
expect(a.data.path.commands).not.toBe(b.data.path.commands);
|
|
77
|
+
expect(a.data.path.data).not.toBe(b.data.path.data);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('createMorphShapeData', () => {
|
|
82
|
+
it('samples the requested initial endpoint exactly', () => {
|
|
83
|
+
const morph = createTestMorph();
|
|
84
|
+
|
|
85
|
+
const data = createMorphShapeData(morph, { progress: 1 });
|
|
86
|
+
|
|
87
|
+
expect(data.path.data).toStrictEqual(morph.endData);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe('createMorphShapeRuntime', () => {
|
|
92
|
+
it('creates the standard Shape bounds runtime', () => {
|
|
93
|
+
expect(createMorphShapeRuntime().computeLocalBoundsRectangle).toBeTypeOf('function');
|
|
94
|
+
});
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('getMorphShapeRuntime', () => {
|
|
98
|
+
it('returns the runtime attached to the retained shape', () => {
|
|
99
|
+
expect(getMorphShapeRuntime(createMorphShape(createTestMorph()))).not.toBeNull();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('setMorphShapeProgress', () => {
|
|
104
|
+
it('does not invalidate or resample unchanged progress', () => {
|
|
105
|
+
const shape = createMorphShape(createTestMorph());
|
|
106
|
+
const revision = getNodeLocalContentRevision(shape);
|
|
107
|
+
const data = shape.data.path.data.slice();
|
|
108
|
+
|
|
109
|
+
setMorphShapeProgress(shape, 0);
|
|
110
|
+
|
|
111
|
+
expect(shape.data.path.data).toStrictEqual(data);
|
|
112
|
+
expect(getNodeLocalContentRevision(shape)).toBe(revision);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('resamples stable buffers, stores progress, and invalidates content', () => {
|
|
116
|
+
const shape = createMorphShape(createTestMorph());
|
|
117
|
+
appendMorphShapePath(shape);
|
|
118
|
+
const commands = shape.data.path.commands;
|
|
119
|
+
const data = shape.data.path.data;
|
|
120
|
+
const revision = getNodeLocalContentRevision(shape);
|
|
121
|
+
|
|
122
|
+
setMorphShapeProgress(shape, 0.5);
|
|
123
|
+
|
|
124
|
+
expect(shape.data.progress).toBe(0.5);
|
|
125
|
+
expect(shape.data.path.commands).toBe(commands);
|
|
126
|
+
expect(shape.data.path.data).toBe(data);
|
|
127
|
+
expect(shape.data.path.data).toStrictEqual([5, 10, 10, 10, 15, 10, 20, 10]);
|
|
128
|
+
expect(getNodeLocalContentRevision(shape)).toBe(revision + 1);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('updates the bounds observed through the ordinary Shape runtime', () => {
|
|
132
|
+
const shape = createMorphShape(createTestMorph());
|
|
133
|
+
appendMorphShapePath(shape);
|
|
134
|
+
const bounds = createRectangle();
|
|
135
|
+
getShapeBounds(bounds, shape);
|
|
136
|
+
expect(bounds).toMatchObject({ x: 0, y: 0, width: 10, height: 0 });
|
|
137
|
+
|
|
138
|
+
setMorphShapeProgress(shape, 1);
|
|
139
|
+
getShapeBounds(bounds, shape);
|
|
140
|
+
|
|
141
|
+
expect(bounds).toMatchObject({ x: 10, y: 20, width: 20, height: 0 });
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('preserves unclamped easing overshoot', () => {
|
|
145
|
+
const shape = createMorphShape(createTestMorph());
|
|
146
|
+
|
|
147
|
+
setMorphShapeProgress(shape, 1.5);
|
|
148
|
+
|
|
149
|
+
expect(shape.data.path.data.slice(0, 2)).toStrictEqual([15, 30]);
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
function createTestMorph(): PathMorph {
|
|
154
|
+
const start = createPath();
|
|
155
|
+
appendPathMoveTo(start, 0, 0);
|
|
156
|
+
appendPathLineTo(start, 10, 0);
|
|
157
|
+
const end = createPath();
|
|
158
|
+
appendPathMoveTo(end, 10, 20);
|
|
159
|
+
appendPathLineTo(end, 30, 20);
|
|
160
|
+
return createPathMorph(start, end)!;
|
|
161
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAnimationBlendTree,
|
|
3
|
+
createAnimationBlendTreeInput,
|
|
4
|
+
createAnimationChannel,
|
|
5
|
+
createAnimationClip,
|
|
6
|
+
createAnimationPlayer,
|
|
7
|
+
createAnimationTrack,
|
|
8
|
+
sampleAnimationBlendTree,
|
|
9
|
+
} from '@flighthq/animation/contract';
|
|
10
|
+
import { getNodeLocalContentRevision } from '@flighthq/node/contract';
|
|
11
|
+
import { appendPathLineTo, appendPathMoveTo, createPath, createPathMorph } from '@flighthq/path/contract';
|
|
12
|
+
import type { MorphShape, MorphShapeAnimationTarget } from '@flighthq/types/contract';
|
|
13
|
+
|
|
14
|
+
import { createMorphShape } from './morphShape';
|
|
15
|
+
import {
|
|
16
|
+
applyAnimationClipToMorphShape,
|
|
17
|
+
applyMorphShapeAnimationSample,
|
|
18
|
+
createMorphShapeAnimationTarget,
|
|
19
|
+
} from './morphShapeAnimation';
|
|
20
|
+
|
|
21
|
+
describe('applyAnimationClipToMorphShape', () => {
|
|
22
|
+
it('samples scalar progress while preserving easing overshoot', () => {
|
|
23
|
+
const shape = createTestMorphShape();
|
|
24
|
+
const target = createMorphShapeAnimationTarget(shape);
|
|
25
|
+
const clip = createAnimationClip([
|
|
26
|
+
createAnimationChannel(
|
|
27
|
+
createAnimationTrack({ easing: (progress) => progress * 2, times: [0, 1], values: [0, 1] }),
|
|
28
|
+
target,
|
|
29
|
+
),
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
applyAnimationClipToMorphShape(clip, 0.75);
|
|
33
|
+
|
|
34
|
+
expect(shape.data.progress).toBe(1.5);
|
|
35
|
+
expect(shape.data.path.data.slice(0, 2)).toStrictEqual([30, 45]);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('ignores foreign channels in a composed clip', () => {
|
|
39
|
+
const shape = createTestMorphShape();
|
|
40
|
+
const clip = createAnimationClip([
|
|
41
|
+
createAnimationChannel(createAnimationTrack({ times: [0, 1], values: [0, 100] }), { node: shape, path: 'X' }),
|
|
42
|
+
createAnimationChannel(
|
|
43
|
+
createAnimationTrack({ times: [0, 1], values: [0, 1] }),
|
|
44
|
+
createMorphShapeAnimationTarget(shape),
|
|
45
|
+
),
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
applyAnimationClipToMorphShape(clip, 0.25);
|
|
49
|
+
|
|
50
|
+
expect(shape.x).toBe(0);
|
|
51
|
+
expect(shape.data.progress).toBe(0.25);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
describe('applyMorphShapeAnimationSample', () => {
|
|
56
|
+
it('mutates stable path buffers and invalidates retained content', () => {
|
|
57
|
+
const shape = createTestMorphShape();
|
|
58
|
+
const commands = shape.data.path.commands;
|
|
59
|
+
const data = shape.data.path.data;
|
|
60
|
+
const revision = getNodeLocalContentRevision(shape);
|
|
61
|
+
const channel = createAnimationChannel(
|
|
62
|
+
createAnimationTrack({ times: [0, 1], values: [0, 1] }),
|
|
63
|
+
createMorphShapeAnimationTarget(shape),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
expect(applyMorphShapeAnimationSample([0.5], channel)).toBe(true);
|
|
67
|
+
expect(shape.data.progress).toBe(0.5);
|
|
68
|
+
expect(shape.data.path.commands).toBe(commands);
|
|
69
|
+
expect(shape.data.path.data).toBe(data);
|
|
70
|
+
expect(getNodeLocalContentRevision(shape)).toBe(revision + 1);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('serves as the sink for composed animation samples', () => {
|
|
74
|
+
const shape = createTestMorphShape();
|
|
75
|
+
const target = createMorphShapeAnimationTarget(shape);
|
|
76
|
+
const a = createAnimationPlayer(
|
|
77
|
+
createAnimationClip([createAnimationChannel(createAnimationTrack({ times: [0, 1], values: [0, 1] }), target)]),
|
|
78
|
+
{ time: 0.5 },
|
|
79
|
+
);
|
|
80
|
+
const b = createAnimationPlayer(
|
|
81
|
+
createAnimationClip([createAnimationChannel(createAnimationTrack({ times: [0, 1], values: [0, 0.2] }), target)]),
|
|
82
|
+
{ time: 0.5 },
|
|
83
|
+
);
|
|
84
|
+
const tree = createAnimationBlendTree([createAnimationBlendTreeInput(a, 1), createAnimationBlendTreeInput(b, 1)]);
|
|
85
|
+
|
|
86
|
+
sampleAnimationBlendTree([0], tree, applyMorphShapeAnimationSample);
|
|
87
|
+
|
|
88
|
+
expect(shape.data.progress).toBeCloseTo(0.3);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('returns false for foreign targets without changing the shape', () => {
|
|
92
|
+
const shape = createTestMorphShape();
|
|
93
|
+
const channel = createAnimationChannel(createAnimationTrack({ times: [0, 1], values: [0, 1] }), {
|
|
94
|
+
shape: { kind: 'acme.NotMorphShape' },
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
expect(applyMorphShapeAnimationSample([1], channel)).toBe(false);
|
|
98
|
+
expect(shape.data.progress).toBe(0);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe('createMorphShapeAnimationTarget', () => {
|
|
103
|
+
it('allocates a reusable target descriptor for one MorphShape', () => {
|
|
104
|
+
const shape = createTestMorphShape();
|
|
105
|
+
|
|
106
|
+
const target: MorphShapeAnimationTarget = createMorphShapeAnimationTarget(shape);
|
|
107
|
+
|
|
108
|
+
expect(target).toStrictEqual({ shape });
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
function createTestMorphShape(): MorphShape {
|
|
113
|
+
const start = createPath();
|
|
114
|
+
appendPathMoveTo(start, 0, 0);
|
|
115
|
+
appendPathLineTo(start, 10, 0);
|
|
116
|
+
const end = createPath();
|
|
117
|
+
appendPathMoveTo(end, 20, 30);
|
|
118
|
+
appendPathLineTo(end, 40, 30);
|
|
119
|
+
return createMorphShape(createPathMorph(start, end)!);
|
|
120
|
+
}
|