可视化大屏设计器脚手架:从设计到交付的一站式方案

做可视化大屏时,很多项目一开始只是"画几个图表",后面很快会出现一整套工程问题:

  • 设计稿怎么适配不同屏幕?
  • 图表位置怎么让业务方自己调?
  • 多个页面怎么切换和传参?
  • 主题、背景、卡片装饰怎么复用?
  • 设计好的配置怎么导出、复用、回滚?
  • 图表、3D 地图、业务组件之间怎么通信?

@lius1314/visual-dashboard-scaffold 就是围绕这些问题沉淀出来的 React 可视化大屏脚手架。它不试图替代 ECharts、Three.js 或业务组件,而是提供一个可编辑、可配置、可发布的"大屏装配层"。

npm 地址www.npmjs.com/package/@li...

当前版本 :v1.2.2

技术栈:React + TypeScript + Zustand + react-grid-layout + react-router-dom + autofit.js

它解决什么问题

传统大屏项目常见做法是:开发先按设计稿写死布局,需求变化时再改代码。这样前期很快,后期很重:

  • 图表换位置要改 CSS;
  • 卡片尺寸变化要重新算布局;
  • 背景图、标题图、底部导航样式散落在代码里;
  • 页面跳转和参数传递很容易越写越乱;
  • 交付后业务方想微调,只能继续找开发。

这个脚手架把"大屏的框架能力"和"业务组件"拆开:

  • 框架负责画布、头部、底部、拖拽、缩放、主题、配置、路由、事件;
  • 业务方只需要把图表、地图、指标卡封装成 React 组件,然后注册到指定区块。

最终效果是:开发者可以快速装配页面,业务同学也可以在编辑模式里调整布局和样式,再导出 JSON 配置用于生产环境。

核心能力

1. 可视化编辑

编辑模式下,图表区块可以直接拖拽、缩放、复制、删除和调整层级。区块标题、背景、内容区、卡片背景、标题字体、边距、动画等都可以单独配置。

预览模式下,这些编辑辅助线、拖拽手柄和工具面板会自动隐藏,页面只保留最终展示效果。

2. 多页面大屏

SDK 内置 HashRouter,路由格式为:

text 复制代码
/#/page/:pageId

每个页面独立维护:

  • 中间区域配置 middle
  • 图表区块 chartBlocks
  • 页面参数 params

头部 header 和底部 footer 是全局共享配置,适合真实大屏系统里"统一标题栏 + 统一底部导航"的场景。

3. 区块注册机制

脚手架不绑定任何图表库。你可以注册 ECharts、AntV、Three.js、地图组件,甚至是一个普通业务表格。

tsx 复制代码
import {
  App,
  registerBlock,
  type BlockComponentProps,
} from '@lius1314/visual-dashboard-scaffold';
import '@lius1314/visual-dashboard-scaffold/style.css';

function SalesChart({ title, pageParams, emit }: BlockComponentProps) {
  return (
    <div style={{ width: '100%', height: '100%' }}>
      <button onClick={() => emit?.('sales:refresh', { region: pageParams?.region })}>
        {title}
      </button>
    </div>
  );
}

registerBlock('sales-chart', SalesChart);

export default function AppPage() {
  return <App />;
}

配置中的 chartBlock.layout.i 与注册 ID 对上后,SDK 就会在对应区块里渲染你的组件。

4. 主题和素材资源

项目内置了多类静态资源:

  • themes/:布局主题 JSON
  • images/bg/:全局背景
  • images/card/:卡片和标题装饰
  • images/header/:顶部装饰
  • images/footer/:底部装饰
  • fonts/:常用大屏字体
  • css/webfonts/:Font Awesome 图标资源

资源选择器会按分类展示,便于在编辑面板里直接切换背景、卡片、顶部或底部样式。

如果项目有自己的素材,也可以运行时注入:

ts 复制代码
import { configureImageAssets } from '@lius1314/visual-dashboard-scaffold';

configureImageAssets({
  assets: {
    bg: ['factory.png', 'city.png'],
    business: ['alarm-card.png', 'device-panel.png'],
  },
  folders: [
    { key: 'bg', label: '背景' },
    { key: 'business', label: '业务素材' },
  ],
  basePath: '/images',
});

5. 配置导入导出

编辑完成后,可以在设置面板导出 JSON 配置。宿主项目下次启动时把 JSON 作为 initialConfig 传入即可:

tsx 复制代码
import { App } from '@lius1314/visual-dashboard-scaffold';
import config from './dashboard-config.json';

export default function Dashboard() {
  return <App initialConfig={config} defaultEditMode={false} />;
}

