abstract-3d 2.3.5 → 2.3.10

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.
Files changed (43) hide show
  1. package/lib/abstract-3d.d.ts +3 -1
  2. package/lib/abstract-3d.d.ts.map +1 -1
  3. package/lib/abstract-3d.js.map +1 -1
  4. package/lib/renderers/dxf/dxf-geometries/dxf-image.d.ts.map +1 -1
  5. package/lib/renderers/dxf/dxf-geometries/dxf-image.js +9 -3
  6. package/lib/renderers/dxf/dxf-geometries/dxf-image.js.map +1 -1
  7. package/lib/renderers/react/react-group.d.ts.map +1 -1
  8. package/lib/renderers/react/react-group.js +4 -19
  9. package/lib/renderers/react/react-group.js.map +1 -1
  10. package/lib/renderers/react/react-image.d.ts +29 -0
  11. package/lib/renderers/react/react-image.d.ts.map +1 -0
  12. package/lib/renderers/react/react-image.js +84 -0
  13. package/lib/renderers/react/react-image.js.map +1 -0
  14. package/lib/renderers/react/react-material.d.ts +5 -17
  15. package/lib/renderers/react/react-material.d.ts.map +1 -1
  16. package/lib/renderers/react/react-material.js +21 -92
  17. package/lib/renderers/react/react-material.js.map +1 -1
  18. package/lib/renderers/react/react-mesh.d.ts +8 -1
  19. package/lib/renderers/react/react-mesh.d.ts.map +1 -1
  20. package/lib/renderers/react/react-mesh.js +5 -6
  21. package/lib/renderers/react/react-mesh.js.map +1 -1
  22. package/lib/renderers/svg/svg-encoding.d.ts +1 -0
  23. package/lib/renderers/svg/svg-encoding.d.ts.map +1 -1
  24. package/lib/renderers/svg/svg-encoding.js +8 -3
  25. package/lib/renderers/svg/svg-encoding.js.map +1 -1
  26. package/lib/renderers/svg/svg-geometries/svg-image.d.ts.map +1 -1
  27. package/lib/renderers/svg/svg-geometries/svg-image.js +18 -2
  28. package/lib/renderers/svg/svg-geometries/svg-image.js.map +1 -1
  29. package/lib/renderers/svg/svg-geometries/svg-plane.d.ts.map +1 -1
  30. package/lib/renderers/svg/svg-geometries/svg-plane.js +1 -15
  31. package/lib/renderers/svg/svg-geometries/svg-plane.js.map +1 -1
  32. package/package.json +2 -2
  33. package/src/abstract-3d.ts +9 -5
  34. package/src/renderers/dxf/dxf-geometries/dxf-image.ts +20 -19
  35. package/src/renderers/react/react-group.tsx +26 -34
  36. package/src/renderers/react/react-image.tsx +149 -0
  37. package/src/renderers/react/react-material.tsx +33 -166
  38. package/src/renderers/react/react-mesh.tsx +27 -14
  39. package/src/renderers/svg/svg-encoding.ts +9 -6
  40. package/src/renderers/svg/svg-geometries/svg-image.ts +22 -2
  41. package/src/renderers/svg/svg-geometries/svg-plane.ts +1 -21
  42. package/src/.DS_Store +0 -0
  43. package/src/renderers/.DS_Store +0 -0
@@ -1,8 +1,7 @@
1
1
  import React from "react";
2
- import { createSVG } from "abstract-image";
3
2
  import { ThreeEvent, useFrame } from "@react-three/fiber";
4
3
  import type { Group } from "three";
5
- import { Group as Group_1, Material, Mesh } from "../../abstract-3d.js";
4
+ import { Group as Group_1 } from "../../abstract-3d.js";
6
5
  import { MaterialState, ReactMaterial } from "./react-material.js";
7
6
  import { ReactMesh } from "./react-mesh.js";
8
7
 
@@ -126,40 +125,33 @@ export function ReactGroup({
126
125
  useAlphaTest={useAlphaTest}
127
126
  />
128
127
  ))}
