资讯动态

ToolJet 3.0.0-LTS:在 Custom Component 中用 Plotly 创建支持事件交互的图表

发布时间:2026/9/13 6:46:05 来源:尧图企业网站定制
ToolJet 3.0.0-LTS在 Custom Component 中用 Plotly 创建支持事件交互的图表【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet本文基于 ToolJet 3.0.0-LTS 版本官方教程 use-events-on-chart.md讲解如何在 ToolJet 的 Custom Component自定义组件中借助支持事件回调的第三方绘图库 Plotly 创建可交互图表并通过组件暴露的runQuery能力在图表元素如柱状条被点击时触发查询执行。读完后你将掌握Custom Component 的完整代码编写规范、Plotly 图表的数据/布局/事件传参方式以及runQuery从 iframe 到主页面执行查询的底层通信机制。前置概念Custom Component 是什么Custom Component 是 ToolJet 中用于“用 React 代码自定义画布组件”的 Widget其定位在组件配置 customComponent.js 中定义组件名CustomComponent显示名 Custom Component描述为 Create React components只有两个核心属性data类型code默认值{}和code类型code即你要粘贴的 React 代码默认尺寸 20 宽 × 140 高并自带showOnDesktop/showOnMobile开关与visibility、borderColor、borderRadius、boxShadow等样式项。从源码结构看Custom Component 的用户代码运行在一个独立的 iframe 中CustomComponent.jsx 渲染iframe srcDoc{iframeContent}其中iframeContent是 iframe.html。iframe 内置了 Babel Standalone用于在浏览器端把 JSX 编译成 JS和 React 16.7 UMD 版本用户代码以typetext/babel的 script 标签注入并动态执行。iframe 通过window.Tooljet全局对象向用户代码暴露三个能力见 iframe.html#L109-L127// Tooljet.connectComponent 把用户组件包一层注入三个 props render() { return WrappedComponent data{this.state?.data ?? {}} // 来自组件 data 属性 updateData{(e) Tooljet.updateProps(e)} // 更新组件 data runQuery{(e, params) Tooljet.runQuery(e, params)} // 触发查询 /; }也就是说只要按Tooljet.connectComponent(MyCustomComponent)的模式连接组件你的函数组件就能拿到data、updateData、runQuery三个 props——这正是教程中图表事件回调能够调用查询的基础。Step 1添加 Custom Component打开 App Builder向页面拖入一个 Custom Component点击该组件打开右侧 Properties 面板。如果你还不熟悉 Custom Component 本身可先阅读官方文档 Custom Component 说明。Step 2向 Custom Component 粘贴建图代码在 Properties 面板的code区域粘贴以下完整代码来自原教程import React from https://cdn.skypack.dev/react; import ReactDOM from https://cdn.skypack.dev/react-dom; import { Button, Container } from https://cdn.skypack.dev/material-ui/core; import Plotly from https://cdn.skypack.dev/plotly.js-basic-dist-min; import createPlotlyComponent from https://cdn.skypack.dev/react-plotly.js/factory; // Define the custom component const MyCustomComponent ({ data, updateData, runQuery }) { // Create Plot component using Plotly const Plot createPlotlyComponent(Plotly); // Define onClick handler for bars const barOnClick ({ points }) { alert(A bar is clicked); }; // Render the component return ( Container Plot data{[ { name: Inbound, type: bar, x: [20, 14, 23, 22, 30, 12, 15, 26, 31, 16, 18, 29], y: [Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec], marker: { line: { color: rgba(55, 128, 191, 1.0), width: 1 }, color: rgba(55, 128, 191, 0.6), }, orientation: h, }, { name: Outbound, type: bar, x: [12, 18, 29, 22, 14, 23, 15, 23, 26, 13, 27, 12], y: [Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec], marker: { line: { color: rgba(255, 153, 51, 1.0), width: 1 }, color: rgba(255, 153, 51, 0.6), }, orientation: h, }, ]} layout{{ width: 840, height: 800, title: Tickets Resolved: Inbound Outbound, showlegend: false, }} onClick{barOnClick} / /Container ); }; // Connect the component const ConnectedComponent Tooljet.connectComponent(MyCustomComponent); // Render the connected component to the DOM ReactDOM.render(ConnectedComponent /, document.body);代码实现要点拆解如下导入依赖库。教程使用 Skypack ESM CDNhttps://cdn.skypack.dev/...直接引入 React、React DOM、Material UI、plotly.js-basic-dist-min与react-plotly.js/factory工厂函数import React from https://cdn.skypack.dev/react; // React 库 import ReactDOM from https://cdn.skypack.dev/react-dom; // React DOM 库 import { Button, Container } from https://cdn.skypack.dev/material-ui/core; // Material UI 库 import Plotly from https://cdn.skypack.dev/plotly.js-basic-dist-min; // Plotly 库 import createPlotlyComponent from https://cdn.skypack.dev/react-plotly.js/factory; // Plotly React 工厂需要说明的是仓库中 Custom Component 的默认模板代码见 customComponent.js#L62-L78采用的是 jsdelivr 的esm地址如https://cdn.jsdelivr.net/npm/react17.0.2/esm并固定了版本号。两种 CDN 的 ESM 写法都可行实际项目中建议固定版本以避免依赖漂移。定义函数组件。MyCustomComponent是一个函数组件负责渲染图表内部用createPlotlyComponent(Plotly)把 Plotly 封装成 React 的Plot组件。同时定义barOnClick处理函数——当用户点击柱形时被调用先以alert验证事件触发const MyCustomComponent ({data, updateData, runQuery}) { // 函数组件 const Plot createPlotlyComponent(Plotly); // 创建 Plotly 组件 const barOnClick ({points}) { // 用户点击柱子时调用 alert(A bar is clicked) // 弹出提示消息 }渲染图表。通过Plot组件的data两条水平柱状序列 Inbound / Outbound、layout宽 840、高 800、标题、隐藏图例传参并把barOnClick挂到onClickprop 上return ( Container Plot data{[/* 两条 bar trace含 x/y/marker/orientation */]} layout{{ width: 840, height: 800, title: Tickets Resolved: Inbound Outbound, showlegend: false }} onClick{barOnClick} / /Container );其中orientation: h使柱形沿水平方向展开marker.line与marker.color控制边框与填充色points即回调入参包含 Plotly 点击事件中被命中的数据点信息。连接并渲染到 DOM。用Tooljet.connectComponent包裹后渲染const ConnectedComponent Tooljet.connectComponent(MyCustomComponent); // 连接到 Tooljet store ReactDOM.render(ConnectedComponent /, document.body); // 渲染组件这里渲染目标是 iframe 内部的document.body不是主页面这也是 Custom Component 沙箱模型的一部分。Step 3把事件升级为 runQuery教程中barOnClick最初只做alert演示。真正有业务价值的用法是把事件回调改为调用runQuery从而在图表元素被点击时执行页面上已定义的查询const barOnClick ({points}) { runQuery(queryName) }runQuery接受查询名字符串可再传参数对象用于从 Custom Component 内运行查询。关于向runQuery传参的更多用法可参考同版本教程 pass-query-params-in-custom-components.md。源码纵深runQuery 的跨 iframe 调用链runQuery并不是简单地在 iframe 里执行请求而是一套“iframe 发起 → 主页面执行 → 结果回传”的 postMessage 协议可以结合仓库源码逐段印证iframe 侧发起iframe.html#L22-L44 中Tooljet.runQuery返回一个 Promise并生成唯一requestIdrq_ Date.now() _ 随机串用于并发请求的响应关联。它向父页面 post 出{ from: customComponent, message: RUN_QUERY, queryName, parameters, componentId, requestId }然后挂一个临时 message 监听器收到匹配requestId的RUN_QUERY_RESPONSE后才 resolve。源码注释明确说明其返回值语义与主页面queries.queryName.run()一致成功为{ status: ok, data: { ... } }失败为{ status: failed, message: ..., data: ..., metadata: ... }。主页面侧执行CustomComponent.jsx#L44-L83 的 message 监听器识别RUN_QUERY消息后解析parameters组装options { parameters, queryName }调用 zustand store 的onEvent(onTrigger, [], options)触发查询执行再把结果或失败信息以RUN_QUERY_RESPONSE连同componentId、requestId回传 iframe。失败分支会返回{ status: failed, message: ... }作为兜底。其余消息协议同一监听器与 CustomComponent.jsx#L119-L154INIT/INIT_RESPONSEiframe 加载完成后请求初始化主页面回传data与codeiframe 把code注入为text/babel脚本执行CODE_UPDATEDcode属性变化时主页面推送iframe 移除旧的用户脚本并重新注入实现编辑即刷新DATA_UPDATED/UPDATE_DATA组件data属性变化或 iframe 内调用updateData时的双向数据同步iframe 侧通过Tooljet.subscribe订阅回调触发setState让依赖data的图表重渲染CLEANUP组件卸载时主页面通知 iframe 卸载 React 根ReactDOM.unmountComponentAtNode并清理监听器。由此可以推断本教程中若把图表的x/y数据改为来自dataprop例如data.tickets当你在 Properties 面板修改data属性后DATA_UPDATED消息会驱动 iframe 内组件更新状态并重绘 Plotly 图表而点击事件触发runQuery(queryName)后查询结果会沿RUN_QUERY_RESPONSE通道回到 iframe供你在回调中继续处理。注意事项与适用前提本教程适用于 ToolJet 3.0.0-LTS 版本文档体系版本目录Custom Component 的行为iframe 沙箱 postMessage 协议以当前仓库源码 CustomComponent.jsx 与 iframe.html 为准。Custom Component 的code属性在组件定义中带skipResolve: true见 customComponent.js#L61-L80即代码内容不会被当作{{fx}}表达式解析可放心书写含花括号的 JSX 代码。第三方库Plotly、React 等通过 CDN ESM 引入需要部署/使用环境能访问对应 CDN图表库的选择不限于 Plotly任何支持事件回调的第三方图表库均可套用本教程的“建图 onClick回调 runQuery”模式。完整代码示例、消息协议与默认模板代码均可在仓库对应文件中复核本文未改动任何仓库内容。【免费下载链接】ToolJetOpen-source foundation of ToolJet AI - the enterprise app generation platform for internal tools, dashboards, business applications, workflows and AI agents. Build visually, from a prompt, or from Claude Code, Codex and Cursor over MCP 项目地址: https://gitcode.com/GitHub_Trending/to/ToolJet创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价