visualifyjs 2.5.3-2.dev → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/mem/TIMELINE.md +36 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-external-script-solution.md +24 -0
- package/.claude/mem/notes/2026-02-11-3d-visualization-docs-fix-session-summary.md +43 -0
- package/.claude/mem/notes/2026-02-11-cli-fix-editor-command-alias.md +26 -0
- package/.claude/mem/notes/2026-02-11-phase-3-developer-experience-completed.md +51 -0
- package/.claude/mem/notes/2026-02-11-phase-4-web-workers-implementation-complete.md +59 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-3d-visualization-complete.md +50 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-2-committed-ready-for-phase-3.md +33 -0
- package/.claude/mem/notes/2026-02-11-visualify-phase-3-complete-developer-experience.md +52 -0
- package/.claude/mem/notes/2026-02-11-visualify-repository-cleanup-complete.md +28 -0
- package/.claude/mem/notes/2026-02-18-codebase-cleanup-docsify-plugin-documentation.md +37 -0
- package/.claude/mem/notes/2026-02-19-css-grid-layout-fix-displaycontents-on-vcontroller.md +18 -0
- package/.claude/mem/notes/2026-02-19-docsify-plugin-fixes-latex-and-visualify-code-bloc.md +26 -0
- package/.claude/mem/notes/2026-02-19-page-mode-docs-update-decisions.md +23 -0
- package/.claude/mem/notes/2026-02-19-react-context-infinite-re-render-loop-fix-pattern.md +31 -0
- package/.claude/mem/notes/2026-02-19-version-300-bump-and-build-fixes.md +32 -0
- package/.claude/mem/notes/2026-02-19-visualify-build-deployment-architecture-bug-fixes.md +25 -0
- package/.claude/mem/notes/2026-02-19-visualify-dist-iife-self-contained-build-config.md +30 -0
- package/.claude/mem/notes/2026-02-19-visualify-infinite-loop-i18n-fixes.md +31 -0
- package/.claude/mem/notes/2026-02-19-visualify-v3-bundle-splitting-docs-restructuring.md +32 -0
- package/.claude/mem/notes/2026-02-20-bundle-externalization-final-architecture.md +29 -0
- package/.claude/mem/notes/2026-02-20-chromium-page-fix-unstable-keys-and-double-event-b.md +27 -0
- package/.claude/mem/notes/2026-02-20-console-cleanup-bundle-optimization-commit.md +20 -0
- package/.claude/mem/notes/2026-02-20-dotbio-dot-plot-fix-useeffect-dependency.md +21 -0
- package/.claude/mem/notes/2026-02-20-public-folder-cleanup-and-readme-rewrite.md +25 -0
- package/.claude/mem/notes/2026-02-20-v300-release-and-beta-channel-strategy.md +29 -0
- package/.claude/mem/notes/2026-02-20-visium-background-image-unknown-legend-fix.md +19 -0
- package/.claude/mem/notes/2026-02-20-visualify-cdn-loader-bundle-externalization.md +34 -0
- package/.claude/mem/sessions/session-2026-02-20-031524.md +54 -0
- package/.claude/settings.local.json +21 -0
- package/.github/workflows/static.yml.bak +51 -51
- package/.sisyphus/boulder.json +65 -0
- package/.sisyphus/plans/phase-4-advanced-optimizations.md +217 -0
- package/LICENSE +674 -674
- package/README.md +94 -59
- package/config-overrides.js +31 -31
- package/dist/stats.html +4949 -0
- package/dist/visualify-3d.esm.js +1 -0
- package/dist/visualify-3d.js +1 -0
- package/dist/visualify-core.esm.js +1 -0
- package/dist/visualify-core.js +1 -0
- package/dist/visualify-docs.esm.js +1 -0
- package/dist/visualify-docs.js +1 -0
- package/dist/visualify-loader.js +1 -0
- package/dist/visualify-pages.esm.js +1 -0
- package/dist/visualify-pages.js +1 -0
- package/dist/visualify-portal.esm.js +1 -0
- package/dist/visualify-portal.js +1 -0
- package/dist/visualify-shared.js +26571 -0
- package/dist/visualify.js +1 -188
- package/docs/CHANGELOG.md +148 -0
- package/docs/cli/commands.md +513 -0
- package/docs/configuration/visualify-json.md +474 -0
- package/docs/docs/3d-visualization.md +374 -0
- package/docs/docs/CLI.md +303 -34
- package/docs/docs/README.md +65 -65
- package/docs/docs/Rechart/bar.md +190 -190
- package/docs/docs/Rechart/funnel.md +241 -241
- package/docs/docs/Rechart/line.md +355 -355
- package/docs/docs/Rechart/pie.md +225 -225
- package/docs/docs/Rechart/radar.md +253 -253
- package/docs/docs/Rechart/scatter.md +298 -298
- package/docs/docs/_404.md +51 -51
- package/docs/docs/_coverpage.md +11 -11
- package/docs/docs/_sidebar.md +54 -44
- package/docs/docs/components/dotBio.md +87 -34
- package/docs/docs/components/echart.md +171 -82
- package/docs/docs/components/html.md +61 -34
- package/docs/docs/components/macaron.md +156 -145
- package/docs/docs/components/markdown.md +42 -0
- package/docs/docs/components/more.md +183 -142
- package/docs/docs/components/plotly.md +132 -62
- package/docs/docs/components/scatterL.md +171 -70
- package/docs/docs/components/visium.md +112 -57
- package/docs/docs/configuration.md +121 -121
- package/docs/docs/deploy.md +31 -31
- package/docs/docs/docsify-plugin.md +655 -0
- package/docs/docs/hmr.md +165 -0
- package/docs/docs/i18n.md +332 -0
- package/docs/docs/log.md +30 -9
- package/docs/docs/more-pages.md +23 -23
- package/docs/docs/quickstart.md +148 -124
- package/docs/docs/rechart-attributes.md +74 -74
- package/docs/docs/rechart-basic-usage.md +160 -162
- package/docs/docs/theme.md +5 -5
- package/docs/docs/typescript.md +306 -0
- package/docs/docs/visual-editor.md +359 -0
- package/docs/index.html +85 -71
- package/docs/manifest.json +23 -23
- package/docs/migration/v3-migration.md +392 -0
- package/docs/static/css/fluff-stuff.css +169 -169
- package/docs/static/css/font-awesome.min.css +4 -4
- package/docs/static/css/visualify.css +6 -25
- package/docs/static/js/3d-viz-examples.js +181 -0
- package/docs/static/js/configuration.js +630 -448
- package/docs/static/js/visualify.js +1 -188
- package/package.json +106 -84
- package/rollup.config.mjs +766 -76
- package/src/_css/404.css +115 -115
- package/src/_css/App.css +37 -37
- package/src/_css/autoSuggestion.css +26 -26
- package/src/_css/circular-progress.css +32 -32
- package/src/_css/index.css +36 -36
- package/src/_css/modern.css +350 -25
- package/src/_media/corner.svg +8 -8
- package/src/_media/download.svg +3 -3
- package/src/_media/logo.svg +14 -14
- package/src/_test/App.test.js +15 -15
- package/src/_utils/reportWebVitals.js +13 -13
- package/src/a11y/README.md +177 -0
- package/src/a11y/aria-labels.js +339 -0
- package/src/a11y/color-contrast.js +535 -0
- package/src/a11y/index.js +197 -0
- package/src/a11y/keyboard-nav.js +523 -0
- package/src/a11y/styles.css +165 -0
- package/src/cli/commands/dev.js +214 -0
- package/src/cli/commands/docs.js +521 -0
- package/src/cli/commands/edit.js +379 -0
- package/src/cli/commands/init.js +213 -0
- package/src/cli/commands/portal.js +236 -0
- package/src/cli/dev-server.js +530 -0
- package/src/cli/hmr.js +456 -0
- package/src/cli/index.js +180 -0
- package/src/cli/utils/config.js +207 -0
- package/src/cli/utils/logger.js +241 -0
- package/src/config/defaults.ts +122 -0
- package/src/config/index.ts +72 -0
- package/src/config/loader.ts +478 -0
- package/src/config/schema.ts +227 -0
- package/src/config/validator.ts +337 -0
- package/src/core/appContext.js +34 -27
- package/src/core/components/Bar.js +383 -0
- package/src/core/components/Bar3D.js +473 -0
- package/src/core/components/LargeDatasetChart.js +296 -0
- package/src/core/components/Line3D.js +310 -0
- package/src/core/components/Scatter.js +392 -188
- package/src/core/components/Scatter3D.js +455 -0
- package/src/core/components/ScatterBio.js +601 -572
- package/src/core/components/Surface3D.js +326 -0
- package/src/core/components/ThreeCustom.js +648 -0
- package/src/core/components/ThreeScene.js +459 -0
- package/src/core/components/VisiumPlot.js +191 -165
- package/src/core/components/browser.js +42 -42
- package/src/core/components/dotplot.js +413 -413
- package/src/core/components/html.js +29 -29
- package/src/core/components/list.js +178 -178
- package/src/core/components/macaron.js +206 -201
- package/src/core/components/markdown.js +56 -56
- package/src/core/components/parser.scatterBio.js +582 -587
- package/src/core/components/ratio.js +82 -80
- package/src/core/components/scatterL.js +206 -173
- package/src/core/components/searchbar.js +156 -131
- package/src/core/components/selection.js +310 -193
- package/src/core/components/timeline.js +236 -281
- package/src/core/components/visium.js +114 -97
- package/src/core/data-processor.js +413 -0
- package/src/core/fetch/condfetch.js +82 -82
- package/src/core/fetch/fetch.js +92 -92
- package/src/core/fetch/json.js +29 -29
- package/src/core/fetch/vfetch.js +42 -42
- package/src/core/hmr-client.js +724 -0
- package/src/core/liveEditor.js +44 -44
- package/src/core/modules/codeEditorWithPreview.js +104 -104
- package/src/core/modules/echarts/common.js +20 -20
- package/src/core/modules/echarts/gl.js +228 -0
- package/src/core/modules/echarts/presetHandler.js +41 -41
- package/src/core/modules/echarts/presets/esodev.chromium.js +172 -172
- package/src/core/modules/echarts/presets/esodev.codex.js +130 -130
- package/src/core/modules/echarts/presets/esodev.visium.js +123 -123
- package/src/core/modules/echarts/presets/mmtrbc.js +186 -186
- package/src/core/modules/echarts.js +70 -71
- package/src/core/modules/echartsUtils.js +43 -43
- package/src/core/modules/echartswitcher.js +227 -152
- package/src/core/modules/replotly/presetHandler.js +24 -24
- package/src/core/modules/replotly/presets/minimum.js +18 -18
- package/src/core/modules/replotly/presets/mmtrbc.dot.js +114 -114
- package/src/core/modules/replotly/presets/mmtrbc.violin.js +100 -100
- package/src/core/modules/replotly.js +74 -71
- package/src/core/modules/threejs/Camera.js +373 -0
- package/src/core/modules/threejs/Lighting.js +459 -0
- package/src/core/modules/threejs/Renderer.js +364 -0
- package/src/core/modules/threejs/Scene.js +266 -0
- package/src/core/modules/threejs/index.js +155 -0
- package/src/core/pages/404.js +50 -50
- package/src/core/pages/error.js +27 -27
- package/src/core/pages/jsonPage.js +62 -62
- package/src/core/pages/loading.js +44 -44
- package/src/core/parser/echart.data.js +204 -183
- package/src/core/parser/echart.features.js +125 -125
- package/src/core/parser/echart.general.js +147 -147
- package/src/core/parser/echart.hilbert.js +57 -57
- package/src/core/parser/echart.parser.js +210 -210
- package/src/core/parser/echart.series.js +67 -67
- package/src/core/parser/echart.types.js +76 -76
- package/src/core/parser/plotly.config.js +10 -10
- package/src/core/parser/plotly.data.js +132 -132
- package/src/core/parser/plotly.layout.js +9 -9
- package/src/core/parser/plotly.violin.js +18 -18
- package/src/core/recharts.js +361 -62
- package/src/core/router/alias.js +49 -49
- package/src/core/router/jsonRouter.js +31 -31
- package/src/core/themes/modern.js +32 -32
- package/src/core/themes/themeSelector.js +33 -33
- package/src/core/visualify.js +213 -47
- package/src/core/widgets/circularProgress.js +23 -23
- package/src/core/widgets/controller.js +116 -83
- package/src/core/widgets/errorBoundary.js +36 -36
- package/src/core/widgets/footer.js +185 -177
- package/src/core/widgets/header.js +238 -234
- package/src/core/widgets/layout/Grid.js +31 -31
- package/src/core/widgets/layout.js +36 -36
- package/src/core/widgets/mapping.js +56 -42
- package/src/core/workers/data-worker.js +349 -0
- package/src/core/workers/worker-pool.js +396 -0
- package/src/docsify/bundle.js +215 -0
- package/src/docsify/markdown.js +271 -0
- package/src/docsify/plugin.js +268 -0
- package/src/editor/README.md +172 -0
- package/src/editor/components/ChartBuilder.jsx +341 -0
- package/src/editor/components/ChartTypeSidebar.jsx +91 -0
- package/src/editor/components/Editor.jsx +367 -0
- package/src/editor/components/Preview.jsx +446 -0
- package/src/editor/components/PropertyPanel.jsx +468 -0
- package/src/editor/components/StatusBar.jsx +85 -0
- package/src/editor/context/EditorContext.js +248 -0
- package/src/editor/hooks/useDebounce.js +32 -0
- package/src/editor/index.js +315 -0
- package/src/editor/styles/editor.css +637 -0
- package/src/editor/utils/chartValidator.js +263 -0
- package/src/entries/charts3d.js +70 -0
- package/src/entries/core.js +78 -0
- package/src/entries/docs.js +154 -0
- package/src/entries/pages.js +93 -0
- package/src/entries/portal.js +204 -0
- package/src/entries/shared.js +50 -0
- package/src/i18n/formatters.js +455 -0
- package/src/i18n/index.js +169 -0
- package/src/i18n/locales/ar.json +137 -0
- package/src/i18n/locales/de.json +137 -0
- package/src/i18n/locales/en.json +137 -0
- package/src/i18n/locales/es.json +137 -0
- package/src/i18n/locales/he.json +137 -0
- package/src/i18n/locales/zh.json +137 -0
- package/src/i18n/rtl.css +183 -0
- package/src/index.js +82 -62
- package/src/loader.js +103 -0
- package/src/setupTests.js +5 -5
- package/tsconfig.json +51 -0
- package/types/charts.d.ts +569 -0
- package/types/components.d.ts +441 -0
- package/types/config.d.ts +199 -0
- package/types/index.d.ts +353 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Docsify Markdown Processor for Visualify
|
|
3
|
+
* @module docsify/markdown
|
|
4
|
+
*
|
|
5
|
+
* Parses visualify code blocks in markdown and converts them
|
|
6
|
+
* to HTML with data attributes for chart mounting.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Default chart configuration
|
|
11
|
+
* @type {Object}
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_CONFIG = {
|
|
14
|
+
type: 'scatter',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Valid chart types
|
|
19
|
+
* @type {string[]}
|
|
20
|
+
*/
|
|
21
|
+
const VALID_CHART_TYPES = [
|
|
22
|
+
'scatter',
|
|
23
|
+
'scatter3d',
|
|
24
|
+
'line',
|
|
25
|
+
'bar',
|
|
26
|
+
'pie',
|
|
27
|
+
'heatmap',
|
|
28
|
+
'violin',
|
|
29
|
+
'dotplot',
|
|
30
|
+
'hilbert',
|
|
31
|
+
'visium',
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Validate and normalize chart configuration
|
|
36
|
+
* @param {Object} config - Raw configuration object
|
|
37
|
+
* @returns {Object} Normalized configuration
|
|
38
|
+
*/
|
|
39
|
+
function validateConfig(config) {
|
|
40
|
+
if (!config || typeof config !== 'object') {
|
|
41
|
+
console.warn('[VisualifyDocs] Invalid config, using defaults');
|
|
42
|
+
return { ...DEFAULT_CONFIG };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const normalized = { ...DEFAULT_CONFIG, ...config };
|
|
46
|
+
|
|
47
|
+
// Validate chart type
|
|
48
|
+
if (normalized.type && !VALID_CHART_TYPES.includes(normalized.type)) {
|
|
49
|
+
console.warn(
|
|
50
|
+
`[VisualifyDocs] Unknown chart type "${normalized.type}", defaulting to "scatter"`
|
|
51
|
+
);
|
|
52
|
+
normalized.type = 'scatter';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Ensure data property exists
|
|
56
|
+
if (!normalized.data && !normalized.src) {
|
|
57
|
+
console.warn('[VisualifyDocs] No data or src provided, chart may fail to render');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return normalized;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Parse JSON safely with error handling
|
|
65
|
+
* @param {string} json - JSON string to parse
|
|
66
|
+
* @param {string} [context] - Context for error messages
|
|
67
|
+
* @returns {Object|null} Parsed object or null on error
|
|
68
|
+
*/
|
|
69
|
+
function safeJsonParse(json, context = 'unknown') {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(json);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
console.warn(`[VisualifyDocs] JSON parse error in ${context}:`, err.message);
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Generate a unique ID for chart containers
|
|
80
|
+
* @returns {string} Unique ID
|
|
81
|
+
*/
|
|
82
|
+
function generateChartId() {
|
|
83
|
+
return `visualify-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Process inline visualify configuration
|
|
88
|
+
* @param {string} code - Code block content (JSON)
|
|
89
|
+
* @returns {string} HTML output
|
|
90
|
+
*/
|
|
91
|
+
function processInlineConfig(code) {
|
|
92
|
+
const config = safeJsonParse(code, 'inline config');
|
|
93
|
+
|
|
94
|
+
if (!config) {
|
|
95
|
+
return renderError('Invalid JSON in visualify code block');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const normalizedConfig = validateConfig(config);
|
|
99
|
+
const chartId = generateChartId();
|
|
100
|
+
|
|
101
|
+
return renderChartContainer(chartId, normalizedConfig);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Process external file reference
|
|
106
|
+
* @param {Object} config - Configuration with src property
|
|
107
|
+
* @returns {string} HTML output
|
|
108
|
+
*/
|
|
109
|
+
function processExternalFile(config) {
|
|
110
|
+
const chartId = generateChartId();
|
|
111
|
+
return renderChartContainer(chartId, config);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Render chart container HTML
|
|
116
|
+
* @param {string} id - Unique chart ID
|
|
117
|
+
* @param {Object} config - Chart configuration
|
|
118
|
+
* @returns {string} HTML string
|
|
119
|
+
*/
|
|
120
|
+
function renderChartContainer(id, config) {
|
|
121
|
+
const configJson = JSON.stringify(config).replace(/"/g, '"');
|
|
122
|
+
const { type = 'scatter' } = config;
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
`<div class="visualify-chart-wrapper" data-visualify-type="${type}">` +
|
|
126
|
+
`<div ` +
|
|
127
|
+
`id="${id}" ` +
|
|
128
|
+
`class="visualify-chart-container" ` +
|
|
129
|
+
`data-visualify="${configJson}" ` +
|
|
130
|
+
`style="width: 100%; min-height: 400px;"` +
|
|
131
|
+
`></div>` +
|
|
132
|
+
`</div>`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Render error message HTML
|
|
138
|
+
* @param {string} message - Error message
|
|
139
|
+
* @returns {string} HTML string
|
|
140
|
+
*/
|
|
141
|
+
function renderError(message) {
|
|
142
|
+
return (
|
|
143
|
+
`<div class="visualify-error" style="` +
|
|
144
|
+
`padding: 16px; ` +
|
|
145
|
+
`border: 1px solid #ff4d4f; ` +
|
|
146
|
+
`border-radius: 4px; ` +
|
|
147
|
+
`background: #fff2f0; ` +
|
|
148
|
+
`color: #cf1322; ` +
|
|
149
|
+
`margin: 16px 0;` +
|
|
150
|
+
`">` +
|
|
151
|
+
`<strong>Visualify Error:</strong> ${escapeHtml(message)}` +
|
|
152
|
+
`</div>`
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Escape HTML special characters
|
|
158
|
+
* @param {string} text - Text to escape
|
|
159
|
+
* @returns {string} Escaped text
|
|
160
|
+
*/
|
|
161
|
+
function escapeHtml(text) {
|
|
162
|
+
const div = typeof document !== 'undefined' ? document.createElement('div') : null;
|
|
163
|
+
if (div) {
|
|
164
|
+
div.textContent = text;
|
|
165
|
+
return div.innerHTML;
|
|
166
|
+
}
|
|
167
|
+
// Server-side fallback
|
|
168
|
+
return text
|
|
169
|
+
.replace(/&/g, '&')
|
|
170
|
+
.replace(/</g, '<')
|
|
171
|
+
.replace(/>/g, '>')
|
|
172
|
+
.replace(/"/g, '"')
|
|
173
|
+
.replace(/'/g, ''');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Process visualify code block content
|
|
178
|
+
* @param {string} code - Code block content
|
|
179
|
+
* @returns {string} HTML output
|
|
180
|
+
*/
|
|
181
|
+
function processMarkdown(code) {
|
|
182
|
+
if (!code || typeof code !== 'string') {
|
|
183
|
+
return renderError('Empty visualify code block');
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const trimmedCode = code.trim();
|
|
187
|
+
|
|
188
|
+
if (!trimmedCode) {
|
|
189
|
+
return renderError('Empty visualify code block');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Try to parse as JSON
|
|
193
|
+
const config = safeJsonParse(trimmedCode, 'markdown processor');
|
|
194
|
+
|
|
195
|
+
if (!config) {
|
|
196
|
+
return renderError('Invalid JSON in visualify code block. Ensure your configuration is valid JSON.');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Check for external file reference
|
|
200
|
+
if (config.src) {
|
|
201
|
+
return processExternalFile(config);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Process inline configuration
|
|
205
|
+
return processInlineConfig(trimmedCode);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Process visualify code blocks in full markdown content
|
|
210
|
+
* Useful for pre-processing before Docsify renders
|
|
211
|
+
* @param {string} content - Full markdown content
|
|
212
|
+
* @returns {string} Processed markdown with HTML placeholders
|
|
213
|
+
*/
|
|
214
|
+
function processVisualifyBlocks(content) {
|
|
215
|
+
if (!content || typeof content !== 'string') {
|
|
216
|
+
return content;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Match visualify code blocks
|
|
220
|
+
const visualifyRegex = /```visualify\n([\s\S]*?)```/g;
|
|
221
|
+
|
|
222
|
+
return content.replace(visualifyRegex, (match, code) => {
|
|
223
|
+
return processMarkdown(code);
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Extract visualify configurations from markdown
|
|
229
|
+
* Useful for search indexing or pre-loading
|
|
230
|
+
* @param {string} content - Markdown content
|
|
231
|
+
* @returns {Array<Object>} Array of chart configurations
|
|
232
|
+
*/
|
|
233
|
+
function extractConfigs(content) {
|
|
234
|
+
if (!content || typeof content !== 'string') {
|
|
235
|
+
return [];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const configs = [];
|
|
239
|
+
const visualifyRegex = /```visualify\n([\s\S]*?)```/g;
|
|
240
|
+
let match;
|
|
241
|
+
|
|
242
|
+
while ((match = visualifyRegex.exec(content)) !== null) {
|
|
243
|
+
const config = safeJsonParse(match[1], 'config extraction');
|
|
244
|
+
if (config) {
|
|
245
|
+
configs.push(validateConfig(config));
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return configs;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Check if content has visualify blocks (fast check)
|
|
254
|
+
* @param {string} content - Markdown content
|
|
255
|
+
* @returns {boolean}
|
|
256
|
+
*/
|
|
257
|
+
function hasVisualifyBlocks(content) {
|
|
258
|
+
return typeof content === 'string' && content.includes('```visualify');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export {
|
|
262
|
+
processMarkdown,
|
|
263
|
+
processVisualifyBlocks,
|
|
264
|
+
extractConfigs,
|
|
265
|
+
validateConfig,
|
|
266
|
+
hasVisualifyBlocks,
|
|
267
|
+
DEFAULT_CONFIG,
|
|
268
|
+
VALID_CHART_TYPES,
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
export default processMarkdown;
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Docsify Plugin Hook for Visualify
|
|
3
|
+
* @module docsify/plugin
|
|
4
|
+
*
|
|
5
|
+
* Hooks into Docsify's lifecycle to process visualify code blocks
|
|
6
|
+
* and auto-mount charts with data-visualify attribute.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { processMarkdown } from './markdown';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Chart instance registry for cleanup
|
|
13
|
+
* @type {WeakMap<Element, Object>}
|
|
14
|
+
*/
|
|
15
|
+
const chartRegistry = new WeakMap();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Lazy-loaded Visualify components
|
|
19
|
+
* @type {Object|null}
|
|
20
|
+
*/
|
|
21
|
+
let VisualifyComponents = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Loading promise to prevent duplicate loads
|
|
25
|
+
* @type {Promise|null}
|
|
26
|
+
*/
|
|
27
|
+
let loadPromise = null;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Lazy load Visualify components only when needed
|
|
31
|
+
* @returns {Promise<Object>} Visualify components
|
|
32
|
+
*/
|
|
33
|
+
async function loadVisualifyComponents() {
|
|
34
|
+
if (VisualifyComponents) {
|
|
35
|
+
return VisualifyComponents;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (loadPromise) {
|
|
39
|
+
return loadPromise;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
loadPromise = import('../core/recharts')
|
|
43
|
+
.then((module) => {
|
|
44
|
+
VisualifyComponents = {
|
|
45
|
+
Recharts: module.default,
|
|
46
|
+
};
|
|
47
|
+
return VisualifyComponents;
|
|
48
|
+
})
|
|
49
|
+
.catch((err) => {
|
|
50
|
+
console.error('[VisualifyDocs] Failed to load Visualify components:', err);
|
|
51
|
+
throw err;
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
return loadPromise;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Mount a chart on a single element
|
|
59
|
+
* @param {Element} el - DOM element to mount chart on
|
|
60
|
+
* @param {Object} [config] - Optional config (parsed from data-visualify if not provided)
|
|
61
|
+
*/
|
|
62
|
+
async function mountChart(el, config) {
|
|
63
|
+
// Skip if already mounted
|
|
64
|
+
if (el.dataset.visualifyMounted === 'true') {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const chartConfig = config || JSON.parse(el.dataset.visualify || '{}');
|
|
70
|
+
|
|
71
|
+
// Handle external file reference
|
|
72
|
+
if (chartConfig.src) {
|
|
73
|
+
const response = await fetch(chartConfig.src);
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
throw new Error(`Failed to fetch ${chartConfig.src}: ${response.statusText}`);
|
|
76
|
+
}
|
|
77
|
+
const externalConfig = await response.json();
|
|
78
|
+
Object.assign(chartConfig, externalConfig);
|
|
79
|
+
delete chartConfig.src;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Load Visualify components lazily
|
|
83
|
+
const { Recharts } = await loadVisualifyComponents();
|
|
84
|
+
|
|
85
|
+
// Create and mount chart
|
|
86
|
+
const chart = new Recharts(chartConfig);
|
|
87
|
+
chart.mount(el);
|
|
88
|
+
|
|
89
|
+
// Track for cleanup
|
|
90
|
+
chartRegistry.set(el, chart);
|
|
91
|
+
el.dataset.visualifyMounted = 'true';
|
|
92
|
+
|
|
93
|
+
// Store config for potential re-mounting
|
|
94
|
+
el.dataset.visualify = JSON.stringify(chartConfig);
|
|
95
|
+
} catch (err) {
|
|
96
|
+
console.error('[VisualifyDocs] Failed to mount chart:', err);
|
|
97
|
+
|
|
98
|
+
// Display error in place of chart
|
|
99
|
+
el.innerHTML = `<div style="
|
|
100
|
+
padding: 16px;
|
|
101
|
+
border: 1px solid #ff4d4f;
|
|
102
|
+
border-radius: 4px;
|
|
103
|
+
background: #fff2f0;
|
|
104
|
+
color: #cf1322;
|
|
105
|
+
">
|
|
106
|
+
<strong>Visualify Error:</strong> ${err.message}
|
|
107
|
+
</div>`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Mount all charts in a container
|
|
113
|
+
* @param {Element} [container] - Container element (defaults to document)
|
|
114
|
+
*/
|
|
115
|
+
async function mountAllCharts(container = document) {
|
|
116
|
+
const elements = container.querySelectorAll('[data-visualify]:not([data-visualify-mounted="true"])');
|
|
117
|
+
|
|
118
|
+
if (elements.length === 0) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Load components once for all charts
|
|
123
|
+
await loadVisualifyComponents();
|
|
124
|
+
|
|
125
|
+
// Mount all charts
|
|
126
|
+
const mountPromises = Array.from(elements).map((el) => mountChart(el));
|
|
127
|
+
await Promise.all(mountPromises);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Cleanup charts in a container (for SPA navigation)
|
|
132
|
+
* @param {Element} [container] - Container element (defaults to document)
|
|
133
|
+
*/
|
|
134
|
+
function cleanupCharts(container = document) {
|
|
135
|
+
const elements = container.querySelectorAll('[data-visualify]');
|
|
136
|
+
|
|
137
|
+
elements.forEach((el) => {
|
|
138
|
+
const chart = chartRegistry.get(el);
|
|
139
|
+
if (chart && typeof chart.dispose === 'function') {
|
|
140
|
+
chart.dispose();
|
|
141
|
+
}
|
|
142
|
+
chartRegistry.delete(el);
|
|
143
|
+
el.dataset.visualifyMounted = 'false';
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Check if markdown contains visualify code blocks
|
|
149
|
+
* @param {string} content - Markdown content
|
|
150
|
+
* @returns {boolean}
|
|
151
|
+
*/
|
|
152
|
+
function hasVisualifyBlocks(content) {
|
|
153
|
+
return /```visualify\n/.test(content);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Docsify plugin install function
|
|
158
|
+
* @param {Object} hook - Docsify hook object
|
|
159
|
+
* @param {Object} vm - Docsify vm instance
|
|
160
|
+
*/
|
|
161
|
+
function install(hook, vm) {
|
|
162
|
+
// Initialize - called before Docsify starts
|
|
163
|
+
hook.init(function () {
|
|
164
|
+
console.log('[VisualifyDocs] Initializing Docsify plugin...');
|
|
165
|
+
|
|
166
|
+
// Add custom markdown configuration
|
|
167
|
+
if (window.$docsify && window.$docsify.markdown) {
|
|
168
|
+
const originalRenderer = window.$docsify.markdown.renderer;
|
|
169
|
+
|
|
170
|
+
window.$docsify.markdown.renderer = {
|
|
171
|
+
...originalRenderer,
|
|
172
|
+
code: function (code, lang) {
|
|
173
|
+
if (lang === 'visualify') {
|
|
174
|
+
return processMarkdown(code);
|
|
175
|
+
}
|
|
176
|
+
// Fall back to original renderer for other languages
|
|
177
|
+
if (originalRenderer && originalRenderer.code) {
|
|
178
|
+
return originalRenderer.code.call(this, code, lang);
|
|
179
|
+
}
|
|
180
|
+
return `<pre><code class="lang-${lang}">${code}</code></pre>`;
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// Before each page load - cleanup previous charts
|
|
187
|
+
hook.beforeEach(function (content) {
|
|
188
|
+
// Check if we need to load Visualify (optimization)
|
|
189
|
+
if (hasVisualifyBlocks(content)) {
|
|
190
|
+
// Preload components in background
|
|
191
|
+
loadVisualifyComponents().catch(() => {
|
|
192
|
+
// Silently fail - will retry on mount
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return content;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// After each markdown parsing - process any remaining blocks
|
|
199
|
+
hook.afterEach(function (html, next) {
|
|
200
|
+
// If markdown renderer didn't catch all blocks (e.g., via plugin order)
|
|
201
|
+
// We can process them here as a fallback
|
|
202
|
+
next(html);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Mounted - initial page load
|
|
206
|
+
hook.mounted(function () {
|
|
207
|
+
console.log('[VisualifyDocs] Docsify mounted, scanning for charts...');
|
|
208
|
+
mountAllCharts();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
// Done each - after each route change (SPA navigation)
|
|
212
|
+
hook.doneEach(function () {
|
|
213
|
+
console.log('[VisualifyDocs] Route changed, mounting charts...');
|
|
214
|
+
mountAllCharts();
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
// Destroyed - cleanup when leaving
|
|
218
|
+
hook.destroyed(function () {
|
|
219
|
+
console.log('[VisualifyDocs] Cleaning up charts...');
|
|
220
|
+
cleanupCharts();
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Global API for manual chart mounting
|
|
226
|
+
*/
|
|
227
|
+
const VisualifyDocsify = {
|
|
228
|
+
install,
|
|
229
|
+
mountChart,
|
|
230
|
+
mountAllCharts,
|
|
231
|
+
cleanupCharts,
|
|
232
|
+
loadVisualifyComponents,
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Check if an element has a mounted chart
|
|
236
|
+
* @param {Element} el - DOM element
|
|
237
|
+
* @returns {boolean}
|
|
238
|
+
*/
|
|
239
|
+
isMounted(el) {
|
|
240
|
+
return el.dataset.visualifyMounted === 'true';
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Get chart instance for an element
|
|
245
|
+
* @param {Element} el - DOM element
|
|
246
|
+
* @returns {Object|null}
|
|
247
|
+
*/
|
|
248
|
+
getChart(el) {
|
|
249
|
+
return chartRegistry.get(el) || null;
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Version info
|
|
254
|
+
*/
|
|
255
|
+
version: process.env.VISUALIFY_VERSION || 'dev',
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// Auto-install if Docsify is present
|
|
259
|
+
if (typeof window !== 'undefined' && window.$docsify) {
|
|
260
|
+
window.$docsify.plugins = [].concat(
|
|
261
|
+
window.$docsify.plugins || [],
|
|
262
|
+
install
|
|
263
|
+
);
|
|
264
|
+
console.log('[VisualifyDocs] Auto-registered with Docsify');
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export default VisualifyDocsify;
|
|
268
|
+
export { install, mountChart, mountAllCharts, cleanupCharts, loadVisualifyComponents };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Visualify Visual Editor
|
|
2
|
+
|
|
3
|
+
A visual configuration editor for Visualify.js that makes it easy to create and edit chart configurations without writing JSON.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Drag-and-Drop Interface**: Build charts by dragging chart types from the sidebar
|
|
8
|
+
- **Property Panels**: Dynamic forms for each chart type (2D and 3D)
|
|
9
|
+
- **Live Preview**: Real-time chart rendering as you edit
|
|
10
|
+
- **Import/Export**: Load and save `visualify.json` configurations
|
|
11
|
+
- **Undo/Redo History**: Full editing history with keyboard shortcuts
|
|
12
|
+
- **Auto-Save**: Automatic saving to localStorage
|
|
13
|
+
- **Responsive Design**: Works on different screen sizes
|
|
14
|
+
|
|
15
|
+
## Supported Chart Types
|
|
16
|
+
|
|
17
|
+
### 2D Charts
|
|
18
|
+
- Scatter
|
|
19
|
+
- Bar
|
|
20
|
+
- Line
|
|
21
|
+
- Pie
|
|
22
|
+
- Radar
|
|
23
|
+
- Funnel
|
|
24
|
+
- Heatmap
|
|
25
|
+
- Box Plot
|
|
26
|
+
|
|
27
|
+
### 3D Charts
|
|
28
|
+
- 3D Scatter
|
|
29
|
+
- 3D Bar
|
|
30
|
+
- 3D Surface
|
|
31
|
+
- 3D Line
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### CLI Command
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Open editor with default config
|
|
39
|
+
visualify edit
|
|
40
|
+
|
|
41
|
+
# Open specific config file
|
|
42
|
+
visualify edit my-config.json
|
|
43
|
+
|
|
44
|
+
# Custom port
|
|
45
|
+
visualify edit --port 4000
|
|
46
|
+
|
|
47
|
+
# Don't open browser automatically
|
|
48
|
+
visualify edit --no-open
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Programmatic Usage
|
|
52
|
+
|
|
53
|
+
```javascript
|
|
54
|
+
import { mountEditor } from './editor';
|
|
55
|
+
|
|
56
|
+
// Mount editor to a DOM element
|
|
57
|
+
mountEditor('#editor-container', {
|
|
58
|
+
config: {
|
|
59
|
+
version: '3.0.0',
|
|
60
|
+
charts: [],
|
|
61
|
+
layout: { type: 'grid', rows: 1, cols: 1 },
|
|
62
|
+
theme: 'modern'
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## UI Layout
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
+------------------------------------------+
|
|
71
|
+
| Toolbar (New, Open, Save, Export, Undo) |
|
|
72
|
+
+----------+----------------+--------------+
|
|
73
|
+
| | | |
|
|
74
|
+
| Chart | Canvas | Properties |
|
|
75
|
+
| Types | (D&D) | Panel |
|
|
76
|
+
| | | |
|
|
77
|
+
+----------+----------------+--------------+
|
|
78
|
+
| Status Bar (Errors, Auto-save status) |
|
|
79
|
+
+------------------------------------------+
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Keyboard Shortcuts
|
|
83
|
+
|
|
84
|
+
| Shortcut | Action |
|
|
85
|
+
|----------|--------|
|
|
86
|
+
| `Ctrl/Cmd + Z` | Undo |
|
|
87
|
+
| `Ctrl/Cmd + Y` | Redo |
|
|
88
|
+
| `Ctrl/Cmd + Shift + Z` | Redo (alternative) |
|
|
89
|
+
| `Ctrl/Cmd + S` | Export configuration |
|
|
90
|
+
| `Escape` | Close modals |
|
|
91
|
+
|
|
92
|
+
## File Structure
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
editor/
|
|
96
|
+
├── index.js # Main entry point
|
|
97
|
+
├── context/
|
|
98
|
+
│ └── EditorContext.js # React context for state management
|
|
99
|
+
├── components/
|
|
100
|
+
│ ├── Editor.jsx # Main editor UI
|
|
101
|
+
│ ├── ChartBuilder.jsx # Drag-and-drop canvas
|
|
102
|
+
│ ├── ChartTypeSidebar.jsx # Chart type selector
|
|
103
|
+
│ ├── PropertyPanel.jsx # Property editor
|
|
104
|
+
│ ├── Preview.jsx # Live preview
|
|
105
|
+
│ └── StatusBar.jsx # Status bar
|
|
106
|
+
├── utils/
|
|
107
|
+
│ └── chartValidator.js # Configuration validation
|
|
108
|
+
├── styles/
|
|
109
|
+
│ └── editor.css # Editor styles
|
|
110
|
+
└── README.md # This file
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Architecture
|
|
114
|
+
|
|
115
|
+
### State Management
|
|
116
|
+
|
|
117
|
+
The editor uses React Context for state management with the following structure:
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
{
|
|
121
|
+
config: {
|
|
122
|
+
version: '3.0.0',
|
|
123
|
+
charts: [...],
|
|
124
|
+
layout: {...},
|
|
125
|
+
theme: 'modern'
|
|
126
|
+
},
|
|
127
|
+
selectedChartId: string | null,
|
|
128
|
+
history: {
|
|
129
|
+
past: [...],
|
|
130
|
+
present: {...},
|
|
131
|
+
future: [...]
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Actions
|
|
137
|
+
|
|
138
|
+
- `setConfig(config)` - Replace entire configuration
|
|
139
|
+
- `addChart(chart)` - Add a new chart
|
|
140
|
+
- `updateChart(id, updates)` - Update chart properties
|
|
141
|
+
- `removeChart(id)` - Remove a chart
|
|
142
|
+
- `setSelectedChart(id)` - Select a chart for editing
|
|
143
|
+
- `undo()` / `redo()` - History navigation
|
|
144
|
+
|
|
145
|
+
## Validation
|
|
146
|
+
|
|
147
|
+
Charts are validated in real-time with checks for:
|
|
148
|
+
|
|
149
|
+
- Required fields (type, data)
|
|
150
|
+
- Data format compatibility
|
|
151
|
+
- 3D WebGL support
|
|
152
|
+
- Configuration completeness
|
|
153
|
+
|
|
154
|
+
## Building
|
|
155
|
+
|
|
156
|
+
The editor is built as a React application and bundled for distribution:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Development
|
|
160
|
+
npm run editor:dev
|
|
161
|
+
|
|
162
|
+
# Build
|
|
163
|
+
npm run editor:build
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Browser Support
|
|
167
|
+
|
|
168
|
+
- Chrome/Edge 80+
|
|
169
|
+
- Firefox 75+
|
|
170
|
+
- Safari 13+
|
|
171
|
+
|
|
172
|
+
3D charts require WebGL support.
|