129
- {g.meshes?.map((m, i) => (
130
- <ReactMesh key={`mesh_${i}`} mesh={m}>
131
- <ReactMaterial
132
- material={getMaterial(m)}
133
- id={id}
134
- selectedIds={selectedIds}
135
- isText={m.geometry.type === "Text"}
136
- hoveredId={hoveredId || hoveredIdExternal}
128
+ {g.meshes?.map((m, i) => {
129
+ const hoveredIdFinal = hoveredId || hoveredIdExternal;
130
+ return (
131
+ <ReactMesh
132
+ key={`mesh_${i}`}
133
+ mesh={m}
137
134
  materialStateImages={materialStateImages}
138
- disabled={disabled}
139
- state={materialState}
140
135
  useAlphaTest={useAlphaTest}
141
- />
142
- </ReactMesh>
143
- ))}
136
+ id={id}
137
+ hoveredId={hoveredIdFinal}
138
+ materialState={materialState}
139
+ selectedIds={selectedIds}
140
+ >
141
+ {m.geometry.type === "Image" ? undefined : (
142
+ <ReactMaterial
143
+ material={m.material}
144
+ id={id}
145
+ selectedIds={selectedIds}
146
+ isText={m.geometry.type === "Text"}
147
+ hoveredId={hoveredIdFinal}
148
+ disabled={disabled}
149
+ materialState={materialState}
150
+ />
151
+ )}
152
+ </ReactMesh>
153
+ );
154
+ })}
144
155
  </group>
145
156
  );
146
157
  }
