@thi.ng/scenegraph 1.0.2 → 1.0.4
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 +1 -1
- package/README.md +1 -1
- package/anode.js +87 -84
- package/api.js +0 -1
- package/hiccup.js +11 -24
- package/node2.js +54 -44
- package/node3.js +53 -43
- package/package.json +11 -9
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
package/anode.js
CHANGED
|
@@ -1,92 +1,95 @@
|
|
|
1
1
|
import { isNumber } from "@thi.ng/checks/is-number";
|
|
2
2
|
import { assert } from "@thi.ng/errors/assert";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
this.body = body;
|
|
20
|
-
this.mat = [];
|
|
21
|
-
this.invMat = [];
|
|
22
|
-
this.enabled = true;
|
|
23
|
-
this.display = true;
|
|
24
|
-
}
|
|
25
|
-
appendChild(node) {
|
|
26
|
-
this.children.push(node);
|
|
27
|
-
return this;
|
|
28
|
-
}
|
|
29
|
-
insertChild(i, node) {
|
|
30
|
-
const children = this.children;
|
|
31
|
-
i < 0 && (i += children.length);
|
|
32
|
-
assert(i >= 0 && i <= children.length, "index out of bounds");
|
|
33
|
-
children.splice(i, 0, node);
|
|
34
|
-
node.parent = this;
|
|
35
|
-
node.update();
|
|
36
|
-
return this;
|
|
3
|
+
class ANode {
|
|
4
|
+
id;
|
|
5
|
+
parent;
|
|
6
|
+
children;
|
|
7
|
+
body;
|
|
8
|
+
mat;
|
|
9
|
+
invMat;
|
|
10
|
+
enabled;
|
|
11
|
+
display;
|
|
12
|
+
constructor(id, parent, body) {
|
|
13
|
+
this.id = id;
|
|
14
|
+
this.parent = parent;
|
|
15
|
+
this.children = [];
|
|
16
|
+
if (parent) {
|
|
17
|
+
parent.appendChild(this);
|
|
37
18
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
19
|
+
this.body = body;
|
|
20
|
+
this.mat = [];
|
|
21
|
+
this.invMat = [];
|
|
22
|
+
this.enabled = true;
|
|
23
|
+
this.display = true;
|
|
24
|
+
}
|
|
25
|
+
appendChild(node) {
|
|
26
|
+
this.children.push(node);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
insertChild(i, node) {
|
|
30
|
+
const children = this.children;
|
|
31
|
+
i < 0 && (i += children.length);
|
|
32
|
+
assert(i >= 0 && i <= children.length, "index out of bounds");
|
|
33
|
+
children.splice(i, 0, node);
|
|
34
|
+
node.parent = this;
|
|
35
|
+
node.update();
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
deleteChild(node) {
|
|
39
|
+
const { children } = this;
|
|
40
|
+
const i = isNumber(node) ? node : children.indexOf(node);
|
|
41
|
+
if (i >= 0 && i < children.length) {
|
|
42
|
+
children.splice(i, 1);
|
|
43
|
+
return true;
|
|
46
44
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
draw(ctx) {
|
|
48
|
+
if (this.display) {
|
|
49
|
+
for (let c of this.children) {
|
|
50
|
+
c.draw(ctx);
|
|
51
|
+
}
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}
|
|
73
|
-
const q = this.mapGlobalPoint(p);
|
|
74
|
-
if (q && this.containsLocalPoint(q)) {
|
|
75
|
-
return { node: this, p: q };
|
|
76
|
-
}
|
|
53
|
+
}
|
|
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
|
+
childForPoint(p) {
|
|
65
|
+
if (this.enabled) {
|
|
66
|
+
const children = this.children;
|
|
67
|
+
for (let i = children.length; i-- > 0; ) {
|
|
68
|
+
const n = children[i].childForPoint(p);
|
|
69
|
+
if (n) {
|
|
70
|
+
return n;
|
|
77
71
|
}
|
|
72
|
+
}
|
|
73
|
+
const q = this.mapGlobalPoint(p);
|
|
74
|
+
if (q && this.containsLocalPoint(q)) {
|
|
75
|
+
return { node: this, p: q };
|
|
76
|
+
}
|
|
78
77
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
78
|
+
}
|
|
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
|
+
containsLocalPoint(_) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
92
|
}
|
|
93
|
+
export {
|
|
94
|
+
ANode
|
|
95
|
+
};
|
package/api.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/hiccup.js
CHANGED
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
import { deref } from "@thi.ng/api/deref";
|
|
2
2
|
import { isFunction } from "@thi.ng/checks/is-function";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
? node.children.length
|
|
15
|
-
? [
|
|
16
|
-
"g",
|
|
17
|
-
{},
|
|
18
|
-
node.body
|
|
19
|
-
? ["g", { transform: node.mat }, body]
|
|
20
|
-
: undefined,
|
|
21
|
-
...node.children.map((c) => c.toHiccup(ctx)),
|
|
22
|
-
]
|
|
23
|
-
: body
|
|
24
|
-
? ["g", { transform: node.mat }, body]
|
|
25
|
-
: undefined
|
|
26
|
-
: undefined;
|
|
3
|
+
const toHiccup = (node, ctx) => {
|
|
4
|
+
const body = isFunction(node.body) ? node.body(ctx) : deref(node.body);
|
|
5
|
+
return node.enabled && node.display ? node.children.length ? [
|
|
6
|
+
"g",
|
|
7
|
+
{},
|
|
8
|
+
node.body ? ["g", { transform: node.mat }, body] : void 0,
|
|
9
|
+
...node.children.map((c) => c.toHiccup(ctx))
|
|
10
|
+
] : body ? ["g", { transform: node.mat }, body] : void 0 : void 0;
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
toHiccup
|
|
27
14
|
};
|
package/node2.js
CHANGED
|
@@ -6,49 +6,59 @@ import { transform23 } from "@thi.ng/matrices/transform";
|
|
|
6
6
|
import { set2 } from "@thi.ng/vectors/set";
|
|
7
7
|
import { ANode } from "./anode.js";
|
|
8
8
|
import { toHiccup } from "./hiccup.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
mapLocalPointToNode(dest, p) {
|
|
42
|
-
return mulV23(null, dest.invMat, mulV23([], this.mat, p));
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* By implementing this method (`IToHiccup` interface), scene graph nodes
|
|
46
|
-
* can be directly used by hdom-canvas, hiccup-canvas, rdom-canvas or
|
|
47
|
-
* hiccup-svg (for the latter one needs to call `convertTree()` first).
|
|
48
|
-
*
|
|
49
|
-
* @param ctx - arbitrary user data
|
|
50
|
-
*/
|
|
51
|
-
toHiccup(ctx) {
|
|
52
|
-
return toHiccup(this, ctx);
|
|
9
|
+
class Node2D extends ANode {
|
|
10
|
+
translate;
|
|
11
|
+
rotate;
|
|
12
|
+
scale;
|
|
13
|
+
constructor(id, parent, translate = [0, 0], rotate = 0, scale = 1, body) {
|
|
14
|
+
super(id, parent, body);
|
|
15
|
+
this.translate = translate;
|
|
16
|
+
this.rotate = rotate;
|
|
17
|
+
this.scale = isNumber(scale) ? [scale, scale] : scale;
|
|
18
|
+
this.update();
|
|
19
|
+
}
|
|
20
|
+
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
|
+
);
|
|
29
|
+
}
|
|
30
|
+
update() {
|
|
31
|
+
if (this.enabled) {
|
|
32
|
+
this.mat = transform23([], this.translate, this.rotate, this.scale);
|
|
33
|
+
if (this.parent) {
|
|
34
|
+
mulM23(this.mat, this.parent.mat, this.mat);
|
|
35
|
+
}
|
|
36
|
+
invert23(this.invMat, this.mat);
|
|
37
|
+
for (let c of this.children) {
|
|
38
|
+
c.update();
|
|
39
|
+
}
|
|
53
40
|
}
|
|
41
|
+
}
|
|
42
|
+
mapGlobalPoint(p) {
|
|
43
|
+
return mulV23([], this.invMat, p);
|
|
44
|
+
}
|
|
45
|
+
mapLocalPointToGlobal(p) {
|
|
46
|
+
return mulV23([], this.mat, p);
|
|
47
|
+
}
|
|
48
|
+
mapLocalPointToNode(dest, p) {
|
|
49
|
+
return mulV23(null, dest.invMat, mulV23([], this.mat, p));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* By implementing this method (`IToHiccup` interface), scene graph nodes
|
|
53
|
+
* can be directly used by hdom-canvas, hiccup-canvas, rdom-canvas or
|
|
54
|
+
* hiccup-svg (for the latter one needs to call `convertTree()` first).
|
|
55
|
+
*
|
|
56
|
+
* @param ctx - arbitrary user data
|
|
57
|
+
*/
|
|
58
|
+
toHiccup(ctx) {
|
|
59
|
+
return toHiccup(this, ctx);
|
|
60
|
+
}
|
|
54
61
|
}
|
|
62
|
+
export {
|
|
63
|
+
Node2D
|
|
64
|
+
};
|
package/node3.js
CHANGED
|
@@ -6,48 +6,58 @@ import { transform44 } from "@thi.ng/matrices/transform";
|
|
|
6
6
|
import { set3 } from "@thi.ng/vectors/set";
|
|
7
7
|
import { ANode } from "./anode.js";
|
|
8
8
|
import { toHiccup } from "./hiccup.js";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
mapLocalPointToNode(dest, p) {
|
|
42
|
-
return mulV344(null, dest.invMat, mulV344([], this.mat, p));
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Future support planned. No immediate users of this method in a 3D context
|
|
46
|
-
* available thus far.
|
|
47
|
-
*
|
|
48
|
-
* @param ctx - arbitrary user data
|
|
49
|
-
*/
|
|
50
|
-
toHiccup(ctx) {
|
|
51
|
-
return toHiccup(this, ctx);
|
|
9
|
+
class Node3D extends ANode {
|
|
10
|
+
translate;
|
|
11
|
+
rotate;
|
|
12
|
+
scale;
|
|
13
|
+
constructor(id, parent, translate = [0, 0, 0], rotate = [0, 0, 0], scale = 1, body) {
|
|
14
|
+
super(id, parent, body);
|
|
15
|
+
this.translate = translate;
|
|
16
|
+
this.rotate = rotate;
|
|
17
|
+
this.scale = isNumber(scale) ? [scale, scale, scale] : scale;
|
|
18
|
+
this.update();
|
|
19
|
+
}
|
|
20
|
+
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
|
+
);
|
|
29
|
+
}
|
|
30
|
+
update() {
|
|
31
|
+
if (this.enabled) {
|
|
32
|
+
this.mat = transform44([], this.translate, this.rotate, this.scale);
|
|
33
|
+
if (this.parent) {
|
|
34
|
+
mulM44(this.mat, this.parent.mat, this.mat);
|
|
35
|
+
}
|
|
36
|
+
invert44(this.invMat, this.mat);
|
|
37
|
+
for (let c of this.children) {
|
|
38
|
+
c.update();
|
|
39
|
+
}
|
|
52
40
|
}
|
|
41
|
+
}
|
|
42
|
+
mapGlobalPoint(p) {
|
|
43
|
+
return mulV344([], this.invMat, p);
|
|
44
|
+
}
|
|
45
|
+
mapLocalPointToGlobal(p) {
|
|
46
|
+
return mulV344([], this.mat, p);
|
|
47
|
+
}
|
|
48
|
+
mapLocalPointToNode(dest, p) {
|
|
49
|
+
return mulV344(null, dest.invMat, mulV344([], this.mat, p));
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Future support planned. No immediate users of this method in a 3D context
|
|
53
|
+
* available thus far.
|
|
54
|
+
*
|
|
55
|
+
* @param ctx - arbitrary user data
|
|
56
|
+
*/
|
|
57
|
+
toHiccup(ctx) {
|
|
58
|
+
return toHiccup(this, ctx);
|
|
59
|
+
}
|
|
53
60
|
}
|
|
61
|
+
export {
|
|
62
|
+
Node3D
|
|
63
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thi.ng/scenegraph",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Extensible 2D/3D scene graph with @thi.ng/hiccup-canvas support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"author": "Karsten Schmidt (https://thi.ng)",
|
|
25
25
|
"license": "Apache-2.0",
|
|
26
26
|
"scripts": {
|
|
27
|
-
"build": "yarn
|
|
27
|
+
"build": "yarn build:esbuild && yarn build:decl",
|
|
28
|
+
"build:decl": "tsc --declaration --emitDeclarationOnly",
|
|
29
|
+
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
|
|
28
30
|
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",
|
|
29
31
|
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
32
|
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
@@ -33,15 +35,15 @@
|
|
|
33
35
|
"test": "bun test"
|
|
34
36
|
},
|
|
35
37
|
"dependencies": {
|
|
36
|
-
"@thi.ng/api": "^8.9.
|
|
37
|
-
"@thi.ng/checks": "^3.4.
|
|
38
|
-
"@thi.ng/errors": "^2.4.
|
|
39
|
-
"@thi.ng/matrices": "^2.2.
|
|
40
|
-
"@thi.ng/vectors": "^7.8.
|
|
38
|
+
"@thi.ng/api": "^8.9.12",
|
|
39
|
+
"@thi.ng/checks": "^3.4.12",
|
|
40
|
+
"@thi.ng/errors": "^2.4.6",
|
|
41
|
+
"@thi.ng/matrices": "^2.2.13",
|
|
42
|
+
"@thi.ng/vectors": "^7.8.9"
|
|
41
43
|
},
|
|
42
44
|
"devDependencies": {
|
|
43
45
|
"@microsoft/api-extractor": "^7.38.3",
|
|
44
|
-
"
|
|
46
|
+
"esbuild": "^0.19.8",
|
|
45
47
|
"rimraf": "^5.0.5",
|
|
46
48
|
"tools": "^0.0.1",
|
|
47
49
|
"typedoc": "^0.25.4",
|
|
@@ -97,5 +99,5 @@
|
|
|
97
99
|
],
|
|
98
100
|
"status": "alpha"
|
|
99
101
|
},
|
|
100
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
|
|
101
103
|
}
|