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,42 +1,56 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
-
* @Date : 2023-12-21 13:52:36
|
|
4
|
-
* @FilePath : /visualifyjs/src/core/widgets/mapping.js
|
|
5
|
-
* @Description :
|
|
6
|
-
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import SearchBar from '../components/searchbar';
|
|
10
|
-
import NaiveHTML from '../components/html';
|
|
11
|
-
import Markdown from '../components/markdown';
|
|
12
|
-
import Browser from '../components/browser';
|
|
13
|
-
import Macaron from '../components/macaron';
|
|
14
|
-
import EChartSwitcher from '../modules/echartswitcher';
|
|
15
|
-
import ScatterL from '../components/scatterL';
|
|
16
|
-
import RatioBox from '../components/ratio';
|
|
17
|
-
import Selection from '../components/selection';
|
|
18
|
-
import Timeline from '../components/timeline';
|
|
19
|
-
import VisiumPlot from '../components/VisiumPlot';
|
|
20
|
-
import RePlotly from '../modules/replotly';
|
|
21
|
-
import List from '../components/list';
|
|
22
|
-
import DotBio from '../components/dotplot';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1
|
+
/*
|
|
2
|
+
* @Author : Lihao leolihao@arizona.edu
|
|
3
|
+
* @Date : 2023-12-21 13:52:36
|
|
4
|
+
* @FilePath : /visualifyjs/src/core/widgets/mapping.js
|
|
5
|
+
* @Description :
|
|
6
|
+
* Copyright (c) 2023 by Lihao (leolihao@arizona.edu), All Rights Reserved.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import SearchBar from '../components/searchbar';
|
|
10
|
+
import NaiveHTML from '../components/html';
|
|
11
|
+
import Markdown from '../components/markdown';
|
|
12
|
+
import Browser from '../components/browser';
|
|
13
|
+
import Macaron from '../components/macaron';
|
|
14
|
+
import EChartSwitcher from '../modules/echartswitcher';
|
|
15
|
+
import ScatterL from '../components/scatterL';
|
|
16
|
+
import RatioBox from '../components/ratio';
|
|
17
|
+
import Selection from '../components/selection';
|
|
18
|
+
import Timeline from '../components/timeline';
|
|
19
|
+
import VisiumPlot from '../components/VisiumPlot';
|
|
20
|
+
import RePlotly from '../modules/replotly';
|
|
21
|
+
import List from '../components/list';
|
|
22
|
+
import DotBio from '../components/dotplot';
|
|
23
|
+
import Scatter3D from '../components/Scatter3D';
|
|
24
|
+
import Bar3D from '../components/Bar3D';
|
|
25
|
+
import Surface3D from '../components/Surface3D';
|
|
26
|
+
import Line3D from '../components/Line3D';
|
|
27
|
+
import ThreeScene from '../components/ThreeScene';
|
|
28
|
+
import ThreeCustom from '../components/ThreeCustom';
|
|
29
|
+
|
|
30
|
+
const widgetMapping = {
|
|
31
|
+
// Add components here
|
|
32
|
+
SearchBar,
|
|
33
|
+
Echart: EChartSwitcher,
|
|
34
|
+
HTML: NaiveHTML,
|
|
35
|
+
Markdown,
|
|
36
|
+
Browser,
|
|
37
|
+
Macaron,
|
|
38
|
+
ScatterL,
|
|
39
|
+
RatioBox,
|
|
40
|
+
Selection,
|
|
41
|
+
Timeline,
|
|
42
|
+
Visium: VisiumPlot,
|
|
43
|
+
Plotly: RePlotly,
|
|
44
|
+
List,
|
|
45
|
+
DotBio,
|
|
46
|
+
// 3D Chart Components
|
|
47
|
+
scatter3d: Scatter3D,
|
|
48
|
+
bar3d: Bar3D,
|
|
49
|
+
surface3d: Surface3D,
|
|
50
|
+
line3d: Line3D,
|
|
51
|
+
// Three.js Components
|
|
52
|
+
threejs: ThreeScene,
|
|
53
|
+
threecustom: ThreeCustom,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default widgetMapping;
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Data Processing Web Worker
|
|
3
|
+
* @module core/workers/data-worker
|
|
4
|
+
*
|
|
5
|
+
* Handles data transformations, aggregations, and computations
|
|
6
|
+
* off the main thread for improved performance with large datasets.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Data transformation operations
|
|
11
|
+
*/
|
|
12
|
+
const DataOperations = {
|
|
13
|
+
/**
|
|
14
|
+
* Aggregate data using specified method
|
|
15
|
+
* @param {Array} data - Input data array
|
|
16
|
+
* @param {Object} config - Aggregation config
|
|
17
|
+
* @returns {number} Aggregated value
|
|
18
|
+
*/
|
|
19
|
+
aggregate(data, config) {
|
|
20
|
+
const { method = 'sum', field } = config;
|
|
21
|
+
const values = field ? data.map((item) => item[field]) : data;
|
|
22
|
+
|
|
23
|
+
switch (method) {
|
|
24
|
+
case 'sum':
|
|
25
|
+
return values.reduce((a, b) => a + (b || 0), 0);
|
|
26
|
+
case 'avg':
|
|
27
|
+
case 'mean':
|
|
28
|
+
return values.reduce((a, b) => a + (b || 0), 0) / values.length;
|
|
29
|
+
case 'min':
|
|
30
|
+
return Math.min(...values);
|
|
31
|
+
case 'max':
|
|
32
|
+
return Math.max(...values);
|
|
33
|
+
case 'count':
|
|
34
|
+
return values.length;
|
|
35
|
+
case 'median': {
|
|
36
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
37
|
+
const mid = Math.floor(sorted.length / 2);
|
|
38
|
+
return sorted.length % 2 !== 0
|
|
39
|
+
? sorted[mid]
|
|
40
|
+
: (sorted[mid - 1] + sorted[mid]) / 2;
|
|
41
|
+
}
|
|
42
|
+
case 'std': {
|
|
43
|
+
const mean = values.reduce((a, b) => a + b, 0) / values.length;
|
|
44
|
+
const variance =
|
|
45
|
+
values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) /
|
|
46
|
+
values.length;
|
|
47
|
+
return Math.sqrt(variance);
|
|
48
|
+
}
|
|
49
|
+
default:
|
|
50
|
+
throw new Error(`Unknown aggregation method: ${method}`);
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Filter data based on criteria
|
|
56
|
+
* @param {Array} data - Input data array
|
|
57
|
+
* @param {Object} criteria - Filter criteria
|
|
58
|
+
* @returns {Array} Filtered data
|
|
59
|
+
*/
|
|
60
|
+
filter(data, criteria) {
|
|
61
|
+
return data.filter((item) => {
|
|
62
|
+
for (const [field, condition] of Object.entries(criteria)) {
|
|
63
|
+
const value = item[field];
|
|
64
|
+
|
|
65
|
+
if (typeof condition === 'object') {
|
|
66
|
+
// Range filter: { min: 0, max: 100 }
|
|
67
|
+
if ('min' in condition && value < condition.min) return false;
|
|
68
|
+
if ('max' in condition && value > condition.max) return false;
|
|
69
|
+
|
|
70
|
+
// Comparison operators
|
|
71
|
+
if ('gt' in condition && !(value > condition.gt)) return false;
|
|
72
|
+
if ('gte' in condition && !(value >= condition.gte)) return false;
|
|
73
|
+
if ('lt' in condition && !(value < condition.lt)) return false;
|
|
74
|
+
if ('lte' in condition && !(value <= condition.lte)) return false;
|
|
75
|
+
if ('eq' in condition && value !== condition.eq) return false;
|
|
76
|
+
if ('ne' in condition && value === condition.ne) return false;
|
|
77
|
+
|
|
78
|
+
// Array includes
|
|
79
|
+
if ('in' in condition && !condition.in.includes(value))
|
|
80
|
+
return false;
|
|
81
|
+
if ('nin' in condition && condition.nin.includes(value))
|
|
82
|
+
return false;
|
|
83
|
+
} else {
|
|
84
|
+
// Direct equality
|
|
85
|
+
if (value !== condition) return false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return true;
|
|
89
|
+
});
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Sort data by fields
|
|
94
|
+
* @param {Array} data - Input data array
|
|
95
|
+
* @param {Array} sortConfig - Sort configuration
|
|
96
|
+
* @returns {Array} Sorted data
|
|
97
|
+
*/
|
|
98
|
+
sort(data, sortConfig) {
|
|
99
|
+
const sorts = Array.isArray(sortConfig) ? sortConfig : [sortConfig];
|
|
100
|
+
|
|
101
|
+
return [...data].sort((a, b) => {
|
|
102
|
+
for (const { field, order = 'asc' } of sorts) {
|
|
103
|
+
const aVal = a[field];
|
|
104
|
+
const bVal = b[field];
|
|
105
|
+
|
|
106
|
+
if (aVal === bVal) continue;
|
|
107
|
+
|
|
108
|
+
const comparison =
|
|
109
|
+
aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
|
|
110
|
+
|
|
111
|
+
return order === 'desc' ? -comparison : comparison;
|
|
112
|
+
}
|
|
113
|
+
return 0;
|
|
114
|
+
});
|
|
115
|
+
},
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Group data by field(s)
|
|
119
|
+
* @param {Array} data - Input data array
|
|
120
|
+
* @param {string|Array} fields - Field(s) to group by
|
|
121
|
+
* @returns {Object} Grouped data
|
|
122
|
+
*/
|
|
123
|
+
groupBy(data, fields) {
|
|
124
|
+
const fieldArray = Array.isArray(fields) ? fields : [fields];
|
|
125
|
+
const groups = {};
|
|
126
|
+
|
|
127
|
+
for (const item of data) {
|
|
128
|
+
const key = fieldArray.map((f) => item[f]).join('|');
|
|
129
|
+
if (!groups[key]) {
|
|
130
|
+
groups[key] = [];
|
|
131
|
+
}
|
|
132
|
+
groups[key].push(item);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return groups;
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Sample data for preview (stratified sampling)
|
|
140
|
+
* @param {Array} data - Input data array
|
|
141
|
+
* @param {number} sampleSize - Desired sample size
|
|
142
|
+
* @returns {Array} Sampled data
|
|
143
|
+
*/
|
|
144
|
+
sample(data, sampleSize) {
|
|
145
|
+
if (data.length <= sampleSize) return data;
|
|
146
|
+
|
|
147
|
+
const step = data.length / sampleSize;
|
|
148
|
+
const sampled = [];
|
|
149
|
+
|
|
150
|
+
for (let i = 0; i < sampleSize; i++) {
|
|
151
|
+
const index = Math.floor(i * step);
|
|
152
|
+
sampled.push(data[index]);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return sampled;
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Calculate statistics for numeric data
|
|
160
|
+
* @param {Array} data - Input data array
|
|
161
|
+
* @param {string} field - Field to analyze
|
|
162
|
+
* @returns {Object} Statistics
|
|
163
|
+
*/
|
|
164
|
+
statistics(data, field) {
|
|
165
|
+
const values = data.map((item) => item[field]).filter((v) => typeof v === 'number');
|
|
166
|
+
|
|
167
|
+
if (values.length === 0) {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const sum = values.reduce((a, b) => a + b, 0);
|
|
172
|
+
const mean = sum / values.length;
|
|
173
|
+
const sorted = [...values].sort((a, b) => a - b);
|
|
174
|
+
|
|
175
|
+
// Calculate variance and standard deviation
|
|
176
|
+
const variance =
|
|
177
|
+
values.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) /
|
|
178
|
+
values.length;
|
|
179
|
+
const std = Math.sqrt(variance);
|
|
180
|
+
|
|
181
|
+
return {
|
|
182
|
+
count: values.length,
|
|
183
|
+
sum,
|
|
184
|
+
mean,
|
|
185
|
+
min: sorted[0],
|
|
186
|
+
max: sorted[sorted.length - 1],
|
|
187
|
+
median:
|
|
188
|
+
sorted.length % 2 === 0
|
|
189
|
+
? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2
|
|
190
|
+
: sorted[Math.floor(sorted.length / 2)],
|
|
191
|
+
variance,
|
|
192
|
+
std,
|
|
193
|
+
q1: sorted[Math.floor(sorted.length * 0.25)],
|
|
194
|
+
q3: sorted[Math.floor(sorted.length * 0.75)],
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Parse CSV string to array
|
|
200
|
+
* @param {string} csv - CSV content
|
|
201
|
+
* @param {Object} options - Parse options
|
|
202
|
+
* @returns {Array} Parsed data
|
|
203
|
+
*/
|
|
204
|
+
parseCSV(csv, options = {}) {
|
|
205
|
+
const { delimiter = ',', header = true } = options;
|
|
206
|
+
const lines = csv.trim().split('\n');
|
|
207
|
+
|
|
208
|
+
if (lines.length === 0) return [];
|
|
209
|
+
|
|
210
|
+
const headers = header
|
|
211
|
+
? lines[0].split(delimiter).map((h) => h.trim())
|
|
212
|
+
: null;
|
|
213
|
+
const startRow = header ? 1 : 0;
|
|
214
|
+
|
|
215
|
+
return lines.slice(startRow).map((line) => {
|
|
216
|
+
const values = line.split(delimiter).map((v) => v.trim());
|
|
217
|
+
|
|
218
|
+
if (headers) {
|
|
219
|
+
const obj = {};
|
|
220
|
+
headers.forEach((h, i) => {
|
|
221
|
+
obj[h] = this._parseValue(values[i]);
|
|
222
|
+
});
|
|
223
|
+
return obj;
|
|
224
|
+
}
|
|
225
|
+
return values.map((v) => this._parseValue(v));
|
|
226
|
+
});
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Try to parse a value to appropriate type
|
|
231
|
+
* @private
|
|
232
|
+
* @param {string} value - String value
|
|
233
|
+
* @returns {any} Parsed value
|
|
234
|
+
*/
|
|
235
|
+
_parseValue(value) {
|
|
236
|
+
if (value === '' || value === undefined) return null;
|
|
237
|
+
if (value === 'true') return true;
|
|
238
|
+
if (value === 'false') return false;
|
|
239
|
+
|
|
240
|
+
const num = Number(value);
|
|
241
|
+
if (!isNaN(num) && value !== '') return num;
|
|
242
|
+
|
|
243
|
+
// Try date
|
|
244
|
+
const date = new Date(value);
|
|
245
|
+
if (!isNaN(date.getTime())) return date;
|
|
246
|
+
|
|
247
|
+
return value;
|
|
248
|
+
},
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Transform data using pipeline of operations
|
|
252
|
+
* @param {Array} data - Input data
|
|
253
|
+
* @param {Array} operations - Array of operations to apply
|
|
254
|
+
* @returns {Array} Transformed data
|
|
255
|
+
*/
|
|
256
|
+
pipeline(data, operations) {
|
|
257
|
+
let result = data;
|
|
258
|
+
|
|
259
|
+
for (const op of operations) {
|
|
260
|
+
const { type, config } = op;
|
|
261
|
+
|
|
262
|
+
switch (type) {
|
|
263
|
+
case 'filter':
|
|
264
|
+
result = this.filter(result, config);
|
|
265
|
+
break;
|
|
266
|
+
case 'sort':
|
|
267
|
+
result = this.sort(result, config);
|
|
268
|
+
break;
|
|
269
|
+
case 'groupBy':
|
|
270
|
+
result = this.groupBy(result, config);
|
|
271
|
+
break;
|
|
272
|
+
case 'sample':
|
|
273
|
+
result = this.sample(result, config.size);
|
|
274
|
+
break;
|
|
275
|
+
case 'map':
|
|
276
|
+
result = result.map(config.fn);
|
|
277
|
+
break;
|
|
278
|
+
default:
|
|
279
|
+
throw new Error(`Unknown operation: ${type}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return result;
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Handle incoming messages from main thread
|
|
289
|
+
*/
|
|
290
|
+
self.onmessage = function (event) {
|
|
291
|
+
const { type, taskId, payload } = event.data;
|
|
292
|
+
|
|
293
|
+
if (type !== 'task') {
|
|
294
|
+
self.postMessage({
|
|
295
|
+
type: 'error',
|
|
296
|
+
taskId,
|
|
297
|
+
error: { message: 'Unknown message type' },
|
|
298
|
+
});
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
try {
|
|
303
|
+
const { operation, data, config } = payload;
|
|
304
|
+
let result;
|
|
305
|
+
|
|
306
|
+
switch (operation) {
|
|
307
|
+
case 'aggregate':
|
|
308
|
+
result = DataOperations.aggregate(data, config);
|
|
309
|
+
break;
|
|
310
|
+
case 'filter':
|
|
311
|
+
result = DataOperations.filter(data, config);
|
|
312
|
+
break;
|
|
313
|
+
case 'sort':
|
|
314
|
+
result = DataOperations.sort(data, config);
|
|
315
|
+
break;
|
|
316
|
+
case 'groupBy':
|
|
317
|
+
result = DataOperations.groupBy(data, config);
|
|
318
|
+
break;
|
|
319
|
+
case 'sample':
|
|
320
|
+
result = DataOperations.sample(data, config.size);
|
|
321
|
+
break;
|
|
322
|
+
case 'statistics':
|
|
323
|
+
result = DataOperations.statistics(data, config.field);
|
|
324
|
+
break;
|
|
325
|
+
case 'parseCSV':
|
|
326
|
+
result = DataOperations.parseCSV(data, config);
|
|
327
|
+
break;
|
|
328
|
+
case 'pipeline':
|
|
329
|
+
result = DataOperations.pipeline(data, config);
|
|
330
|
+
break;
|
|
331
|
+
default:
|
|
332
|
+
throw new Error(`Unknown operation: ${operation}`);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
self.postMessage({
|
|
336
|
+
type: 'result',
|
|
337
|
+
taskId,
|
|
338
|
+
payload: result,
|
|
339
|
+
});
|
|
340
|
+
} catch (error) {
|
|
341
|
+
self.postMessage({
|
|
342
|
+
type: 'error',
|
|
343
|
+
taskId,
|
|
344
|
+
error: { message: error.message, stack: error.stack },
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
export default DataOperations;
|