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,201 +1,206 @@
1
- import React, { useState, useEffect, useMemo } from 'react';
2
- import { useAppContext } from '../appContext';
3
- import ReCharts from '../modules/echarts';
4
-
5
- function processData(
6
- nodes,
7
- selected,
8
- _symbolSize,
9
- maxValue,
10
- inner_color,
11
- unclickable,
12
- ) {
13
- const { nodes: selectedNodes, category: selectedCategory } = selected;
14
-
15
- return nodes.nodes.map((node) => {
16
- const symbolSize =
17
- typeof _symbolSize === 'number'
18
- ? _symbolSize
19
- : typeof _symbolSize === 'string'
20
- ? _symbolSize === 'default'
21
- ? (6 - node.category) * 6
22
- : 10 + (parseFloat(node[_symbolSize]) / maxValue) * 30 ||
23
- (6 - node.category) * 6
24
- : (6 - node.category) * 6; // Fallback to default
25
-
26
- const isSelected = selectedNodes.includes(node.name);
27
- const isSameCategory = node.category === selectedCategory;
28
- const isOriginalState =
29
- selectedCategory === null && selectedNodes.length === 0;
30
- const isUnclickable =
31
- unclickable.includes(node.name) ||
32
- unclickable.includes(node.category);
33
- const opacity = isUnclickable
34
- ? 0.8
35
- : isOriginalState
36
- ? 1
37
- : isSelected
38
- ? 1
39
- : isSameCategory
40
- ? 1
41
- : 0.2;
42
- const color = isUnclickable
43
- ? 'gray'
44
- : isOriginalState
45
- ? `hsl(${node.category * 110}, 50%, 50%)`
46
- : isSelected
47
- ? inner_color.selected ?? 'red'
48
- : isSameCategory
49
- ? `hsl(${node.category * 100}, 50%, 50%)`
50
- : inner_color.unselectable ?? 'grey';
51
-
52
- return {
53
- ...node,
54
- symbolSize,
55
- itemStyle: {
56
- color,
57
- opacity,
58
- },
59
- emphasis: {
60
- focus: 'self',
61
- itemStyle: {
62
- color,
63
- opacity,
64
- },
65
- label: {
66
- position: 'insideTop',
67
- show: true, // Show label
68
- },
69
- },
70
- };
71
- });
72
- }
73
-
74
- function Macaron({ props, style }) {
75
- const { debug, style: _style, className } = props;
76
- const { id, title, data } = props;
77
-
78
- const {
79
- animation = false,
80
- draggable = true,
81
- repulsion = 100,
82
- edgeLength = 40,
83
- height: inner_height = '93%',
84
- width: inner_width = '100%',
85
- unclickable = [],
86
- symbolSize: _symbolSize = 'default',
87
- color: inner_color = {
88
- selected: 'red',
89
- unselectable: 'grey',
90
- },
91
- singleclick = true,
92
- } = props.config;
93
-
94
- const [selected, setSelected] = useState({ nodes: [], category: null });
95
- const { val = 'vnode' } = props;
96
-
97
- const inner_style = {
98
- border: debug ? '1px solid black' : 'none',
99
- height: inner_height,
100
- width: inner_width,
101
- };
102
-
103
- const maxValue = useMemo(() => {
104
- const values = data.nodes.map(
105
- (node) => parseFloat(node[_symbolSize]) || 50,
106
- );
107
- return Math.max(...values);
108
- }, [data, _symbolSize]);
109
-
110
- const processedData = useMemo(
111
- () =>
112
- processData(
113
- data,
114
- selected,
115
- _symbolSize,
116
- maxValue,
117
- inner_color,
118
- unclickable,
119
- ),
120
- [data, selected, _symbolSize, maxValue, inner_color, unclickable],
121
- );
122
-
123
- const onChartClick = (params) => {
124
- const category = params.data.category;
125
- const name = params.data.name;
126
- if (
127
- params.dataType === 'node' &&
128
- !unclickable.includes(category) &&
129
- !unclickable.includes(name) &&
130
- (selected.category === null || category === selected.category)
131
- ) {
132
- let updatedSelectedNodes = [...selected.nodes];
133
- let updatedSelectedCategory = selected.category;
134
- if (selected.nodes.includes(name)) {
135
- updatedSelectedNodes = updatedSelectedNodes.filter(
136
- (nodeName) => nodeName !== name,
137
- );
138
- if (updatedSelectedNodes.length === 0) {
139
- updatedSelectedCategory = null;
140
- }
141
- } else {
142
- if (singleclick) updatedSelectedNodes = [name];
143
- else updatedSelectedNodes.push(name);
144
- updatedSelectedCategory = category;
145
- }
146
- setSelected({
147
- nodes: updatedSelectedNodes,
148
- category: updatedSelectedCategory,
149
- });
150
- }
151
- };
152
-
153
- const { setSharedData } = useAppContext();
154
-
155
- useEffect(() => {
156
- if (
157
- val &&
158
- Array.isArray(selected.nodes) &&
159
- selected.nodes.length >= 0
160
- ) {
161
- setSharedData((prevSharedData) => ({
162
- ...prevSharedData,
163
- [val]: selected.nodes,
164
- }));
165
- }
166
- }, [selected, val, setSharedData]);
167
-
168
- return (
169
- <div
170
- key={id}
171
- style={{ ...style, ..._style }}
172
- className={className}>
173
- {title && <h3>{title}</h3>}
174
- <ReCharts
175
- options={{
176
- series: [
177
- {
178
- type: 'graph',
179
- layout: 'force',
180
- animation,
181
- draggable,
182
- label: {
183
- position: 'top',
184
- formatter: '{b}',
185
- show: true,
186
- },
187
- data: processedData,
188
- categories: data.categories,
189
- edges: data.edges,
190
- force: { repulsion, edgeLength },
191
- },
192
- ],
193
- }}
194
- style={inner_style}
195
- onEvents={{ click: onChartClick }}
196
- />
197
- </div>
198
- );
199
- }
200
-
201
- export default Macaron;
1
+ import React, { useState, useEffect, useMemo } from 'react';
2
+ import { useAppContext } from '../appContext';
3
+ import ReCharts from '../modules/echarts';
4
+
5
+ function processData(
6
+ nodes,
7
+ selected,
8
+ _symbolSize,
9
+ maxValue,
10
+ inner_color,
11
+ unclickable,
12
+ ) {
13
+ const { nodes: selectedNodes, category: selectedCategory } = selected;
14
+
15
+ return nodes.nodes.map((node) => {
16
+ const symbolSize =
17
+ typeof _symbolSize === 'number'
18
+ ? _symbolSize
19
+ : typeof _symbolSize === 'string'
20
+ ? _symbolSize === 'default'
21
+ ? (6 - node.category) * 6
22
+ : 10 + (parseFloat(node[_symbolSize]) / maxValue) * 30 ||
23
+ (6 - node.category) * 6
24
+ : (6 - node.category) * 6; // Fallback to default
25
+
26
+ const isSelected = selectedNodes.includes(node.name);
27
+ const isSameCategory = node.category === selectedCategory;
28
+ const isOriginalState =
29
+ selectedCategory === null && selectedNodes.length === 0;
30
+ const isUnclickable =
31
+ unclickable.includes(node.name) ||
32
+ unclickable.includes(node.category);
33
+ const opacity = isUnclickable
34
+ ? 0.8
35
+ : isOriginalState
36
+ ? 1
37
+ : isSelected
38
+ ? 1
39
+ : isSameCategory
40
+ ? 1
41
+ : 0.2;
42
+ const color = isUnclickable
43
+ ? 'gray'
44
+ : isOriginalState
45
+ ? `hsl(${node.category * 110}, 50%, 50%)`
46
+ : isSelected
47
+ ? inner_color.selected ?? 'red'
48
+ : isSameCategory
49
+ ? `hsl(${node.category * 100}, 50%, 50%)`
50
+ : inner_color.unselectable ?? 'grey';
51
+
52
+ return {
53
+ ...node,
54
+ symbolSize,
55
+ itemStyle: {
56
+ color,
57
+ opacity,
58
+ },
59
+ emphasis: {
60
+ focus: 'self',
61
+ itemStyle: {
62
+ color,
63
+ opacity,
64
+ },
65
+ label: {
66
+ position: 'insideTop',
67
+ show: true, // Show label
68
+ },
69
+ },
70
+ };
71
+ });
72
+ }
73
+
74
+ function Macaron({ props, style }) {
75
+ const { debug, style: _style, className } = props;
76
+ const { id, title, data } = props;
77
+
78
+ const {
79
+ animation = false,
80
+ draggable = true,
81
+ repulsion = 100,
82
+ edgeLength = 40,
83
+ height: inner_height = '93%',
84
+ width: inner_width = '100%',
85
+ unclickable = [],
86
+ symbolSize: _symbolSize = 'default',
87
+ color: inner_color = {
88
+ selected: 'red',
89
+ unselectable: 'grey',
90
+ },
91
+ singleclick = true,
92
+ } = props.config;
93
+
94
+ const [selected, setSelected] = useState({ nodes: [], category: null });
95
+ const { val = 'vnode' } = props;
96
+
97
+ const inner_style = {
98
+ border: debug ? '1px solid black' : 'none',
99
+ height: inner_height,
100
+ width: inner_width,
101
+ };
102
+
103
+ const maxValue = useMemo(() => {
104
+ const values = data.nodes.map(
105
+ (node) => parseFloat(node[_symbolSize]) || 50,
106
+ );
107
+ return Math.max(...values);
108
+ }, [data, _symbolSize]);
109
+
110
+ const processedData = useMemo(
111
+ () =>
112
+ processData(
113
+ data,
114
+ selected,
115
+ _symbolSize,
116
+ maxValue,
117
+ inner_color,
118
+ unclickable,
119
+ ),
120
+ [data, selected, _symbolSize, maxValue, inner_color, unclickable],
121
+ );
122
+
123
+ const onChartClick = (params) => {
124
+ const category = params.data.category;
125
+ const name = params.data.name;
126
+ if (
127
+ params.dataType === 'node' &&
128
+ !unclickable.includes(category) &&
129
+ !unclickable.includes(name) &&
130
+ (selected.category === null || category === selected.category)
131
+ ) {
132
+ let updatedSelectedNodes = [...selected.nodes];
133
+ let updatedSelectedCategory = selected.category;
134
+ if (selected.nodes.includes(name)) {
135
+ updatedSelectedNodes = updatedSelectedNodes.filter(
136
+ (nodeName) => nodeName !== name,
137
+ );
138
+ if (updatedSelectedNodes.length === 0) {
139
+ updatedSelectedCategory = null;
140
+ }
141
+ } else {
142
+ if (singleclick) updatedSelectedNodes = [name];
143
+ else updatedSelectedNodes.push(name);
144
+ updatedSelectedCategory = category;
145
+ }
146
+ setSelected({
147
+ nodes: updatedSelectedNodes,
148
+ category: updatedSelectedCategory,
149
+ });
150
+ }
151
+ };
152
+
153
+ const { setSharedData } = useAppContext();
154
+
155
+ // Only sync to sharedData when selection actually changes to non-empty
156
+ // Use JSON for stable comparison to avoid re-renders from new array references
157
+ const selectedNodesKey = JSON.stringify(selected.nodes);
158
+ useEffect(() => {
159
+ if (val) {
160
+ setSharedData((prevSharedData) => {
161
+ const prev = prevSharedData[val];
162
+ // Skip update if the value is already the same
163
+ if (JSON.stringify(prev) === selectedNodesKey) return prevSharedData;
164
+ return {
165
+ ...prevSharedData,
166
+ [val]: selected.nodes,
167
+ };
168
+ });
169
+ }
170
+ // eslint-disable-next-line react-hooks/exhaustive-deps
171
+ }, [selectedNodesKey, val, setSharedData]);
172
+
173
+ return (
174
+ <div
175
+ key={id}
176
+ style={{ ...style, ..._style }}
177
+ className={className}>
178
+ {title && <h3>{title}</h3>}
179
+ <ReCharts
180
+ options={{
181
+ series: [
182
+ {
183
+ type: 'graph',
184
+ layout: 'force',
185
+ animation,
186
+ draggable,
187
+ label: {
188
+ position: 'top',
189
+ formatter: '{b}',
190
+ show: true,
191
+ },
192
+ data: processedData,
193
+ categories: data.categories,
194
+ edges: data.edges,
195
+ force: { repulsion, edgeLength },
196
+ },
197
+ ],
198
+ }}
199
+ style={inner_style}
200
+ onEvents={{ click: onChartClick }}
201
+ />
202
+ </div>
203
+ );
204
+ }
205
+
206
+ export default Macaron;
@@ -1,56 +1,56 @@
1
- import React, { useEffect, useState } from 'react';
2
- import axios from 'axios';
3
- import { unified } from 'unified';
4
- import remarkParse from 'remark-parse';
5
- import remarkHtml from 'remark-html';
6
-
7
- function Markdown({ props, style }) {
8
- const { path } = props;
9
- const [markdownContent, setMarkdownContent] = useState('');
10
- const [error, setError] = useState(null);
11
-
12
- useEffect(() => {
13
- // Fetch the Markdown content from the specified path or file
14
- axios.get(path).then(
15
- (response) => {
16
- const markdown = response.data;
17
-
18
- // Create a new unified processor and use remark-parse and remark-html plugins
19
- unified()
20
- .use(remarkParse)
21
- .use(remarkHtml)
22
- .process(markdown, (err, file) => {
23
- if (err) {
24
- console.error('Error processing Markdown:', err);
25
- setError('Error processing Markdown');
26
- } else {
27
- // Set the HTML content to be rendered
28
- setMarkdownContent(String(file));
29
- }
30
- });
31
- },
32
- (error) => {
33
- console.error('Error fetching Markdown:', error);
34
- setError('Error fetching Markdown');
35
- }
36
- );
37
- }, [path]);
38
-
39
- if (error) {
40
- return (
41
- <div className='markdown-error' style={{ ...style }}>
42
- {error}
43
- </div>
44
- );
45
- }
46
-
47
- return (
48
- <div
49
- className='markdown-content'
50
- style={{ ...style }}
51
- dangerouslySetInnerHTML={{ __html: markdownContent }}
52
- />
53
- );
54
- }
55
-
56
- export default Markdown;
1
+ import React, { useEffect, useState } from 'react';
2
+ import axios from 'axios';
3
+ import { unified } from 'unified';
4
+ import remarkParse from 'remark-parse';
5
+ import remarkHtml from 'remark-html';
6
+
7
+ function Markdown({ props, style }) {
8
+ const { path } = props;
9
+ const [markdownContent, setMarkdownContent] = useState('');
10
+ const [error, setError] = useState(null);
11
+
12
+ useEffect(() => {
13
+ // Fetch the Markdown content from the specified path or file
14
+ axios.get(path).then(
15
+ (response) => {
16
+ const markdown = response.data;
17
+
18
+ // Create a new unified processor and use remark-parse and remark-html plugins
19
+ unified()
20
+ .use(remarkParse)
21
+ .use(remarkHtml)
22
+ .process(markdown, (err, file) => {
23
+ if (err) {
24
+ console.error('Error processing Markdown:', err);
25
+ setError('Error processing Markdown');
26
+ } else {
27
+ // Set the HTML content to be rendered
28
+ setMarkdownContent(String(file));
29
+ }
30
+ });
31
+ },
32
+ (error) => {
33
+ console.error('Error fetching Markdown:', error);
34
+ setError('Error fetching Markdown');
35
+ }
36
+ );
37
+ }, [path]);
38
+
39
+ if (error) {
40
+ return (
41
+ <div className='markdown-error' style={{ ...style }}>
42
+ {error}
43
+ </div>
44
+ );
45
+ }
46
+
47
+ return (
48
+ <div
49
+ className='markdown-content'
50
+ style={{ ...style }}
51
+ dangerouslySetInnerHTML={{ __html: markdownContent }}
52
+ />
53
+ );
54
+ }
55
+
56
+ export default Markdown;