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,373 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Camera.js - Three.js Camera Manager for Visualify.js
|
|
3
|
+
* Handles perspective and orthographic cameras with animation helpers
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as THREE from 'three';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Camera types
|
|
10
|
+
*/
|
|
11
|
+
export const CameraType = {
|
|
12
|
+
PERSPECTIVE: 'perspective',
|
|
13
|
+
ORTHOGRAPHIC: 'orthographic',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* CameraManager class for managing cameras
|
|
18
|
+
*/
|
|
19
|
+
export class CameraManager {
|
|
20
|
+
constructor(options = {}) {
|
|
21
|
+
this.cameras = new Map();
|
|
22
|
+
this.activeCameraId = null;
|
|
23
|
+
this.defaultOptions = {
|
|
24
|
+
type: CameraType.PERSPECTIVE,
|
|
25
|
+
position: [0, 0, 100],
|
|
26
|
+
target: [0, 0, 0],
|
|
27
|
+
up: [0, 1, 0],
|
|
28
|
+
...options,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Create a perspective camera
|
|
34
|
+
* @param {string} id - Camera identifier
|
|
35
|
+
* @param {Object} options - Camera options
|
|
36
|
+
* @returns {THREE.PerspectiveCamera}
|
|
37
|
+
*/
|
|
38
|
+
createPerspectiveCamera(id, options = {}) {
|
|
39
|
+
const config = {
|
|
40
|
+
fov: 75,
|
|
41
|
+
near: 0.1,
|
|
42
|
+
far: 1000,
|
|
43
|
+
aspect: window.innerWidth / window.innerHeight,
|
|
44
|
+
...this.defaultOptions,
|
|
45
|
+
...options,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const camera = new THREE.PerspectiveCamera(
|
|
49
|
+
config.fov,
|
|
50
|
+
config.aspect,
|
|
51
|
+
config.near,
|
|
52
|
+
config.far
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
this.setupCamera(camera, config);
|
|
56
|
+
this.storeCamera(id, camera, config);
|
|
57
|
+
|
|
58
|
+
return camera;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Create an orthographic camera
|
|
63
|
+
* @param {string} id - Camera identifier
|
|
64
|
+
* @param {Object} options - Camera options
|
|
65
|
+
* @returns {THREE.OrthographicCamera}
|
|
66
|
+
*/
|
|
67
|
+
createOrthographicCamera(id, options = {}) {
|
|
68
|
+
const config = {
|
|
69
|
+
left: -50,
|
|
70
|
+
right: 50,
|
|
71
|
+
top: 50,
|
|
72
|
+
bottom: -50,
|
|
73
|
+
near: 0.1,
|
|
74
|
+
far: 1000,
|
|
75
|
+
...this.defaultOptions,
|
|
76
|
+
...options,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const camera = new THREE.OrthographicCamera(
|
|
80
|
+
config.left,
|
|
81
|
+
config.right,
|
|
82
|
+
config.top,
|
|
83
|
+
config.bottom,
|
|
84
|
+
config.near,
|
|
85
|
+
config.far
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
this.setupCamera(camera, config);
|
|
89
|
+
this.storeCamera(id, camera, config);
|
|
90
|
+
|
|
91
|
+
return camera;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Setup camera position and orientation
|
|
96
|
+
* @param {THREE.Camera} camera
|
|
97
|
+
* @param {Object} config
|
|
98
|
+
*/
|
|
99
|
+
setupCamera(camera, config) {
|
|
100
|
+
// Set position
|
|
101
|
+
if (config.position) {
|
|
102
|
+
camera.position.set(...config.position);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Set up vector
|
|
106
|
+
if (config.up) {
|
|
107
|
+
camera.up.set(...config.up);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Look at target
|
|
111
|
+
if (config.target) {
|
|
112
|
+
camera.lookAt(...config.target);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Store camera in manager
|
|
118
|
+
* @param {string} id
|
|
119
|
+
* @param {THREE.Camera} camera
|
|
120
|
+
* @param {Object} config
|
|
121
|
+
*/
|
|
122
|
+
storeCamera(id, camera, config) {
|
|
123
|
+
if (this.cameras.has(id)) {
|
|
124
|
+
console.warn(`Camera with id "${id}" already exists. Replacing.`);
|
|
125
|
+
this.disposeCamera(id);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
this.cameras.set(id, {
|
|
129
|
+
camera,
|
|
130
|
+
config,
|
|
131
|
+
createdAt: Date.now(),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// Set as active if it's the first camera
|
|
135
|
+
if (!this.activeCameraId) {
|
|
136
|
+
this.activeCameraId = id;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Create a camera from configuration
|
|
142
|
+
* @param {string} id - Camera identifier
|
|
143
|
+
* @param {Object} config - Camera configuration
|
|
144
|
+
* @returns {THREE.Camera}
|
|
145
|
+
*/
|
|
146
|
+
createCamera(id, config = {}) {
|
|
147
|
+
const type = config.type || this.defaultOptions.type;
|
|
148
|
+
|
|
149
|
+
switch (type) {
|
|
150
|
+
case CameraType.PERSPECTIVE:
|
|
151
|
+
return this.createPerspectiveCamera(id, config);
|
|
152
|
+
case CameraType.ORTHOGRAPHIC:
|
|
153
|
+
return this.createOrthographicCamera(id, config);
|
|
154
|
+
default:
|
|
155
|
+
throw new Error(`Unknown camera type: ${type}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get a camera by ID
|
|
161
|
+
* @param {string} id - Camera identifier
|
|
162
|
+
* @returns {THREE.Camera|null}
|
|
163
|
+
*/
|
|
164
|
+
getCamera(id) {
|
|
165
|
+
const cameraData = this.cameras.get(id);
|
|
166
|
+
return cameraData ? cameraData.camera : null;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Get the currently active camera
|
|
171
|
+
* @returns {THREE.Camera|null}
|
|
172
|
+
*/
|
|
173
|
+
getActiveCamera() {
|
|
174
|
+
return this.activeCameraId ? this.getCamera(this.activeCameraId) : null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Set the active camera
|
|
179
|
+
* @param {string} id - Camera identifier
|
|
180
|
+
*/
|
|
181
|
+
setActiveCamera(id) {
|
|
182
|
+
if (!this.cameras.has(id)) {
|
|
183
|
+
throw new Error(`Camera with id "${id}" does not exist`);
|
|
184
|
+
}
|
|
185
|
+
this.activeCameraId = id;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Update camera aspect ratio (for perspective cameras)
|
|
190
|
+
* @param {string} id - Camera identifier
|
|
191
|
+
* @param {number} aspect - Aspect ratio
|
|
192
|
+
*/
|
|
193
|
+
updateAspectRatio(id, aspect) {
|
|
194
|
+
const cameraData = this.cameras.get(id);
|
|
195
|
+
if (!cameraData) return;
|
|
196
|
+
|
|
197
|
+
const camera = cameraData.camera;
|
|
198
|
+
if (camera.isPerspectiveCamera) {
|
|
199
|
+
camera.aspect = aspect;
|
|
200
|
+
camera.updateProjectionMatrix();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Update orthographic camera bounds
|
|
206
|
+
* @param {string} id - Camera identifier
|
|
207
|
+
* @param {Object} bounds - Bounds { left, right, top, bottom }
|
|
208
|
+
*/
|
|
209
|
+
updateOrthographicBounds(id, bounds) {
|
|
210
|
+
const cameraData = this.cameras.get(id);
|
|
211
|
+
if (!cameraData) return;
|
|
212
|
+
|
|
213
|
+
const camera = cameraData.camera;
|
|
214
|
+
if (camera.isOrthographicCamera) {
|
|
215
|
+
Object.assign(camera, bounds);
|
|
216
|
+
camera.updateProjectionMatrix();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Animate camera to a new position
|
|
222
|
+
* @param {string} id - Camera identifier
|
|
223
|
+
* @param {Object} target - Target position and lookAt
|
|
224
|
+
* @param {number} duration - Animation duration in milliseconds
|
|
225
|
+
* @returns {Promise<void>}
|
|
226
|
+
*/
|
|
227
|
+
async animateTo(id, target, duration = 1000) {
|
|
228
|
+
const camera = this.getCamera(id);
|
|
229
|
+
if (!camera) throw new Error(`Camera with id "${id}" does not exist`);
|
|
230
|
+
|
|
231
|
+
const startPosition = camera.position.clone();
|
|
232
|
+
const startTarget = new THREE.Vector3(0, 0, -1).applyQuaternion(camera.quaternion).add(camera.position);
|
|
233
|
+
|
|
234
|
+
const endPosition = new THREE.Vector3(...(target.position || [0, 0, 100]));
|
|
235
|
+
const endTarget = new THREE.Vector3(...(target.target || [0, 0, 0]));
|
|
236
|
+
|
|
237
|
+
const startTime = Date.now();
|
|
238
|
+
|
|
239
|
+
return new Promise((resolve) => {
|
|
240
|
+
const animate = () => {
|
|
241
|
+
const elapsed = Date.now() - startTime;
|
|
242
|
+
const progress = Math.min(elapsed / duration, 1);
|
|
243
|
+
|
|
244
|
+
// Easing function (ease-in-out cubic)
|
|
245
|
+
const eased = progress < 0.5
|
|
246
|
+
? 4 * progress * progress * progress
|
|
247
|
+
: 1 - Math.pow(-2 * progress + 2, 3) / 2;
|
|
248
|
+
|
|
249
|
+
// Interpolate position
|
|
250
|
+
camera.position.lerpVectors(startPosition, endPosition, eased);
|
|
251
|
+
|
|
252
|
+
// Interpolate target and look at it
|
|
253
|
+
const currentTarget = new THREE.Vector3().lerpVectors(startTarget, endTarget, eased);
|
|
254
|
+
camera.lookAt(currentTarget);
|
|
255
|
+
|
|
256
|
+
if (progress < 1) {
|
|
257
|
+
requestAnimationFrame(animate);
|
|
258
|
+
} else {
|
|
259
|
+
resolve();
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
|
|
263
|
+
animate();
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Reset camera to initial configuration
|
|
269
|
+
* @param {string} id - Camera identifier
|
|
270
|
+
* @param {number} duration - Animation duration
|
|
271
|
+
*/
|
|
272
|
+
async resetCamera(id, duration = 1000) {
|
|
273
|
+
const cameraData = this.cameras.get(id);
|
|
274
|
+
if (!cameraData) return;
|
|
275
|
+
|
|
276
|
+
const config = cameraData.config;
|
|
277
|
+
await this.animateTo(id, {
|
|
278
|
+
position: config.position,
|
|
279
|
+
target: config.target,
|
|
280
|
+
}, duration);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Remove a camera
|
|
285
|
+
* @param {string} id - Camera identifier
|
|
286
|
+
*/
|
|
287
|
+
removeCamera(id) {
|
|
288
|
+
this.disposeCamera(id);
|
|
289
|
+
|
|
290
|
+
this.cameras.delete(id);
|
|
291
|
+
|
|
292
|
+
// Update active camera if needed
|
|
293
|
+
if (this.activeCameraId === id) {
|
|
294
|
+
const remainingCameras = Array.from(this.cameras.keys());
|
|
295
|
+
this.activeCameraId = remainingCameras.length > 0 ? remainingCameras[0] : null;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Dispose camera resources
|
|
301
|
+
* @param {string} id - Camera identifier
|
|
302
|
+
*/
|
|
303
|
+
disposeCamera(id) {
|
|
304
|
+
const cameraData = this.cameras.get(id);
|
|
305
|
+
if (!cameraData) return;
|
|
306
|
+
|
|
307
|
+
// Cameras don't have much to dispose, but we clean up references
|
|
308
|
+
cameraData.camera = null;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Get all camera IDs
|
|
313
|
+
* @returns {string[]}
|
|
314
|
+
*/
|
|
315
|
+
getCameraIds() {
|
|
316
|
+
return Array.from(this.cameras.keys());
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Dispose all cameras
|
|
321
|
+
*/
|
|
322
|
+
dispose() {
|
|
323
|
+
this.getCameraIds().forEach((id) => this.removeCamera(id));
|
|
324
|
+
this.activeCameraId = null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Create a camera from configuration object
|
|
330
|
+
* @param {Object} config - Camera configuration
|
|
331
|
+
* @returns {THREE.Camera}
|
|
332
|
+
*/
|
|
333
|
+
export function createCameraFromConfig(config = {}) {
|
|
334
|
+
const type = config.type || CameraType.PERSPECTIVE;
|
|
335
|
+
let camera;
|
|
336
|
+
|
|
337
|
+
if (type === CameraType.PERSPECTIVE) {
|
|
338
|
+
camera = new THREE.PerspectiveCamera(
|
|
339
|
+
config.fov || 75,
|
|
340
|
+
config.aspect || window.innerWidth / window.innerHeight,
|
|
341
|
+
config.near || 0.1,
|
|
342
|
+
config.far || 1000
|
|
343
|
+
);
|
|
344
|
+
} else {
|
|
345
|
+
camera = new THREE.OrthographicCamera(
|
|
346
|
+
config.left || -50,
|
|
347
|
+
config.right || 50,
|
|
348
|
+
config.top || 50,
|
|
349
|
+
config.bottom || -50,
|
|
350
|
+
config.near || 0.1,
|
|
351
|
+
config.far || 1000
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Set position
|
|
356
|
+
if (config.position) {
|
|
357
|
+
camera.position.set(...config.position);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Set up vector
|
|
361
|
+
if (config.up) {
|
|
362
|
+
camera.up.set(...config.up);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Look at target
|
|
366
|
+
if (config.target) {
|
|
367
|
+
camera.lookAt(...config.target);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return camera;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export default CameraManager;
|