147
-
148
- function getMaterial(mesh: Mesh): Material {
149
- if(mesh.geometry.type !== "Image") {
150
- return mesh.material;
151
- }
152
-
153
- switch(mesh.geometry.image.type) {
154
- case "AbstractImage": {
155
- const svg = createSVG(mesh.geometry.image.image);
156
- const svgUrl = `data:image/svg+xml,${svg}`;
157
- return {
158
- ...mesh.material,
159
- imageUrl: svgUrl,
160
- };
161
- }
162
- default:
163
- return mesh.material;
164
- }
165
- }
@@ -0,0 +1,149 @@
1
+ import React, { useEffect } from "react";
2
+ import { suspend } from "suspend-react";
3
+ import { createSVG } from "abstract-image";
4
+ import { CanvasTexture, DoubleSide, PlaneGeometry, SRGBColorSpace, type Texture, TextureLoader } from "three";
5
+ import { Material, Image as A3dImage } from "../../abstract-3d.js";
6
+ import { ERROR_IMG_KEY, getColor, materialDefaults, MaterialState } from "./react-material.js";
7
+
8
+ export const planeGeometry = new PlaneGeometry();
9
+
10
+ export enum MinificationFilter {
11
+ Nearest = 1003,
12
+ Linear = 1006,
13
+ LinearMipmap = 1008,
14
+ }
15
+
16
+ export enum MagnificationFilter {
17
+ Nearest = 1003,
18
+ Linear = 1006,
19
+ }
20
+
21
+ export type TextureFilter = {
22
+ readonly min: MinificationFilter;
23
+ readonly mag: MagnificationFilter;
24
+ };
25
+
26
+ const filter: TextureFilter = { min: MinificationFilter.LinearMipmap, mag: MagnificationFilter.Linear };
27
+
28
+ export function ImageMesh({
29
+ image,
30
+ materialStateImages,
31
+ material,
32
+ id,
33
+ useAlphaTest,
34
+ hoveredId,
35
+ selectedIds,
36
+ materialState,
37
+ }: {
38
+ readonly image: A3dImage;
39
+ readonly material: Material;
40
+ readonly id: string | undefined;
41
+ readonly materialStateImages: Record<string, string> | undefined;
42
+ readonly hoveredId: string | undefined;
43
+ readonly selectedIds: Record<string, boolean> | undefined;
44
+ readonly useAlphaTest: boolean | undefined;
45
+ readonly materialState: MaterialState | undefined;
46
+ }): React.JSX.Element {
47
+ const url =
48
+ materialState === "Error" && materialStateImages?.[ERROR_IMG_KEY]
49
+ ? materialStateImages[ERROR_IMG_KEY]
50
+ : image.image.type === "AbstractImage"
51
+ ? `data:image/svg+xml,${createSVG(image.image.image)}`
52
+ : image.image.url;
53
+
54
+ const texture = suspend(urlIsSvg(url) ? loadSvg(url, filter) : loadNormal(url, filter), [url]) as Texture | null;
55
+ useEffect(() => {
56
+ return () => {
57
+ if (texture) {
58
+ texture.dispose();
59
+ }
60
+ };
61
+ }, [texture]);
62
+
63
+ return (
64
+ <mesh
65
+ geometry={planeGeometry}
66
+ scale={[image.size.x, image.size.y, 1]}
67
+ position={[image.pos.x, image.pos.y, image.pos.z]}
68
+ rotation={[image.rot?.x ?? 0, image.rot?.y ?? 0, image.rot?.z ?? 0]}
69
+ castShadow
70
+ receiveShadow
71
+ >
72
+ <meshBasicMaterial
73
+ color={getColor(selectedIds, id, hoveredId, material)}
74
+ side={DoubleSide}
75
+ alphaTest={useAlphaTest ?? true ? 0.8 : undefined}
76
+ map={texture}
77
+ {...(material.opacity !== undefined && material.opacity < 1 ? { opacity: material.opacity } : materialDefaults)}
78
+ transparent
79
+ />
80
+ </mesh>
81
+ );
82
+ }
83
+
84
+ function urlIsSvg(url: string): boolean {
85
+ return url.startsWith("data:image/svg+xml") || url.endsWith(".svg") || url.includes(".svg?");
86
+ }
87
+
88
+ function loadSvg(url: string, filter: TextureFilter): Promise<Texture | null> {
89
+ const maxSize = 4096;
90
+
91
+ return new Promise((res) => {
92
+ const img = new Image();
93
+
94
+ // eslint-disable-next-line consistent-return
95
+ img.onload = (): void => {
96
+ const canvas = document.createElement("canvas");
97
+ const imgW = img.naturalWidth;
98
+ const imgH = img.naturalHeight;
99
+ const width = imgW >= imgH ? maxSize : maxSize * (imgW / imgH);
100
+ const height = imgH >= imgW ? maxSize : maxSize * (imgH / imgW);
101
+
102
+ canvas.width = width;
103
+ canvas.height = height;
104
+
105
+ const ctx = canvas.getContext("2d");
106
+ if (!ctx) {
107
+ return res(null);
108
+ }
109
+
110
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
111
+ ctx.imageSmoothingEnabled = true;
112
+ ctx.imageSmoothingQuality = "high";
113
+ ctx.drawImage(img, 0, 0, width, height);
114
+
115
+ const texture = new CanvasTexture(canvas);
116
+ texture.colorSpace = SRGBColorSpace;
117
+ texture.minFilter = filter.min;
118
+ texture.magFilter = filter.mag;
119
+ texture.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
120
+ texture.anisotropy = 4;
121
+ texture.needsUpdate = true;
122
+
123
+ res(texture);
124
+ };
125
+
126
+ img.onerror = () => res(null);
127
+ img.src = url;
128
+ });
129
+ }
130
+
131
+ function loadNormal(url: string, filter: TextureFilter): Promise<Texture | null> {
132
+ return new Promise((res) =>
133
+ textureLoader.load(
134
+ url,
135
+ (data) => {
136
+ data.colorSpace = SRGBColorSpace;
137
+ data.minFilter = filter.min;
138
+ data.magFilter = filter.mag;
139
+ data.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
140
+ data.anisotropy = 4;
141
+ res(data);
142
+ },
143
+ undefined,
144
+ () => res(null)
145
+ )
146
+ );
147
+ }
148
+
149
+ const textureLoader = new TextureLoader();
@@ -1,38 +1,10 @@
1
- import React, { useEffect } from "react";
2
- import { suspend } from "suspend-react";
3
- import {
4
- BackSide,
5
- CanvasTexture,
6
- type Color,
7
- DoubleSide,
8
- FrontSide,
9
- type MaterialParameters,
10
- SRGBColorSpace,
11
- type Texture,
12
- TextureLoader,
13
- } from "three";
1
+ import React from "react";
2
+ import { BackSide, DoubleSide, FrontSide, type MaterialParameters } from "three";
14
3
  import { Material } from "../../abstract-3d.js";
15
4
  import { shade } from "../../utils.js";
16
- import { mx_gradient_float } from "three/src/nodes/materialx/lib/mx_noise.js";
17
5
 
18
6
  const decreasedOpacity = 0.125;
