项目:html5-dataviz | 版本:v1.0 | 生成日期:2026-10-05 | 依据:源码分析
html5-dataviz(站点品牌名 DevCanvas Dataviz,见 src/components/layout/AppHeader.vue 中的品牌文案与 package.json 的 name 字段)是一个纯前端、无后端依赖的数据可视化案例合集站点。它把两类可视化资产整合在同一个 Vue 3 单页应用里:
.vue 文件;src/config/bigscreenData.ts 的 bigscreenList),覆盖政务、工业、公安、金融、消防、农业、物流、生态、物联网、3D 可视化等行业场景。项目 README.md 将其概括为"数据可视化站点(纯前端静态版):大屏模板集 + ECharts/AntV 图表示例库"。从源码痕迹看(src/api/chart-examples.ts 注释"语义对齐原后端"、scripts/slim-chart-json.mjs 注释"编辑能力移除后,SFC 是唯一真源"),本项目此前依赖一个配套后端(server)提供图表示例数据,2026-10 完成了"去后端化"改造:所有元数据固化为 src/data/charts/*.json 三个静态 JSON,所有示例固化为 src/chart-examples/ 下的本地 .vue 单文件组件,站点可整体托管在任意静态服务器或内网环境(smoke 脚本 scripts/smoke.mjs 甚至把"运行时零外链请求"作为硬性断言)。
目标用户:
src/components/datav/ 组件族);三个图表库的元数据分别存放在 src/data/charts/echarts.json(348 条)、src/data/charts/antv.json(351 条)、src/data/charts/three.json(989 条),数量由守恒测试 src/data/charts/__tests__/charts-data.test.ts 与 three-data.test.ts 硬编码锁定。其中"本地 SFC"指在 src/chart-examples/{library}/ 下存在同名 {id}.vue 文件、由 src/chart-examples/manifest.ts(及 three-manifest.ts)索引的条目;"JSON 兜底"指无本地 SFC、渲染时走 ChartExampleRenderer 对 JSON 内嵌代码字符串求值的条目(echarts 54 条 + antv 17 条,由 scripts/slim-chart-json.mjs 的判定逻辑保留代码字段)。
| 图表库 | 案例总数 | 本地 SFC | JSON 兜底 | 分类数 | 分类示例(数量靠前) |
|---|---|---|---|---|---|
| echarts | 348 | 294 | 54 | 37 | 自定义系列(约 30)、柱状图(约 60)、折线图(约 40)、散点图(约 30)、地图(约 20)、关系图(11)、饼图(15)、矩阵图(14)、地球仪(9)等 |
| antv | 351 | 334 | 17 | 51 | 柱状图(约 60)、折线图(约 30)、面积图(约 20)、案例 cases(14)、热力图(7)、双轴图 dual-axes(约 25)、微型图 tiny-*(11)等 |
| three | 989 | 989 | 0 | 61 | WebGPU(213)、shader(88)、WebGL(78)、application(61)、材质(54)、加载器(54)、basic(52)、后期处理(26)、粒子(24)、WebXR(26)等 |
| 合计 | 1688 | 1617 | 71 | 149 | — |
大屏模板统计(数据源 src/config/bigscreenData.ts):
| 类别 | 数量 | 代表大屏(id) |
|---|---|---|
| 数据仪表盘 | 6 | business-dashboard、report-dashboard、dashboard、echarts-vision、mobile-sales-dashboard |
| 3D可视化 | 4 | sc-datav-demo0 ~ demo3(3D 四川地图系列、3D 风力涡轮机) |
| 企业通用 | 3 | cool-data-center、sales-analysis、data-analysis-template |
| 政务 | 2 | smart-center-stats、command-center |
| 工业 / 公安 / 金融 / 消防 / 农业 / 物流 / 生态 / 物联网 | 各 1 | pressure-vessel、police-monitor、bank-data-viz、fire-monitor、tea-traceability、logistics-center、nature-reserve、ioftv-bigscreen |
注:echarts/antv 的"分类数"来自 JSON 全量统计(含兜底条目),运行时侧边栏分类树由
src/api/chart-examples.ts的getChartCategories()聚合生成,因兜底条目一并计入,两侧一致。
以下均摘自 package.json(dependencies / devDependencies)并在源码中核实了实际用途:
| 类别 | 选型 | 版本 | 用途与选型理由 |
|---|---|---|---|
| 构建工具 | Vite | ^5.0.0 | 开发服务器固定 5566 端口(pnpm dev);vite.config.ts 通过 alias 把 5 个 jsdelivr CDN 导入重写到 npm 包,实现"外链清零" |
| 前端框架 | Vue | ^3.5.0 | 全站 SFC + <script setup>;src/App.vue 用 KeepAlive 缓存图表库列表页 |
| 语言 | TypeScript | ^5.0.0(strict) | tsconfig.json 开启 strict/noUnusedLocals;pnpm typecheck(vue-tsc)为 CI 阻塞项 |
| 路由 | vue-router | ^4.3.0 | src/router/routes.ts 独立成表便于测试回归;history 模式 |
| 状态管理 | Pinia | ^2.1.0 | 全站仅 1 个 store(src/stores/reportStore.ts),其余状态走 composable |
| 服务端状态 | @vueuse/core | ^14.3.0 | useStorage(主题持久化)、watchDebounced(搜索防抖)等 |
| 图表 1 | echarts + vue-echarts + echarts-gl | ^6.1.0 / ^8.0.1 / ^2.1.0 | 主力图表库;src/utils/v-chart.ts 全局注册懒加载 <v-chart>;@echarts-x/custom-liquid-fill、custom-word-cloud 为补充系列 |
| 图表 2 | @antv/g2plot | ^2.4.35 | AntV 示例的运行时(ChartExampleRenderer 动态 import) |
| 三维 | three(+约 25 个 three 生态包) | ^0.186.1 | three 示例运行时;生态包含 postprocessing、three-mesh-bvh、@takram/three-geospatial、物理引擎等 |
| SFC 运行时编译 | @vue/compiler-sfc | ^3.5.43 | src/utils/sfcRuntime.ts 在浏览器端把 JSON 内嵌的 SFC 字符串编译为组件(兜底渲染链路) |
| UI 组件 | Element Plus(按需) | ^2.14.0 | 仅用 el-pagination / el-breadcrumb / ElMessage 等;经 unplugin-auto-import + unplugin-vue-components 按需引入 |
| 样式 | Tailwind CSS | ^4.0.0 | src/assets/main.css 用 @theme inline 定义 RGB 变量令牌体系,配合暗/亮主题 |
| 代码高亮 | shiki | ^1.29.2 | src/utils/highlighter.ts 为源码弹窗/代码块提供高亮 |
| 单元测试 | Vitest + happy-dom + @vue/test-utils | ^2.1.9 | vitest.config.ts:环境 happy-dom、globals、20s 超时(图表 JSON 体量大) |
| 覆盖率 | @vitest/coverage-v8 | ^2.1.9 | 已安装,可通过 pnpm vitest run --coverage 启用(package.json 未单独定义 coverage script,⚠️ 待确认是否有 CI 覆盖率门禁) |
| 冒烟测试 | Playwright | ^1.61.0 | scripts/smoke.mjs:10 个页面遍历 + canvas 断言 + 外链零请求断言 + 截图到 smoke-shots/ |
| 图像处理 | sharp | ^0.35.5 | scripts/gen-thumbs-webp.mjs 把 PNG 缩略图批量转 WebP(宽 640、质量 78) |
| 图标字体 | material-symbols | ^0.45.8 | src/main.ts 引入 outlined 样式,AppIcon 组件统一消费 ms:xxx 图标名 |
html5-dataviz/
├── index.html # 入口 HTML(zh-CN,Google Fonts 预连接,仅字体走外链)
├── package.json # 脚本:dev(5566)/build/test/test:smoke/typecheck/lint
├── vite.config.ts # alias、CDN→npm 重映射、vendor manualChunks 分包
├── vitest.config.ts # happy-dom + globals + 20s 超时
├── eslint.config.js # flat config;src/chart-examples/** 与迁移存量大屏豁免
├── auto-imports.d.ts # unplugin-auto-import 生成(勿手改)
├── components.d.ts # unplugin-vue-components 生成(勿手改)
├── docs/
│ └── CODE_TO_VCHART_GUIDE.md # 官方脚本改写为 <v-chart> 的执行手册(子代理迁移用)
├── scripts/ # Node 工具脚本(.mjs)
│ ├── smoke.mjs # Playwright 冒烟:10 页面 + canvas/外链断言 + 截图
│ ├── slim-chart-json.mjs # JSON 瘦身:有本地 SFC 的条目删除代码字段
│ ├── gen-three-registry.mjs # curio → 本项目 three 示例迁移/注册表生成
│ ├── gen-thumbs-webp.mjs # PNG→WebP 缩略图批量转换(sharp)
│ └── ...(sweep-fallback / heal-sweep / audit-bigscreen 等治理脚本)
├── public/ # 静态资产(运行时零外链的关键)
│ ├── echarts-data/ # 官方示例数据集与 ecStat 等扩展库(约 71MB)
│ ├── map-geojson/ # china.json / world.json 地图注册数据
│ ├── chart-thumbs/ 等 # 各库示例缩略图(webp/jpg)
│ ├── threejs-official/ 等三大目录 # three 示例的模型/纹理/音频资产(约 800MB)
│ └── vendor-ammo|basis|draco|rhino3dm # wasm/解码器本地化副本
└── src/
├── main.ts # 应用入口:Pinia + router + 全局 VChart + EP 按需样式
├── App.vue # 布局壳:AppHeader + RouterView + KeepAlive
├── router/ # routes.ts(路由表)+ index.ts(实例与守卫)
├── api/
│ └── chart-examples.ts # 图表示例静态访问层:懒加载 JSON + 内存筛选/分页/搜索
├── chart-examples/ # ★ 1617 个本地图表 SFC + 执行契约
│ ├── manifest.ts # echarts/antv 清单(脚本生成,勿手改)+ LOCAL_LIBRARY_MANIFESTS
│ ├── three-manifest.ts # three 清单(gen-three-registry.mjs 生成,勿手改)
│ ├── EChartDemo.vue # 294 个 echarts SFC 的统一渲染容器(执行契约)
│ ├── loadScript.ts # UMD 脚本幂等加载器(处理 AMD define 冲突)
│ ├── echarts/{分类}/{id}.vue # 294 个 ECharts 示例
│ ├── antv/{分类}/{id}.vue # 334 个 AntV 示例
│ └── three/… # 989 个 Three.js 示例 + ExampleScene 壳组件 + stage 组合式
├── components/
│ ├── chart-examples/ # 渲染链:ChartExampleRenderer / VueSfcRenderer / SourceCodeModal
│ ├── common/ # AppButton / AppIcon / AppInput / CategoryChips + code/ 代码块
│ ├── datav/ # 大屏通用组件:DatavContainer(1920×1080 缩放)/边框/计数/滚动表等
│ └── layout/ # AppHeader / Pagination / EmptyState / SkeletonGrid / TreeSidebar
├── composables/ # useTheme / useListFilter / usePagination / useResourceFetch /
│ # useMapGeoJson / useScreenData / useToast / useCopy 等
├── config/
│ ├── chartLibraries.ts # ★ 图表库白名单注册表(echarts/antv/three)
│ ├── bigscreenData.ts # 22 个大屏元数据清单
│ ├── bigscreenComponents.ts# 大屏 id → 组件懒加载器映射(与清单由测试锁定一致)
│ ├── bigscreenTokens.ts / dashboardDark.ts # 大屏设计令牌与 ECharts 暗色主题引用
├── data/charts/ # echarts.json / antv.json / three.json 元数据(懒加载)
├── stores/reportStore.ts # 唯一 Pinia store(report 大屏静态数据)
├── types/ # chart-examples / ui / datav / datavDashboard 等类型定义
├── utils/
│ ├── v-chart.ts # ★ 全站 <v-chart> 统一注册源(懒加载)
│ ├── sfcRuntime.ts # SFC 运行时编译核心(安全验证/模块重写/沙箱执行)
│ ├── sfc-modules.ts # 沙箱模块注册表(npm 白名单 + @/ 别名自动发现)
│ ├── echarts-theme.ts # 大屏 ECharts 暗色主题对象
│ └── map-data.ts / highlighter.ts / logger.ts 等
└── views/
├── DataVisualizationHomePage.vue # 首页(模块导航卡片)
├── ChartLibraryPage.vue # 图表库列表页(侧栏分类+网格+分页)
├── ChartExampleDetailPage.vue # 示例详情页(本地 SFC 优先渲染)
├── NotFoundPage.vue # 404
└── bigscreen/ # 22 个大屏 + 列表/详情壳页 + 共享 components/src/views/ChartExampleDetailPage.vue 先查 LOCAL_LIBRARY_MANIFESTS(src/chart-examples/manifest.ts)命中本地 SFC 则用 import.meta.glob 异步直挂(方案 B,1617 条走此链路);未命中则回退 src/api/chart-examples.ts 读 JSON 元数据,交给 src/components/chart-examples/ChartExampleRenderer.vue 按 loaderKind 分派(option/api-async → ECharts 求值;antv-config → G2Plot 实例化;component → VueSfcRenderer 运行时编译)。src/config/chartLibraries.ts 是唯一真源,导航下拉与图表库页自动联动;apexcharts/chartjs/d3 已于 2026-10 删除。src/config/bigscreenData.ts(清单)与 src/config/bigscreenComponents.ts(组件映射),src/config/__tests__/bigscreenComponents.test.ts 锁定两者不漂移。src/composables/useTheme.ts 提供暗/亮/跟随系统三态,写入 localStorage(键 devcanvas-theme),通过 documentElement 的 .dark/.light class 驱动 src/assets/main.css 中的 RGB 变量令牌。# 环境要求:Node 22(CI 使用 node-version: 22)、pnpm 10(CI 使用 pnpm/action-setup@4 version 10)
pnpm install # 安装依赖
pnpm dev # 开发服务器 http://localhost:5566
pnpm typecheck # vue-tsc 类型检查(CI 阻塞项)
pnpm lint # ESLint
pnpm test # Vitest 单元测试(19 个测试文件)
pnpm build # 生产构建(NODE_OPTIONS --max-old-space-size=8192)
pnpm preview # 预览构建产物
pnpm test:smoke # Playwright 冒烟(需先 pnpm dev 或 pnpm preview;BASE_URL 可指定地址)首次启动建议访问顺序:/(首页)→ /charts/echarts(图表库,感受分类侧栏与分页)→ 任一示例详情页(打开"查看源代码"弹窗)→ /bigscreen(大屏列表)→ 任一大屏(验证 1920×1080 自适应缩放与 canvas 渲染)。
健康的启动信号有三条:其一,浏览器控制台不应出现 myChart.xxx 实例尚未就绪 告警(该告警来自 src/chart-examples/EChartDemo.vue 的延迟代理,偶发于极慢设备,持续出现则说明图表 chunk 加载受阻);其二,/charts/echarts 列表应显示 348 个示例、37 个分类(与 src/data/charts/echarts.json 一致);其三,Network 面板中 echarts/three/antv 的 vendor chunk 与库级 JSON chunk 应为按需加载——首次停留在首页时不应看到任何图表库代码被下载,这是懒加载架构生效的直接证据。若需要验证内网部署可用性,跑一遍 pnpm test:smoke 并确认输出"冒烟全部通过",其中外链零请求断言是最容易在改依赖后被破坏的一条。
项目处于高频治理期,源码注释中留有清晰的演进痕迹,理解这些背景能避免"复活旧坑":
| 时间(注释标注) | 事件 | 证据位置 |
|---|---|---|
| 2026-10-03 | 修复 EChartDemo 缺注册导致"图表静默空白"的问题 | src/utils/v-chart.ts 注释("与 2026-10-03 EChartDemo 修复的是同一类缺注册问题") |
| 2026-10 | apexcharts / chartjs / d3 三库整体删除(渲染器从未实现、数据残缺) | README.md 关键约定、src/api/chart-examples.ts 注释、scripts/slim-chart-json.mjs(死库返回空集) |
| 2026-10 | 移除在线编辑能力,JSON 代码字段瘦身(SFC 成为唯一真源) | scripts/slim-chart-json.mjs 头注释 |
| 2026-10-04 | three 示例库从 curio 仓库迁入(989 条 + 资产裁剪) | scripts/gen-three-registry.mjs 头注释、src/chart-examples/three/stage/useExampleStage.ts 头注释 |
| 2026-10 | 外链清零专项:5 个 CDN import alias 到 npm 包、AmmoPhysics wasm 本地化 | vite.config.ts alias 注释块 |
| 2026-10 | vendor 分包治理:Vue 运行时从 echarts-vendor 拆出独立 vendor 桶 | vite.config.ts manualChunks 注释 |
| 2026-10(重设计) | EChartDemo 收敛为"option / onReady / setup"三模式执行契约,退役 optionCode/code/gl 字符串执行路径 | src/chart-examples/EChartDemo.vue 头注释 |
| 术语 | 含义 |
|---|---|
| 本地 SFC / 方案 B | src/chart-examples/ 下真实存在的 .vue 示例文件,详情页经 import.meta.glob 异步直挂渲染(src/views/ChartExampleDetailPage.vue 注释"方案 B:直接落 .vue 文件") |
| JSON 兜底条目 | 无本地 SFC、仅存在于 src/data/charts/*.json 且保留代码字段、由 ChartExampleRenderer 求值渲染的条目(71 条) |
| manifest | src/chart-examples/manifest.ts 与 three-manifest.ts 中的本地案例清单(脚本生成),详情页据此判断"是否有本地 SFC" |
| 双链路 | 详情页渲染的两条路径:本地 SFC 直挂(优先)与 JSON 代码求值(兜底) |
| 渲染代次 | renderSeq/compileSeq/requestId/loadId 等递增序号机制,保证并发渲染/请求"最后请求胜出" |
| 大屏 | src/views/bigscreen/ 下以 1920×1080 设计稿为基准、经 DatavContainer 等比缩放的全屏可视化页面(22 个) |
| 设计令牌 | src/assets/main.css 中以 --*-rgb 命名的 RGB 变量体系,Tailwind 4 经 @theme inline 映射为工具类 |
| smoke | scripts/smoke.mjs 的 Playwright 冒烟测试,截图输出到 smoke-shots/ |
| 外链清零 | 运行时不发起任何第三方 CDN 请求的硬约束(内网部署前提),由 smoke 断言 |