initialConfig 的设计比较克制:它只在首次没有本地持久化数据时加载。用户后续编辑会被保存在本地,不会被每次刷新覆盖。如果需要回到默认配置,可以点击设置面板里的"重置"。

6. 本地持久化

状态管理使用 Zustand。持久化没有简单地把整个大 JSON 都塞进 localStorage,而是使用混合存储:

  • 小体积元信息写入 localStorage
  • 页面详情写入 IndexedDB
  • 高频拖拽更新做节流合并
  • 页面删除后清理 IndexedDB 中的旧数据

这样在拖拽、缩放、频繁调整区块时,不会因为不断 JSON.stringify 大配置而明显卡顿。

7. 页面跳转和参数传递

页面参数支持三层合并:

text 复制代码
URL search params > switchPage params > PageConfig.params

区块内部可以通过 usePageContext 获取页面上下文:

tsx 复制代码
import { usePageContext } from '@lius1314/visual-dashboard-scaffold';

function RegionCard() {
  const { switchPage, pageParams } = usePageContext();

  return (
    <button onClick={() => switchPage('detail-page', { region: pageParams.region ?? 'beijing' })}>
      查看详情
    </button>
  );
}

也可以直接访问可分享链接:

text 复制代码
/#/page/detail-page?region=beijing&theme=dark

8. 行为系统

底部按钮、头部面板、图表区块都可以配置点击行为:

ts 复制代码
type BlockAction =
  | { type: 'switchPage'; pageId: string; params?: Record<string, unknown> }
  | { type: 'emitEvent'; eventName: string; payload?: unknown }
  | { type: 'custom'; handlerKey: string }
  | { type: 'none' };

常见场景:

  • 点击底部按钮跳转页面;
  • 点击地图区块发送事件;
  • 点击头部指标面板打开业务弹窗;
  • 只展示不响应点击。

自定义 handler 也可以在宿主项目注册:

tsx 复制代码
import { registerActionHandler } from '@lius1314/visual-dashboard-scaffold';

registerActionHandler('openAlarmDialog', () => {
  console.log('打开告警弹窗');
});

架构拆解

整体结构可以理解成三层:

text 复制代码
OuterContainer
  HeaderSection   # 全局头部:标题 + 可拖拽面板
  MiddleSection   # 页面主体:图表区块编排
  FooterSection   # 全局底部:导航 Dock

对应的数据结构:

text 复制代码
DashboardConfig
  outer
  header
  footer
  activePageId
  pages[]
    middle
    chartBlocks[]
    params

这个结构的好处是边界非常清楚:

  • 全局区域统一配置;
  • 页面内容相互隔离;
  • 区块组件独立注册;
  • 配置可以完整序列化;
  • 宿主项目仍然掌握业务组件的实现。

拖拽布局为什么选择像素坐标

很多后台系统更适合网格栅格,但可视化大屏通常来自设计稿,落点是明确的像素位置。如果继续用普通响应式布局,开发时反而要不断换算。

这个项目的 ChartBlockLayout 使用像素坐标:

ts 复制代码
interface ChartBlockLayout {
  i: string;
  x: number;
  y: number;
  w: number;
  h: number;
  zIndex?: number;
  minW?: number;
  minH?: number;
}

它更贴近设计交付:区块放在什么位置、占多大、层级多少,都能直接表达。预览时再交给 autofit.js 做整体等比缩放。

自适应方案

预览模式下,SDK 使用 autofit.js 按设计尺寸等比缩放。默认设计尺寸是 1920 x 1080,设置面板支持:

  • 16:9 标准宽屏
  • 16:10 办公宽屏
  • 21:9 超宽屏
  • 32:9 拼接屏
  • 9:16 竖屏

编辑模式下,不直接把整个 body 交给 autofit 缩放,而是对内容区域做单独缩放。这样工具栏、抽屉、配置面板仍然保持可操作,不会出现编辑 UI 被一起缩小后难以点击的问题。

事件通信

脚手架内置 EventBus,支持页面级 scope。发送方可以这样写:

tsx 复制代码
function MapBlock({ emit }: BlockComponentProps) {
  return (
    <button onClick={() => emit?.('map:regionClicked', { region: '华东' })}>
      点击区域
    </button>
  );
}

接收方监听同一页面内的事件:

tsx 复制代码
import { useEventBus, type BlockComponentProps } from '@lius1314/visual-dashboard-scaffold';

function TrendBlock({ pageId }: BlockComponentProps) {
  useEventBus('map:regionClicked', (payload) => {
    console.log('刷新趋势图', payload);
  }, { scope: pageId ? `page:${pageId}` : undefined });

  return <div>趋势图</div>;
}

页面卸载时,SDK 会清理当前页面 scope 下的监听,避免切换页面后旧组件继续响应事件。

