@thi.ng/scenegraph 1.0.79 → 2.0.1
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/CHANGELOG.md +24 -1
- package/README.md +9 -8
- package/anode.d.ts +5 -43
- package/anode.js +9 -23
- package/api.d.ts +91 -0
- package/node2.d.ts +9 -3
- package/node2.js +27 -12
- package/node3.d.ts +9 -3
- package/node3.js +27 -12
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
- **Last updated**: 2025-
|
|
3
|
+
- **Last updated**: 2025-03-09T19:21:53Z
|
|
4
4
|
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
5
|
|
|
6
6
|
All notable changes to this project will be documented in this file.
|
|
@@ -11,6 +11,29 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
|
|
|
11
11
|
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
12
12
|
and/or version bumps of transitive dependencies.
|
|
13
13
|
|
|
14
|
+
# [2.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/scenegraph@2.0.0) (2025-02-25)
|
|
15
|
+
|
|
16
|
+
#### 🛑 Breaking changes
|
|
17
|
+
|
|
18
|
+
- switch to using option objects for node ctors ([9b85ae7](https://github.com/thi-ng/umbrella/commit/9b85ae7))
|
|
19
|
+
- BREAKING CHANGE: replace positional ctor args w/ options objects (aka named params)
|
|
20
|
+
- add `CommonNodeOpts`, `Node2DOpts`, `Node3DOpts`
|
|
21
|
+
- update all ctors: `ANode`, `Node2D`, `Node3D`
|
|
22
|
+
- migrate `enabled`/`display` flags to `ISceneNode` interface
|
|
23
|
+
- update tests
|
|
24
|
+
|
|
25
|
+
#### 🚀 Features
|
|
26
|
+
|
|
27
|
+
- add `scaleWithReferencePoint()` ([60b388c](https://github.com/thi-ng/umbrella/commit/60b388c))
|
|
28
|
+
- add `ISceneNode.scaleWithReferencePoint()` and impls in `Node2D`/`Node3D`
|
|
29
|
+
- add/update `ISceneNode` doc strings
|
|
30
|
+
- minor update/cleanup `ANode`
|
|
31
|
+
- add tests
|
|
32
|
+
- add `scaleWithReferencePoint()` ([3cef74c](https://github.com/thi-ng/umbrella/commit/3cef74c))
|
|
33
|
+
- add `ISceneNode.scaleWithReferencePoint()` and impls in `Node2D`/`Node3D`
|
|
34
|
+
- add/update `ISceneNode` doc strings
|
|
35
|
+
- minor update/cleanup `ANode`
|
|
36
|
+
|
|
14
37
|
### [1.0.41](https://github.com/thi-ng/umbrella/tree/@thi.ng/scenegraph@1.0.41) (2024-04-20)
|
|
15
38
|
|
|
16
39
|
#### ♻️ Refactoring
|
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](https://mastodon.thi.ng/@toxi)
|
|
8
8
|
|
|
9
9
|
> [!NOTE]
|
|
10
|
-
> This is one of
|
|
10
|
+
> This is one of 203 standalone projects, maintained as part
|
|
11
11
|
> of the [@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
|
|
12
12
|
> and anti-framework.
|
|
13
13
|
>
|
|
@@ -68,7 +68,7 @@ For Node.js REPL:
|
|
|
68
68
|
const sg = await import("@thi.ng/scenegraph");
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
-
Package sizes (brotli'd, pre-treeshake): ESM:
|
|
71
|
+
Package sizes (brotli'd, pre-treeshake): ESM: 1.11 KB
|
|
72
72
|
|
|
73
73
|
## Dependencies
|
|
74
74
|
|
|
@@ -82,15 +82,16 @@ Note: @thi.ng/api is in _most_ cases a type-only import (not used at runtime)
|
|
|
82
82
|
|
|
83
83
|
## Usage examples
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
Four projects in this repo's
|
|
86
86
|
[/examples](https://github.com/thi-ng/umbrella/tree/develop/examples)
|
|
87
87
|
directory are using this package:
|
|
88
88
|
|
|
89
|
-
| Screenshot
|
|
90
|
-
|
|
91
|
-
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph.png" width="240"/>
|
|
92
|
-
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph-image.png" width="240"/>
|
|
93
|
-
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/
|
|
89
|
+
| Screenshot | Description | Live demo | Source |
|
|
90
|
+
|:----------------------------------------------------------------------------------------------------------------------------|:--------------------------------------------------------|:----------------------------------------------------------|:---------------------------------------------------------------------------------------|
|
|
91
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph.png" width="240"/> | 2D scenegraph & shape picking | [Demo](https://demo.thi.ng/umbrella/scenegraph/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/scenegraph) |
|
|
92
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph-image.png" width="240"/> | 2D scenegraph & image map based geometry manipulation | [Demo](https://demo.thi.ng/umbrella/scenegraph-image/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/scenegraph-image) |
|
|
93
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/scenegraph-pan-zoom.avif" width="240"/> | Basic 2D scenegraph example with pan/zoom functionality | [Demo](https://demo.thi.ng/umbrella/scenegraph-pan-zoom/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/scenegraph-pan-zoom) |
|
|
94
|
+
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/shader-graph.jpg" width="240"/> | Minimal shader graph developed during livestream #2 | [Demo](https://demo.thi.ng/umbrella/shader-graph/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/shader-graph) |
|
|
94
95
|
|
|
95
96
|
## API
|
|
96
97
|
|
package/anode.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Maybe, Nullable } from "@thi.ng/api";
|
|
2
2
|
import type { Mat } from "@thi.ng/matrices";
|
|
3
3
|
import type { ReadonlyVec, Vec } from "@thi.ng/vectors";
|
|
4
|
-
import type { ISceneNode, NodeInfo } from "./api.js";
|
|
4
|
+
import type { CommonNodeOpts, ISceneNode, NodeInfo } from "./api.js";
|
|
5
5
|
export declare abstract class ANode<T extends ISceneNode<any>> {
|
|
6
6
|
id: string;
|
|
7
7
|
parent: Nullable<T>;
|
|
@@ -11,55 +11,17 @@ export declare abstract class ANode<T extends ISceneNode<any>> {
|
|
|
11
11
|
invMat: Mat;
|
|
12
12
|
enabled: boolean;
|
|
13
13
|
display: boolean;
|
|
14
|
-
constructor(id
|
|
14
|
+
constructor({ id, parent, body, enabled, display, }: CommonNodeOpts<T>);
|
|
15
15
|
appendChild(node: T): this;
|
|
16
16
|
insertChild(i: number, node: T): this;
|
|
17
17
|
deleteChild(node: number | T): boolean;
|
|
18
|
-
abstract update(): void;
|
|
19
18
|
draw<T>(ctx: T): void;
|
|
20
|
-
/**
|
|
21
|
-
* Checks all children in reverse order, then (if no child matched)
|
|
22
|
-
* node itself for containment of given point (in world/screen
|
|
23
|
-
* coords). Returns `NodeInfo` object with matched node (if any) or
|
|
24
|
-
* undefined.
|
|
25
|
-
*
|
|
26
|
-
* **Important:** Disabled nodes and their children will be skipped!
|
|
27
|
-
*
|
|
28
|
-
* @param p -
|
|
29
|
-
*/
|
|
30
19
|
childForPoint(p: ReadonlyVec): Maybe<NodeInfo<T>>;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* node's local coordinate system.
|
|
34
|
-
*
|
|
35
|
-
* @param p -
|
|
36
|
-
*/
|
|
20
|
+
containsLocalPoint(_: ReadonlyVec): boolean;
|
|
21
|
+
abstract update(): void;
|
|
37
22
|
abstract mapGlobalPoint(p: ReadonlyVec): Maybe<Vec>;
|
|
38
|
-
/**
|
|
39
|
-
* Returns copy of node local space point `p`, transformed into the global
|
|
40
|
-
* worldspace.
|
|
41
|
-
*
|
|
42
|
-
* @param p
|
|
43
|
-
*/
|
|
44
23
|
abstract mapLocalPointToGlobal(p: ReadonlyVec): Maybe<Vec>;
|
|
45
|
-
/**
|
|
46
|
-
* Returns copy of node local space point `p`, transformed into the
|
|
47
|
-
* coordinate system of `dest` node.
|
|
48
|
-
*
|
|
49
|
-
* @param dest -
|
|
50
|
-
* @param p -
|
|
51
|
-
*/
|
|
52
24
|
abstract mapLocalPointToNode(dest: T, p: ReadonlyVec): Maybe<Vec>;
|
|
53
|
-
|
|
54
|
-
* Returns true, if given point is contained within the boundary of
|
|
55
|
-
* this node. Since this class is used as generic base
|
|
56
|
-
* implementation for other, more specialized scene graph nodes,
|
|
57
|
-
* this base impl always returns false (meaning these nodes cannot
|
|
58
|
-
* will not be selectable by the user unless a subclass overrides
|
|
59
|
-
* this method).
|
|
60
|
-
*
|
|
61
|
-
* @param p -
|
|
62
|
-
*/
|
|
63
|
-
containsLocalPoint(_: ReadonlyVec): boolean;
|
|
25
|
+
abstract scaleWithReferencePoint(ref: ReadonlyVec, scale: ReadonlyVec | number): this;
|
|
64
26
|
}
|
|
65
27
|
//# sourceMappingURL=anode.d.ts.map
|
package/anode.js
CHANGED
|
@@ -9,7 +9,13 @@ class ANode {
|
|
|
9
9
|
invMat;
|
|
10
10
|
enabled;
|
|
11
11
|
display;
|
|
12
|
-
constructor(
|
|
12
|
+
constructor({
|
|
13
|
+
id,
|
|
14
|
+
parent,
|
|
15
|
+
body,
|
|
16
|
+
enabled = true,
|
|
17
|
+
display = true
|
|
18
|
+
}) {
|
|
13
19
|
this.id = id;
|
|
14
20
|
this.parent = parent;
|
|
15
21
|
this.children = [];
|
|
@@ -19,8 +25,8 @@ class ANode {
|
|
|
19
25
|
this.body = body;
|
|
20
26
|
this.mat = [];
|
|
21
27
|
this.invMat = [];
|
|
22
|
-
this.enabled =
|
|
23
|
-
this.display =
|
|
28
|
+
this.enabled = enabled;
|
|
29
|
+
this.display = display;
|
|
24
30
|
}
|
|
25
31
|
appendChild(node) {
|
|
26
32
|
this.children.push(node);
|
|
@@ -51,16 +57,6 @@ class ANode {
|
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
59
|
}
|
|
54
|
-
/**
|
|
55
|
-
* Checks all children in reverse order, then (if no child matched)
|
|
56
|
-
* node itself for containment of given point (in world/screen
|
|
57
|
-
* coords). Returns `NodeInfo` object with matched node (if any) or
|
|
58
|
-
* undefined.
|
|
59
|
-
*
|
|
60
|
-
* **Important:** Disabled nodes and their children will be skipped!
|
|
61
|
-
*
|
|
62
|
-
* @param p -
|
|
63
|
-
*/
|
|
64
60
|
childForPoint(p) {
|
|
65
61
|
if (this.enabled) {
|
|
66
62
|
const children = this.children;
|
|
@@ -76,16 +72,6 @@ class ANode {
|
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
}
|
|
79
|
-
/**
|
|
80
|
-
* Returns true, if given point is contained within the boundary of
|
|
81
|
-
* this node. Since this class is used as generic base
|
|
82
|
-
* implementation for other, more specialized scene graph nodes,
|
|
83
|
-
* this base impl always returns false (meaning these nodes cannot
|
|
84
|
-
* will not be selectable by the user unless a subclass overrides
|
|
85
|
-
* this method).
|
|
86
|
-
*
|
|
87
|
-
* @param p -
|
|
88
|
-
*/
|
|
89
75
|
containsLocalPoint(_) {
|
|
90
76
|
return false;
|
|
91
77
|
}
|
package/api.d.ts
CHANGED
|
@@ -6,15 +6,78 @@ export interface ISceneNode<T extends ISceneNode<T>> extends IID<string> {
|
|
|
6
6
|
children: T[];
|
|
7
7
|
mat: Mat;
|
|
8
8
|
invMat: Mat;
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
display: boolean;
|
|
9
11
|
appendChild(node: T): this;
|
|
10
12
|
insertChild(i: number, node: T): this;
|
|
11
13
|
deleteChild(node: number | T): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* Recursively recomputes this node's (and its children's) transformation
|
|
16
|
+
* matrices (i.e. {@link ANode.mat} and {@link ANode.invMat}).
|
|
17
|
+
*
|
|
18
|
+
* @remarks
|
|
19
|
+
* This function is a no-op if the node is currently disabled (see
|
|
20
|
+
* {@link ANode.enabled}).
|
|
21
|
+
*/
|
|
12
22
|
update(): void;
|
|
13
23
|
draw<D>(ctx: D): void;
|
|
24
|
+
/**
|
|
25
|
+
* Returns copy of world space point `p`, transformed into this
|
|
26
|
+
* node's local coordinate system.
|
|
27
|
+
*
|
|
28
|
+
* @param p -
|
|
29
|
+
*/
|
|
14
30
|
mapGlobalPoint(p: ReadonlyVec): Maybe<Vec>;
|
|
31
|
+
/**
|
|
32
|
+
* Returns copy of node local space point `p`, transformed into the global
|
|
33
|
+
* worldspace.
|
|
34
|
+
*
|
|
35
|
+
* @param p
|
|
36
|
+
*/
|
|
37
|
+
mapLocalPointToGlobal(p: ReadonlyVec): Maybe<Vec>;
|
|
38
|
+
/**
|
|
39
|
+
* Returns copy of node local space point `p`, transformed into the
|
|
40
|
+
* coordinate system of `dest` node.
|
|
41
|
+
*
|
|
42
|
+
* @param dest -
|
|
43
|
+
* @param p -
|
|
44
|
+
*/
|
|
15
45
|
mapLocalPointToNode(dest: ISceneNode<T>, p: ReadonlyVec): Maybe<Vec>;
|
|
46
|
+
/**
|
|
47
|
+
* Returns true, if given point is contained within the boundary of
|
|
48
|
+
* this node. Since this class is used as generic base
|
|
49
|
+
* implementation for other, more specialized scene graph nodes,
|
|
50
|
+
* this base impl always returns false (meaning these nodes cannot
|
|
51
|
+
* will not be selectable by the user unless a subclass overrides
|
|
52
|
+
* this method).
|
|
53
|
+
*
|
|
54
|
+
* @param p -
|
|
55
|
+
*/
|
|
16
56
|
containsLocalPoint(_: ReadonlyVec): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Checks all children in reverse order, then (if no child matched)
|
|
59
|
+
* node itself for containment of given point (in world/screen
|
|
60
|
+
* coords). Returns `NodeInfo` object with matched node (if any) or
|
|
61
|
+
* undefined.
|
|
62
|
+
*
|
|
63
|
+
* **Important:** Disabled nodes and their children will be skipped!
|
|
64
|
+
*
|
|
65
|
+
* @param p -
|
|
66
|
+
*/
|
|
17
67
|
childForPoint(p: ReadonlyVec): Maybe<NodeInfo<T>>;
|
|
68
|
+
/**
|
|
69
|
+
* Scales node to new given `scale` factor and translates it such that given
|
|
70
|
+
* `ref`erence point (given in local space) would stay constant in world
|
|
71
|
+
* space. Useful for zoomable UIs, e.g. for zooming relative to the mouse
|
|
72
|
+
* position.
|
|
73
|
+
*
|
|
74
|
+
* @remarks
|
|
75
|
+
* This function is a no-op if the node is currently not enabled.
|
|
76
|
+
*
|
|
77
|
+
* @param ref
|
|
78
|
+
* @param scale
|
|
79
|
+
*/
|
|
80
|
+
scaleWithReferencePoint(ref: ReadonlyVec, scale: ReadonlyVec | number): this;
|
|
18
81
|
}
|
|
19
82
|
/**
|
|
20
83
|
* Node information for mouse picking.
|
|
@@ -29,4 +92,32 @@ export interface NodeInfo<T> {
|
|
|
29
92
|
*/
|
|
30
93
|
p?: Vec;
|
|
31
94
|
}
|
|
95
|
+
export interface CommonNodeOpts<T extends ISceneNode<any>> {
|
|
96
|
+
/**
|
|
97
|
+
* Node ID
|
|
98
|
+
*/
|
|
99
|
+
id: string;
|
|
100
|
+
/**
|
|
101
|
+
* Parent node (if any).
|
|
102
|
+
*/
|
|
103
|
+
parent?: Nullable<T>;
|
|
104
|
+
/**
|
|
105
|
+
* Arbitrary node data/content
|
|
106
|
+
*/
|
|
107
|
+
body?: any;
|
|
108
|
+
/**
|
|
109
|
+
* If false, node (and its children) will not be updated via
|
|
110
|
+
* {@link ISceneNode.update}.
|
|
111
|
+
*
|
|
112
|
+
* @defaultValue true
|
|
113
|
+
*/
|
|
114
|
+
enabled?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* If false, node (and its children) will not be processed via
|
|
117
|
+
* {@link ISceneNode.draw}.
|
|
118
|
+
*
|
|
119
|
+
* @defaultValue true
|
|
120
|
+
*/
|
|
121
|
+
display?: boolean;
|
|
122
|
+
}
|
|
32
123
|
//# sourceMappingURL=api.d.ts.map
|
package/node2.d.ts
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import type { ICopy, IToHiccup
|
|
1
|
+
import type { ICopy, IToHiccup } from "@thi.ng/api";
|
|
2
2
|
import type { ReadonlyVec, Vec } from "@thi.ng/vectors";
|
|
3
3
|
import { ANode } from "./anode.js";
|
|
4
|
-
import type { ISceneNode } from "./api.js";
|
|
4
|
+
import type { CommonNodeOpts, ISceneNode } from "./api.js";
|
|
5
|
+
export interface Node2DOpts extends CommonNodeOpts<Node2D> {
|
|
6
|
+
translate?: Vec;
|
|
7
|
+
rotate?: number;
|
|
8
|
+
scale?: Vec | number;
|
|
9
|
+
}
|
|
5
10
|
export declare class Node2D extends ANode<Node2D> implements ICopy<Node2D>, ISceneNode<Node2D>, IToHiccup {
|
|
6
11
|
translate: Vec;
|
|
7
12
|
rotate: number;
|
|
8
13
|
scale: Vec | number;
|
|
9
|
-
constructor(
|
|
14
|
+
constructor(opts: Node2DOpts);
|
|
10
15
|
copy(): Node2D;
|
|
11
16
|
update(): void;
|
|
12
17
|
mapGlobalPoint(p: ReadonlyVec): Vec;
|
|
13
18
|
mapLocalPointToGlobal(p: ReadonlyVec): Vec;
|
|
14
19
|
mapLocalPointToNode(dest: Node2D, p: ReadonlyVec): Vec;
|
|
20
|
+
scaleWithReferencePoint(ref: ReadonlyVec, scale: ReadonlyVec | number): this;
|
|
15
21
|
/**
|
|
16
22
|
* By implementing this method (`IToHiccup` interface), scene graph nodes
|
|
17
23
|
* can be directly used by hdom-canvas, hiccup-canvas, rdom-canvas or
|
package/node2.js
CHANGED
|
@@ -3,29 +3,33 @@ import { invert23 } from "@thi.ng/matrices/invert";
|
|
|
3
3
|
import { mulM23 } from "@thi.ng/matrices/mulm";
|
|
4
4
|
import { mulV23 } from "@thi.ng/matrices/mulv";
|
|
5
5
|
import { transform23 } from "@thi.ng/matrices/transform";
|
|
6
|
+
import { madd2 } from "@thi.ng/vectors/madd";
|
|
6
7
|
import { set2 } from "@thi.ng/vectors/set";
|
|
8
|
+
import { setN2 } from "@thi.ng/vectors/setn";
|
|
9
|
+
import { sub2 } from "@thi.ng/vectors/sub";
|
|
7
10
|
import { ANode } from "./anode.js";
|
|
8
11
|
import { toHiccup } from "./hiccup.js";
|
|
9
12
|
class Node2D extends ANode {
|
|
10
13
|
translate;
|
|
11
14
|
rotate;
|
|
12
15
|
scale;
|
|
13
|
-
constructor(
|
|
14
|
-
super(
|
|
15
|
-
this.translate = translate;
|
|
16
|
-
this.rotate = rotate;
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
super(opts);
|
|
18
|
+
this.translate = opts.translate ?? [0, 0];
|
|
19
|
+
this.rotate = opts.rotate ?? 0;
|
|
20
|
+
const scale = opts.scale ?? 1;
|
|
17
21
|
this.scale = isNumber(scale) ? [scale, scale] : scale;
|
|
18
22
|
this.update();
|
|
19
23
|
}
|
|
20
24
|
copy() {
|
|
21
|
-
return new Node2D(
|
|
22
|
-
this.id,
|
|
23
|
-
this.parent,
|
|
24
|
-
set2([], this.translate),
|
|
25
|
-
this.rotate,
|
|
26
|
-
set2([], this.scale),
|
|
27
|
-
this.body
|
|
28
|
-
);
|
|
25
|
+
return new Node2D({
|
|
26
|
+
id: this.id,
|
|
27
|
+
parent: this.parent,
|
|
28
|
+
translate: set2([], this.translate),
|
|
29
|
+
rotate: this.rotate,
|
|
30
|
+
scale: set2([], this.scale),
|
|
31
|
+
body: this.body
|
|
32
|
+
});
|
|
29
33
|
}
|
|
30
34
|
update() {
|
|
31
35
|
if (this.enabled) {
|
|
@@ -48,6 +52,17 @@ class Node2D extends ANode {
|
|
|
48
52
|
mapLocalPointToNode(dest, p) {
|
|
49
53
|
return mulV23(null, dest.invMat, mulV23([], this.mat, p));
|
|
50
54
|
}
|
|
55
|
+
scaleWithReferencePoint(ref, scale) {
|
|
56
|
+
if (this.enabled) {
|
|
57
|
+
const currScale = isNumber(this.scale) ? setN2([], this.scale) : this.scale;
|
|
58
|
+
const newScale = isNumber(scale) ? setN2([], scale) : scale;
|
|
59
|
+
const delta = sub2([], currScale, newScale);
|
|
60
|
+
this.scale = newScale;
|
|
61
|
+
this.translate = madd2([], ref, delta, this.translate);
|
|
62
|
+
this.update();
|
|
63
|
+
}
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
51
66
|
/**
|
|
52
67
|
* By implementing this method (`IToHiccup` interface), scene graph nodes
|
|
53
68
|
* can be directly used by hdom-canvas, hiccup-canvas, rdom-canvas or
|
package/node3.d.ts
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import type { ICopy, IToHiccup
|
|
1
|
+
import type { ICopy, IToHiccup } from "@thi.ng/api";
|
|
2
2
|
import type { ReadonlyVec, Vec } from "@thi.ng/vectors";
|
|
3
3
|
import { ANode } from "./anode.js";
|
|
4
|
-
import type { ISceneNode } from "./api.js";
|
|
4
|
+
import type { CommonNodeOpts, ISceneNode } from "./api.js";
|
|
5
|
+
export interface Node3DOpts extends CommonNodeOpts<Node3D> {
|
|
6
|
+
translate?: Vec;
|
|
7
|
+
rotate?: Vec;
|
|
8
|
+
scale?: Vec | number;
|
|
9
|
+
}
|
|
5
10
|
export declare class Node3D extends ANode<Node3D> implements ICopy<Node3D>, ISceneNode<Node3D>, IToHiccup {
|
|
6
11
|
translate: Vec;
|
|
7
12
|
rotate: Vec;
|
|
8
13
|
scale: Vec | number;
|
|
9
|
-
constructor(
|
|
14
|
+
constructor(opts: Node3DOpts);
|
|
10
15
|
copy(): Node3D;
|
|
11
16
|
update(): void;
|
|
12
17
|
mapGlobalPoint(p: ReadonlyVec): Vec | undefined;
|
|
13
18
|
mapLocalPointToGlobal(p: ReadonlyVec): Vec | undefined;
|
|
14
19
|
mapLocalPointToNode(dest: Node3D, p: ReadonlyVec): Vec | undefined;
|
|
20
|
+
scaleWithReferencePoint(ref: ReadonlyVec, scale: ReadonlyVec | number): this;
|
|
15
21
|
/**
|
|
16
22
|
* Future support planned. No immediate users of this method in a 3D context
|
|
17
23
|
* available thus far.
|
package/node3.js
CHANGED
|
@@ -3,29 +3,33 @@ import { invert44 } from "@thi.ng/matrices/invert";
|
|
|
3
3
|
import { mulM44 } from "@thi.ng/matrices/mulm";
|
|
4
4
|
import { mulV344 } from "@thi.ng/matrices/mulv";
|
|
5
5
|
import { transform44 } from "@thi.ng/matrices/transform";
|
|
6
|
+
import { madd3 } from "@thi.ng/vectors/madd";
|
|
6
7
|
import { set3 } from "@thi.ng/vectors/set";
|
|
8
|
+
import { setN3 } from "@thi.ng/vectors/setn";
|
|
9
|
+
import { sub3 } from "@thi.ng/vectors/sub";
|
|
7
10
|
import { ANode } from "./anode.js";
|
|
8
11
|
import { toHiccup } from "./hiccup.js";
|
|
9
12
|
class Node3D extends ANode {
|
|
10
13
|
translate;
|
|
11
14
|
rotate;
|
|
12
15
|
scale;
|
|
13
|
-
constructor(
|
|
14
|
-
super(
|
|
15
|
-
this.translate = translate;
|
|
16
|
-
this.rotate = rotate;
|
|
16
|
+
constructor(opts) {
|
|
17
|
+
super(opts);
|
|
18
|
+
this.translate = opts.translate ?? [0, 0, 0];
|
|
19
|
+
this.rotate = opts.rotate ?? [0, 0, 0];
|
|
20
|
+
const scale = opts.scale ?? 1;
|
|
17
21
|
this.scale = isNumber(scale) ? [scale, scale, scale] : scale;
|
|
18
22
|
this.update();
|
|
19
23
|
}
|
|
20
24
|
copy() {
|
|
21
|
-
return new Node3D(
|
|
22
|
-
this.id,
|
|
23
|
-
this.parent,
|
|
24
|
-
set3([], this.translate),
|
|
25
|
-
set3([], this.rotate),
|
|
26
|
-
set3([], this.scale),
|
|
27
|
-
this.body
|
|
28
|
-
);
|
|
25
|
+
return new Node3D({
|
|
26
|
+
id: this.id,
|
|
27
|
+
parent: this.parent,
|
|
28
|
+
translate: set3([], this.translate),
|
|
29
|
+
rotate: set3([], this.rotate),
|
|
30
|
+
scale: set3([], this.scale),
|
|
31
|
+
body: this.body
|
|
32
|
+
});
|
|
29
33
|
}
|
|
30
34
|
update() {
|
|
31
35
|
if (this.enabled) {
|
|
@@ -48,6 +52,17 @@ class Node3D extends ANode {
|
|
|
48
52
|
mapLocalPointToNode(dest, p) {
|
|
49
53
|
return mulV344(null, dest.invMat, mulV344([], this.mat, p));
|
|
50
54
|
}
|
|
55
|
+
scaleWithReferencePoint(ref, scale) {
|
|
56
|
+
if (this.enabled) {
|
|
57
|
+
const currScale = isNumber(this.scale) ? setN3([], this.scale) : this.scale;
|
|
58
|
+
const newScale = isNumber(scale) ? setN3([], scale) : scale;
|
|
59
|
+
const delta = sub3([], currScale, newScale);
|
|
60
|
+
this.scale = newScale;
|
|
61
|
+
this.translate = madd3([], ref, delta, this.translate);
|
|
62
|
+
this.update();
|
|
63
|
+
}
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
51
66
|
/**
|
|
52
67
|
* Future support planned. No immediate users of this method in a 3D context
|
|
53
68
|
* available thus far.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/scenegraph",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Extensible 2D/3D scene graph with @thi.ng/hiccup-canvas support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -39,11 +39,11 @@
|
|
|
39
39
|
"tool:tangle": "../../node_modules/.bin/tangle src/**/*.ts"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@thi.ng/api": "^8.11.
|
|
43
|
-
"@thi.ng/checks": "^3.7.
|
|
44
|
-
"@thi.ng/errors": "^2.5.
|
|
45
|
-
"@thi.ng/matrices": "^2.4.
|
|
46
|
-
"@thi.ng/vectors": "^7.12.
|
|
42
|
+
"@thi.ng/api": "^8.11.22",
|
|
43
|
+
"@thi.ng/checks": "^3.7.2",
|
|
44
|
+
"@thi.ng/errors": "^2.5.28",
|
|
45
|
+
"@thi.ng/matrices": "^2.4.36",
|
|
46
|
+
"@thi.ng/vectors": "^7.12.24"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"esbuild": "^0.25.0",
|
|
@@ -101,5 +101,5 @@
|
|
|
101
101
|
],
|
|
102
102
|
"status": "alpha"
|
|
103
103
|
},
|
|
104
|
-
"gitHead": "
|
|
104
|
+
"gitHead": "55987d581e4985b1c3091ba6be3f9b53a0c5eeea\n"
|
|
105
105
|
}
|