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.
Files changed (252) hide show
  1. package/.claude/mem/TIMELINE.md +36 -0
  2. package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-external-script-solution.md +24 -0
  3. package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-session-summary.md +43 -0
  4. package/.claude/mem/notes/2026-02-11-cli-fix-editor-command-alias.md +26 -0
  5. package/.claude/mem/notes/2026-02-11-phase-3-developer-experience-completed.md +51 -0
  6. package/.claude/mem/notes/2026-02-11-phase-4-web-workers-implementation-complete.md +59 -0
  7. package/.claude/mem/notes/2026-02-11-visualify-phase-2-3d-visualization-complete.md +50 -0
  8. package/.claude/mem/notes/2026-02-11-visualify-phase-2-committed-ready-for-phase-3.md +33 -0
  9. package/.claude/mem/notes/2026-02-11-visualify-phase-3-complete-developer-experience.md +52 -0
  10. package/.claude/mem/notes/2026-02-11-visualify-repository-cleanup-complete.md +28 -0
  11. package/.claude/mem/notes/2026-02-18-codebase-cleanup-docsify-plugin-documentation.md +37 -0
  12. package/.claude/mem/notes/2026-02-19-css-grid-layout-fix-displaycontents-on-vcontroller.md +18 -0
  13. package/.claude/mem/notes/2026-02-19-docsify-plugin-fixes-latex-and-visualify-code-bloc.md +26 -0
  14. package/.claude/mem/notes/2026-02-19-page-mode-docs-update-decisions.md +23 -0
  15. package/.claude/mem/notes/2026-02-19-react-context-infinite-re-render-loop-fix-pattern.md +31 -0
  16. package/.claude/mem/notes/2026-02-19-version-300-bump-and-build-fixes.md +32 -0
  17. package/.claude/mem/notes/2026-02-19-visualify-build-deployment-architecture-bug-fixes.md +25 -0
  18. package/.claude/mem/notes/2026-02-19-visualify-dist-iife-self-contained-build-config.md +30 -0
  19. package/.claude/mem/notes/2026-02-19-visualify-infinite-loop-i18n-fixes.md +31 -0
  20. package/.claude/mem/notes/2026-02-19-visualify-v3-bundle-splitting-docs-restructuring.md +32 -0
  21. package/.claude/mem/notes/2026-02-20-bundle-externalization-final-architecture.md +29 -0
  22. package/.claude/mem/notes/2026-02-20-chromium-page-fix-unstable-keys-and-double-event-b.md +27 -0
  23. package/.claude/mem/notes/2026-02-20-console-cleanup-bundle-optimization-commit.md +20 -0
  24. package/.claude/mem/notes/2026-02-20-dotbio-dot-plot-fix-useeffect-dependency.md +21 -0
  25. package/.claude/mem/notes/2026-02-20-public-folder-cleanup-and-readme-rewrite.md +25 -0
  26. package/.claude/mem/notes/2026-02-20-v300-release-and-beta-channel-strategy.md +29 -0
  27. package/.claude/mem/notes/2026-02-20-visium-background-image-unknown-legend-fix.md +19 -0
  28. package/.claude/mem/notes/2026-02-20-visualify-cdn-loader-bundle-externalization.md +34 -0
  29. package/.claude/mem/sessions/session-2026-02-20-031524.md +54 -0
  30. package/.claude/settings.local.json +21 -0
  31. package/.github/workflows/static.yml.bak +51 -51
  32. package/.sisyphus/boulder.json +65 -0
  33. package/.sisyphus/plans/phase-4-advanced-optimizations.md +217 -0
  34. package/LICENSE +674 -674
  35. package/README.md +94 -59
  36. package/config-overrides.js +31 -31
  37. package/dist/stats.html +4949 -0
  38. package/dist/visualify-3d.esm.js +1 -0
  39. package/dist/visualify-3d.js +1 -0
  40. package/dist/visualify-core.esm.js +1 -0
  41. package/dist/visualify-core.js +1 -0
  42. package/dist/visualify-docs.esm.js +1 -0
  43. package/dist/visualify-docs.js +1 -0
  44. package/dist/visualify-loader.js +1 -0
  45. package/dist/visualify-pages.esm.js +1 -0
  46. package/dist/visualify-pages.js +1 -0
  47. package/dist/visualify-portal.esm.js +1 -0
  48. package/dist/visualify-portal.js +1 -0
  49. package/dist/visualify-shared.js +26571 -0
  50. package/dist/visualify.js +1 -188
  51. package/docs/CHANGELOG.md +148 -0
  52. package/docs/cli/commands.md +513 -0
  53. package/docs/configuration/visualify-json.md +474 -0
  54. package/docs/docs/3d-visualization.md +374 -0
  55. package/docs/docs/CLI.md +303 -34
  56. package/docs/docs/README.md +65 -65
  57. package/docs/docs/Rechart/bar.md +190 -190
  58. package/docs/docs/Rechart/funnel.md +241 -241
  59. package/docs/docs/Rechart/line.md +355 -355
  60. package/docs/docs/Rechart/pie.md +225 -225
  61. package/docs/docs/Rechart/radar.md +253 -253
  62. package/docs/docs/Rechart/scatter.md +298 -298
  63. package/docs/docs/_404.md +51 -51
  64. package/docs/docs/_coverpage.md +11 -11
  65. package/docs/docs/_sidebar.md +54 -44
  66. package/docs/docs/components/dotBio.md +87 -34
  67. package/docs/docs/components/echart.md +171 -82
  68. package/docs/docs/components/html.md +61 -34
  69. package/docs/docs/components/macaron.md +156 -145
  70. package/docs/docs/components/markdown.md +42 -0
  71. package/docs/docs/components/more.md +183 -142
  72. package/docs/docs/components/plotly.md +132 -62
  73. package/docs/docs/components/scatterL.md +171 -70
  74. package/docs/docs/components/visium.md +112 -57
  75. package/docs/docs/configuration.md +121 -121
  76. package/docs/docs/deploy.md +31 -31
  77. package/docs/docs/docsify-plugin.md +655 -0
  78. package/docs/docs/hmr.md +165 -0
  79. package/docs/docs/i18n.md +332 -0
  80. package/docs/docs/log.md +30 -9
  81. package/docs/docs/more-pages.md +23 -23
  82. package/docs/docs/quickstart.md +148 -124
  83. package/docs/docs/rechart-attributes.md +74 -74
  84. package/docs/docs/rechart-basic-usage.md +160 -162
  85. package/docs/docs/theme.md +5 -5
  86. package/docs/docs/typescript.md +306 -0
  87. package/docs/docs/visual-editor.md +359 -0
  88. package/docs/index.html +85 -71
  89. package/docs/manifest.json +23 -23
  90. package/docs/migration/v3-migration.md +392 -0
  91. package/docs/static/css/fluff-stuff.css +169 -169
  92. package/docs/static/css/font-awesome.min.css +4 -4
  93. package/docs/static/css/visualify.css +6 -25
  94. package/docs/static/js/3d-viz-examples.js +181 -0
  95. package/docs/static/js/configuration.js +630 -448
  96. package/docs/static/js/visualify.js +1 -188
  97. package/package.json +106 -84
  98. package/rollup.config.mjs +766 -76
  99. package/src/_css/404.css +115 -115
  100. package/src/_css/App.css +37 -37
  101. package/src/_css/autoSuggestion.css +26 -26
  102. package/src/_css/circular-progress.css +32 -32
  103. package/src/_css/index.css +36 -36
  104. package/src/_css/modern.css +350 -25
  105. package/src/_media/corner.svg +8 -8
  106. package/src/_media/download.svg +3 -3
  107. package/src/_media/logo.svg +14 -14
  108. package/src/_test/App.test.js +15 -15
  109. package/src/_utils/reportWebVitals.js +13 -13
  110. package/src/a11y/README.md +177 -0
  111. package/src/a11y/aria-labels.js +339 -0
  112. package/src/a11y/color-contrast.js +535 -0
  113. package/src/a11y/index.js +197 -0
  114. package/src/a11y/keyboard-nav.js +523 -0
  115. package/src/a11y/styles.css +165 -0
  116. package/src/cli/commands/dev.js +214 -0
  117. package/src/cli/commands/docs.js +521 -0
  118. package/src/cli/commands/edit.js +379 -0
  119. package/src/cli/commands/init.js +213 -0
  120. package/src/cli/commands/portal.js +236 -0
  121. package/src/cli/dev-server.js +530 -0
  122. package/src/cli/hmr.js +456 -0
  123. package/src/cli/index.js +180 -0
  124. package/src/cli/utils/config.js +207 -0
  125. package/src/cli/utils/logger.js +241 -0
  126. package/src/config/defaults.ts +122 -0
  127. package/src/config/index.ts +72 -0
  128. package/src/config/loader.ts +478 -0
  129. package/src/config/schema.ts +227 -0
  130. package/src/config/validator.ts +337 -0
  131. package/src/core/appContext.js +34 -27
  132. package/src/core/components/Bar.js +383 -0
  133. package/src/core/components/Bar3D.js +473 -0
  134. package/src/core/components/LargeDatasetChart.js +296 -0
  135. package/src/core/components/Line3D.js +310 -0
  136. package/src/core/components/Scatter.js +392 -188
  137. package/src/core/components/Scatter3D.js +455 -0
  138. package/src/core/components/ScatterBio.js +601 -572
  139. package/src/core/components/Surface3D.js +326 -0
  140. package/src/core/components/ThreeCustom.js +648 -0
  141. package/src/core/components/ThreeScene.js +459 -0
  142. package/src/core/components/VisiumPlot.js +191 -165
  143. package/src/core/components/browser.js +42 -42
  144. package/src/core/components/dotplot.js +413 -413
  145. package/src/core/components/html.js +29 -29
  146. package/src/core/components/list.js +178 -178
  147. package/src/core/components/macaron.js +206 -201
  148. package/src/core/components/markdown.js +56 -56
  149. package/src/core/components/parser.scatterBio.js +582 -587
  150. package/src/core/components/ratio.js +82 -80
  151. package/src/core/components/scatterL.js +206 -173
  152. package/src/core/components/searchbar.js +156 -131
  153. package/src/core/components/selection.js +310 -193
  154. package/src/core/components/timeline.js +236 -281
  155. package/src/core/components/visium.js +114 -97
  156. package/src/core/data-processor.js +413 -0
  157. package/src/core/fetch/condfetch.js +82 -82
  158. package/src/core/fetch/fetch.js +92 -92
  159. package/src/core/fetch/json.js +29 -29
  160. package/src/core/fetch/vfetch.js +42 -42
  161. package/src/core/hmr-client.js +724 -0
  162. package/src/core/liveEditor.js +44 -44
  163. package/src/core/modules/codeEditorWithPreview.js +104 -104
  164. package/src/core/modules/echarts/common.js +20 -20
  165. package/src/core/modules/echarts/gl.js +228 -0
  166. package/src/core/modules/echarts/presetHandler.js +41 -41
  167. package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
  168. package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
  169. package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
  170. package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
  171. package/src/core/modules/echarts.js +70 -71
  172. package/src/core/modules/echartsUtils.js +43 -43
  173. package/src/core/modules/echartswitcher.js +227 -152
  174. package/src/core/modules/replotly/presetHandler.js +24 -24
  175. package/src/core/modules/replotly/presets/minimum.js +18 -18
  176. package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
  177. package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
  178. package/src/core/modules/replotly.js +74 -71
  179. package/src/core/modules/threejs/Camera.js +373 -0
  180. package/src/core/modules/threejs/Lighting.js +459 -0
  181. package/src/core/modules/threejs/Renderer.js +364 -0
  182. package/src/core/modules/threejs/Scene.js +266 -0
  183. package/src/core/modules/threejs/index.js +155 -0
  184. package/src/core/pages/404.js +50 -50
  185. package/src/core/pages/error.js +27 -27
  186. package/src/core/pages/jsonPage.js +62 -62
  187. package/src/core/pages/loading.js +44 -44
  188. package/src/core/parser/echart.data.js +204 -183
  189. package/src/core/parser/echart.features.js +125 -125
  190. package/src/core/parser/echart.general.js +147 -147
  191. package/src/core/parser/echart.hilbert.js +57 -57
  192. package/src/core/parser/echart.parser.js +210 -210
  193. package/src/core/parser/echart.series.js +67 -67
  194. package/src/core/parser/echart.types.js +76 -76
  195. package/src/core/parser/plotly.config.js +10 -10
  196. package/src/core/parser/plotly.data.js +132 -132
  197. package/src/core/parser/plotly.layout.js +9 -9
  198. package/src/core/parser/plotly.violin.js +18 -18
  199. package/src/core/recharts.js +361 -62
  200. package/src/core/router/alias.js +49 -49
  201. package/src/core/router/jsonRouter.js +31 -31
  202. package/src/core/themes/modern.js +32 -32
  203. package/src/core/themes/themeSelector.js +33 -33
  204. package/src/core/visualify.js +213 -47
  205. package/src/core/widgets/circularProgress.js +23 -23
  206. package/src/core/widgets/controller.js +116 -83
  207. package/src/core/widgets/errorBoundary.js +36 -36
  208. package/src/core/widgets/footer.js +185 -177
  209. package/src/core/widgets/header.js +238 -234
  210. package/src/core/widgets/layout/Grid.js +31 -31
  211. package/src/core/widgets/layout.js +36 -36
  212. package/src/core/widgets/mapping.js +56 -42
  213. package/src/core/workers/data-worker.js +349 -0
  214. package/src/core/workers/worker-pool.js +396 -0
  215. package/src/docsify/bundle.js +215 -0
  216. package/src/docsify/markdown.js +271 -0
  217. package/src/docsify/plugin.js +268 -0
  218. package/src/editor/README.md +172 -0
  219. package/src/editor/components/ChartBuilder.jsx +341 -0
  220. package/src/editor/components/ChartTypeSidebar.jsx +91 -0
  221. package/src/editor/components/Editor.jsx +367 -0
  222. package/src/editor/components/Preview.jsx +446 -0
  223. package/src/editor/components/PropertyPanel.jsx +468 -0
  224. package/src/editor/components/StatusBar.jsx +85 -0
  225. package/src/editor/context/EditorContext.js +248 -0
  226. package/src/editor/hooks/useDebounce.js +32 -0
  227. package/src/editor/index.js +315 -0
  228. package/src/editor/styles/editor.css +637 -0
  229. package/src/editor/utils/chartValidator.js +263 -0
  230. package/src/entries/charts3d.js +70 -0
  231. package/src/entries/core.js +78 -0
  232. package/src/entries/docs.js +154 -0
  233. package/src/entries/pages.js +93 -0
  234. package/src/entries/portal.js +204 -0
  235. package/src/entries/shared.js +50 -0
  236. package/src/i18n/formatters.js +455 -0
  237. package/src/i18n/index.js +169 -0
  238. package/src/i18n/locales/ar.json +137 -0
  239. package/src/i18n/locales/de.json +137 -0
  240. package/src/i18n/locales/en.json +137 -0
  241. package/src/i18n/locales/es.json +137 -0
  242. package/src/i18n/locales/he.json +137 -0
  243. package/src/i18n/locales/zh.json +137 -0
  244. package/src/i18n/rtl.css +183 -0
  245. package/src/index.js +82 -62
  246. package/src/loader.js +103 -0
  247. package/src/setupTests.js +5 -5
  248. package/tsconfig.json +51 -0
  249. package/types/charts.d.ts +569 -0
  250. package/types/components.d.ts +441 -0
  251. package/types/config.d.ts +199 -0
  252. package/types/index.d.ts +353 -0