快速接入

安装:

bash 复制代码
npm install @lius1314/visual-dashboard-scaffold
npm install react react-dom react-router-dom

宿主入口:

tsx 复制代码
import { App } from '@lius1314/visual-dashboard-scaffold';
import '@lius1314/visual-dashboard-scaffold/style.css';

export default function Dashboard() {
  return <App editable defaultEditMode={false} />;
}

只读生产模式:

tsx 复制代码
<App editable={false} initialConfig={config} />

自定义区块:

tsx 复制代码
import { registerBlock, type BlockComponentProps } from '@lius1314/visual-dashboard-scaffold';

function DevicePanel({ title, pageParams }: BlockComponentProps) {
  return (
    <div style={{ width: '100%', height: '100%' }}>
      {title}: {String(pageParams?.deviceId ?? '-')}
    </div>
  );
}

registerBlock('device-panel', DevicePanel);

使用时要注意的点

1. 静态资源需要同步

npm 包会携带 public/ 目录,但浏览器最终访问的是宿主项目的静态资源路径。因此需要把包里的 public 同步到宿主 public

text 复制代码
node_modules/@lius1314/visual-dashboard-scaffold/public -> public

否则主题、背景、字体、Font Awesome 图标可能出现 404。

如果资源被改乱,或升级 SDK 后想恢复内置资源,可以加一个重置脚本:

json 复制代码
{
  "scripts": {
    "reset:datavis-assets": "node -e "const fs=require('fs'); ['themes','images','fonts','css','webfonts'].forEach(d=>fs.rmSync('public/'+d,{recursive:true,force:true})); fs.cpSync('node_modules/@lius1314/visual-dashboard-scaffold/public','public',{recursive:true,force:true});""
  }
}

然后执行:

bash 复制代码
npm run reset:datavis-assets

这个命令只重置 SDK 相关的 themesimagesfontscsswebfonts 目录。如果业务素材也放在这些目录里,执行前要先备份,或者把业务素材放到独立目录,再用 configureImageAssets 接入。

2. initialConfig 不是强制覆盖

它是"首次默认配置",不是"每次启动覆盖配置"。这样设计是为了保护用户在编辑模式里的本地修改。

如果要强制恢复默认,可以使用设置面板的"重置",或调用 store 的 resetConfig()

3. header/footer 已经全局化

新版配置里,headerfooter 位于 DashboardConfig 顶层。旧版页面级 header / footer 仍会兼容迁移,但新项目建议统一使用顶层字段。

适合哪些场景

这个脚手架适合:

  • 智慧园区、智慧工厂、智慧城市类大屏;
  • 运维监控、态势感知、设备监控系统;
  • 需要多页面导航和页面参数传递的大屏;
  • 需要交付后可视化调参、导出配置的项目;
  • 想把图表组件和大屏框架解耦的团队。

如果只是一个固定的单页展示、没有编辑配置需求,手写页面可能更轻。但只要项目开始出现"可配置、可复用、多页面、可交付"的要求,这类脚手架就能明显减少重复劳动。

总结

@lius1314/visual-dashboard-scaffold 的定位不是图表库,而是大屏应用的装配层。

它把拖拽布局、多页面路由、主题素材、配置持久化、导入导出、事件通信和行为配置这些通用能力沉到框架里,让业务开发更专注于图表、地图和数据逻辑本身。

对于需要快速搭建可视化大屏,又希望后续能持续调整和复用配置的项目,它可以作为一个比较完整的起点。

项目地址:www.npmjs.com/package/@li...

如果你对可视化、3D技术感兴趣的话,欢迎来公众号 柳杉前端 瞧一瞧 看一看

相关推荐
jump_jump11 小时前
网页 UI 终于能进游戏和 3D 场景了:HTML-in-Canvas 为什么重要
浏览器·three.js·canvas
kyriewen15 小时前
我手写了一个 EventEmitter,面试官追问了 6 个问题——第 4 个我没答上来
前端·javascript·面试
IT_陈寒15 小时前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
小林攻城狮15 小时前
使用 Transport 节流解决 Vercel AI SDK 流式渲染卡死问题
前端·react.js
前端缘梦16 小时前
告别 TS 运行时类型漏洞!Zod 完整入门实战教程(前端 / 全栈必备)
前端·react.js·全栈
the_answer16 小时前
Webpack vs Vite 深度对比分析
前端·webpack
转转技术团队16 小时前
验证码识别实战:前端不写页面,改训模型了?
前端
MomentYY16 小时前
Temperature:AI 的“脑洞旋钮”
前端·llm·ai编程
远航_16 小时前
OpenSpec 完整详细介绍
前端·后端