19
7
 
20
- export enum MinificationFilter {
21
- Nearest = 1003,
22
- Linear = 1006,
23
- LinearMipmap = 1008,
24
- };
25
-
26
- export enum MagnificationFilter {
27
- Nearest = 1003,
28
- Linear = 1006,
29
- }
30
-
31
- export type TextureFilter = {
32
- readonly min: MinificationFilter;
33
- readonly mag: MagnificationFilter;
34
- }
35
-
36
8
  export type MaterialState = "Accept" | "Error" | "Warning";
37
9
  export const ERROR_IMG_KEY = "error";
38
10
 
@@ -42,40 +14,29 @@ export function ReactMaterial({
42
14
  selectedIds,
43
15
  hoveredId,
44
16
  disabled,
45
- materialStateImages,
46
- state,
17
+ materialState,
47
18
  isText,
48
19
  isHotSpot,
49
20
  drawBackOnly,
50
- useAlphaTest,
51
21
  }: {
52
22
  readonly material: Material;
53
23
  readonly id?: string;
54
24
  readonly hoveredId?: string | undefined;
55
25
  readonly selectedIds?: Record<string, boolean> | undefined;
56
26
  readonly disabled?: boolean;
57
- readonly materialStateImages?: Record<string, string>;
58
- readonly state?: MaterialState | undefined;
27
+ readonly materialState?: MaterialState | undefined;
59
28
  readonly isText: boolean;
60
29
  readonly isHotSpot?: boolean;
61
30
  readonly drawBackOnly?: boolean;
62
- readonly useAlphaTest?: boolean;
63
31
  }): React.JSX.Element {
64
- const mat =
65
- !state || material.imageUrl === "UrlImage"
66
- ? material
67
- : state === "Accept"
68
- ? acceptMat
69
- : state === "Error"
70
- ? errorMar
71
- : warningMat;
72
- const color = selectedIds?.[id]
73
- ? hoveredId === id
74
- ? shade(-0.4, selectMat.normal)
75
- : selectMat.normal
76
- : hoveredId === id
77
- ? shade(-0.4, mat.normal)
78
- : mat.normal;
32
+ const mat = !materialState
33
+ ? material
34
+ : materialState === "Accept"
35
+ ? acceptMat
36
+ : materialState === "Error"
37
+ ? errorMar
38
+ : warningMat;
39
+ const color = getColor(selectedIds, id, hoveredId, mat);
79
40
  const colorText = selectedIds?.[id]
80
41
  ? hoveredId === id
81
42
  ? shade(-0.4, textSelectMat.normal)
@@ -84,17 +45,6 @@ export function ReactMaterial({
84
45
  ? shade(-0.4, mat.normal)
85
46
  : mat.normal;
86
47
  const opacity = material.opacity !== undefined ? material.opacity : materialDefaults.opacity!;
87
- if (material.imageUrl) {
88
- return (
89
- <TextureMaterial
90
- url={state === "Error" ? materialStateImages?.[ERROR_IMG_KEY] ?? material.imageUrl : material.imageUrl}
91
- color={color}
92
- material={mat}
93
- useAlphaTest={useAlphaTest}
94
- filter={{ mag: MagnificationFilter.Linear, min: MinificationFilter.LinearMipmap }}
95
- />
96
- );
97
- }
98
48
  if (isText) {
99
49
  return (
100
50
  <meshBasicMaterial
@@ -137,114 +87,31 @@ export function ReactMaterial({
137
87
  />
138
88
  );
139
89
  }
140
- const materialDefaults: MaterialParameters = { transparent: false, depthWrite: true, depthTest: true, opacity: 1.0 };
141
-
142
- function TextureMaterial({
143
- url,
144
- color,
145
- material,
146
- useAlphaTest = true,
147
- filter = {
148
- min: MinificationFilter.LinearMipmap,
149
- mag: MagnificationFilter.Linear
150
- },
151
- }: {
152
- readonly url: string;
153
- readonly color: string | Color | undefined;
154
- readonly material: Material;
155
- readonly useAlphaTest?: boolean;
156
- readonly filter?: TextureFilter;
157
- }): React.JSX.Element {
158
- const texture = suspend(urlIsSvg(url) ? loadSvg(url, filter) : loadNormal(url, filter), [url]) as Texture | null;
159
- useEffect(() => {
160
- return () => {
161
- if (texture) {
162
- texture.dispose();
163
- }
164
- };
165
- }, [texture]);
166
-
167
- return (
168
- <meshBasicMaterial
169
- color={color}
170
- side={DoubleSide}
171
- alphaTest={useAlphaTest ? 0.8 : undefined}
172
- map={texture}
173
- {...(material.opacity !== undefined && material.opacity < 1 ? { opacity: material.opacity } : materialDefaults)}
174
- transparent
175
- />
176
- );
177
- }
178
-
179
- function urlIsSvg(url: string): boolean {
180
- return url.startsWith("data:image/svg+xml") || url.endsWith(".svg") || url.includes(".svg?");
181
- }
182
-
183
- function loadSvg(url: string, filter: TextureFilter): Promise<Texture | null> {
184
- const maxSize = 4096;
185
-
186
- return new Promise((res) => {
187
- const img = new Image();
188
-
189
- // eslint-disable-next-line consistent-return
190
- img.onload = ((): void => {
191
- const canvas = document.createElement("canvas");
192
- const imgW = img.naturalWidth;
193
- const imgH = img.naturalHeight;
194
- const width = imgW >= imgH ? maxSize : (maxSize * (imgW / imgH));
195
- const height = imgH >= imgW ? maxSize : (maxSize * (imgH / imgW));
196
-
197
- canvas.width = width;
198
- canvas.height = height;
199
-
200
- const ctx = canvas.getContext("2d");
201
- if (!ctx) {
202
- return res(null);
203
- }
204
-
205
- ctx.clearRect(0, 0, canvas.width, canvas.height);
206
- ctx.imageSmoothingEnabled = true;
207
- ctx.imageSmoothingQuality = "high";
208
- ctx.drawImage(img, 0, 0, width, height);
209
-
210
- const texture = new CanvasTexture(canvas);
211
- texture.colorSpace = SRGBColorSpace;
212
- texture.minFilter = filter.min;
213
- texture.magFilter = filter.mag;
214
- texture.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
215
- texture.anisotropy = 4;
216
- texture.needsUpdate = true;
217
-
218
- res(texture);
219
- });
220
-
221
- img.onerror = () => res(null);
222
- img.src = url;
223
- });
224
- }
225
-
226
- function loadNormal(url: string, filter: TextureFilter): Promise<Texture | null> {
227
- return new Promise((res) =>
228
- textureLoader.load(
229
- url,
230
- (data) => {
231
- data.colorSpace = SRGBColorSpace;
232
- data.minFilter = filter.min;
233
- data.magFilter = filter.mag;
234
- data.generateMipmaps = filter.min === MinificationFilter.LinearMipmap;
235
- data.anisotropy = 4;
236
- res(data);
237
- },
238
- undefined,
239
- () => res(null)
240
- )
241
- );
242
- }
243
90
 
244
- const textureLoader = new TextureLoader();
91
+ export const materialDefaults: MaterialParameters = {
92
+ transparent: false,
93
+ depthWrite: true,
94
+ depthTest: true,
95
+ opacity: 1.0,
96
+ };
245
97
 
246
98
  const acceptMat: Material = { normal: "rgb(0,148,91)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
247
99
  const selectMat: Material = { normal: "rgb(14,82,184)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
248
100
  const textSelectMat: Material = { normal: "rgb(0, 26, 65)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
249
101
  const errorMar: Material = { normal: "#b82f3a", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
250
102
  const warningMat: Material = { normal: "rgb(240, 197, 48)", opacity: 1.0, metalness: 0.5, roughness: 0.5 };
103
+
104
+ export function getColor(
105
+ selectedIds: Record<string, boolean> | undefined,
106
+ id: string | undefined,
107
+ hoveredId: string | undefined,
108
+ mat: Material
109
+ ): string | undefined {
110
+ return selectedIds?.[id ?? ""]
111
+ ? hoveredId === id
112
+ ? shade(-0.4, selectMat.normal)
113
+ : selectMat.normal
114
+ : hoveredId === id
115
+ ? shade(-0.4, mat.normal)
116
+ : mat.normal;
117
+ }
@@ -41,6 +41,10 @@ import {
41
41
  equals,
42
42
  } from "../../abstract-3d.js";
43
43
  import { exhaustiveCheck } from "ts-exhaustive-check";
44
+ import { ImageMesh, planeGeometry } from "./react-image.js";
45
+ import { MaterialState } from "./react-material.js";
46
+
47
+ // dummy
44
48
 
45
49
  extend({
46
50
  SphereGeometry,
@@ -64,7 +68,6 @@ const boxGeometry = new BoxGeometry();
64
68
  const cylinderGeometry = new CylinderGeometry(1, 1, 1, CYLINDER_SEGMENTS, 1);
65
69
  const cylinderGeometryOpen = new CylinderGeometry(1, 1, 1, CYLINDER_SEGMENTS, 1, true);
66
70
  const coneGeometry = new ConeGeometry(1, 1, 16, 1);
67
- const planeGeometry = new PlaneGeometry();
68
71
  const sphereGeometry = new SphereGeometry(1, 12, 12);
69
72
  export const euler = new Euler();
70
73
  export const vector3 = new Vector3();
@@ -73,9 +76,21 @@ export const quaternion = new Quaternion();
73
76
  export function ReactMesh({
74
77
  mesh,
75
78
  children,
79
+ id,
80
+ hoveredId,
81
+ selectedIds,
82
+ materialStateImages,
83
+ materialState,
84
+ useAlphaTest,
76
85
  }: {
77
86
  readonly mesh: Mesh;
78
87
  readonly children?: React.JSX.Element;
88
+ readonly id?: string | undefined;
89
+ readonly hoveredId?: string | undefined;
90
+ readonly selectedIds?: Record<string, boolean> | undefined;
91
+ readonly materialStateImages?: Record<string, string> | undefined;
92
+ readonly materialState?: MaterialState | undefined;
93
+ readonly useAlphaTest?: boolean | undefined;
79
94
  }): React.JSX.Element {
80
95
  switch (mesh.geometry.type) {
81
96
  case "Box": {
@@ -185,21 +200,19 @@ export function ReactMesh({
185
200
  );
186
201
  }
187
202
  }
188
- case "Image": {
189
- const { pos, size, rot } = mesh.geometry;
203
+ case "Image":
190
204
  return (
191
- <mesh
192
- geometry={planeGeometry}
193
- scale={[size.x, size.y, 1]}
194
- position={[pos.x, pos.y, pos.z]}
195
- rotation={[rot?.x ?? 0, rot?.y ?? 0, rot?.z ?? 0]}
196
- castShadow
197
- receiveShadow
198
- >
199
- {children}
200
- </mesh>
205
+ <ImageMesh
206
+ image={mesh.geometry}
207
+ materialStateImages={materialStateImages}
208
+ useAlphaTest={useAlphaTest}
209
+ id={id}
210
+ hoveredId={hoveredId}
211
+ selectedIds={selectedIds}
212
+ materialState={materialState}
213
+ material={mesh.material}
214
+ />
201
215
  );
202
- }
203
216
  case "Plane": {
204
217
  const { pos, size, rot, holes } = mesh.geometry;
205
218
  const filteredHoles = holes?.filter((h) => !holeIsZero(h));
@@ -173,6 +173,8 @@ export type EmbededImage =
173
173
  | { readonly type: "url"; readonly url: string }
174
174
  | { readonly type: "svg"; readonly svg: string };
175
175
 
176
+ export const rawSvgPrefix = "data:image/svg+xml,";
177
+
176
178
  export const svgImage = (
177
179
  p: Vec2,
178
180
  size: Vec2,
@@ -183,13 +185,14 @@ export const svgImage = (
183
185
  ): string => {
184
186
  const matrix = svgTrsMatrix(p, rot, scale);
185
187
 
186
- return `<g transform="${matrix}">${
188
+ const bg = background
189
+ ? `<rect width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" fill="${background}"/>`
190
+ : "";
191
+ const content =
187
192
  data.type === "url"
188
- ? `${
189
- background ? `<rect width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" fill="${background}"/>` : ""
190
- }<image width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" href="${data.url}"/>`
191
- : `<svg width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}">${data.svg}</svg>`
192
- }</g>`;
193
+ ? `<image width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}" href="${data.url}"/>`
194
+ : `<svg width="${size.x.toFixed(0)}" height="${size.y.toFixed(0)}">${data.svg}</svg>`;
195
+ return `<g transform="${matrix}">${bg}${content}</g>`;
193
196
  };
194
197
 
195
198
  const counter = (() => {
@@ -1,7 +1,7 @@
1
1
  import { createSVG } from "abstract-image";
2
2
  import { Image, Vec2, Vec3, vec2Scale, vec3TransRot, vec3RotCombine, vec3Zero, vec3 } from "../../../abstract-3d.js";
3
3
  import { zElem, zOrderElement, SvgOptions } from "./shared.js";
4
- import { svgImage } from "../svg-encoding.js";
4
+ import { EmbededImage, rawSvgPrefix, svgImage } from "../svg-encoding.js";
5
5
  import { exhaustiveCheck } from "ts-exhaustive-check";
6
6
 
7
7
  export function image(
@@ -29,7 +29,27 @@ export function image(
29
29
  const img = svgImage(point(v4.x, v4.y), i.size, rot, { type: "svg", svg }, opts.background, scale);
30
30
  return [zElem(img, (v2.z + v4.z) / 2)];
31
31
  }
32
+ case "Url": {
33
+ const imageData = opts.imageDataByUrl?.[i.image.url];
34
+ const image: EmbededImage | undefined = imageData?.startsWith(rawSvgPrefix)
35
+ ? {
36
+ type: "svg",
37
+ svg: decodeURIComponent(imageData.slice(rawSvgPrefix.length)).replace(
38
+ /^\s*(<\?xml[^>]*\?>\s*)?(<!DOCTYPE[^>]*>\s*)?/i,
39
+ ""
40
+ ),
41
+ }
42
+ : i.image.url
43
+ ? { type: "url", url: imageData ?? i.image.url }
44
+ : undefined;
45
+
46
+ if (image) {
47
+ const img = svgImage(point(v4.x, v4.y), i.size, rot, image, opts.background);
48
+ return [zElem(img, (v2.z + v4.z) / 2)];
49
+ }
50
+ return [];
51
+ }
32
52
  default:
33
- return exhaustiveCheck(i.image.type);
53
+ return exhaustiveCheck(i.image);
34
54
  }
35
55
  }
@@ -12,7 +12,7 @@ import {
12
12
  Hole,
13
13
  } from "../../../abstract-3d.js";
14
14
  import { gray, black, zElem, zOrderElement, SvgOptions } from "./shared.js";
15
- import { EmbededImage, svgImage, svgPolygon } from "../svg-encoding.js";
15
+ import { svgPolygon } from "../svg-encoding.js";
16
16
  import { rgbGrayScale } from "../../../utils.js";
17
17
 
18
18
  export function plane(
@@ -34,24 +34,6 @@ export function plane(
34
34
  const v3 = vec3tr(half.x, half.y);
35
35
  const v4 = vec3tr(-half.x, half.y);
36
36
 
37
- const imageData = material.imageUrl ? opts.imageDataByUrl?.[material.imageUrl] : undefined;
38
- const image: EmbededImage | undefined = imageData?.startsWith(rawSvgPrefix)
39
- ? {
40
- type: "svg",
41
- svg: decodeURIComponent(imageData.slice(rawSvgPrefix.length)).replace(
42
- /^\s*(<\?xml[^>]*\?>\s*)?(<!DOCTYPE[^>]*>\s*)?/i,
43
- ""
44
- ),
45
- }
46
- : material.imageUrl
47
- ? { type: "url", url: imageData ?? material.imageUrl }
48
- : undefined;
49
-
50
- if (image) {
51
- const img = svgImage(point(v4.x, v4.y), p.size, rot, image, opts.background);
52
- return [zElem(img, (v2.z + v4.z) / 2)];
53
- }
54
-
55
37
  const points = [point(v1.x, v1.y), point(v2.x, v2.y), point(v3.x, v3.y), point(v4.x, v4.y)];
56
38
 
57
39
  const [strokeColor, fill, strokeThickness] = opts.only_stroke
@@ -64,5 +46,3 @@ export function plane(
64
46
  ),
65
47
  ];
66
48
  }
67
-
68
- const rawSvgPrefix = "data:image/svg+xml,";
package/src/.DS_Store DELETED
Binary file
Binary file