visualifyjs 2.5.3-2.dev → 3.0.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/.claude/mem/TIMELINE.md +36 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-external-script-solution.md +24 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-session-summary.md +43 -0
- package/.claude/mem/notes/2026-02-11-cli-fix-editor-command-alias.md +26 -0
- package/.claude/mem/notes/2026-02-11-phase-3-developer-experience-completed.md +51 -0
- package/.claude/mem/notes/2026-02-11-phase-4-web-workers-implementation-complete.md +59 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-3d-visualization-complete.md +50 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-committed-ready-for-phase-3.md +33 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-3-complete-developer-experience.md +52 -0
- package/.claude/mem/notes/2026-02-11-visualify-repository-cleanup-complete.md +28 -0
- package/.claude/mem/notes/2026-02-18-codebase-cleanup-docsify-plugin-documentation.md +37 -0
- package/.claude/mem/notes/2026-02-19-css-grid-layout-fix-displaycontents-on-vcontroller.md +18 -0
- package/.claude/mem/notes/2026-02-19-docsify-plugin-fixes-latex-and-visualify-code-bloc.md +26 -0
- package/.claude/mem/notes/2026-02-19-page-mode-docs-update-decisions.md +23 -0
- package/.claude/mem/notes/2026-02-19-react-context-infinite-re-render-loop-fix-pattern.md +31 -0
- package/.claude/mem/notes/2026-02-19-version-300-bump-and-build-fixes.md +32 -0
- package/.claude/mem/notes/2026-02-19-visualify-build-deployment-architecture-bug-fixes.md +25 -0
- package/.claude/mem/notes/2026-02-19-visualify-dist-iife-self-contained-build-config.md +30 -0
- package/.claude/mem/notes/2026-02-19-visualify-infinite-loop-i18n-fixes.md +31 -0
- package/.claude/mem/notes/2026-02-19-visualify-v3-bundle-splitting-docs-restructuring.md +32 -0
- package/.claude/mem/notes/2026-02-20-bundle-externalization-final-architecture.md +29 -0
- package/.claude/mem/notes/2026-02-20-chromium-page-fix-unstable-keys-and-double-event-b.md +27 -0
- package/.claude/mem/notes/2026-02-20-console-cleanup-bundle-optimization-commit.md +20 -0
- package/.claude/mem/notes/2026-02-20-dotbio-dot-plot-fix-useeffect-dependency.md +21 -0
- package/.claude/mem/notes/2026-02-20-public-folder-cleanup-and-readme-rewrite.md +25 -0
- package/.claude/mem/notes/2026-02-20-v300-release-and-beta-channel-strategy.md +29 -0
- package/.claude/mem/notes/2026-02-20-visium-background-image-unknown-legend-fix.md +19 -0
- package/.claude/mem/notes/2026-02-20-visualify-cdn-loader-bundle-externalization.md +34 -0
- package/.claude/mem/sessions/session-2026-02-20-031524.md +54 -0
- package/.claude/settings.local.json +21 -0
- package/.github/workflows/static.yml.bak +51 -51
- package/.sisyphus/boulder.json +65 -0
- package/.sisyphus/plans/phase-4-advanced-optimizations.md +217 -0
- package/LICENSE +674 -674
- package/README.md +94 -59
- package/config-overrides.js +31 -31
- package/dist/stats.html +4949 -0
- package/dist/visualify-3d.esm.js +1 -0
- package/dist/visualify-3d.js +1 -0
- package/dist/visualify-core.esm.js +1 -0
- package/dist/visualify-core.js +1 -0
- package/dist/visualify-docs.esm.js +1 -0
- package/dist/visualify-docs.js +1 -0
- package/dist/visualify-loader.js +1 -0
- package/dist/visualify-pages.esm.js +1 -0
- package/dist/visualify-pages.js +1 -0
- package/dist/visualify-portal.esm.js +1 -0
- package/dist/visualify-portal.js +1 -0
- package/dist/visualify-shared.js +26571 -0
- package/dist/visualify.js +1 -188
- package/docs/CHANGELOG.md +148 -0
- package/docs/cli/commands.md +513 -0
- package/docs/configuration/visualify-json.md +474 -0
- package/docs/docs/3d-visualization.md +374 -0
- package/docs/docs/CLI.md +303 -34
- package/docs/docs/README.md +65 -65
- package/docs/docs/Rechart/bar.md +190 -190
- package/docs/docs/Rechart/funnel.md +241 -241
- package/docs/docs/Rechart/line.md +355 -355
- package/docs/docs/Rechart/pie.md +225 -225
- package/docs/docs/Rechart/radar.md +253 -253
- package/docs/docs/Rechart/scatter.md +298 -298
- package/docs/docs/_404.md +51 -51
- package/docs/docs/_coverpage.md +11 -11
- package/docs/docs/_sidebar.md +54 -44
- package/docs/docs/components/dotBio.md +87 -34
- package/docs/docs/components/echart.md +171 -82
- package/docs/docs/components/html.md +61 -34
- package/docs/docs/components/macaron.md +156 -145
- package/docs/docs/components/markdown.md +42 -0
- package/docs/docs/components/more.md +183 -142
- package/docs/docs/components/plotly.md +132 -62
- package/docs/docs/components/scatterL.md +171 -70
- package/docs/docs/components/visium.md +112 -57
- package/docs/docs/configuration.md +121 -121
- package/docs/docs/deploy.md +31 -31
- package/docs/docs/docsify-plugin.md +655 -0
- package/docs/docs/hmr.md +165 -0
- package/docs/docs/i18n.md +332 -0
- package/docs/docs/log.md +30 -9
- package/docs/docs/more-pages.md +23 -23
- package/docs/docs/quickstart.md +148 -124
- package/docs/docs/rechart-attributes.md +74 -74
- package/docs/docs/rechart-basic-usage.md +160 -162
- package/docs/docs/theme.md +5 -5
- package/docs/docs/typescript.md +306 -0
- package/docs/docs/visual-editor.md +359 -0
- package/docs/index.html +85 -71
- package/docs/manifest.json +23 -23
- package/docs/migration/v3-migration.md +392 -0
- package/docs/static/css/fluff-stuff.css +169 -169
- package/docs/static/css/font-awesome.min.css +4 -4
- package/docs/static/css/visualify.css +6 -25
- package/docs/static/js/3d-viz-examples.js +181 -0
- package/docs/static/js/configuration.js +630 -448
- package/docs/static/js/visualify.js +1 -188
- package/package.json +106 -84
- package/rollup.config.mjs +766 -76
- package/src/_css/404.css +115 -115
- package/src/_css/App.css +37 -37
- package/src/_css/autoSuggestion.css +26 -26
- package/src/_css/circular-progress.css +32 -32
- package/src/_css/index.css +36 -36
- package/src/_css/modern.css +350 -25
- package/src/_media/corner.svg +8 -8
- package/src/_media/download.svg +3 -3
- package/src/_media/logo.svg +14 -14
- package/src/_test/App.test.js +15 -15
- package/src/_utils/reportWebVitals.js +13 -13
- package/src/a11y/README.md +177 -0
- package/src/a11y/aria-labels.js +339 -0
- package/src/a11y/color-contrast.js +535 -0
- package/src/a11y/index.js +197 -0
- package/src/a11y/keyboard-nav.js +523 -0
- package/src/a11y/styles.css +165 -0
- package/src/cli/commands/dev.js +214 -0
- package/src/cli/commands/docs.js +521 -0
- package/src/cli/commands/edit.js +379 -0
- package/src/cli/commands/init.js +213 -0
- package/src/cli/commands/portal.js +236 -0
- package/src/cli/dev-server.js +530 -0
- package/src/cli/hmr.js +456 -0
- package/src/cli/index.js +180 -0
- package/src/cli/utils/config.js +207 -0
- package/src/cli/utils/logger.js +241 -0
- package/src/config/defaults.ts +122 -0
- package/src/config/index.ts +72 -0
- package/src/config/loader.ts +478 -0
- package/src/config/schema.ts +227 -0
- package/src/config/validator.ts +337 -0
- package/src/core/appContext.js +34 -27
- package/src/core/components/Bar.js +383 -0
- package/src/core/components/Bar3D.js +473 -0
- package/src/core/components/LargeDatasetChart.js +296 -0
- package/src/core/components/Line3D.js +310 -0
- package/src/core/components/Scatter.js +392 -188
- package/src/core/components/Scatter3D.js +455 -0
- package/src/core/components/ScatterBio.js +601 -572
- package/src/core/components/Surface3D.js +326 -0
- package/src/core/components/ThreeCustom.js +648 -0
- package/src/core/components/ThreeScene.js +459 -0
- package/src/core/components/VisiumPlot.js +191 -165
- package/src/core/components/browser.js +42 -42
- package/src/core/components/dotplot.js +413 -413
- package/src/core/components/html.js +29 -29
- package/src/core/components/list.js +178 -178
- package/src/core/components/macaron.js +206 -201
- package/src/core/components/markdown.js +56 -56
- package/src/core/components/parser.scatterBio.js +582 -587
- package/src/core/components/ratio.js +82 -80
- package/src/core/components/scatterL.js +206 -173
- package/src/core/components/searchbar.js +156 -131
- package/src/core/components/selection.js +310 -193
- package/src/core/components/timeline.js +236 -281
- package/src/core/components/visium.js +114 -97
- package/src/core/data-processor.js +413 -0
- package/src/core/fetch/condfetch.js +82 -82
- package/src/core/fetch/fetch.js +92 -92
- package/src/core/fetch/json.js +29 -29
- package/src/core/fetch/vfetch.js +42 -42
- package/src/core/hmr-client.js +724 -0
- package/src/core/liveEditor.js +44 -44
- package/src/core/modules/codeEditorWithPreview.js +104 -104
- package/src/core/modules/echarts/common.js +20 -20
- package/src/core/modules/echarts/gl.js +228 -0
- package/src/core/modules/echarts/presetHandler.js +41 -41
- package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
- package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
- package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
- package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
- package/src/core/modules/echarts.js +70 -71
- package/src/core/modules/echartsUtils.js +43 -43
- package/src/core/modules/echartswitcher.js +227 -152
- package/src/core/modules/replotly/presetHandler.js +24 -24
- package/src/core/modules/replotly/presets/minimum.js +18 -18
- package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
- package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
- package/src/core/modules/replotly.js +74 -71
- package/src/core/modules/threejs/Camera.js +373 -0
- package/src/core/modules/threejs/Lighting.js +459 -0
- package/src/core/modules/threejs/Renderer.js +364 -0
- package/src/core/modules/threejs/Scene.js +266 -0
- package/src/core/modules/threejs/index.js +155 -0
- package/src/core/pages/404.js +50 -50
- package/src/core/pages/error.js +27 -27
- package/src/core/pages/jsonPage.js +62 -62
- package/src/core/pages/loading.js +44 -44
- package/src/core/parser/echart.data.js +204 -183
- package/src/core/parser/echart.features.js +125 -125
- package/src/core/parser/echart.general.js +147 -147
- package/src/core/parser/echart.hilbert.js +57 -57
- package/src/core/parser/echart.parser.js +210 -210
- package/src/core/parser/echart.series.js +67 -67
- package/src/core/parser/echart.types.js +76 -76
- package/src/core/parser/plotly.config.js +10 -10
- package/src/core/parser/plotly.data.js +132 -132
- package/src/core/parser/plotly.layout.js +9 -9
- package/src/core/parser/plotly.violin.js +18 -18
- package/src/core/recharts.js +361 -62
- package/src/core/router/alias.js +49 -49
- package/src/core/router/jsonRouter.js +31 -31
- package/src/core/themes/modern.js +32 -32
- package/src/core/themes/themeSelector.js +33 -33
- package/src/core/visualify.js +213 -47
- package/src/core/widgets/circularProgress.js +23 -23
- package/src/core/widgets/controller.js +116 -83
- package/src/core/widgets/errorBoundary.js +36 -36
- package/src/core/widgets/footer.js +185 -177
- package/src/core/widgets/header.js +238 -234
- package/src/core/widgets/layout/Grid.js +31 -31
- package/src/core/widgets/layout.js +36 -36
- package/src/core/widgets/mapping.js +56 -42
- package/src/core/workers/data-worker.js +349 -0
- package/src/core/workers/worker-pool.js +396 -0
- package/src/docsify/bundle.js +215 -0
- package/src/docsify/markdown.js +271 -0
- package/src/docsify/plugin.js +268 -0
- package/src/editor/README.md +172 -0
- package/src/editor/components/ChartBuilder.jsx +341 -0
- package/src/editor/components/ChartTypeSidebar.jsx +91 -0
- package/src/editor/components/Editor.jsx +367 -0
- package/src/editor/components/Preview.jsx +446 -0
- package/src/editor/components/PropertyPanel.jsx +468 -0
- package/src/editor/components/StatusBar.jsx +85 -0
- package/src/editor/context/EditorContext.js +248 -0
- package/src/editor/hooks/useDebounce.js +32 -0
- package/src/editor/index.js +315 -0
- package/src/editor/styles/editor.css +637 -0
- package/src/editor/utils/chartValidator.js +263 -0
- package/src/entries/charts3d.js +70 -0
- package/src/entries/core.js +78 -0
- package/src/entries/docs.js +154 -0
- package/src/entries/pages.js +93 -0
- package/src/entries/portal.js +204 -0
- package/src/entries/shared.js +50 -0
- package/src/i18n/formatters.js +455 -0
- package/src/i18n/index.js +169 -0
- package/src/i18n/locales/ar.json +137 -0
- package/src/i18n/locales/de.json +137 -0
- package/src/i18n/locales/en.json +137 -0
- package/src/i18n/locales/es.json +137 -0
- package/src/i18n/locales/he.json +137 -0
- package/src/i18n/locales/zh.json +137 -0
- package/src/i18n/rtl.css +183 -0
- package/src/index.js +82 -62
- package/src/loader.js +103 -0
- package/src/setupTests.js +5 -5
- package/tsconfig.json +51 -0
- package/types/charts.d.ts +569 -0
- package/types/components.d.ts +441 -0
- package/types/config.d.ts +199 -0
- package/types/index.d.ts +353 -0
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renderer.js - Three.js WebGL Renderer for Visualify.js
|
|
3
|
+
* Handles renderer setup, antialiasing, resize handling, and pixel ratio support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as THREE from 'three';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* RendererManager class for managing WebGL renderers
|
|
10
|
+
*/
|
|
11
|
+
export class RendererManager {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.renderers = new Map();
|
|
14
|
+
this.activeRendererId = null;
|
|
15
|
+
|
|
16
|
+
this.defaultOptions = {
|
|
17
|
+
antialias: true,
|
|
18
|
+
alpha: true,
|
|
19
|
+
powerPreference: 'high-performance',
|
|
20
|
+
precision: 'highp',
|
|
21
|
+
stencil: false,
|
|
22
|
+
depth: true,
|
|
23
|
+
logarithmicDepthBuffer: false,
|
|
24
|
+
...options,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a new WebGL renderer
|
|
30
|
+
* @param {string} id - Renderer identifier
|
|
31
|
+
* @param {HTMLCanvasElement} canvas - Canvas element
|
|
32
|
+
* @param {Object} options - Renderer options
|
|
33
|
+
* @returns {THREE.WebGLRenderer}
|
|
34
|
+
*/
|
|
35
|
+
createRenderer(id, canvas, options = {}) {
|
|
36
|
+
if (this.renderers.has(id)) {
|
|
37
|
+
console.warn(`Renderer with id "${id}" already exists. Returning existing renderer.`);
|
|
38
|
+
return this.renderers.get(id).renderer;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const config = { ...this.defaultOptions, ...options };
|
|
42
|
+
|
|
43
|
+
// Create renderer
|
|
44
|
+
const renderer = new THREE.WebGLRenderer({
|
|
45
|
+
canvas,
|
|
46
|
+
antialias: config.antialias,
|
|
47
|
+
alpha: config.alpha,
|
|
48
|
+
powerPreference: config.powerPreference,
|
|
49
|
+
stencil: config.stencil,
|
|
50
|
+
depth: config.depth,
|
|
51
|
+
logarithmicDepthBuffer: config.logarithmicDepthBuffer,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Configure renderer
|
|
55
|
+
this.configureRenderer(renderer, config);
|
|
56
|
+
|
|
57
|
+
// Store renderer
|
|
58
|
+
this.renderers.set(id, {
|
|
59
|
+
renderer,
|
|
60
|
+
config,
|
|
61
|
+
canvas,
|
|
62
|
+
resizeObserver: null,
|
|
63
|
+
createdAt: Date.now(),
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Set as active if it's the first renderer
|
|
67
|
+
if (!this.activeRendererId) {
|
|
68
|
+
this.activeRendererId = id;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return renderer;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Configure renderer settings
|
|
76
|
+
* @param {THREE.WebGLRenderer} renderer
|
|
77
|
+
* @param {Object} config
|
|
78
|
+
*/
|
|
79
|
+
configureRenderer(renderer, config) {
|
|
80
|
+
// Set pixel ratio (capped at 2 for performance)
|
|
81
|
+
const pixelRatio = Math.min(window.devicePixelRatio, 2);
|
|
82
|
+
renderer.setPixelRatio(pixelRatio);
|
|
83
|
+
|
|
84
|
+
// Set size
|
|
85
|
+
if (config.width && config.height) {
|
|
86
|
+
renderer.setSize(config.width, config.height);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Set precision
|
|
90
|
+
if (config.precision) {
|
|
91
|
+
renderer.capabilities.precision = config.precision;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Configure shadow map
|
|
95
|
+
if (config.shadowMap !== false) {
|
|
96
|
+
renderer.shadowMap.enabled = true;
|
|
97
|
+
renderer.shadowMap.type = config.shadowMapType || THREE.PCFSoftShadowMap;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Set output color space
|
|
101
|
+
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
|
102
|
+
|
|
103
|
+
// Set tone mapping
|
|
104
|
+
if (config.toneMapping) {
|
|
105
|
+
renderer.toneMapping = config.toneMapping;
|
|
106
|
+
if (config.toneMappingExposure) {
|
|
107
|
+
renderer.toneMappingExposure = config.toneMappingExposure;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Set clear color
|
|
112
|
+
if (config.clearColor !== undefined) {
|
|
113
|
+
renderer.setClearColor(config.clearColor, config.clearAlpha ?? 1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Get a renderer by ID
|
|
119
|
+
* @param {string} id - Renderer identifier
|
|
120
|
+
* @returns {THREE.WebGLRenderer|null}
|
|
121
|
+
*/
|
|
122
|
+
getRenderer(id) {
|
|
123
|
+
const rendererData = this.renderers.get(id);
|
|
124
|
+
return rendererData ? rendererData.renderer : null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Get the currently active renderer
|
|
129
|
+
* @returns {THREE.WebGLRenderer|null}
|
|
130
|
+
*/
|
|
131
|
+
getActiveRenderer() {
|
|
132
|
+
return this.activeRendererId ? this.getRenderer(this.activeRendererId) : null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Set the active renderer
|
|
137
|
+
* @param {string} id - Renderer identifier
|
|
138
|
+
*/
|
|
139
|
+
setActiveRenderer(id) {
|
|
140
|
+
if (!this.renderers.has(id)) {
|
|
141
|
+
throw new Error(`Renderer with id "${id}" does not exist`);
|
|
142
|
+
}
|
|
143
|
+
this.activeRendererId = id;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Update renderer size
|
|
148
|
+
* @param {string} id - Renderer identifier
|
|
149
|
+
* @param {number} width
|
|
150
|
+
* @param {number} height
|
|
151
|
+
*/
|
|
152
|
+
updateSize(id, width, height) {
|
|
153
|
+
const rendererData = this.renderers.get(id);
|
|
154
|
+
if (!rendererData) return;
|
|
155
|
+
|
|
156
|
+
const renderer = rendererData.renderer;
|
|
157
|
+
renderer.setSize(width, height);
|
|
158
|
+
|
|
159
|
+
// Update config
|
|
160
|
+
rendererData.config.width = width;
|
|
161
|
+
rendererData.config.height = height;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Update pixel ratio
|
|
166
|
+
* @param {string} id - Renderer identifier
|
|
167
|
+
* @param {number} pixelRatio
|
|
168
|
+
*/
|
|
169
|
+
updatePixelRatio(id, pixelRatio) {
|
|
170
|
+
const rendererData = this.renderers.get(id);
|
|
171
|
+
if (!rendererData) return;
|
|
172
|
+
|
|
173
|
+
const renderer = rendererData.renderer;
|
|
174
|
+
renderer.setPixelRatio(Math.min(pixelRatio, 2));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Enable automatic resize handling
|
|
179
|
+
* @param {string} id - Renderer identifier
|
|
180
|
+
* @param {HTMLElement} container - Container element
|
|
181
|
+
*/
|
|
182
|
+
enableAutoResize(id, container) {
|
|
183
|
+
const rendererData = this.renderers.get(id);
|
|
184
|
+
if (!rendererData) return;
|
|
185
|
+
|
|
186
|
+
// Clean up existing observer
|
|
187
|
+
if (rendererData.resizeObserver) {
|
|
188
|
+
rendererData.resizeObserver.disconnect();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Create resize observer
|
|
192
|
+
const resizeObserver = new ResizeObserver((entries) => {
|
|
193
|
+
for (const entry of entries) {
|
|
194
|
+
const { width, height } = entry.contentRect;
|
|
195
|
+
this.updateSize(id, width, height);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
resizeObserver.observe(container);
|
|
200
|
+
rendererData.resizeObserver = resizeObserver;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Disable automatic resize handling
|
|
205
|
+
* @param {string} id - Renderer identifier
|
|
206
|
+
*/
|
|
207
|
+
disableAutoResize(id) {
|
|
208
|
+
const rendererData = this.renderers.get(id);
|
|
209
|
+
if (!rendererData || !rendererData.resizeObserver) return;
|
|
210
|
+
|
|
211
|
+
rendererData.resizeObserver.disconnect();
|
|
212
|
+
rendererData.resizeObserver = null;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Render a scene with a camera
|
|
217
|
+
* @param {string} id - Renderer identifier
|
|
218
|
+
* @param {THREE.Scene} scene
|
|
219
|
+
* @param {THREE.Camera} camera
|
|
220
|
+
*/
|
|
221
|
+
render(id, scene, camera) {
|
|
222
|
+
const renderer = this.getRenderer(id);
|
|
223
|
+
if (!renderer) return;
|
|
224
|
+
|
|
225
|
+
renderer.render(scene, camera);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Take a screenshot
|
|
230
|
+
* @param {string} id - Renderer identifier
|
|
231
|
+
* @param {string} mimeType - Image mime type
|
|
232
|
+
* @param {number} quality - Image quality (0-1)
|
|
233
|
+
* @returns {string} Data URL
|
|
234
|
+
*/
|
|
235
|
+
takeScreenshot(id, mimeType = 'image/png', quality = 1) {
|
|
236
|
+
const renderer = this.getRenderer(id);
|
|
237
|
+
if (!renderer) return null;
|
|
238
|
+
|
|
239
|
+
return renderer.domElement.toDataURL(mimeType, quality);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get WebGL info
|
|
244
|
+
* @param {string} id - Renderer identifier
|
|
245
|
+
* @returns {Object|null}
|
|
246
|
+
*/
|
|
247
|
+
getWebGLInfo(id) {
|
|
248
|
+
const renderer = this.getRenderer(id);
|
|
249
|
+
if (!renderer) return null;
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
renderer: renderer.info.render,
|
|
253
|
+
memory: renderer.info.memory,
|
|
254
|
+
programs: renderer.info.programs?.length || 0,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Reset WebGL info counters
|
|
260
|
+
* @param {string} id - Renderer identifier
|
|
261
|
+
*/
|
|
262
|
+
resetInfo(id) {
|
|
263
|
+
const renderer = this.getRenderer(id);
|
|
264
|
+
if (!renderer) return;
|
|
265
|
+
|
|
266
|
+
renderer.info.reset();
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Compile shaders for a scene
|
|
271
|
+
* @param {string} id - Renderer identifier
|
|
272
|
+
* @param {THREE.Scene} scene
|
|
273
|
+
* @param {THREE.Camera} camera
|
|
274
|
+
*/
|
|
275
|
+
compile(id, scene, camera) {
|
|
276
|
+
const renderer = this.getRenderer(id);
|
|
277
|
+
if (!renderer) return;
|
|
278
|
+
|
|
279
|
+
renderer.compile(scene, camera);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Dispose of a renderer
|
|
284
|
+
* @param {string} id - Renderer identifier
|
|
285
|
+
*/
|
|
286
|
+
removeRenderer(id) {
|
|
287
|
+
const rendererData = this.renderers.get(id);
|
|
288
|
+
if (!rendererData) return;
|
|
289
|
+
|
|
290
|
+
// Disable auto resize
|
|
291
|
+
this.disableAutoResize(id);
|
|
292
|
+
|
|
293
|
+
// Dispose renderer
|
|
294
|
+
rendererData.renderer.dispose();
|
|
295
|
+
|
|
296
|
+
// Remove from map
|
|
297
|
+
this.renderers.delete(id);
|
|
298
|
+
|
|
299
|
+
// Update active renderer if needed
|
|
300
|
+
if (this.activeRendererId === id) {
|
|
301
|
+
const remainingRenderers = Array.from(this.renderers.keys());
|
|
302
|
+
this.activeRendererId = remainingRenderers.length > 0 ? remainingRenderers[0] : null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Get all renderer IDs
|
|
308
|
+
* @returns {string[]}
|
|
309
|
+
*/
|
|
310
|
+
getRendererIds() {
|
|
311
|
+
return Array.from(this.renderers.keys());
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Dispose all renderers
|
|
316
|
+
*/
|
|
317
|
+
dispose() {
|
|
318
|
+
this.getRendererIds().forEach((id) => this.removeRenderer(id));
|
|
319
|
+
this.activeRendererId = null;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Create a renderer from configuration
|
|
325
|
+
* @param {HTMLCanvasElement} canvas
|
|
326
|
+
* @param {Object} config
|
|
327
|
+
* @returns {THREE.WebGLRenderer}
|
|
328
|
+
*/
|
|
329
|
+
export function createRendererFromConfig(canvas, config = {}) {
|
|
330
|
+
const manager = new RendererManager(config);
|
|
331
|
+
return manager.createRenderer('default', canvas, config);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Handle window resize for a renderer
|
|
336
|
+
* @param {THREE.WebGLRenderer} renderer
|
|
337
|
+
* @param {THREE.Camera} camera
|
|
338
|
+
* @param {HTMLElement} container
|
|
339
|
+
*/
|
|
340
|
+
export function handleResize(renderer, camera, container) {
|
|
341
|
+
const width = container.clientWidth;
|
|
342
|
+
const height = container.clientHeight;
|
|
343
|
+
|
|
344
|
+
renderer.setSize(width, height);
|
|
345
|
+
|
|
346
|
+
if (camera.isPerspectiveCamera) {
|
|
347
|
+
camera.aspect = width / height;
|
|
348
|
+
camera.updateProjectionMatrix();
|
|
349
|
+
} else if (camera.isOrthographicCamera) {
|
|
350
|
+
const aspect = width / height;
|
|
351
|
+
const frustumSize = Math.max(
|
|
352
|
+
camera.right - camera.left,
|
|
353
|
+
camera.top - camera.bottom
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
camera.left = -frustumSize * aspect / 2;
|
|
357
|
+
camera.right = frustumSize * aspect / 2;
|
|
358
|
+
camera.top = frustumSize / 2;
|
|
359
|
+
camera.bottom = -frustumSize / 2;
|
|
360
|
+
camera.updateProjectionMatrix();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
export default RendererManager;
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scene.js - Three.js Scene Manager for Visualify.js
|
|
3
|
+
* Handles scene creation, scene graph operations, and multiple viewport support
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as THREE from 'three';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* SceneManager class for managing Three.js scenes
|
|
10
|
+
*/
|
|
11
|
+
export class SceneManager {
|
|
12
|
+
constructor(options = {}) {
|
|
13
|
+
this.scenes = new Map();
|
|
14
|
+
this.activeSceneId = null;
|
|
15
|
+
this.defaultOptions = {
|
|
16
|
+
backgroundColor: 0x000000,
|
|
17
|
+
fog: null,
|
|
18
|
+
...options,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a new scene
|
|
24
|
+
* @param {string} id - Unique scene identifier
|
|
25
|
+
* @param {Object} options - Scene configuration options
|
|
26
|
+
* @returns {THREE.Scene} The created scene
|
|
27
|
+
*/
|
|
28
|
+
createScene(id, options = {}) {
|
|
29
|
+
if (this.scenes.has(id)) {
|
|
30
|
+
console.warn(`Scene with id "${id}" already exists. Returning existing scene.`);
|
|
31
|
+
return this.scenes.get(id).scene;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const scene = new THREE.Scene();
|
|
35
|
+
const config = { ...this.defaultOptions, ...options };
|
|
36
|
+
|
|
37
|
+
// Set background
|
|
38
|
+
if (config.backgroundColor !== undefined) {
|
|
39
|
+
scene.background = new THREE.Color(config.backgroundColor);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Set fog if provided
|
|
43
|
+
if (config.fog) {
|
|
44
|
+
scene.fog = new THREE.Fog(
|
|
45
|
+
config.fog.color || 0x000000,
|
|
46
|
+
config.fog.near || 1,
|
|
47
|
+
config.fog.far || 1000
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Store scene with metadata
|
|
52
|
+
this.scenes.set(id, {
|
|
53
|
+
scene,
|
|
54
|
+
config,
|
|
55
|
+
objects: new Map(),
|
|
56
|
+
createdAt: Date.now(),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Set as active if it's the first scene
|
|
60
|
+
if (!this.activeSceneId) {
|
|
61
|
+
this.activeSceneId = id;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return scene;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get a scene by ID
|
|
69
|
+
* @param {string} id - Scene identifier
|
|
70
|
+
* @returns {THREE.Scene|null}
|
|
71
|
+
*/
|
|
72
|
+
getScene(id) {
|
|
73
|
+
const sceneData = this.scenes.get(id);
|
|
74
|
+
return sceneData ? sceneData.scene : null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get the currently active scene
|
|
79
|
+
* @returns {THREE.Scene|null}
|
|
80
|
+
*/
|
|
81
|
+
getActiveScene() {
|
|
82
|
+
return this.activeSceneId ? this.getScene(this.activeSceneId) : null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Set the active scene
|
|
87
|
+
* @param {string} id - Scene identifier
|
|
88
|
+
*/
|
|
89
|
+
setActiveScene(id) {
|
|
90
|
+
if (!this.scenes.has(id)) {
|
|
91
|
+
throw new Error(`Scene with id "${id}" does not exist`);
|
|
92
|
+
}
|
|
93
|
+
this.activeSceneId = id;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Add an object to a scene
|
|
98
|
+
* @param {string} sceneId - Scene identifier
|
|
99
|
+
* @param {string} objectId - Object identifier
|
|
100
|
+
* @param {THREE.Object3D} object - Three.js object
|
|
101
|
+
*/
|
|
102
|
+
addObject(sceneId, objectId, object) {
|
|
103
|
+
const sceneData = this.scenes.get(sceneId);
|
|
104
|
+
if (!sceneData) {
|
|
105
|
+
throw new Error(`Scene with id "${sceneId}" does not exist`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
sceneData.scene.add(object);
|
|
109
|
+
sceneData.objects.set(objectId, object);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Remove an object from a scene
|
|
114
|
+
* @param {string} sceneId - Scene identifier
|
|
115
|
+
* @param {string} objectId - Object identifier
|
|
116
|
+
*/
|
|
117
|
+
removeObject(sceneId, objectId) {
|
|
118
|
+
const sceneData = this.scenes.get(sceneId);
|
|
119
|
+
if (!sceneData) return;
|
|
120
|
+
|
|
121
|
+
const object = sceneData.objects.get(objectId);
|
|
122
|
+
if (object) {
|
|
123
|
+
sceneData.scene.remove(object);
|
|
124
|
+
this.disposeObject(object);
|
|
125
|
+
sceneData.objects.delete(objectId);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Get an object from a scene
|
|
131
|
+
* @param {string} sceneId - Scene identifier
|
|
132
|
+
* @param {string} objectId - Object identifier
|
|
133
|
+
* @returns {THREE.Object3D|null}
|
|
134
|
+
*/
|
|
135
|
+
getObject(sceneId, objectId) {
|
|
136
|
+
const sceneData = this.scenes.get(sceneId);
|
|
137
|
+
return sceneData ? sceneData.objects.get(objectId) || null : null;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Clear all objects from a scene
|
|
142
|
+
* @param {string} sceneId - Scene identifier
|
|
143
|
+
*/
|
|
144
|
+
clearScene(sceneId) {
|
|
145
|
+
const sceneData = this.scenes.get(sceneId);
|
|
146
|
+
if (!sceneData) return;
|
|
147
|
+
|
|
148
|
+
// Remove and dispose all objects
|
|
149
|
+
sceneData.objects.forEach((object, objectId) => {
|
|
150
|
+
sceneData.scene.remove(object);
|
|
151
|
+
this.disposeObject(object);
|
|
152
|
+
});
|
|
153
|
+
sceneData.objects.clear();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Remove a scene and dispose all resources
|
|
158
|
+
* @param {string} id - Scene identifier
|
|
159
|
+
*/
|
|
160
|
+
removeScene(id) {
|
|
161
|
+
const sceneData = this.scenes.get(id);
|
|
162
|
+
if (!sceneData) return;
|
|
163
|
+
|
|
164
|
+
// Clear all objects
|
|
165
|
+
this.clearScene(id);
|
|
166
|
+
|
|
167
|
+
// Dispose scene
|
|
168
|
+
if (sceneData.scene.background) {
|
|
169
|
+
if (sceneData.scene.background.dispose) {
|
|
170
|
+
sceneData.scene.background.dispose();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
this.scenes.delete(id);
|
|
175
|
+
|
|
176
|
+
// Update active scene if needed
|
|
177
|
+
if (this.activeSceneId === id) {
|
|
178
|
+
const remainingScenes = Array.from(this.scenes.keys());
|
|
179
|
+
this.activeSceneId = remainingScenes.length > 0 ? remainingScenes[0] : null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Dispose a Three.js object and its resources
|
|
185
|
+
* @param {THREE.Object3D} object
|
|
186
|
+
*/
|
|
187
|
+
disposeObject(object) {
|
|
188
|
+
if (!object) return;
|
|
189
|
+
|
|
190
|
+
// Traverse and dispose geometries and materials
|
|
191
|
+
object.traverse((child) => {
|
|
192
|
+
if (child.geometry) {
|
|
193
|
+
child.geometry.dispose();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (child.material) {
|
|
197
|
+
if (Array.isArray(child.material)) {
|
|
198
|
+
child.material.forEach((material) => this.disposeMaterial(material));
|
|
199
|
+
} else {
|
|
200
|
+
this.disposeMaterial(child.material);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Dispose material and its textures
|
|
208
|
+
* @param {THREE.Material} material
|
|
209
|
+
*/
|
|
210
|
+
disposeMaterial(material) {
|
|
211
|
+
if (!material) return;
|
|
212
|
+
|
|
213
|
+
// Dispose textures
|
|
214
|
+
Object.keys(material).forEach((key) => {
|
|
215
|
+
const value = material[key];
|
|
216
|
+
if (value && value.isTexture) {
|
|
217
|
+
value.dispose();
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
material.dispose();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Get all scene IDs
|
|
226
|
+
* @returns {string[]}
|
|
227
|
+
*/
|
|
228
|
+
getSceneIds() {
|
|
229
|
+
return Array.from(this.scenes.keys());
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Dispose all scenes and resources
|
|
234
|
+
*/
|
|
235
|
+
dispose() {
|
|
236
|
+
this.getSceneIds().forEach((id) => this.removeScene(id));
|
|
237
|
+
this.activeSceneId = null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Create a scene from configuration
|
|
243
|
+
* @param {Object} config - Scene configuration
|
|
244
|
+
* @returns {THREE.Scene}
|
|
245
|
+
*/
|
|
246
|
+
export function createSceneFromConfig(config = {}) {
|
|
247
|
+
const scene = new THREE.Scene();
|
|
248
|
+
|
|
249
|
+
// Set background color
|
|
250
|
+
if (config.backgroundColor) {
|
|
251
|
+
scene.background = new THREE.Color(config.backgroundColor);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Set fog
|
|
255
|
+
if (config.fog) {
|
|
256
|
+
scene.fog = new THREE.Fog(
|
|
257
|
+
config.fog.color || 0x000000,
|
|
258
|
+
config.fog.near || 1,
|
|
259
|
+
config.fog.far || 1000
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return scene;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export default SceneManager;
|