@twick/2d 0.14.0 → 1.14.3
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/LICENSE +21 -21
- package/editor/editor/tsconfig.build.tsbuildinfo +1 -1
- package/lib/components/Audio.d.ts.map +1 -1
- package/lib/components/Audio.js +33 -3
- package/lib/components/CodeBlock.d.ts +1 -1
- package/lib/components/Img.js +23 -23
- package/lib/components/Line.js +31 -31
- package/lib/components/Media.d.ts +6 -0
- package/lib/components/Media.d.ts.map +1 -1
- package/lib/components/Media.js +277 -61
- package/lib/components/Node.d.ts +1 -1
- package/lib/components/Path.d.ts +1 -1
- package/lib/components/SVG.d.ts +1 -1
- package/lib/components/Shape.d.ts +1 -1
- package/lib/components/Spline.js +25 -25
- package/lib/components/Video.d.ts +0 -1
- package/lib/components/Video.d.ts.map +1 -1
- package/lib/components/Video.js +70 -65
- package/lib/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +4 -5
- package/src/editor/NodeInspectorConfig.tsx +76 -76
- package/src/editor/PreviewOverlayConfig.tsx +67 -67
- package/src/editor/Provider.tsx +93 -93
- package/src/editor/SceneGraphTabConfig.tsx +81 -81
- package/src/editor/icons/CircleIcon.tsx +7 -7
- package/src/editor/icons/CodeBlockIcon.tsx +8 -8
- package/src/editor/icons/CurveIcon.tsx +7 -7
- package/src/editor/icons/GridIcon.tsx +7 -7
- package/src/editor/icons/IconMap.ts +35 -35
- package/src/editor/icons/ImgIcon.tsx +8 -8
- package/src/editor/icons/LayoutIcon.tsx +9 -9
- package/src/editor/icons/LineIcon.tsx +7 -7
- package/src/editor/icons/NodeIcon.tsx +7 -7
- package/src/editor/icons/RayIcon.tsx +7 -7
- package/src/editor/icons/RectIcon.tsx +7 -7
- package/src/editor/icons/ShapeIcon.tsx +7 -7
- package/src/editor/icons/TxtIcon.tsx +8 -8
- package/src/editor/icons/VideoIcon.tsx +7 -7
- package/src/editor/icons/View2DIcon.tsx +10 -10
- package/src/editor/index.ts +17 -17
- package/src/editor/tree/DetachedRoot.tsx +23 -23
- package/src/editor/tree/NodeElement.tsx +74 -74
- package/src/editor/tree/TreeElement.tsx +72 -72
- package/src/editor/tree/TreeRoot.tsx +10 -10
- package/src/editor/tree/ViewRoot.tsx +20 -20
- package/src/editor/tree/index.module.scss +38 -38
- package/src/editor/tree/index.ts +3 -3
- package/src/editor/tsconfig.build.json +5 -5
- package/src/editor/tsconfig.json +12 -12
- package/src/editor/tsdoc.json +4 -4
- package/src/editor/vite-env.d.ts +1 -1
- package/src/lib/code/CodeCursor.ts +445 -445
- package/src/lib/code/CodeDiffer.ts +78 -78
- package/src/lib/code/CodeFragment.ts +97 -97
- package/src/lib/code/CodeHighlighter.ts +75 -75
- package/src/lib/code/CodeMetrics.ts +47 -47
- package/src/lib/code/CodeRange.test.ts +74 -74
- package/src/lib/code/CodeRange.ts +216 -216
- package/src/lib/code/CodeScope.ts +101 -101
- package/src/lib/code/CodeSelection.ts +24 -24
- package/src/lib/code/CodeSignal.ts +327 -327
- package/src/lib/code/CodeTokenizer.ts +54 -54
- package/src/lib/code/DefaultHighlightStyle.ts +98 -98
- package/src/lib/code/LezerHighlighter.ts +113 -113
- package/src/lib/code/diff.test.ts +311 -311
- package/src/lib/code/diff.ts +319 -319
- package/src/lib/code/extractRange.ts +126 -126
- package/src/lib/code/index.ts +13 -13
- package/src/lib/components/Audio.ts +168 -131
- package/src/lib/components/Bezier.ts +105 -105
- package/src/lib/components/Circle.ts +266 -266
- package/src/lib/components/Code.ts +526 -526
- package/src/lib/components/CodeBlock.ts +576 -576
- package/src/lib/components/CubicBezier.ts +112 -112
- package/src/lib/components/Curve.ts +455 -455
- package/src/lib/components/Grid.ts +135 -135
- package/src/lib/components/Icon.ts +96 -96
- package/src/lib/components/Img.ts +319 -319
- package/src/lib/components/Knot.ts +157 -157
- package/src/lib/components/Latex.ts +122 -122
- package/src/lib/components/Layout.ts +1092 -1092
- package/src/lib/components/Line.ts +429 -429
- package/src/lib/components/Media.ts +576 -346
- package/src/lib/components/Node.ts +1940 -1940
- package/src/lib/components/Path.ts +137 -137
- package/src/lib/components/Polygon.ts +171 -171
- package/src/lib/components/QuadBezier.ts +100 -100
- package/src/lib/components/Ray.ts +125 -125
- package/src/lib/components/Rect.ts +187 -187
- package/src/lib/components/Rive.ts +156 -156
- package/src/lib/components/SVG.ts +797 -797
- package/src/lib/components/Shape.ts +143 -143
- package/src/lib/components/Spline.ts +344 -344
- package/src/lib/components/Txt.test.tsx +81 -81
- package/src/lib/components/Txt.ts +203 -203
- package/src/lib/components/TxtLeaf.ts +205 -205
- package/src/lib/components/Video.ts +461 -462
- package/src/lib/components/View2D.ts +98 -98
- package/src/lib/components/__tests__/children.test.tsx +142 -142
- package/src/lib/components/__tests__/clone.test.tsx +126 -126
- package/src/lib/components/__tests__/generatorTest.ts +28 -28
- package/src/lib/components/__tests__/mockScene2D.ts +45 -45
- package/src/lib/components/__tests__/query.test.tsx +122 -122
- package/src/lib/components/__tests__/state.test.tsx +60 -60
- package/src/lib/components/index.ts +28 -28
- package/src/lib/components/types.ts +35 -35
- package/src/lib/curves/ArcSegment.ts +159 -159
- package/src/lib/curves/CircleSegment.ts +77 -77
- package/src/lib/curves/CubicBezierSegment.ts +78 -78
- package/src/lib/curves/CurveDrawingInfo.ts +11 -11
- package/src/lib/curves/CurvePoint.ts +15 -15
- package/src/lib/curves/CurveProfile.ts +7 -7
- package/src/lib/curves/KnotInfo.ts +10 -10
- package/src/lib/curves/LineSegment.ts +62 -62
- package/src/lib/curves/Polynomial.ts +355 -355
- package/src/lib/curves/Polynomial2D.ts +62 -62
- package/src/lib/curves/PolynomialSegment.ts +124 -124
- package/src/lib/curves/QuadBezierSegment.ts +64 -64
- package/src/lib/curves/Segment.ts +17 -17
- package/src/lib/curves/UniformPolynomialCurveSampler.ts +94 -94
- package/src/lib/curves/createCurveProfileLerp.ts +471 -471
- package/src/lib/curves/getBezierSplineProfile.ts +223 -223
- package/src/lib/curves/getCircleProfile.ts +86 -86
- package/src/lib/curves/getPathProfile.ts +178 -178
- package/src/lib/curves/getPointAtDistance.ts +21 -21
- package/src/lib/curves/getPolylineProfile.test.ts +21 -21
- package/src/lib/curves/getPolylineProfile.ts +89 -89
- package/src/lib/curves/getRectProfile.ts +139 -139
- package/src/lib/curves/index.ts +16 -16
- package/src/lib/decorators/canvasStyleSignal.ts +16 -16
- package/src/lib/decorators/colorSignal.ts +9 -9
- package/src/lib/decorators/compound.ts +72 -72
- package/src/lib/decorators/computed.ts +18 -18
- package/src/lib/decorators/defaultStyle.ts +18 -18
- package/src/lib/decorators/filtersSignal.ts +136 -136
- package/src/lib/decorators/index.ts +10 -10
- package/src/lib/decorators/initializers.ts +32 -32
- package/src/lib/decorators/nodeName.ts +13 -13
- package/src/lib/decorators/signal.test.ts +90 -90
- package/src/lib/decorators/signal.ts +345 -345
- package/src/lib/decorators/spacingSignal.ts +15 -15
- package/src/lib/decorators/vector2Signal.ts +30 -30
- package/src/lib/globals.d.ts +2 -2
- package/src/lib/index.ts +8 -8
- package/src/lib/jsx-dev-runtime.ts +2 -2
- package/src/lib/jsx-runtime.ts +46 -46
- package/src/lib/parse-svg-path.d.ts +14 -14
- package/src/lib/partials/Filter.ts +180 -180
- package/src/lib/partials/Gradient.ts +102 -102
- package/src/lib/partials/Pattern.ts +34 -34
- package/src/lib/partials/ShaderConfig.ts +117 -117
- package/src/lib/partials/index.ts +4 -4
- package/src/lib/partials/types.ts +58 -58
- package/src/lib/scenes/Scene2D.ts +242 -242
- package/src/lib/scenes/index.ts +3 -3
- package/src/lib/scenes/makeScene2D.ts +16 -16
- package/src/lib/scenes/useScene2D.ts +6 -6
- package/src/lib/tsconfig.build.json +5 -5
- package/src/lib/tsconfig.json +10 -10
- package/src/lib/tsdoc.json +4 -4
- package/src/lib/utils/CanvasUtils.ts +306 -306
- package/src/lib/utils/diff.test.ts +453 -453
- package/src/lib/utils/diff.ts +148 -148
- package/src/lib/utils/index.ts +2 -2
- package/src/lib/utils/is.ts +11 -11
- package/src/lib/utils/makeSignalExtensions.ts +30 -30
- package/src/lib/utils/video/declarations.d.ts +1 -1
- package/src/lib/utils/video/ffmpeg-client.ts +50 -50
- package/src/lib/utils/video/mp4-parser-manager.ts +72 -72
- package/src/lib/utils/video/parser/index.ts +1 -1
- package/src/lib/utils/video/parser/parser.ts +257 -257
- package/src/lib/utils/video/parser/sampler.ts +72 -72
- package/src/lib/utils/video/parser/segment.ts +302 -302
- package/src/lib/utils/video/parser/sink.ts +29 -29
- package/src/lib/utils/video/parser/utils.ts +31 -31
- package/src/tsconfig.base.json +19 -19
- package/src/tsconfig.build.json +8 -8
- package/src/tsconfig.json +5 -5
- package/tsconfig.project.json +7 -7
- package/lib/components/utils/waitUntil.d.ts +0 -7
- package/lib/components/utils/waitUntil.d.ts.map +0 -1
- package/lib/components/utils/waitUntil.js +0 -15
- package/lib/utils/waitUntil.d.ts +0 -7
- package/lib/utils/waitUntil.d.ts.map +0 -1
- package/lib/utils/waitUntil.js +0 -15
- package/src/lib/utils/waitUntil.ts +0 -18
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import {createSignal, join, waitFor} from '@twick/core';
|
|
2
|
-
import {describe, expect, it} from 'vitest';
|
|
3
|
-
import {Circle} from '../Circle';
|
|
4
|
-
import {generatorTest} from './generatorTest';
|
|
5
|
-
import {mockScene2D} from './mockScene2D';
|
|
6
|
-
|
|
7
|
-
describe('state', () => {
|
|
8
|
-
mockScene2D();
|
|
9
|
-
|
|
10
|
-
it('Restoring state', () => {
|
|
11
|
-
const signal = createSignal(45);
|
|
12
|
-
const circle = (
|
|
13
|
-
<Circle lineWidth={8} startAngle={signal} end={0.5} />
|
|
14
|
-
) as Circle;
|
|
15
|
-
circle.save();
|
|
16
|
-
|
|
17
|
-
circle.lineWidth(16);
|
|
18
|
-
circle.startAngle(90);
|
|
19
|
-
circle.end(0.25);
|
|
20
|
-
|
|
21
|
-
circle.restore();
|
|
22
|
-
|
|
23
|
-
expect(circle.lineWidth()).toBe(8);
|
|
24
|
-
expect(circle.startAngle()).toBe(45);
|
|
25
|
-
expect(circle.end()).toBe(0.5);
|
|
26
|
-
|
|
27
|
-
signal(180);
|
|
28
|
-
|
|
29
|
-
expect(circle.startAngle()).toBe(45);
|
|
30
|
-
expect(circle.startArrow.context.isInitial()).toBe(true);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it(
|
|
34
|
-
'Tweening state',
|
|
35
|
-
generatorTest(function* () {
|
|
36
|
-
const signal = createSignal(20);
|
|
37
|
-
const circle = (
|
|
38
|
-
<Circle lineWidth={8} startAngle={signal} end={0.5} />
|
|
39
|
-
) as Circle;
|
|
40
|
-
circle.save();
|
|
41
|
-
|
|
42
|
-
circle.lineWidth(16);
|
|
43
|
-
circle.startAngle(40);
|
|
44
|
-
circle.end(0.3);
|
|
45
|
-
|
|
46
|
-
const task = yield circle.restore(2);
|
|
47
|
-
yield* waitFor(1);
|
|
48
|
-
|
|
49
|
-
expect(circle.lineWidth()).closeTo(12, 0.0001);
|
|
50
|
-
expect(circle.startAngle()).closeTo(30, 0.0001);
|
|
51
|
-
expect(circle.end()).closeTo(0.4, 0.0001);
|
|
52
|
-
|
|
53
|
-
yield* join(task);
|
|
54
|
-
|
|
55
|
-
expect(circle.lineWidth()).toBe(8);
|
|
56
|
-
expect(circle.startAngle()).toBe(20);
|
|
57
|
-
expect(circle.end()).toBe(0.5);
|
|
58
|
-
}),
|
|
59
|
-
);
|
|
60
|
-
});
|
|
1
|
+
import {createSignal, join, waitFor} from '@twick/core';
|
|
2
|
+
import {describe, expect, it} from 'vitest';
|
|
3
|
+
import {Circle} from '../Circle';
|
|
4
|
+
import {generatorTest} from './generatorTest';
|
|
5
|
+
import {mockScene2D} from './mockScene2D';
|
|
6
|
+
|
|
7
|
+
describe('state', () => {
|
|
8
|
+
mockScene2D();
|
|
9
|
+
|
|
10
|
+
it('Restoring state', () => {
|
|
11
|
+
const signal = createSignal(45);
|
|
12
|
+
const circle = (
|
|
13
|
+
<Circle lineWidth={8} startAngle={signal} end={0.5} />
|
|
14
|
+
) as Circle;
|
|
15
|
+
circle.save();
|
|
16
|
+
|
|
17
|
+
circle.lineWidth(16);
|
|
18
|
+
circle.startAngle(90);
|
|
19
|
+
circle.end(0.25);
|
|
20
|
+
|
|
21
|
+
circle.restore();
|
|
22
|
+
|
|
23
|
+
expect(circle.lineWidth()).toBe(8);
|
|
24
|
+
expect(circle.startAngle()).toBe(45);
|
|
25
|
+
expect(circle.end()).toBe(0.5);
|
|
26
|
+
|
|
27
|
+
signal(180);
|
|
28
|
+
|
|
29
|
+
expect(circle.startAngle()).toBe(45);
|
|
30
|
+
expect(circle.startArrow.context.isInitial()).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it(
|
|
34
|
+
'Tweening state',
|
|
35
|
+
generatorTest(function* () {
|
|
36
|
+
const signal = createSignal(20);
|
|
37
|
+
const circle = (
|
|
38
|
+
<Circle lineWidth={8} startAngle={signal} end={0.5} />
|
|
39
|
+
) as Circle;
|
|
40
|
+
circle.save();
|
|
41
|
+
|
|
42
|
+
circle.lineWidth(16);
|
|
43
|
+
circle.startAngle(40);
|
|
44
|
+
circle.end(0.3);
|
|
45
|
+
|
|
46
|
+
const task = yield circle.restore(2);
|
|
47
|
+
yield* waitFor(1);
|
|
48
|
+
|
|
49
|
+
expect(circle.lineWidth()).closeTo(12, 0.0001);
|
|
50
|
+
expect(circle.startAngle()).closeTo(30, 0.0001);
|
|
51
|
+
expect(circle.end()).closeTo(0.4, 0.0001);
|
|
52
|
+
|
|
53
|
+
yield* join(task);
|
|
54
|
+
|
|
55
|
+
expect(circle.lineWidth()).toBe(8);
|
|
56
|
+
expect(circle.startAngle()).toBe(20);
|
|
57
|
+
expect(circle.end()).toBe(0.5);
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
});
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
export * from './Audio';
|
|
2
|
-
export * from './Bezier';
|
|
3
|
-
export * from './Circle';
|
|
4
|
-
export * from './Code';
|
|
5
|
-
export * from './CubicBezier';
|
|
6
|
-
export * from './Curve';
|
|
7
|
-
export * from './Grid';
|
|
8
|
-
export * from './Icon';
|
|
9
|
-
export * from './Img';
|
|
10
|
-
export * from './Knot';
|
|
11
|
-
export * from './Latex';
|
|
12
|
-
export * from './Layout';
|
|
13
|
-
export * from './Line';
|
|
14
|
-
export * from './Media';
|
|
15
|
-
export * from './Node';
|
|
16
|
-
export * from './Path';
|
|
17
|
-
export * from './Polygon';
|
|
18
|
-
export * from './QuadBezier';
|
|
19
|
-
export * from './Ray';
|
|
20
|
-
export * from './Rect';
|
|
21
|
-
export * from './Rive';
|
|
22
|
-
export * from './Shape';
|
|
23
|
-
export * from './Spline';
|
|
24
|
-
export * from './SVG';
|
|
25
|
-
export * from './Txt';
|
|
26
|
-
export * from './types';
|
|
27
|
-
export * from './Video';
|
|
28
|
-
export * from './View2D';
|
|
1
|
+
export * from './Audio';
|
|
2
|
+
export * from './Bezier';
|
|
3
|
+
export * from './Circle';
|
|
4
|
+
export * from './Code';
|
|
5
|
+
export * from './CubicBezier';
|
|
6
|
+
export * from './Curve';
|
|
7
|
+
export * from './Grid';
|
|
8
|
+
export * from './Icon';
|
|
9
|
+
export * from './Img';
|
|
10
|
+
export * from './Knot';
|
|
11
|
+
export * from './Latex';
|
|
12
|
+
export * from './Layout';
|
|
13
|
+
export * from './Line';
|
|
14
|
+
export * from './Media';
|
|
15
|
+
export * from './Node';
|
|
16
|
+
export * from './Path';
|
|
17
|
+
export * from './Polygon';
|
|
18
|
+
export * from './QuadBezier';
|
|
19
|
+
export * from './Ray';
|
|
20
|
+
export * from './Rect';
|
|
21
|
+
export * from './Rive';
|
|
22
|
+
export * from './Shape';
|
|
23
|
+
export * from './Spline';
|
|
24
|
+
export * from './SVG';
|
|
25
|
+
export * from './Txt';
|
|
26
|
+
export * from './types';
|
|
27
|
+
export * from './Video';
|
|
28
|
+
export * from './View2D';
|
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
import type {ReferenceReceiver} from '@twick/core';
|
|
2
|
-
import type {Node} from './Node';
|
|
3
|
-
|
|
4
|
-
export type ComponentChild =
|
|
5
|
-
| Node
|
|
6
|
-
| object
|
|
7
|
-
| string
|
|
8
|
-
| number
|
|
9
|
-
| bigint
|
|
10
|
-
| boolean
|
|
11
|
-
| null
|
|
12
|
-
| undefined;
|
|
13
|
-
|
|
14
|
-
export type ComponentChildren = ComponentChild | ComponentChild[];
|
|
15
|
-
export type NodeChildren = Node | Node[];
|
|
16
|
-
|
|
17
|
-
export type PropsOf<T> =
|
|
18
|
-
T extends NodeConstructor<infer P>
|
|
19
|
-
? P
|
|
20
|
-
: T extends FunctionComponent<infer P>
|
|
21
|
-
? P
|
|
22
|
-
: never;
|
|
23
|
-
|
|
24
|
-
export interface JSXProps {
|
|
25
|
-
children?: ComponentChildren;
|
|
26
|
-
ref?: ReferenceReceiver<Node>;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export interface FunctionComponent<T = any> {
|
|
30
|
-
(props: T): Node | null;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface NodeConstructor<TProps = any, TNode = Node> {
|
|
34
|
-
new (props: TProps): TNode;
|
|
35
|
-
}
|
|
1
|
+
import type {ReferenceReceiver} from '@twick/core';
|
|
2
|
+
import type {Node} from './Node';
|
|
3
|
+
|
|
4
|
+
export type ComponentChild =
|
|
5
|
+
| Node
|
|
6
|
+
| object
|
|
7
|
+
| string
|
|
8
|
+
| number
|
|
9
|
+
| bigint
|
|
10
|
+
| boolean
|
|
11
|
+
| null
|
|
12
|
+
| undefined;
|
|
13
|
+
|
|
14
|
+
export type ComponentChildren = ComponentChild | ComponentChild[];
|
|
15
|
+
export type NodeChildren = Node | Node[];
|
|
16
|
+
|
|
17
|
+
export type PropsOf<T> =
|
|
18
|
+
T extends NodeConstructor<infer P>
|
|
19
|
+
? P
|
|
20
|
+
: T extends FunctionComponent<infer P>
|
|
21
|
+
? P
|
|
22
|
+
: never;
|
|
23
|
+
|
|
24
|
+
export interface JSXProps {
|
|
25
|
+
children?: ComponentChildren;
|
|
26
|
+
ref?: ReferenceReceiver<Node>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface FunctionComponent<T = any> {
|
|
30
|
+
(props: T): Node | null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface NodeConstructor<TProps = any, TNode = Node> {
|
|
34
|
+
new (props: TProps): TNode;
|
|
35
|
+
}
|
|
@@ -1,159 +1,159 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BBox,
|
|
3
|
-
DEG2RAD,
|
|
4
|
-
Matrix2D,
|
|
5
|
-
Vector2,
|
|
6
|
-
lazy,
|
|
7
|
-
transformVector,
|
|
8
|
-
} from '@twick/core';
|
|
9
|
-
import {View2D} from '../components/View2D';
|
|
10
|
-
import type {CurvePoint} from './CurvePoint';
|
|
11
|
-
import {Segment} from './Segment';
|
|
12
|
-
|
|
13
|
-
export class ArcSegment extends Segment {
|
|
14
|
-
@lazy(() => {
|
|
15
|
-
const root = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
16
|
-
const el = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
17
|
-
root.appendChild(el);
|
|
18
|
-
View2D.shadowRoot.appendChild(root);
|
|
19
|
-
return el;
|
|
20
|
-
})
|
|
21
|
-
private static el: SVGPathElement;
|
|
22
|
-
public readonly center: Vector2;
|
|
23
|
-
// angle in radian
|
|
24
|
-
public readonly startAngle: number;
|
|
25
|
-
public readonly deltaAngle: number;
|
|
26
|
-
public readonly xAxisRotation: number;
|
|
27
|
-
private xAxisRotationMatrix: DOMMatrix;
|
|
28
|
-
public override readonly points: Vector2[];
|
|
29
|
-
private length: number;
|
|
30
|
-
|
|
31
|
-
public constructor(
|
|
32
|
-
public readonly startPoint: Vector2,
|
|
33
|
-
public readonly radius: Vector2,
|
|
34
|
-
public readonly xAxisRotationDegree: number,
|
|
35
|
-
public readonly largeArcFlag: number,
|
|
36
|
-
public readonly sweepFlag: number,
|
|
37
|
-
public readonly endPoint: Vector2,
|
|
38
|
-
) {
|
|
39
|
-
super();
|
|
40
|
-
|
|
41
|
-
this.xAxisRotation = this.xAxisRotationDegree * DEG2RAD;
|
|
42
|
-
this.radius = new Vector2(Math.abs(radius.x), Math.abs(radius.y));
|
|
43
|
-
|
|
44
|
-
const rotationMatrix =
|
|
45
|
-
Matrix2D.fromRotation(-xAxisRotationDegree).domMatrix;
|
|
46
|
-
const pAccent = transformVector(
|
|
47
|
-
startPoint.sub(endPoint).div(2),
|
|
48
|
-
rotationMatrix,
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
const L =
|
|
52
|
-
(pAccent.x * pAccent.x) / (radius.x * radius.x) +
|
|
53
|
-
(pAccent.y * pAccent.y) / (radius.y * radius.y);
|
|
54
|
-
|
|
55
|
-
if (L > 1) {
|
|
56
|
-
const Lsqrt = Math.sqrt(L);
|
|
57
|
-
radius.x = Lsqrt * radius.x;
|
|
58
|
-
radius.y = Lsqrt * radius.y;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const cAccent = new Vector2(
|
|
62
|
-
radius.ctg * pAccent.y,
|
|
63
|
-
radius.perpendicular.ctg * pAccent.x,
|
|
64
|
-
).scale(
|
|
65
|
-
Math.sqrt(
|
|
66
|
-
1 /
|
|
67
|
-
((pAccent.x * pAccent.x) / (radius.x * radius.x) +
|
|
68
|
-
(pAccent.y * pAccent.y) / (radius.y * radius.y)) -
|
|
69
|
-
1,
|
|
70
|
-
) * (largeArcFlag === sweepFlag ? -1 : 1),
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
this.xAxisRotationMatrix =
|
|
74
|
-
Matrix2D.fromRotation(xAxisRotationDegree).domMatrix;
|
|
75
|
-
const rotatedCAccent = transformVector(cAccent, this.xAxisRotationMatrix);
|
|
76
|
-
this.center = rotatedCAccent.add(startPoint.add(endPoint).div(2));
|
|
77
|
-
|
|
78
|
-
const q = pAccent.sub(cAccent).div(radius);
|
|
79
|
-
const s = pAccent.scale(-1).sub(cAccent).div(radius);
|
|
80
|
-
this.startAngle = q.radians;
|
|
81
|
-
this.deltaAngle = Vector2.angleBetween(q, s) % (Math.PI * 2);
|
|
82
|
-
if (this.sweepFlag === 0 && this.deltaAngle > 0) {
|
|
83
|
-
this.deltaAngle -= Math.PI * 2;
|
|
84
|
-
}
|
|
85
|
-
if (this.sweepFlag === 1 && this.deltaAngle < 0) {
|
|
86
|
-
this.deltaAngle += Math.PI * 2;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
ArcSegment.el.setAttribute(
|
|
90
|
-
'd',
|
|
91
|
-
`M ${this.startPoint.x} ${this.startPoint.y} A ${this.radius.x} ${this.radius.y} ${this.xAxisRotationDegree} ${this.largeArcFlag} ${this.sweepFlag} ${this.endPoint.x} ${this.endPoint.y}`,
|
|
92
|
-
);
|
|
93
|
-
this.length = ArcSegment.el.getTotalLength();
|
|
94
|
-
|
|
95
|
-
const bbox = new BBox(ArcSegment.el.getBBox());
|
|
96
|
-
this.points = [bbox.topLeft, bbox.bottomRight];
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
public getAnglePosition(angle: number) {
|
|
100
|
-
const rotatedVector = transformVector(
|
|
101
|
-
this.radius.mul(Vector2.fromRadians(angle)),
|
|
102
|
-
this.xAxisRotationMatrix,
|
|
103
|
-
);
|
|
104
|
-
return rotatedVector.add(this.center);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
public getAngleDerivative(angle: number) {
|
|
108
|
-
const derivative = new Vector2(
|
|
109
|
-
-this.radius.x * Math.sin(angle),
|
|
110
|
-
this.radius.y * Math.cos(angle),
|
|
111
|
-
);
|
|
112
|
-
return transformVector(derivative, this.xAxisRotationMatrix);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
public draw(
|
|
116
|
-
context: CanvasRenderingContext2D | Path2D,
|
|
117
|
-
start: number,
|
|
118
|
-
end: number,
|
|
119
|
-
move: boolean,
|
|
120
|
-
): [CurvePoint, CurvePoint] {
|
|
121
|
-
const startAngle = this.startAngle + this.deltaAngle * start;
|
|
122
|
-
const endAngle = this.startAngle + this.deltaAngle * end;
|
|
123
|
-
const startPos = this.getPoint(start);
|
|
124
|
-
const endPos = this.getPoint(end);
|
|
125
|
-
|
|
126
|
-
if (move) context.moveTo(startPos.position.x, startPos.position.y);
|
|
127
|
-
|
|
128
|
-
context.ellipse(
|
|
129
|
-
this.center.x,
|
|
130
|
-
this.center.y,
|
|
131
|
-
this.radius.x,
|
|
132
|
-
this.radius.y,
|
|
133
|
-
this.xAxisRotation,
|
|
134
|
-
startAngle,
|
|
135
|
-
endAngle,
|
|
136
|
-
this.sweepFlag === 0,
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
return [startPos, endPos];
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
public getPoint(distance: number): CurvePoint {
|
|
143
|
-
const angle = this.startAngle + distance * this.deltaAngle;
|
|
144
|
-
const tangent = this.getAngleDerivative(angle).normalized;
|
|
145
|
-
return {
|
|
146
|
-
position:
|
|
147
|
-
distance === 0
|
|
148
|
-
? this.startPoint
|
|
149
|
-
: distance === 1
|
|
150
|
-
? this.endPoint
|
|
151
|
-
: this.getAnglePosition(angle),
|
|
152
|
-
tangent,
|
|
153
|
-
normal: tangent.perpendicular,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
public get arcLength(): number {
|
|
157
|
-
return this.length;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
BBox,
|
|
3
|
+
DEG2RAD,
|
|
4
|
+
Matrix2D,
|
|
5
|
+
Vector2,
|
|
6
|
+
lazy,
|
|
7
|
+
transformVector,
|
|
8
|
+
} from '@twick/core';
|
|
9
|
+
import {View2D} from '../components/View2D';
|
|
10
|
+
import type {CurvePoint} from './CurvePoint';
|
|
11
|
+
import {Segment} from './Segment';
|
|
12
|
+
|
|
13
|
+
export class ArcSegment extends Segment {
|
|
14
|
+
@lazy(() => {
|
|
15
|
+
const root = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
16
|
+
const el = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
|
17
|
+
root.appendChild(el);
|
|
18
|
+
View2D.shadowRoot.appendChild(root);
|
|
19
|
+
return el;
|
|
20
|
+
})
|
|
21
|
+
private static el: SVGPathElement;
|
|
22
|
+
public readonly center: Vector2;
|
|
23
|
+
// angle in radian
|
|
24
|
+
public readonly startAngle: number;
|
|
25
|
+
public readonly deltaAngle: number;
|
|
26
|
+
public readonly xAxisRotation: number;
|
|
27
|
+
private xAxisRotationMatrix: DOMMatrix;
|
|
28
|
+
public override readonly points: Vector2[];
|
|
29
|
+
private length: number;
|
|
30
|
+
|
|
31
|
+
public constructor(
|
|
32
|
+
public readonly startPoint: Vector2,
|
|
33
|
+
public readonly radius: Vector2,
|
|
34
|
+
public readonly xAxisRotationDegree: number,
|
|
35
|
+
public readonly largeArcFlag: number,
|
|
36
|
+
public readonly sweepFlag: number,
|
|
37
|
+
public readonly endPoint: Vector2,
|
|
38
|
+
) {
|
|
39
|
+
super();
|
|
40
|
+
|
|
41
|
+
this.xAxisRotation = this.xAxisRotationDegree * DEG2RAD;
|
|
42
|
+
this.radius = new Vector2(Math.abs(radius.x), Math.abs(radius.y));
|
|
43
|
+
|
|
44
|
+
const rotationMatrix =
|
|
45
|
+
Matrix2D.fromRotation(-xAxisRotationDegree).domMatrix;
|
|
46
|
+
const pAccent = transformVector(
|
|
47
|
+
startPoint.sub(endPoint).div(2),
|
|
48
|
+
rotationMatrix,
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const L =
|
|
52
|
+
(pAccent.x * pAccent.x) / (radius.x * radius.x) +
|
|
53
|
+
(pAccent.y * pAccent.y) / (radius.y * radius.y);
|
|
54
|
+
|
|
55
|
+
if (L > 1) {
|
|
56
|
+
const Lsqrt = Math.sqrt(L);
|
|
57
|
+
radius.x = Lsqrt * radius.x;
|
|
58
|
+
radius.y = Lsqrt * radius.y;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const cAccent = new Vector2(
|
|
62
|
+
radius.ctg * pAccent.y,
|
|
63
|
+
radius.perpendicular.ctg * pAccent.x,
|
|
64
|
+
).scale(
|
|
65
|
+
Math.sqrt(
|
|
66
|
+
1 /
|
|
67
|
+
((pAccent.x * pAccent.x) / (radius.x * radius.x) +
|
|
68
|
+
(pAccent.y * pAccent.y) / (radius.y * radius.y)) -
|
|
69
|
+
1,
|
|
70
|
+
) * (largeArcFlag === sweepFlag ? -1 : 1),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
this.xAxisRotationMatrix =
|
|
74
|
+
Matrix2D.fromRotation(xAxisRotationDegree).domMatrix;
|
|
75
|
+
const rotatedCAccent = transformVector(cAccent, this.xAxisRotationMatrix);
|
|
76
|
+
this.center = rotatedCAccent.add(startPoint.add(endPoint).div(2));
|
|
77
|
+
|
|
78
|
+
const q = pAccent.sub(cAccent).div(radius);
|
|
79
|
+
const s = pAccent.scale(-1).sub(cAccent).div(radius);
|
|
80
|
+
this.startAngle = q.radians;
|
|
81
|
+
this.deltaAngle = Vector2.angleBetween(q, s) % (Math.PI * 2);
|
|
82
|
+
if (this.sweepFlag === 0 && this.deltaAngle > 0) {
|
|
83
|
+
this.deltaAngle -= Math.PI * 2;
|
|
84
|
+
}
|
|
85
|
+
if (this.sweepFlag === 1 && this.deltaAngle < 0) {
|
|
86
|
+
this.deltaAngle += Math.PI * 2;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
ArcSegment.el.setAttribute(
|
|
90
|
+
'd',
|
|
91
|
+
`M ${this.startPoint.x} ${this.startPoint.y} A ${this.radius.x} ${this.radius.y} ${this.xAxisRotationDegree} ${this.largeArcFlag} ${this.sweepFlag} ${this.endPoint.x} ${this.endPoint.y}`,
|
|
92
|
+
);
|
|
93
|
+
this.length = ArcSegment.el.getTotalLength();
|
|
94
|
+
|
|
95
|
+
const bbox = new BBox(ArcSegment.el.getBBox());
|
|
96
|
+
this.points = [bbox.topLeft, bbox.bottomRight];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public getAnglePosition(angle: number) {
|
|
100
|
+
const rotatedVector = transformVector(
|
|
101
|
+
this.radius.mul(Vector2.fromRadians(angle)),
|
|
102
|
+
this.xAxisRotationMatrix,
|
|
103
|
+
);
|
|
104
|
+
return rotatedVector.add(this.center);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public getAngleDerivative(angle: number) {
|
|
108
|
+
const derivative = new Vector2(
|
|
109
|
+
-this.radius.x * Math.sin(angle),
|
|
110
|
+
this.radius.y * Math.cos(angle),
|
|
111
|
+
);
|
|
112
|
+
return transformVector(derivative, this.xAxisRotationMatrix);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
public draw(
|
|
116
|
+
context: CanvasRenderingContext2D | Path2D,
|
|
117
|
+
start: number,
|
|
118
|
+
end: number,
|
|
119
|
+
move: boolean,
|
|
120
|
+
): [CurvePoint, CurvePoint] {
|
|
121
|
+
const startAngle = this.startAngle + this.deltaAngle * start;
|
|
122
|
+
const endAngle = this.startAngle + this.deltaAngle * end;
|
|
123
|
+
const startPos = this.getPoint(start);
|
|
124
|
+
const endPos = this.getPoint(end);
|
|
125
|
+
|
|
126
|
+
if (move) context.moveTo(startPos.position.x, startPos.position.y);
|
|
127
|
+
|
|
128
|
+
context.ellipse(
|
|
129
|
+
this.center.x,
|
|
130
|
+
this.center.y,
|
|
131
|
+
this.radius.x,
|
|
132
|
+
this.radius.y,
|
|
133
|
+
this.xAxisRotation,
|
|
134
|
+
startAngle,
|
|
135
|
+
endAngle,
|
|
136
|
+
this.sweepFlag === 0,
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
return [startPos, endPos];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public getPoint(distance: number): CurvePoint {
|
|
143
|
+
const angle = this.startAngle + distance * this.deltaAngle;
|
|
144
|
+
const tangent = this.getAngleDerivative(angle).normalized;
|
|
145
|
+
return {
|
|
146
|
+
position:
|
|
147
|
+
distance === 0
|
|
148
|
+
? this.startPoint
|
|
149
|
+
: distance === 1
|
|
150
|
+
? this.endPoint
|
|
151
|
+
: this.getAnglePosition(angle),
|
|
152
|
+
tangent,
|
|
153
|
+
normal: tangent.perpendicular,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
public get arcLength(): number {
|
|
157
|
+
return this.length;
|
|
158
|
+
}
|
|
159
|
+
}
|