pptx-react-viewer 4.1.6 → 4.2.0
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 +6 -0
- package/dist/{AiChatPanel-Y2RKSHOO.mjs → AiChatPanel-SEIRQ3XP.mjs} +3 -3
- package/dist/AiChatPanel-SEIRQ3XP.mjs.br +0 -0
- package/dist/AiChatPanel-SEIRQ3XP.mjs.gz +0 -0
- package/dist/{AiChatPanel-DRCY3T2Z.js → AiChatPanel-VVTLQXQ5.js} +27 -27
- package/dist/AiChatPanel-VVTLQXQ5.js.br +0 -0
- package/dist/AiChatPanel-VVTLQXQ5.js.gz +0 -0
- package/dist/{Model3DScene-ITHRMCLT.mjs → Model3DScene-DCTVSK2F.mjs} +1 -1
- package/dist/Model3DScene-DCTVSK2F.mjs.br +0 -0
- package/dist/Model3DScene-DCTVSK2F.mjs.gz +0 -0
- package/dist/{Model3DScene-VJZS726S.js → Model3DScene-SCWQXMEA.js} +2 -2
- package/dist/Model3DScene-SCWQXMEA.js.br +0 -0
- package/dist/Model3DScene-SCWQXMEA.js.gz +0 -0
- package/dist/{chunk-IXS7DALE.js → OrbitControls-4TDJCTBA.js} +1 -0
- package/dist/OrbitControls-4TDJCTBA.js.br +0 -0
- package/dist/OrbitControls-4TDJCTBA.js.gz +0 -0
- package/dist/{chunk-MV2GCDBR.mjs → OrbitControls-WCOIJFFL.mjs} +1 -0
- package/dist/OrbitControls-WCOIJFFL.mjs.br +0 -0
- package/dist/OrbitControls-WCOIJFFL.mjs.gz +0 -0
- package/dist/{chunk-2O66VMWK.js → chunk-3WYNGYB6.js} +5 -5
- package/dist/chunk-3WYNGYB6.js.br +0 -0
- package/dist/chunk-3WYNGYB6.js.gz +0 -0
- package/dist/{chunk-OFSKGB3W.mjs → chunk-4GTDG2FH.mjs} +157 -579
- package/dist/chunk-4GTDG2FH.mjs.br +0 -0
- package/dist/chunk-4GTDG2FH.mjs.gz +0 -0
- package/dist/{chunk-P5LF34BT.js → chunk-5MRNT4V6.js} +173 -173
- package/dist/chunk-5MRNT4V6.js.br +0 -0
- package/dist/chunk-5MRNT4V6.js.gz +0 -0
- package/dist/{chunk-KDTE5JOW.mjs → chunk-B5YZABYX.mjs} +1 -1
- package/dist/chunk-B5YZABYX.mjs.br +0 -0
- package/dist/chunk-B5YZABYX.mjs.gz +0 -0
- package/dist/{chunk-LNSYROED.js → chunk-KTSDPBQZ.js} +1309 -1210
- package/dist/chunk-KTSDPBQZ.js.br +0 -0
- package/dist/chunk-KTSDPBQZ.js.gz +0 -0
- package/dist/{chunk-QEYWSHNE.mjs → chunk-L4XBWL7J.mjs} +1 -1
- package/dist/chunk-L4XBWL7J.mjs.br +0 -0
- package/dist/chunk-L4XBWL7J.mjs.gz +0 -0
- package/dist/{chunk-VWGJXNMR.js → chunk-P2SBIMYF.js} +1645 -2073
- package/dist/chunk-P2SBIMYF.js.br +0 -0
- package/dist/chunk-P2SBIMYF.js.gz +0 -0
- package/dist/{chunk-QMSSDBKN.js → chunk-S65QSO6T.js} +26522 -22546
- package/dist/chunk-S65QSO6T.js.br +0 -0
- package/dist/chunk-S65QSO6T.js.gz +0 -0
- package/dist/{chunk-FT3MMIXW.mjs → chunk-VPJOJJ36.mjs} +26518 -22532
- package/dist/chunk-VPJOJJ36.mjs.br +0 -0
- package/dist/chunk-VPJOJJ36.mjs.gz +0 -0
- package/dist/{chunk-YHTDDCSC.mjs → chunk-ZYIJODUR.mjs} +254 -155
- package/dist/chunk-ZYIJODUR.mjs.br +0 -0
- package/dist/chunk-ZYIJODUR.mjs.gz +0 -0
- package/dist/index.d.ts +65 -18
- package/dist/index.js +47 -47
- package/dist/index.js.br +0 -0
- package/dist/index.js.gz +0 -0
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.br +0 -0
- package/dist/index.mjs.gz +0 -0
- package/dist/internals.d.ts +65 -18
- package/dist/internals.js +104 -104
- package/dist/internals.js.br +0 -0
- package/dist/internals.js.gz +0 -0
- package/dist/internals.mjs +3 -3
- package/dist/internals.mjs.br +0 -0
- package/dist/internals.mjs.gz +0 -0
- package/dist/pptx-viewer.css +1 -1
- package/dist/pptx-viewer.css.br +0 -0
- package/dist/pptx-viewer.css.gz +0 -0
- package/dist/viewer/index.d.ts +48 -1
- package/dist/viewer/index.js +26 -26
- package/dist/viewer/index.js.br +0 -0
- package/dist/viewer/index.js.gz +0 -0
- package/dist/viewer/index.mjs +5 -5
- package/dist/viewer/index.mjs.br +0 -0
- package/dist/viewer/index.mjs.gz +0 -0
- package/package.json +1 -1
- package/dist/AiChatPanel-DRCY3T2Z.js.br +0 -0
- package/dist/AiChatPanel-DRCY3T2Z.js.gz +0 -0
- package/dist/AiChatPanel-Y2RKSHOO.mjs.br +0 -0
- package/dist/AiChatPanel-Y2RKSHOO.mjs.gz +0 -0
- package/dist/Area3DChartScene-J4LMNSGM.js +0 -64
- package/dist/Area3DChartScene-J4LMNSGM.js.br +0 -0
- package/dist/Area3DChartScene-J4LMNSGM.js.gz +0 -0
- package/dist/Area3DChartScene-TDACCSOI.mjs +0 -62
- package/dist/Area3DChartScene-TDACCSOI.mjs.br +0 -0
- package/dist/Area3DChartScene-TDACCSOI.mjs.gz +0 -0
- package/dist/Bar3DChartScene-AD72DLBJ.mjs +0 -62
- package/dist/Bar3DChartScene-AD72DLBJ.mjs.br +0 -0
- package/dist/Bar3DChartScene-AD72DLBJ.mjs.gz +0 -0
- package/dist/Bar3DChartScene-T7334CTK.js +0 -64
- package/dist/Bar3DChartScene-T7334CTK.js.br +0 -0
- package/dist/Bar3DChartScene-T7334CTK.js.gz +0 -0
- package/dist/Line3DChartScene-2ZQSCHK3.mjs +0 -62
- package/dist/Line3DChartScene-2ZQSCHK3.mjs.br +0 -0
- package/dist/Line3DChartScene-2ZQSCHK3.mjs.gz +0 -0
- package/dist/Line3DChartScene-ELVKCFJZ.js +0 -64
- package/dist/Line3DChartScene-ELVKCFJZ.js.br +0 -0
- package/dist/Line3DChartScene-ELVKCFJZ.js.gz +0 -0
- package/dist/Model3DScene-ITHRMCLT.mjs.br +0 -0
- package/dist/Model3DScene-ITHRMCLT.mjs.gz +0 -0
- package/dist/Model3DScene-VJZS726S.js.br +0 -0
- package/dist/Model3DScene-VJZS726S.js.gz +0 -0
- package/dist/OrbitControls-2XOMWUVE.mjs +0 -3
- package/dist/OrbitControls-2XOMWUVE.mjs.br +0 -0
- package/dist/OrbitControls-2XOMWUVE.mjs.gz +0 -0
- package/dist/OrbitControls-CGYUF3BY.js +0 -12
- package/dist/OrbitControls-CGYUF3BY.js.br +0 -0
- package/dist/OrbitControls-CGYUF3BY.js.gz +0 -0
- package/dist/PieChart3DScene-N3DM33FW.js +0 -58
- package/dist/PieChart3DScene-N3DM33FW.js.br +0 -0
- package/dist/PieChart3DScene-N3DM33FW.js.gz +0 -0
- package/dist/PieChart3DScene-PYHOA7BO.mjs +0 -56
- package/dist/PieChart3DScene-PYHOA7BO.mjs.br +0 -0
- package/dist/PieChart3DScene-PYHOA7BO.mjs.gz +0 -0
- package/dist/SmartArt3DScene-D4VNNPHS.mjs +0 -500
- package/dist/SmartArt3DScene-D4VNNPHS.mjs.br +0 -0
- package/dist/SmartArt3DScene-D4VNNPHS.mjs.gz +0 -0
- package/dist/SmartArt3DScene-NHD7CZJ5.js +0 -502
- package/dist/SmartArt3DScene-NHD7CZJ5.js.br +0 -0
- package/dist/SmartArt3DScene-NHD7CZJ5.js.gz +0 -0
- package/dist/SurfaceChart3DScene-IFBUOLNB.mjs +0 -62
- package/dist/SurfaceChart3DScene-IFBUOLNB.mjs.br +0 -0
- package/dist/SurfaceChart3DScene-IFBUOLNB.mjs.gz +0 -0
- package/dist/SurfaceChart3DScene-PUWIMT7V.js +0 -64
- package/dist/SurfaceChart3DScene-PUWIMT7V.js.br +0 -0
- package/dist/SurfaceChart3DScene-PUWIMT7V.js.gz +0 -0
- package/dist/chunk-2O66VMWK.js.br +0 -0
- package/dist/chunk-2O66VMWK.js.gz +0 -0
- package/dist/chunk-DNR6CH6I.js +0 -30
- package/dist/chunk-DNR6CH6I.js.br +0 -0
- package/dist/chunk-DNR6CH6I.js.gz +0 -0
- package/dist/chunk-FT3MMIXW.mjs.br +0 -0
- package/dist/chunk-FT3MMIXW.mjs.gz +0 -0
- package/dist/chunk-IXS7DALE.js.br +0 -0
- package/dist/chunk-IXS7DALE.js.gz +0 -0
- package/dist/chunk-KDTE5JOW.mjs.br +0 -0
- package/dist/chunk-KDTE5JOW.mjs.gz +0 -0
- package/dist/chunk-LNSYROED.js.br +0 -0
- package/dist/chunk-LNSYROED.js.gz +0 -0
- package/dist/chunk-MV2GCDBR.mjs.br +0 -0
- package/dist/chunk-MV2GCDBR.mjs.gz +0 -0
- package/dist/chunk-OFSKGB3W.mjs.br +0 -0
- package/dist/chunk-OFSKGB3W.mjs.gz +0 -0
- package/dist/chunk-P5LF34BT.js.br +0 -0
- package/dist/chunk-P5LF34BT.js.gz +0 -0
- package/dist/chunk-QEYWSHNE.mjs.br +0 -0
- package/dist/chunk-QEYWSHNE.mjs.gz +0 -0
- package/dist/chunk-QMSSDBKN.js.br +0 -0
- package/dist/chunk-QMSSDBKN.js.gz +0 -0
- package/dist/chunk-T6GFCLSM.mjs +0 -27
- package/dist/chunk-T6GFCLSM.mjs.br +0 -4
- package/dist/chunk-T6GFCLSM.mjs.gz +0 -0
- package/dist/chunk-VWGJXNMR.js.br +0 -0
- package/dist/chunk-VWGJXNMR.js.gz +0 -0
- package/dist/chunk-YHTDDCSC.mjs.br +0 -0
- package/dist/chunk-YHTDDCSC.mjs.gz +0 -0
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkDNR6CH6I_js = require('./chunk-DNR6CH6I.js');
|
|
4
|
-
var chunkQMSSDBKN_js = require('./chunk-QMSSDBKN.js');
|
|
5
|
-
require('./chunk-4VNS5WPM.js');
|
|
6
|
-
var react = require('react');
|
|
7
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
-
|
|
9
|
-
function PieChart3DScene({
|
|
10
|
-
options,
|
|
11
|
-
interaction,
|
|
12
|
-
selectedPart = null
|
|
13
|
-
}) {
|
|
14
|
-
const containerRef = react.useRef(null);
|
|
15
|
-
const handleRef = react.useRef(null);
|
|
16
|
-
const stableInteraction = chunkDNR6CH6I_js.useStableChart3DInteraction(interaction);
|
|
17
|
-
const selectedPartRef = chunkDNR6CH6I_js.useLatestRef(selectedPart);
|
|
18
|
-
react.useEffect(() => {
|
|
19
|
-
const container = containerRef.current;
|
|
20
|
-
if (!container) {
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
let disposed = false;
|
|
24
|
-
void chunkQMSSDBKN_js.mountPieChart3D(container, options, stableInteraction).then((handle) => {
|
|
25
|
-
if (disposed) {
|
|
26
|
-
handle.dispose();
|
|
27
|
-
} else {
|
|
28
|
-
handleRef.current = handle;
|
|
29
|
-
handle.setSelectedPart(selectedPartRef.current);
|
|
30
|
-
}
|
|
31
|
-
return void 0;
|
|
32
|
-
});
|
|
33
|
-
return () => {
|
|
34
|
-
disposed = true;
|
|
35
|
-
handleRef.current?.dispose();
|
|
36
|
-
handleRef.current = null;
|
|
37
|
-
};
|
|
38
|
-
}, [options, stableInteraction]);
|
|
39
|
-
react.useEffect(() => {
|
|
40
|
-
handleRef.current?.resize(options.width, options.height);
|
|
41
|
-
}, [options.width, options.height]);
|
|
42
|
-
react.useEffect(() => {
|
|
43
|
-
handleRef.current?.setSelectedPart(selectedPart);
|
|
44
|
-
}, [selectedPart]);
|
|
45
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
46
|
-
"div",
|
|
47
|
-
{
|
|
48
|
-
ref: containerRef,
|
|
49
|
-
style: {
|
|
50
|
-
width: options.width,
|
|
51
|
-
height: options.height,
|
|
52
|
-
willChange: "transform"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
module.exports = PieChart3DScene;
|
|
Binary file
|
|
Binary file
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { useStableChart3DInteraction, useLatestRef } from './chunk-T6GFCLSM.mjs';
|
|
2
|
-
import { mountPieChart3D } from './chunk-FT3MMIXW.mjs';
|
|
3
|
-
import './chunk-XGB3TDIC.mjs';
|
|
4
|
-
import { useRef, useEffect } from 'react';
|
|
5
|
-
import { jsx } from 'react/jsx-runtime';
|
|
6
|
-
|
|
7
|
-
function PieChart3DScene({
|
|
8
|
-
options,
|
|
9
|
-
interaction,
|
|
10
|
-
selectedPart = null
|
|
11
|
-
}) {
|
|
12
|
-
const containerRef = useRef(null);
|
|
13
|
-
const handleRef = useRef(null);
|
|
14
|
-
const stableInteraction = useStableChart3DInteraction(interaction);
|
|
15
|
-
const selectedPartRef = useLatestRef(selectedPart);
|
|
16
|
-
useEffect(() => {
|
|
17
|
-
const container = containerRef.current;
|
|
18
|
-
if (!container) {
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
let disposed = false;
|
|
22
|
-
void mountPieChart3D(container, options, stableInteraction).then((handle) => {
|
|
23
|
-
if (disposed) {
|
|
24
|
-
handle.dispose();
|
|
25
|
-
} else {
|
|
26
|
-
handleRef.current = handle;
|
|
27
|
-
handle.setSelectedPart(selectedPartRef.current);
|
|
28
|
-
}
|
|
29
|
-
return void 0;
|
|
30
|
-
});
|
|
31
|
-
return () => {
|
|
32
|
-
disposed = true;
|
|
33
|
-
handleRef.current?.dispose();
|
|
34
|
-
handleRef.current = null;
|
|
35
|
-
};
|
|
36
|
-
}, [options, stableInteraction]);
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
handleRef.current?.resize(options.width, options.height);
|
|
39
|
-
}, [options.width, options.height]);
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
handleRef.current?.setSelectedPart(selectedPart);
|
|
42
|
-
}, [selectedPart]);
|
|
43
|
-
return /* @__PURE__ */ jsx(
|
|
44
|
-
"div",
|
|
45
|
-
{
|
|
46
|
-
ref: containerRef,
|
|
47
|
-
style: {
|
|
48
|
-
width: options.width,
|
|
49
|
-
height: options.height,
|
|
50
|
-
willChange: "transform"
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export { PieChart3DScene as default };
|
|
Binary file
|
|
Binary file
|
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
import { useLatestRef } from './chunk-T6GFCLSM.mjs';
|
|
2
|
-
import { OrbitControls } from './chunk-MV2GCDBR.mjs';
|
|
3
|
-
import { WebGLRenderer, Scene, Color, PerspectiveCamera, AmbientLight, DirectionalLight, Group, MeshStandardMaterial, Mesh, EdgesGeometry, LineBasicMaterial, LineSegments, PlaneGeometry, MeshBasicMaterial, DoubleSide, Euler, Vector3, BufferGeometry, Line, Shape, ExtrudeGeometry, CanvasTexture, SRGBColorSpace, LinearFilter, RepeatWrapping } from './chunk-7TAWW5QQ.mjs';
|
|
4
|
-
import './chunk-XGB3TDIC.mjs';
|
|
5
|
-
import { useRef, useEffect } from 'react';
|
|
6
|
-
import { jsx } from 'react/jsx-runtime';
|
|
7
|
-
|
|
8
|
-
// ../shared/dist/smartart-3d/index.mjs
|
|
9
|
-
var SUPERSAMPLE = 4;
|
|
10
|
-
var FILL = 0.86;
|
|
11
|
-
function wrapLines(ctx, text, maxWidth) {
|
|
12
|
-
const words = text.split(/\s+/u).filter(Boolean);
|
|
13
|
-
if (words.length === 0) {
|
|
14
|
-
return [];
|
|
15
|
-
}
|
|
16
|
-
const lines = [];
|
|
17
|
-
let line = words[0];
|
|
18
|
-
for (let i = 1; i < words.length; i++) {
|
|
19
|
-
const candidate = `${line} ${words[i]}`;
|
|
20
|
-
if (ctx.measureText(candidate).width <= maxWidth) {
|
|
21
|
-
line = candidate;
|
|
22
|
-
} else {
|
|
23
|
-
lines.push(line);
|
|
24
|
-
line = words[i];
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
lines.push(line);
|
|
28
|
-
return lines;
|
|
29
|
-
}
|
|
30
|
-
function resolveEmphasisFont(color, emphasis) {
|
|
31
|
-
const weight = emphasis?.bold === void 0 ? "600" : emphasis.bold ? "700" : "400";
|
|
32
|
-
const italic = emphasis?.italic ? "italic " : "";
|
|
33
|
-
const scale = typeof emphasis?.fontScale === "number" && Number.isFinite(emphasis.fontScale) && emphasis.fontScale > 0 ? emphasis.fontScale : 1;
|
|
34
|
-
return { weight, italic, color: emphasis?.color ?? color, scale };
|
|
35
|
-
}
|
|
36
|
-
function makeTextTexture(text, color, fontSize, footW, footH, emphasis) {
|
|
37
|
-
if (typeof document === "undefined" || !text.trim() || footW <= 0 || footH <= 0) {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
const { weight, italic, color: effectiveColor, scale } = resolveEmphasisFont(color, emphasis);
|
|
41
|
-
const worldWidth = footW * FILL;
|
|
42
|
-
const worldHeight = footH * FILL;
|
|
43
|
-
const canvas = document.createElement("canvas");
|
|
44
|
-
canvas.width = Math.max(8, Math.round(worldWidth * SUPERSAMPLE));
|
|
45
|
-
canvas.height = Math.max(8, Math.round(worldHeight * SUPERSAMPLE));
|
|
46
|
-
const ctx = canvas.getContext("2d");
|
|
47
|
-
if (!ctx) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
const family = "system-ui, -apple-system, Segoe UI, Roboto, sans-serif";
|
|
51
|
-
const maxTextWidth = canvas.width * 0.94;
|
|
52
|
-
const fontString = (px2) => `${italic}${weight} ${px2}px ${family}`;
|
|
53
|
-
let px = Math.max(6, fontSize) * scale * SUPERSAMPLE;
|
|
54
|
-
let lines = [];
|
|
55
|
-
for (let attempt = 0; attempt < 12; attempt++) {
|
|
56
|
-
ctx.font = fontString(px);
|
|
57
|
-
lines = wrapLines(ctx, text, maxTextWidth);
|
|
58
|
-
const lineHeight2 = px * 1.2;
|
|
59
|
-
if (lines.length * lineHeight2 <= canvas.height * 0.96 || px <= 6 * SUPERSAMPLE) {
|
|
60
|
-
break;
|
|
61
|
-
}
|
|
62
|
-
px *= 0.88;
|
|
63
|
-
}
|
|
64
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
65
|
-
ctx.fillStyle = effectiveColor;
|
|
66
|
-
ctx.textAlign = "center";
|
|
67
|
-
ctx.textBaseline = "middle";
|
|
68
|
-
ctx.font = fontString(px);
|
|
69
|
-
const lineHeight = px * 1.2;
|
|
70
|
-
const blockHeight = lines.length * lineHeight;
|
|
71
|
-
const startY = canvas.height / 2 - blockHeight / 2 + lineHeight / 2;
|
|
72
|
-
for (let i = 0; i < lines.length; i++) {
|
|
73
|
-
const y = startY + i * lineHeight;
|
|
74
|
-
ctx.fillText(lines[i], canvas.width / 2, y);
|
|
75
|
-
if (emphasis?.underline) {
|
|
76
|
-
const w = ctx.measureText(lines[i]).width;
|
|
77
|
-
ctx.strokeStyle = effectiveColor;
|
|
78
|
-
ctx.lineWidth = Math.max(1, px * 0.06);
|
|
79
|
-
ctx.beginPath();
|
|
80
|
-
ctx.moveTo(canvas.width / 2 - w / 2, y + px * 0.32);
|
|
81
|
-
ctx.lineTo(canvas.width / 2 + w / 2, y + px * 0.32);
|
|
82
|
-
ctx.stroke();
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
const texture = new CanvasTexture(canvas);
|
|
86
|
-
texture.colorSpace = SRGBColorSpace;
|
|
87
|
-
texture.minFilter = LinearFilter;
|
|
88
|
-
texture.magFilter = LinearFilter;
|
|
89
|
-
texture.flipY = false;
|
|
90
|
-
texture.premultiplyAlpha = false;
|
|
91
|
-
texture.wrapT = RepeatWrapping;
|
|
92
|
-
texture.repeat.set(1, -1);
|
|
93
|
-
texture.offset.set(0, 1);
|
|
94
|
-
texture.needsUpdate = true;
|
|
95
|
-
return { texture, worldWidth, worldHeight };
|
|
96
|
-
}
|
|
97
|
-
function extrudeGeometry(m) {
|
|
98
|
-
const shape = new Shape();
|
|
99
|
-
m.outline.forEach((p, i) => {
|
|
100
|
-
if (i === 0) {
|
|
101
|
-
shape.moveTo(p.x, p.y);
|
|
102
|
-
} else {
|
|
103
|
-
shape.lineTo(p.x, p.y);
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
shape.closePath();
|
|
107
|
-
const bevelEnabled = m.bevel > 0;
|
|
108
|
-
return new ExtrudeGeometry(shape, {
|
|
109
|
-
depth: m.depth,
|
|
110
|
-
bevelEnabled,
|
|
111
|
-
bevelThickness: m.bevel,
|
|
112
|
-
bevelSize: m.bevel,
|
|
113
|
-
bevelSegments: 2,
|
|
114
|
-
curveSegments: m.rounded ? 24 : 1,
|
|
115
|
-
steps: 1
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
function addBlock(group, disposables, m) {
|
|
119
|
-
const geo = extrudeGeometry(m);
|
|
120
|
-
const material = new MeshStandardMaterial({
|
|
121
|
-
color: new Color(m.fill),
|
|
122
|
-
metalness: 0.12,
|
|
123
|
-
roughness: 0.52,
|
|
124
|
-
transparent: m.opacity < 1,
|
|
125
|
-
opacity: m.opacity
|
|
126
|
-
});
|
|
127
|
-
const mesh = new Mesh(geo, material);
|
|
128
|
-
mesh.position.set(m.position.x, m.position.y, m.position.z);
|
|
129
|
-
mesh.rotation.set(m.rotation.x, m.rotation.y, m.rotation.z);
|
|
130
|
-
group.add(mesh);
|
|
131
|
-
disposables.push(geo, material);
|
|
132
|
-
if (m.strokeWidth > 0) {
|
|
133
|
-
const edges = new EdgesGeometry(geo, 30);
|
|
134
|
-
const lineMaterial = new LineBasicMaterial({ color: new Color(m.stroke) });
|
|
135
|
-
const line = new LineSegments(edges, lineMaterial);
|
|
136
|
-
line.position.copy(mesh.position);
|
|
137
|
-
line.rotation.copy(mesh.rotation);
|
|
138
|
-
group.add(line);
|
|
139
|
-
disposables.push(edges, lineMaterial);
|
|
140
|
-
}
|
|
141
|
-
return geo;
|
|
142
|
-
}
|
|
143
|
-
function buildLabelPlane(m, textStyle) {
|
|
144
|
-
if (!m.text) {
|
|
145
|
-
return null;
|
|
146
|
-
}
|
|
147
|
-
const tex = makeTextTexture(
|
|
148
|
-
m.text,
|
|
149
|
-
m.textColor,
|
|
150
|
-
m.fontSize,
|
|
151
|
-
m.halfWidth * 2,
|
|
152
|
-
m.halfHeight * 2,
|
|
153
|
-
textStyle
|
|
154
|
-
);
|
|
155
|
-
if (!tex) {
|
|
156
|
-
return null;
|
|
157
|
-
}
|
|
158
|
-
const planeGeo = new PlaneGeometry(tex.worldWidth, tex.worldHeight);
|
|
159
|
-
const planeMaterial = new MeshBasicMaterial({
|
|
160
|
-
map: tex.texture,
|
|
161
|
-
transparent: true,
|
|
162
|
-
depthWrite: false,
|
|
163
|
-
depthTest: false,
|
|
164
|
-
side: DoubleSide
|
|
165
|
-
});
|
|
166
|
-
const plane = new Mesh(planeGeo, planeMaterial);
|
|
167
|
-
plane.renderOrder = 1;
|
|
168
|
-
const euler = new Euler(m.rotation.x, m.rotation.y, m.rotation.z);
|
|
169
|
-
const offset = new Vector3(0, 0, m.depth + m.bevel + 0.4).applyEuler(euler);
|
|
170
|
-
plane.position.set(m.position.x + offset.x, m.position.y + offset.y, m.position.z + offset.z);
|
|
171
|
-
plane.rotation.copy(euler);
|
|
172
|
-
return { plane, disposables: [planeGeo, planeMaterial, tex.texture] };
|
|
173
|
-
}
|
|
174
|
-
function addConnectors(group, disposables, model) {
|
|
175
|
-
for (const c of model.connectors) {
|
|
176
|
-
if (c.points.length < 2) {
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
const geo = new BufferGeometry().setFromPoints(c.points.map((p) => new Vector3(p.x, p.y, p.z)));
|
|
180
|
-
const material = new LineBasicMaterial({
|
|
181
|
-
color: new Color(c.color),
|
|
182
|
-
transparent: true,
|
|
183
|
-
opacity: 0.7
|
|
184
|
-
});
|
|
185
|
-
group.add(new Line(geo, material));
|
|
186
|
-
disposables.push(geo, material);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
function clearLabel(group, entry) {
|
|
190
|
-
if (entry.plane) {
|
|
191
|
-
group.remove(entry.plane);
|
|
192
|
-
}
|
|
193
|
-
for (const d of entry.disposables) {
|
|
194
|
-
d.dispose();
|
|
195
|
-
}
|
|
196
|
-
entry.plane = null;
|
|
197
|
-
entry.disposables = [];
|
|
198
|
-
}
|
|
199
|
-
function buildMeshGroup(model, textStyle) {
|
|
200
|
-
const group = new Group();
|
|
201
|
-
const blockDisposables = [];
|
|
202
|
-
const labelEntries = model.meshes.map((m) => {
|
|
203
|
-
addBlock(group, blockDisposables, m);
|
|
204
|
-
const built = buildLabelPlane(m, textStyle);
|
|
205
|
-
if (built) {
|
|
206
|
-
group.add(built.plane);
|
|
207
|
-
}
|
|
208
|
-
return { node: m, plane: built?.plane ?? null, disposables: built?.disposables ?? [] };
|
|
209
|
-
});
|
|
210
|
-
addConnectors(group, blockDisposables, model);
|
|
211
|
-
return {
|
|
212
|
-
group,
|
|
213
|
-
setTextStyle(style) {
|
|
214
|
-
for (const entry of labelEntries) {
|
|
215
|
-
clearLabel(group, entry);
|
|
216
|
-
const built = buildLabelPlane(entry.node, style);
|
|
217
|
-
if (built) {
|
|
218
|
-
group.add(built.plane);
|
|
219
|
-
entry.plane = built.plane;
|
|
220
|
-
entry.disposables = built.disposables;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
},
|
|
224
|
-
forEachLabelPlane(fn) {
|
|
225
|
-
for (const entry of labelEntries) {
|
|
226
|
-
if (entry.plane) {
|
|
227
|
-
fn(entry.plane);
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
},
|
|
231
|
-
dispose() {
|
|
232
|
-
for (const d of blockDisposables) {
|
|
233
|
-
d.dispose();
|
|
234
|
-
}
|
|
235
|
-
for (const entry of labelEntries) {
|
|
236
|
-
clearLabel(group, entry);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
var FOV = 42;
|
|
242
|
-
function expandForMesh(expand, m) {
|
|
243
|
-
const hx = m.halfWidth + m.bevel;
|
|
244
|
-
const hy = m.halfHeight + m.bevel;
|
|
245
|
-
const hz = m.depth / 2 + m.bevel;
|
|
246
|
-
const midZ = m.position.z + m.depth / 2;
|
|
247
|
-
const cosY = Math.cos(m.rotation.y);
|
|
248
|
-
const sinY = Math.sin(m.rotation.y);
|
|
249
|
-
const worldHalfX = Math.abs(hx * cosY) + Math.abs(hz * sinY);
|
|
250
|
-
const worldHalfZ = Math.abs(hx * sinY) + Math.abs(hz * cosY);
|
|
251
|
-
expand(m.position.x, m.position.y, midZ, worldHalfX, hy, worldHalfZ);
|
|
252
|
-
}
|
|
253
|
-
function contentSphere(model) {
|
|
254
|
-
let minX = Infinity;
|
|
255
|
-
let minY = Infinity;
|
|
256
|
-
let minZ = Infinity;
|
|
257
|
-
let maxX = -Infinity;
|
|
258
|
-
let maxY = -Infinity;
|
|
259
|
-
let maxZ = -Infinity;
|
|
260
|
-
const expand = (x, y, z, rx, ry, rz) => {
|
|
261
|
-
minX = Math.min(minX, x - rx);
|
|
262
|
-
minY = Math.min(minY, y - ry);
|
|
263
|
-
minZ = Math.min(minZ, z - rz);
|
|
264
|
-
maxX = Math.max(maxX, x + rx);
|
|
265
|
-
maxY = Math.max(maxY, y + ry);
|
|
266
|
-
maxZ = Math.max(maxZ, z + rz);
|
|
267
|
-
};
|
|
268
|
-
for (const m of model.meshes) {
|
|
269
|
-
expandForMesh(expand, m);
|
|
270
|
-
}
|
|
271
|
-
for (const c of model.connectors) {
|
|
272
|
-
for (const p of c.points) {
|
|
273
|
-
expand(p.x, p.y, p.z, 1, 1, 1);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (!Number.isFinite(minX)) {
|
|
277
|
-
const halfW = model.bounds.width / 2 || 1;
|
|
278
|
-
const halfH = model.bounds.height / 2 || 1;
|
|
279
|
-
const fallback = Math.max(halfW, halfH);
|
|
280
|
-
return { cx: 0, cy: 0, cz: 0, radius: fallback, halfW, halfH, halfD: 1 };
|
|
281
|
-
}
|
|
282
|
-
return {
|
|
283
|
-
cx: (minX + maxX) / 2,
|
|
284
|
-
cy: (minY + maxY) / 2,
|
|
285
|
-
cz: (minZ + maxZ) / 2,
|
|
286
|
-
radius: 0.5 * Math.hypot(maxX - minX, maxY - minY, maxZ - minZ) || 1,
|
|
287
|
-
halfW: (maxX - minX) / 2,
|
|
288
|
-
halfH: (maxY - minY) / 2,
|
|
289
|
-
halfD: (maxZ - minZ) / 2
|
|
290
|
-
};
|
|
291
|
-
}
|
|
292
|
-
function frameDistance(radius, aspect) {
|
|
293
|
-
const vFov = FOV * Math.PI / 180;
|
|
294
|
-
const hFov = 2 * Math.atan(Math.tan(vFov / 2) * aspect);
|
|
295
|
-
const minFov = Math.min(vFov, hFov);
|
|
296
|
-
return radius / Math.sin(minFov / 2) * 1.1;
|
|
297
|
-
}
|
|
298
|
-
var FRAME_FILL = 0.92;
|
|
299
|
-
function placeCamera(bounds, family, dist) {
|
|
300
|
-
const { cx, cy, cz, radius } = bounds;
|
|
301
|
-
const elevation = cameraElevation(family, radius, dist);
|
|
302
|
-
return {
|
|
303
|
-
position: [cx + radius * 0.25, cy + elevation, cz + dist],
|
|
304
|
-
target: [cx, cy, cz],
|
|
305
|
-
dist
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
function projectedFill(bounds, placement, aspect) {
|
|
309
|
-
const vFov = FOV * Math.PI / 180;
|
|
310
|
-
const tanV = Math.tan(vFov / 2);
|
|
311
|
-
const tanH = tanV * aspect;
|
|
312
|
-
const [px, py, pz] = placement.position;
|
|
313
|
-
const [tx, ty, tz] = placement.target;
|
|
314
|
-
let fx = tx - px, fy = ty - py, fz = tz - pz;
|
|
315
|
-
const fl = Math.hypot(fx, fy, fz) || 1;
|
|
316
|
-
fx /= fl;
|
|
317
|
-
fy /= fl;
|
|
318
|
-
fz /= fl;
|
|
319
|
-
let rx = -fz, rz = fx;
|
|
320
|
-
const rl = Math.hypot(rx, rz) || 1;
|
|
321
|
-
rx /= rl;
|
|
322
|
-
rz /= rl;
|
|
323
|
-
const ux = -rz * fy, uy = rz * fx - rx * fz, uz = rx * fy;
|
|
324
|
-
let worst = 0;
|
|
325
|
-
for (const sx of [-1, 1]) {
|
|
326
|
-
for (const sy of [-1, 1]) {
|
|
327
|
-
for (const sz of [-1, 1]) {
|
|
328
|
-
const dx = bounds.cx + sx * bounds.halfW - px;
|
|
329
|
-
const dy = bounds.cy + sy * bounds.halfH - py;
|
|
330
|
-
const dz = bounds.cz + sz * bounds.halfD - pz;
|
|
331
|
-
const depth = dx * fx + dy * fy + dz * fz;
|
|
332
|
-
if (depth <= 1e-6) {
|
|
333
|
-
return Infinity;
|
|
334
|
-
}
|
|
335
|
-
const x = Math.abs(dx * rx + dz * rz) / (depth * tanH);
|
|
336
|
-
const y = Math.abs(dx * ux + dy * uy + dz * uz) / (depth * tanV);
|
|
337
|
-
worst = Math.max(worst, x, y);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
return worst;
|
|
342
|
-
}
|
|
343
|
-
function fitCamera(bounds, family, aspect) {
|
|
344
|
-
let dist = frameDistance(bounds.radius, aspect);
|
|
345
|
-
let placement = placeCamera(bounds, family, dist);
|
|
346
|
-
for (let step = 0; step < 8; step++) {
|
|
347
|
-
const fill = projectedFill(bounds, placement, aspect);
|
|
348
|
-
if (!Number.isFinite(fill)) {
|
|
349
|
-
dist *= 2;
|
|
350
|
-
} else {
|
|
351
|
-
const ratio = fill / FRAME_FILL;
|
|
352
|
-
if (Math.abs(ratio - 1) < 0.01) {
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
dist *= ratio;
|
|
356
|
-
}
|
|
357
|
-
placement = placeCamera(bounds, family, dist);
|
|
358
|
-
}
|
|
359
|
-
return placement;
|
|
360
|
-
}
|
|
361
|
-
var CAROUSEL_ELEVATION_DEG = 34;
|
|
362
|
-
function cameraElevation(family, radius, dist) {
|
|
363
|
-
if (family === "cycle" || family === "radial") {
|
|
364
|
-
return dist * Math.tan(CAROUSEL_ELEVATION_DEG * Math.PI / 180);
|
|
365
|
-
}
|
|
366
|
-
return radius * 0.3;
|
|
367
|
-
}
|
|
368
|
-
function billboardLabels(built, camera) {
|
|
369
|
-
built.forEachLabelPlane((plane) => {
|
|
370
|
-
const dx = camera.position.x - plane.position.x;
|
|
371
|
-
const dz = camera.position.z - plane.position.z;
|
|
372
|
-
plane.rotation.set(0, Math.atan2(dx, dz), 0);
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
function mountSmartArt3D(canvas, model, width, height, options = {}) {
|
|
376
|
-
const renderer = new WebGLRenderer({ canvas, antialias: true, alpha: !options.background });
|
|
377
|
-
renderer.setPixelRatio(
|
|
378
|
-
Math.min(
|
|
379
|
-
typeof window === "undefined" ? 1 : window.devicePixelRatio || 1,
|
|
380
|
-
options.maxPixelRatio ?? 2
|
|
381
|
-
)
|
|
382
|
-
);
|
|
383
|
-
renderer.setSize(width, height, false);
|
|
384
|
-
const scene = new Scene();
|
|
385
|
-
if (options.background) {
|
|
386
|
-
scene.background = new Color(options.background);
|
|
387
|
-
}
|
|
388
|
-
const bounds = contentSphere(model);
|
|
389
|
-
const { cx, cy, cz, radius } = bounds;
|
|
390
|
-
const aspect = width / Math.max(1, height);
|
|
391
|
-
const placement = fitCamera(bounds, model.family, aspect);
|
|
392
|
-
const { dist } = placement;
|
|
393
|
-
const camera = new PerspectiveCamera(FOV, aspect, 0.1, dist * 8 + radius * 4);
|
|
394
|
-
camera.position.set(...placement.position);
|
|
395
|
-
camera.lookAt(...placement.target);
|
|
396
|
-
scene.add(new AmbientLight(16777215, 0.62));
|
|
397
|
-
const key = new DirectionalLight(16777215, 0.95);
|
|
398
|
-
key.position.set(cx + radius, cy + radius * 1.4, cz + dist);
|
|
399
|
-
scene.add(key);
|
|
400
|
-
const fill = new DirectionalLight(16777215, 0.3);
|
|
401
|
-
fill.position.set(cx - radius, cy - radius * 0.6, cz + dist * 0.6);
|
|
402
|
-
scene.add(fill);
|
|
403
|
-
const built = buildMeshGroup(model, options.textStyle);
|
|
404
|
-
scene.add(built.group);
|
|
405
|
-
let controls = null;
|
|
406
|
-
const enableControls = (on) => {
|
|
407
|
-
if (on && !controls) {
|
|
408
|
-
controls = new OrbitControls(camera, canvas);
|
|
409
|
-
controls.enablePan = false;
|
|
410
|
-
controls.target.set(cx, cy, cz);
|
|
411
|
-
controls.minDistance = dist * 0.4;
|
|
412
|
-
controls.maxDistance = dist * 3;
|
|
413
|
-
controls.update();
|
|
414
|
-
} else if (!on && controls) {
|
|
415
|
-
controls.dispose();
|
|
416
|
-
controls = null;
|
|
417
|
-
}
|
|
418
|
-
if (controls) {
|
|
419
|
-
controls.autoRotate = Boolean(options.autoRotate);
|
|
420
|
-
controls.autoRotateSpeed = 1.2;
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
enableControls(Boolean(options.interactive));
|
|
424
|
-
let frame = 0;
|
|
425
|
-
let disposed = false;
|
|
426
|
-
const renderLoop = () => {
|
|
427
|
-
if (disposed) {
|
|
428
|
-
return;
|
|
429
|
-
}
|
|
430
|
-
frame = requestAnimationFrame(renderLoop);
|
|
431
|
-
billboardLabels(built, camera);
|
|
432
|
-
controls?.update();
|
|
433
|
-
renderer.render(scene, camera);
|
|
434
|
-
};
|
|
435
|
-
frame = requestAnimationFrame(renderLoop);
|
|
436
|
-
return {
|
|
437
|
-
resize(w, h) {
|
|
438
|
-
camera.aspect = w / Math.max(1, h);
|
|
439
|
-
camera.updateProjectionMatrix();
|
|
440
|
-
renderer.setSize(w, h, false);
|
|
441
|
-
},
|
|
442
|
-
setInteractive(on) {
|
|
443
|
-
enableControls(on);
|
|
444
|
-
},
|
|
445
|
-
setTextStyle(style) {
|
|
446
|
-
built.setTextStyle(style);
|
|
447
|
-
},
|
|
448
|
-
dispose() {
|
|
449
|
-
disposed = true;
|
|
450
|
-
cancelAnimationFrame(frame);
|
|
451
|
-
controls?.dispose();
|
|
452
|
-
built.dispose();
|
|
453
|
-
renderer.dispose();
|
|
454
|
-
}
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
function SmartArt3DScene({
|
|
458
|
-
model,
|
|
459
|
-
width,
|
|
460
|
-
height,
|
|
461
|
-
interactive,
|
|
462
|
-
textStyle
|
|
463
|
-
}) {
|
|
464
|
-
const canvasRef = useRef(null);
|
|
465
|
-
const handleRef = useRef(null);
|
|
466
|
-
const textStyleRef = useLatestRef(textStyle);
|
|
467
|
-
useEffect(() => {
|
|
468
|
-
const canvas = canvasRef.current;
|
|
469
|
-
if (!canvas) {
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
const handle = mountSmartArt3D(canvas, model, width, height, {
|
|
473
|
-
interactive,
|
|
474
|
-
textStyle: textStyleRef.current
|
|
475
|
-
});
|
|
476
|
-
handleRef.current = handle;
|
|
477
|
-
return () => {
|
|
478
|
-
handle.dispose();
|
|
479
|
-
handleRef.current = null;
|
|
480
|
-
};
|
|
481
|
-
}, [model]);
|
|
482
|
-
useEffect(() => {
|
|
483
|
-
handleRef.current?.resize(width, height);
|
|
484
|
-
}, [width, height]);
|
|
485
|
-
useEffect(() => {
|
|
486
|
-
handleRef.current?.setInteractive(interactive);
|
|
487
|
-
}, [interactive]);
|
|
488
|
-
useEffect(() => {
|
|
489
|
-
handleRef.current?.setTextStyle(textStyle);
|
|
490
|
-
}, [textStyle]);
|
|
491
|
-
return /* @__PURE__ */ jsx(
|
|
492
|
-
"canvas",
|
|
493
|
-
{
|
|
494
|
-
ref: canvasRef,
|
|
495
|
-
style: { width, height, display: "block", pointerEvents: interactive ? "auto" : "none" }
|
|
496
|
-
}
|
|
497
|
-
);
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
export { SmartArt3DScene as default };
|
|
Binary file
|
|
Binary file
|