@@ -1,80 +1,82 @@
1
- /*
2
- * @Author : Lihao leolihao@arizona.edu
3
- * @Date : 2023-12-30 15:11:35
4
- * @FilePath : /visualifyjs/src/core/components/ratio.js
5
- * @Description :
6
- * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
- */
8
- import React, { useState, useEffect } from 'react';
9
- import { useAppContext } from '../appContext';
10
-
11
- function RatioBox({ props, style }) {
12
- const { debug } = props;
13
-
14
- const { style: blockStyle } = props;
15
- // if debug is true, then border is red, else no border
16
- style = {
17
- ...style,
18
- ...blockStyle,
19
- border: debug ? '1px solid red' : 'none',
20
- };
21
-
22
- const { title } = props;
23
- const renderTitle = () => {
24
- return title && <h3>{title}</h3>;
25
- };
26
-
27
- const { setSharedData } = useAppContext();
28
- const { choice = [] } = props;
29
-
30
- // State to keep track of selected choice
31
- const [selectedChoice, setSelectedChoice] = useState(
32
- choice.length > 0 ? choice[0] : null,
33
- );
34
-
35
- // Handler for radio button change
36
- const handleRadioChange = (event) => {
37
- setSelectedChoice(event.target.value);
38
- };
39
-
40
- const {
41
- id,
42
- val,
43
- ratio_style = {
44
- margin: 'auto 15px',
45
- },
46
- } = props;
47
-
48
- // Store the selected choice in shared data whenever it changes
49
- useEffect(() => {
50
- if (val) {
51
- setSharedData((prevSharedData) => {
52
- return { ...prevSharedData, [val]: selectedChoice };
53
- });
54
- }
55
- }, [selectedChoice, val, setSharedData]);
56
-
57
- return (
58
- <div
59
- key={id}
60
- style={style}
61
- className='ratio-box-container'>
62
- {renderTitle()}
63
- {choice.map((item, index) => (
64
- <label
65
- key={index}
66
- style={ratio_style}>
67
- <input
68
- type='radio'
69
- value={item}
70
- checked={selectedChoice === item}
71
- onChange={handleRadioChange}
72
- />
73
- {item}
74
- </label>
75
- ))}
76
- </div>
77
- );
78
- }
79
-
80
- export default RatioBox;
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2023-12-30 15:11:35
4
+ * @FilePath : /visualifyjs/src/core/components/ratio.js
5
+ * @Description :
6
+ * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ import React, { useState, useEffect } from 'react';
9
+ import { useAppContext } from '../appContext';
10
+
11
+ function RatioBox({ props, style }) {
12
+ const { debug } = props;
13
+
14
+ const { style: blockStyle } = props;
15
+ // if debug is true, then border is red, else no border
16
+ style = {
17
+ ...style,
18
+ ...blockStyle,
19
+ border: debug ? '1px solid red' : 'none',
20
+ };
21
+
22
+ const { title } = props;
23
+ const renderTitle = () => {
24
+ return title && <h3>{title}</h3>;
25
+ };
26
+
27
+ const { setSharedData } = useAppContext();
28
+ const { choice = [] } = props;
29
+
30
+ // State to keep track of selected choice
31
+ const [selectedChoice, setSelectedChoice] = useState(
32
+ choice.length > 0 ? choice[0] : null,
33
+ );
34
+
35
+ // Handler for radio button change
36
+ const handleRadioChange = (event) => {
37
+ setSelectedChoice(event.target.value);
38
+ };
39
+
40
+ const {
41
+ id,
42
+ val,
43
+ ratio_style = {
44
+ margin: 'auto 15px',
45
+ },
46
+ } = props;
47
+
48
+ // Store the selected choice in shared data whenever it changes
49
+ useEffect(() => {
50
+ if (val) {
51
+ setSharedData((prevSharedData) => {
52
+ // Skip update if the value is already the same
53
+ if (prevSharedData[val] === selectedChoice) return prevSharedData;
54
+ return { ...prevSharedData, [val]: selectedChoice };
55
+ });
56
+ }
57
+ }, [selectedChoice, val, setSharedData]);
58
+
59
+ return (
60
+ <div
61
+ key={id}
62
+ style={style}
63
+ className='ratio-box-container'>
64
+ {renderTitle()}
65
+ {choice.map((item, index) => (
66
+ <label
67
+ key={index}
68
+ style={ratio_style}>
69
+ <input
70
+ type='radio'
71
+ value={item}
72
+ checked={selectedChoice === item}
73
+ onChange={handleRadioChange}
74
+ />
75
+ {item}
76
+ </label>
77
+ ))}
78
+ </div>
79
+ );
80
+ }
81
+
82
+ export default RatioBox;
@@ -1,173 +1,206 @@
1
- /*
2
- * @Author : Lihao leolihao@arizona.edu
3
- * @Date : 2023-11-06 17:23:59
4
- * @FilePath : /visualify.js/src/core/components/scatterL.js
5
- * @Description :
6
- * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
- */
8
- import React, { useEffect, useRef, useState } from 'react';
9
- import { useAppContext } from '../appContext';
10
- import Loading from '../pages/loading';
11
- import {
12
- initChart,
13
- handleChartForSharedDataChange,
14
- } from '../modules/echartsUtils';
15
- import {
16
- parseConfig,
17
- validateConfig,
18
- handleAPI,
19
- handleSimplyLoad,
20
- onDataZoom,
21
- parseData,
22
- outputAxisValues,
23
- } from './parser.scatterBio';
24
-
25
- function ScatterBio({ props, style }) {
26
- const chartRef = useRef(null);
27
- const { sharedData } = useAppContext();
28
- const [loading, setLoading] = useState({ active: true, message: null });
29
-
30
- // Store the previous sharedData value using a ref
31
- const previousSharedDataRef = useRef(null);
32
-
33
- useEffect(() => {
34
- let option = parseConfig(props);
35
- //console.log('option: ', option);
36
- let fetched_dat = null;
37
-
38
- // Check if the sharedData has changed
39
- handleChartForSharedDataChange(
40
- chartRef,
41
- sharedData,
42
- previousSharedDataRef,
43
- () => {
44
- option.xAxis.min = props?.echart?.xAxis?.min;
45
- option.xAxis.max = props?.echart?.xAxis?.max;
46
- option.yAxis.min = props?.echart?.yAxis?.min;
47
- option.yAxis.max = props?.echart?.yAxis?.max;
48
- },
49
- );
50
-
51
- // Simulate fetching data asynchronously (replace with your data fetching logic)
52
- const updatePlot = async () => {
53
- try {
54
- setLoading({ active: true, message: null });
55
- validateConfig(props.config);
56
- const myChart = initChart(chartRef, option);
57
- if (props.config.simpleload)
58
- handleSimplyLoad(props.config.simpleload);
59
- else {
60
- const ibox = props.config?.ibox ?? {
61
- xMin: -9999,
62
- yMin: -9999,
63
- xMax: 9999,
64
- yMax: 9999,
65
- };
66
- fetched_dat = await handleAPI(
67
- props.config,
68
- sharedData,
69
- ibox,
70
- );
71
- //console.log(fetched_dat, 'fetched_dat');
72
- }
73
- var { series, legend, visualMap, title } = parseData(
74
- fetched_dat,
75
- props.config,
76
- sharedData,
77
- );
78
- // Chart options
79
- option.series = props?.echart?.series ?? series;
80
- option.legend = {
81
- ...option.legend,
82
- ...legend,
83
- };
84
-
85
- option.visualMap = visualMap;
86
- option.title = {
87
- ...option.title,
88
- text: title,
89
- };
90
-
91
- // Set the initial option
92
- myChart.setOption(option);
93
-
94
- let zoomTimeout;
95
- const zoom_action = () => {
96
- clearTimeout(zoomTimeout);
97
- zoomTimeout = setTimeout(async () => {
98
- await onDataZoom(
99
- props,
100
- sharedData,
101
- fetched_dat,
102
- myChart,
103
- option,
104
- );
105
- }, 500);
106
- };
107
-
108
- myChart.on('dataZoom', zoom_action);
109
-
110
- setLoading({ active: false, message: null });
111
-
112
- let bbox = outputAxisValues(myChart);
113
- option.xAxis.min = option.xAxis.min ?? bbox.xMin;
114
- option.xAxis.max = option.xAxis.max ?? bbox.xMax;
115
- option.yAxis.min = option.yAxis.min ?? bbox.yMin;
116
- option.yAxis.max = option.yAxis.max ?? bbox.yMax;
117
-
118
- // Cleanup event listeners on component unmount
119
- return () => {
120
- myChart.off('dataZoom', zoom_action);
121
- myChart.dispose();
122
- };
123
- } catch (error) {
124
- setLoading({ active: true, message: error.message });
125
- }
126
- };
127
-
128
- // Execute the updatePlot function
129
- updatePlot();
130
-
131
- // Observe changes to the size of the chart container
132
- const resizeObserver = new ResizeObserver((entries) => {
133
- for (let entry of entries) {
134
- if (entry.contentRect.width && entry.contentRect.height) {
135
- updatePlot();
136
- resizeObserver.disconnect();
137
- }
138
- }
139
- });
140
-
141
- if (chartRef.current) {
142
- resizeObserver.observe(chartRef.current);
143
- }
144
-
145
- // Cleanup function
146
- return () => {
147
- resizeObserver.disconnect();
148
- };
149
- }, [props, sharedData]);
150
-
151
- return (
152
- <div
153
- id={props.id}
154
- style={{ ...style, position: 'relative' }}>
155
- {loading.active && (
156
- <Loading
157
- message={loading.message}
158
- style={{ marginTop: '10px' }}
159
- />
160
- )}
161
- <div
162
- ref={chartRef}
163
- style={{
164
- opacity: loading.active ? 0 : 1,
165
- width: props.config?.size?.width || '100%',
166
- height: props.config?.size?.height || '100%',
167
- }}
168
- />
169
- </div>
170
- );
171
- }
172
-
173
- export default ScatterBio;
1
+ /*
2
+ * @Author : Lihao leolihao@arizona.edu
3
+ * @Date : 2023-11-06 17:23:59
4
+ * @FilePath : /visualify.js/src/core/components/scatterL.js
5
+ * @Description :
6
+ * Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
7
+ */
8
+ import React, { useEffect, useRef, useState } from 'react';
9
+ import { useAppContext } from '../appContext';
10
+ import Loading from '../pages/loading';
11
+ import {
12
+ initChart,
13
+ handleChartForSharedDataChange,
14
+ } from '../modules/echartsUtils';
15
+ import {
16
+ parseConfig,
17
+ validateConfig,
18
+ handleAPI,
19
+ handleSimplyLoad,
20
+ onDataZoom,
21
+ parseData,
22
+ outputAxisValues,
23
+ } from './parser.scatterBio';
24
+
25
+ function ScatterBio({ props, style }) {
26
+ const chartRef = useRef(null);
27
+ const { sharedData } = useAppContext();
28
+ const [loading, setLoading] = useState({ active: true, message: null });
29
+
30
+ // Store the previous sharedData value using a ref
31
+ const previousSharedDataRef = useRef(null);
32
+
33
+ // Use refs for sharedData and props to access latest values without depending on them
34
+ const sharedDataRef = useRef(sharedData);
35
+ sharedDataRef.current = sharedData;
36
+ const propsRef = useRef(props);
37
+ propsRef.current = props;
38
+
39
+ // Extract stable dependency keys from props.config.api and colourby
40
+ // These are the only sharedData keys this component actually reads
41
+ const apiConfig = props.config?.api;
42
+ const colourbyKey = props.config?.colourby;
43
+ const apiVals = apiConfig
44
+ ? Object.values(apiConfig).map((attr) => attr.val).sort().join(',')
45
+ : '';
46
+ // Build a serialized snapshot of the specific sharedData values we depend on
47
+ const relevantKeys = [];
48
+ if (apiConfig) {
49
+ Object.values(apiConfig).forEach((attr) => {
50
+ if (attr.val) relevantKeys.push(attr.val);
51
+ });
52
+ }
53
+ if (colourbyKey) relevantKeys.push(colourbyKey);
54
+ const sharedDataSnapshot = JSON.stringify(
55
+ relevantKeys.reduce((acc, key) => {
56
+ acc[key] = sharedData[key];
57
+ return acc;
58
+ }, {}),
59
+ );
60
+
61
+ useEffect(() => {
62
+ const currentProps = propsRef.current;
63
+ const currentSharedData = sharedDataRef.current;
64
+
65
+ let option = parseConfig(currentProps);
66
+ //console.log('option: ', option);
67
+ let fetched_dat = null;
68
+
69
+ // Check if the sharedData has changed
70
+ handleChartForSharedDataChange(
71
+ chartRef,
72
+ currentSharedData,
73
+ previousSharedDataRef,
74
+ () => {
75
+ option.xAxis.min = currentProps?.echart?.xAxis?.min;
76
+ option.xAxis.max = currentProps?.echart?.xAxis?.max;
77
+ option.yAxis.min = currentProps?.echart?.yAxis?.min;
78
+ option.yAxis.max = currentProps?.echart?.yAxis?.max;
79
+ },
80
+ );
81
+
82
+ // Simulate fetching data asynchronously (replace with your data fetching logic)
83
+ const updatePlot = async () => {
84
+ try {
85
+ setLoading({ active: true, message: null });
86
+ validateConfig(currentProps.config);
87
+ const myChart = initChart(chartRef, option);
88
+ if (currentProps.config.simpleload)
89
+ handleSimplyLoad(currentProps.config.simpleload);
90
+ else {
91
+ const ibox = currentProps.config?.ibox ?? {
92
+ xMin: -9999,
93
+ yMin: -9999,
94
+ xMax: 9999,
95
+ yMax: 9999,
96
+ };
97
+ fetched_dat = await handleAPI(
98
+ currentProps.config,
99
+ currentSharedData,
100
+ ibox,
101
+ );
102
+ //console.log(fetched_dat, 'fetched_dat');
103
+ }
104
+ var { series, legend, visualMap, title } = parseData(
105
+ fetched_dat,
106
+ currentProps.config,
107
+ currentSharedData,
108
+ );
109
+ // Chart options
110
+ option.series = currentProps?.echart?.series ?? series;
111
+ option.legend = {
112
+ ...option.legend,
113
+ ...legend,
114
+ };
115
+
116
+ option.visualMap = visualMap;
117
+ option.title = {
118
+ ...option.title,
119
+ text: title,
120
+ };
121
+
122
+ // Set the initial option
123
+ myChart.setOption(option);
124
+
125
+ let zoomTimeout;
126
+ const zoom_action = () => {
127
+ clearTimeout(zoomTimeout);
128
+ zoomTimeout = setTimeout(async () => {
129
+ await onDataZoom(
130
+ currentProps,
131
+ sharedDataRef.current,
132
+ fetched_dat,
133
+ myChart,
134
+ option,
135
+ );
136
+ }, 500);
137
+ };
138
+
139
+ myChart.on('dataZoom', zoom_action);
140
+
141
+ setLoading({ active: false, message: null });
142
+
143
+ let bbox = outputAxisValues(myChart);
144
+ option.xAxis.min = option.xAxis.min ?? bbox.xMin;
145
+ option.xAxis.max = option.xAxis.max ?? bbox.xMax;
146
+ option.yAxis.min = option.yAxis.min ?? bbox.yMin;
147
+ option.yAxis.max = option.yAxis.max ?? bbox.yMax;
148
+
149
+ // Cleanup event listeners on component unmount
150
+ return () => {
151
+ myChart.off('dataZoom', zoom_action);
152
+ myChart.dispose();
153
+ };
154
+ } catch (error) {
155
+ setLoading({ active: true, message: error.message });
156
+ }
157
+ };
158
+
159
+ // Execute the updatePlot function
160
+ updatePlot();
161
+
162
+ // Observe changes to the size of the chart container
163
+ const resizeObserver = new ResizeObserver((entries) => {
164
+ for (let entry of entries) {
165
+ if (entry.contentRect.width && entry.contentRect.height) {
166
+ updatePlot();
167
+ resizeObserver.disconnect();
168
+ }
169
+ }
170
+ });
171
+
172
+ if (chartRef.current) {
173
+ resizeObserver.observe(chartRef.current);
174
+ }
175
+
176
+ // Cleanup function
177
+ return () => {
178
+ resizeObserver.disconnect();
179
+ };
180
+ // Only re-run when relevant sharedData values actually change (serialized comparison)
181
+ // eslint-disable-next-line react-hooks/exhaustive-deps
182
+ }, [sharedDataSnapshot, apiVals, colourbyKey]);
183
+
184
+ return (
185
+ <div
186
+ id={props.id}
187
+ style={{ ...style, position: 'relative' }}>
188
+ {loading.active && (
189
+ <Loading
190
+ message={loading.message}
191
+ style={{ marginTop: '10px' }}
192
+ />
193
+ )}
194
+ <div
195
+ ref={chartRef}
196
+ style={{
197
+ opacity: loading.active ? 0 : 1,
198
+ width: props.config?.size?.width || '100%',
199
+ height: props.config?.size?.height || '100%',
200
+ }}
201
+ />
202
+ </div>
203
+ );
204
+ }
205
+
206
+ export default ScatterBio;