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
|
@@ -1,71 +1,70 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-12-01 14:18:43
|
|
4
|
-
* @FilePath : /
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
import React, { useEffect, useRef, forwardRef } from 'react';
|
|
9
|
-
import ReactEcharts from 'echarts-for-react';
|
|
10
|
-
|
|
11
|
-
const ReCharts = forwardRef(({ options, style, onEvents = {} }, ref) => {
|
|
12
|
-
const internalRef = useRef(null);
|
|
13
|
-
|
|
14
|
-
// Use the provided ref or the internalRef
|
|
15
|
-
const chartRef = ref || internalRef;
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
// Ensure the chart instance is available
|
|
19
|
-
if (chartRef.current) {
|
|
20
|
-
const chart = chartRef.current.getEchartsInstance();
|
|
21
|
-
|
|
22
|
-
// Set the 'silent' option to suppress warnings
|
|
23
|
-
chart.setOption({
|
|
24
|
-
...options,
|
|
25
|
-
silent: true,
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
// Efficiently update options
|
|
29
|
-
if (JSON.stringify(options) !== JSON.stringify(chart.getOption())) {
|
|
30
|
-
chart.clear();
|
|
31
|
-
chart.setOption(options);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Handle events
|
|
35
|
-
Object.keys(onEvents).forEach((eventName) => {
|
|
36
|
-
chart.off(eventName); // Remove old listener
|
|
37
|
-
chart.on(eventName, onEvents[eventName]); // Attach new listener
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
// Resize observer for responsive charts
|
|
41
|
-
const resizeObserver = new ResizeObserver(() => {
|
|
42
|
-
chart.resize();
|
|
43
|
-
});
|
|
44
|
-
const parent = chart.getDom().parentElement;
|
|
45
|
-
if (parent) {
|
|
46
|
-
resizeObserver.observe(parent);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Cleanup
|
|
50
|
-
return () => {
|
|
51
|
-
resizeObserver.disconnect();
|
|
52
|
-
|
|
53
|
-
if (!chart.isDisposed()) {
|
|
54
|
-
chart.off();
|
|
55
|
-
chart.dispose();
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
}, [options, chartRef, onEvents]); // Include onEvents in the dependency array
|
|
60
|
-
|
|
61
|
-
return (
|
|
62
|
-
<ReactEcharts
|
|
63
|
-
ref={chartRef}
|
|
64
|
-
option={options}
|
|
65
|
-
style={style}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
export default ReCharts;
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-12-01 14:18:43
|
|
4
|
+
* @FilePath : /visualify.js/src/core/modules/echarts.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useEffect, useRef, forwardRef } from 'react';
|
|
9
|
+
import ReactEcharts from 'echarts-for-react';
|
|
10
|
+
|
|
11
|
+
const ReCharts = forwardRef(({ options, style, onEvents = {} }, ref) => {
|
|
12
|
+
const internalRef = useRef(null);
|
|
13
|
+
|
|
14
|
+
// Use the provided ref or the internalRef
|
|
15
|
+
const chartRef = ref || internalRef;
|
|
16
|
+
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
// Ensure the chart instance is available
|
|
19
|
+
if (chartRef.current) {
|
|
20
|
+
const chart = chartRef.current.getEchartsInstance();
|
|
21
|
+
|
|
22
|
+
// Set the 'silent' option to suppress warnings
|
|
23
|
+
chart.setOption({
|
|
24
|
+
...options,
|
|
25
|
+
silent: true,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Efficiently update options
|
|
29
|
+
if (JSON.stringify(options) !== JSON.stringify(chart.getOption())) {
|
|
30
|
+
chart.clear();
|
|
31
|
+
chart.setOption(options);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Handle events
|
|
35
|
+
Object.keys(onEvents).forEach((eventName) => {
|
|
36
|
+
chart.off(eventName); // Remove old listener
|
|
37
|
+
chart.on(eventName, onEvents[eventName]); // Attach new listener
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Resize observer for responsive charts
|
|
41
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
42
|
+
chart.resize();
|
|
43
|
+
});
|
|
44
|
+
const parent = chart.getDom().parentElement;
|
|
45
|
+
if (parent) {
|
|
46
|
+
resizeObserver.observe(parent);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Cleanup
|
|
50
|
+
return () => {
|
|
51
|
+
resizeObserver.disconnect();
|
|
52
|
+
|
|
53
|
+
if (!chart.isDisposed()) {
|
|
54
|
+
chart.off();
|
|
55
|
+
chart.dispose();
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}, [options, chartRef, onEvents]); // Include onEvents in the dependency array
|
|
60
|
+
|
|
61
|
+
return (
|
|
62
|
+
<ReactEcharts
|
|
63
|
+
ref={chartRef}
|
|
64
|
+
option={options}
|
|
65
|
+
style={style}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
export default ReCharts;
|
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-11-11 23:09:44
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/lib/echartsUtils
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
// echartsUtils.js
|
|
9
|
-
import * as echarts from 'echarts';
|
|
10
|
-
|
|
11
|
-
export const initChart = (chartRef, chartOption) => {
|
|
12
|
-
if (!chartRef.current) {
|
|
13
|
-
throw new Error('Chart container DOM element not available.');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
let chartInstance = echarts.getInstanceByDom(chartRef.current);
|
|
17
|
-
if (!chartInstance) {
|
|
18
|
-
chartInstance = echarts.init(chartRef.current);
|
|
19
|
-
}
|
|
20
|
-
chartInstance.setOption(chartOption);
|
|
21
|
-
return chartInstance;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export const disposeChart = (chartInstance) => {
|
|
25
|
-
chartInstance && chartInstance.dispose();
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export const handleChartForSharedDataChange = (
|
|
29
|
-
chartRef,
|
|
30
|
-
sharedData,
|
|
31
|
-
previousSharedDataRef,
|
|
32
|
-
extra_Excute_Func = null,
|
|
33
|
-
) => {
|
|
34
|
-
if (sharedData !== previousSharedDataRef.current) {
|
|
35
|
-
const chartInstance = echarts.getInstanceByDom(chartRef.current);
|
|
36
|
-
disposeChart(chartInstance);
|
|
37
|
-
previousSharedDataRef.current = sharedData;
|
|
38
|
-
if (extra_Excute_Func) {
|
|
39
|
-
//console.log('excute func: ', extra_Excute_Func);
|
|
40
|
-
extra_Excute_Func();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
};
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-11-11 23:09:44
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/lib/echartsUtils
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
// echartsUtils.js
|
|
9
|
+
import * as echarts from 'echarts';
|
|
10
|
+
|
|
11
|
+
export const initChart = (chartRef, chartOption) => {
|
|
12
|
+
if (!chartRef.current) {
|
|
13
|
+
throw new Error('Chart container DOM element not available.');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let chartInstance = echarts.getInstanceByDom(chartRef.current);
|
|
17
|
+
if (!chartInstance) {
|
|
18
|
+
chartInstance = echarts.init(chartRef.current);
|
|
19
|
+
}
|
|
20
|
+
chartInstance.setOption(chartOption);
|
|
21
|
+
return chartInstance;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const disposeChart = (chartInstance) => {
|
|
25
|
+
chartInstance && chartInstance.dispose();
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const handleChartForSharedDataChange = (
|
|
29
|
+
chartRef,
|
|
30
|
+
sharedData,
|
|
31
|
+
previousSharedDataRef,
|
|
32
|
+
extra_Excute_Func = null,
|
|
33
|
+
) => {
|
|
34
|
+
if (sharedData !== previousSharedDataRef.current) {
|
|
35
|
+
const chartInstance = echarts.getInstanceByDom(chartRef.current);
|
|
36
|
+
disposeChart(chartInstance);
|
|
37
|
+
previousSharedDataRef.current = sharedData;
|
|
38
|
+
if (extra_Excute_Func) {
|
|
39
|
+
//console.log('excute func: ', extra_Excute_Func);
|
|
40
|
+
extra_Excute_Func();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -1,152 +1,227 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-12-01 14:21:40
|
|
4
|
-
* @FilePath : /visualify.js/src/core/modules/echartswitcher.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
import React, { useState, useEffect, useRef } from 'react';
|
|
9
|
-
import ReCharts from './echarts';
|
|
10
|
-
import Loading from '../pages/loading';
|
|
11
|
-
import _ from 'lodash';
|
|
12
|
-
import _parser_gereral from '../parser/echart.general';
|
|
13
|
-
import _parser_data from '../parser/echart.data';
|
|
14
|
-
import _fetch_data, { _process_fetched_data } from '../parser/echart.parser';
|
|
15
|
-
|
|
16
|
-
import {
|
|
17
|
-
fetchPresetFromURL,
|
|
18
|
-
getEmbeddedPreset,
|
|
19
|
-
} from '../modules/echarts/presetHandler';
|
|
20
|
-
import minimumPreset from './echarts/common';
|
|
21
|
-
|
|
22
|
-
import ErrorBoundary from '../widgets/errorBoundary';
|
|
23
|
-
import { useAppContext } from '../appContext';
|
|
24
|
-
|
|
25
|
-
import downsampleSeries from '../parser/echart.hilbert';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-12-01 14:21:40
|
|
4
|
+
* @FilePath : /visualify.js/src/core/modules/echartswitcher.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
9
|
+
import ReCharts from './echarts';
|
|
10
|
+
import Loading from '../pages/loading';
|
|
11
|
+
import _ from 'lodash';
|
|
12
|
+
import _parser_gereral from '../parser/echart.general';
|
|
13
|
+
import _parser_data from '../parser/echart.data';
|
|
14
|
+
import _fetch_data, { _process_fetched_data } from '../parser/echart.parser';
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
fetchPresetFromURL,
|
|
18
|
+
getEmbeddedPreset,
|
|
19
|
+
} from '../modules/echarts/presetHandler';
|
|
20
|
+
import minimumPreset from './echarts/common';
|
|
21
|
+
|
|
22
|
+
import ErrorBoundary from '../widgets/errorBoundary';
|
|
23
|
+
import { useAppContext } from '../appContext';
|
|
24
|
+
|
|
25
|
+
import downsampleSeries from '../parser/echart.hilbert';
|
|
26
|
+
import {
|
|
27
|
+
generateChartAriaAttributes,
|
|
28
|
+
formatDataForScreenReader,
|
|
29
|
+
announceToScreenReader,
|
|
30
|
+
} from '../../a11y/aria-labels';
|
|
31
|
+
import { createEChartsSwitcherKeyboardHandlers } from '../../a11y/keyboard-nav';
|
|
32
|
+
import { validateChartColors, applyAccessibleColors } from '../../a11y/color-contrast';
|
|
33
|
+
|
|
34
|
+
const EChartSwitcher = ({ props, style }) => {
|
|
35
|
+
const { config = {}, parser, advanced, style: _style } = props;
|
|
36
|
+
const chartId = props.id || `echart-switcher-${Math.random().toString(36).substr(2, 9)}`;
|
|
37
|
+
|
|
38
|
+
// Accessibility: Validate and fix colors
|
|
39
|
+
const accessibleConfig = React.useMemo(() => {
|
|
40
|
+
const validation = validateChartColors(config);
|
|
41
|
+
if (!validation.valid && config.a11y?.autoFix !== false) {
|
|
42
|
+
return applyAccessibleColors(config);
|
|
43
|
+
}
|
|
44
|
+
return config;
|
|
45
|
+
}, [config]);
|
|
46
|
+
|
|
47
|
+
const [loading, setLoading] = useState({
|
|
48
|
+
active: true,
|
|
49
|
+
message: null,
|
|
50
|
+
style: advanced?.loadingStlye ?? {},
|
|
51
|
+
});
|
|
52
|
+
// Store the previous sharedData value using a ref
|
|
53
|
+
const previousSharedDataRef = useRef(null);
|
|
54
|
+
const chartRef = useRef(null);
|
|
55
|
+
const containerRef = useRef(null);
|
|
56
|
+
const [presetData, setPresetData] = useState(null);
|
|
57
|
+
const [Options, setOptions] = useState({});
|
|
58
|
+
const [onEvents] = useState({});
|
|
59
|
+
const { width, height = '400px' } = accessibleConfig;
|
|
60
|
+
const { sharedData } = useAppContext();
|
|
61
|
+
|
|
62
|
+
// Use ref for sharedData to access latest value without depending on it
|
|
63
|
+
const sharedDataRef = useRef(sharedData);
|
|
64
|
+
sharedDataRef.current = sharedData;
|
|
65
|
+
|
|
66
|
+
// Build a serialized snapshot of the specific sharedData keys this component reads
|
|
67
|
+
// via the parser config (parser.api attributes)
|
|
68
|
+
const parserApiKeys = React.useMemo(() => {
|
|
69
|
+
if (!parser?.api) return [];
|
|
70
|
+
return Object.values(parser.api)
|
|
71
|
+
.map((attr) => attr.val)
|
|
72
|
+
.filter(Boolean)
|
|
73
|
+
.sort();
|
|
74
|
+
}, [parser]);
|
|
75
|
+
const sharedDataSnapshot = JSON.stringify(
|
|
76
|
+
parserApiKeys.reduce((acc, key) => {
|
|
77
|
+
acc[key] = sharedData[key];
|
|
78
|
+
return acc;
|
|
79
|
+
}, {}),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Generate ARIA attributes
|
|
83
|
+
const ariaAttributes = React.useMemo(() =>
|
|
84
|
+
generateChartAriaAttributes(accessibleConfig, 'chart', chartId),
|
|
85
|
+
[accessibleConfig, chartId]
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Keyboard handlers
|
|
89
|
+
const { handleKeyDown } = React.useMemo(() =>
|
|
90
|
+
createEChartsSwitcherKeyboardHandlers(chartRef, accessibleConfig),
|
|
91
|
+
[accessibleConfig]
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
useEffect(() => {
|
|
95
|
+
let fetched_data, combinedOptions;
|
|
96
|
+
const parsedGeneral = _parser_gereral(config, presetData);
|
|
97
|
+
const parsedData = _parser_data(config, parsedGeneral);
|
|
98
|
+
|
|
99
|
+
const loadPreset = async () => {
|
|
100
|
+
try {
|
|
101
|
+
if (typeof accessibleConfig.preset === 'string') {
|
|
102
|
+
if (
|
|
103
|
+
accessibleConfig.preset.startsWith('http://') ||
|
|
104
|
+
accessibleConfig.preset.startsWith('https://')
|
|
105
|
+
) {
|
|
106
|
+
const presetData = await fetchPresetFromURL(
|
|
107
|
+
accessibleConfig.preset,
|
|
108
|
+
);
|
|
109
|
+
setPresetData(presetData);
|
|
110
|
+
} else {
|
|
111
|
+
const embeddedPreset = getEmbeddedPreset(accessibleConfig.preset);
|
|
112
|
+
setPresetData(embeddedPreset);
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
setPresetData(minimumPreset);
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('Error loading preset:', error);
|
|
119
|
+
// Handle error or set to a default value
|
|
120
|
+
setPresetData(minimumPreset);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
const updatePlot = async () => {
|
|
125
|
+
try {
|
|
126
|
+
let parsedAPI = parsedData;
|
|
127
|
+
const currentSharedData = sharedDataRef.current;
|
|
128
|
+
|
|
129
|
+
if (parser) {
|
|
130
|
+
// fetch data from api
|
|
131
|
+
fetched_data = await _fetch_data(
|
|
132
|
+
parser,
|
|
133
|
+
parsedData,
|
|
134
|
+
currentSharedData,
|
|
135
|
+
);
|
|
136
|
+
parsedAPI = _process_fetched_data(
|
|
137
|
+
fetched_data,
|
|
138
|
+
parser,
|
|
139
|
+
parsedData,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
combinedOptions = _.merge(parsedAPI, accessibleConfig.overrides);
|
|
144
|
+
|
|
145
|
+
if (advanced?.hilbert)
|
|
146
|
+
combinedOptions.series = downsampleSeries(
|
|
147
|
+
combinedOptions.series,
|
|
148
|
+
advanced.hilbert,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
setOptions(combinedOptions);
|
|
152
|
+
|
|
153
|
+
setLoading((prev) => ({
|
|
154
|
+
...prev,
|
|
155
|
+
active: false,
|
|
156
|
+
message: null,
|
|
157
|
+
}));
|
|
158
|
+
|
|
159
|
+
// Announce chart load to screen readers
|
|
160
|
+
if (accessibleConfig.a11y?.announceLoad !== false) {
|
|
161
|
+
announceToScreenReader(
|
|
162
|
+
`${ariaAttributes['aria-label']}. Chart loaded with ${combinedOptions.series?.[0]?.data?.length || 0} data points.`,
|
|
163
|
+
'polite'
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
} catch (error) {
|
|
167
|
+
setLoading((prev) => ({
|
|
168
|
+
...prev,
|
|
169
|
+
active: true,
|
|
170
|
+
message: error.message,
|
|
171
|
+
}));
|
|
172
|
+
|
|
173
|
+
// Announce error to screen readers
|
|
174
|
+
announceToScreenReader(`Error loading chart: ${error.message}`, 'assertive');
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
loadPreset();
|
|
179
|
+
|
|
180
|
+
updatePlot();
|
|
181
|
+
|
|
182
|
+
const currentSharedDataFull = sharedDataRef.current;
|
|
183
|
+
if (!_.isEqual(currentSharedDataFull, previousSharedDataRef.current))
|
|
184
|
+
previousSharedDataRef.current = currentSharedDataFull;
|
|
185
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
186
|
+
}, [config, parser, advanced, presetData, sharedDataSnapshot]);
|
|
187
|
+
|
|
188
|
+
return (
|
|
189
|
+
<div
|
|
190
|
+
id={chartId}
|
|
191
|
+
ref={containerRef}
|
|
192
|
+
style={{ ...style, position: 'relative' }}
|
|
193
|
+
className="visualify-chart visualify-echart-switcher"
|
|
194
|
+
{...ariaAttributes}
|
|
195
|
+
onKeyDown={handleKeyDown}
|
|
196
|
+
data-testid="echart-switcher"
|
|
197
|
+
>
|
|
198
|
+
{/* Screen reader description */}
|
|
199
|
+
<div id={`${chartId}-description`} className="sr-only">
|
|
200
|
+
{ariaAttributes['aria-label']}
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
{loading.active && (
|
|
204
|
+
<Loading
|
|
205
|
+
message={loading.message}
|
|
206
|
+
style={loading.style}
|
|
207
|
+
/>
|
|
208
|
+
)}
|
|
209
|
+
<ErrorBoundary>
|
|
210
|
+
<ReCharts
|
|
211
|
+
options={Options}
|
|
212
|
+
style={{
|
|
213
|
+
opacity: loading.active ? 0 : 1,
|
|
214
|
+
width,
|
|
215
|
+
height,
|
|
216
|
+
..._style,
|
|
217
|
+
}}
|
|
218
|
+
onEvents={onEvents}
|
|
219
|
+
ref={chartRef}
|
|
220
|
+
aria-hidden="true"
|
|
221
|
+
/>
|
|
222
|
+
</ErrorBoundary>
|
|
223
|
+
</div>
|
|
224
|
+
);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
export default EChartSwitcher;
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2024-01-14 14:54:27
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/modules/replotly/presetHandler.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2024 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import minimumPreset from './presets/minimum';
|
|
10
|
-
import mmtrbc_violin from './presets/mmtrbc.violin';
|
|
11
|
-
import mmtrbc_dot from './presets/mmtrbc.dot';
|
|
12
|
-
|
|
13
|
-
// Example embedded presets
|
|
14
|
-
const embeddedPresets = {
|
|
15
|
-
mmtrbc_violin,
|
|
16
|
-
mmtrbc_dot,
|
|
17
|
-
// 'presetName': { ...preset data... }
|
|
18
|
-
// Define embedded presets here
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export const getPreset = (presetKey) => {
|
|
22
|
-
// Return minimumPreset if preset not found
|
|
23
|
-
return embeddedPresets[presetKey] || minimumPreset;
|
|
24
|
-
};
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2024-01-14 14:54:27
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/modules/replotly/presetHandler.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2024 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import minimumPreset from './presets/minimum';
|
|
10
|
+
import mmtrbc_violin from './presets/mmtrbc.violin';
|
|
11
|
+
import mmtrbc_dot from './presets/mmtrbc.dot';
|
|
12
|
+
|
|
13
|
+
// Example embedded presets
|
|
14
|
+
const embeddedPresets = {
|
|
15
|
+
mmtrbc_violin,
|
|
16
|
+
mmtrbc_dot,
|
|
17
|
+
// 'presetName': { ...preset data... }
|
|
18
|
+
// Define embedded presets here
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const getPreset = (presetKey) => {
|
|
22
|
+
// Return minimumPreset if preset not found
|
|
23
|
+
return embeddedPresets[presetKey] || minimumPreset;
|
|
24
|
+
};
|