如何在TwinCAT 3中实现实时动态饼图?
TwinCAT TcHmiHtmlHost嵌入Chart.js实现实时饼图更新方案
问题背景
在TwinCAT项目中通过TcHmiHtmlHost嵌入Chart.js绘制饼图,目前仅能通过异步方法单次读取PLC变量完成初始赋值,无法实现数据的实时动态更新;尝试过创建用户控件、CreateEx方法及订阅PLC变量均未成功。
解决方案
核心思路是利用TcHmi的变量订阅机制监听PLC数据变化,通过TcHmiHtmlHost的跨上下文消息传递将数据同步到内部Chart,并触发图表重绘。
步骤1:TcHmi页面侧实现变量订阅与数据传递
替换原有单次读取的代码,改为持续订阅PLC变量,并在变量变化时向HtmlHost发送更新消息:
// 初始化变量 let underValue = 0; let overValue = 0; // 获取HtmlHost控件实例 const htmlHost = TcHmi.Controls.get('htmlhost_piechart'); // 订阅PLC变量(持续监听变化) TcHmi.Symbol.readEx('%s%PLC1.ProductCounter.f_undercounter.rOpCount.Count%/s%', (response) => { if (response.error === TcHmi.Errors.NONE) { underValue = response.value; syncChartData(); } }, true); // 第三个参数设为true开启持续订阅 TcHmi.Symbol.readEx('%s%PLC1.ProductCounter.f_overcounter.rOpCount.Count%/s%', (response) => { if (response.error === TcHmi.Errors.NONE) { overValue = response.value; syncChartData(); } }, true); // 向HtmlHost发送更新数据 function syncChartData() { if (htmlHost) { htmlHost.sendMessage({ type: 'UPDATE_CHART', payload: { pass: underValue, reject: overValue } }); } }
步骤2:修改HtmlHost内部Chart代码
调整内部脚本,添加消息监听逻辑,接收外部数据后更新图表并触发重绘:
<div id="htmlhost_piechart" data-tchmi-type="TcHmi.Controls.System.TcHmiHtmlHost" data-tchmi-height="100" data-tchmi-height-unit="%" data-tchmi-left-unit="px" data-tchmi-top="0" data-tchmi-top-unit="px" data-tchmi-width-unit="%" data-tchmi-creator-visibility="Visible" data-tchmi-zindex="1" data-tchmi-width="100" data-tchmi-creator-locked="False" data-tchmi-left="0"> <script src="../../../CodeBehind/Scripts/Chart.js"></script> <canvas id="pieChart" style="width:90%;height:90%;float:right"></canvas> <script> const xValues = ["Pass", "Reject"]; const barColors = ['#02c39a', '#fe4a49']; // 初始化饼图实例 const pieChart = new Chart("pieChart", { type: 'pie', data: { labels: xValues, datasets: [{ backgroundColor: barColors, data: [0, 0], // 初始占位值 borderWidth: 2 }] }, options: { title: { display: false }, plugins: { legend: { display: false } } } }); // 监听来自TcHmi主页面的消息 window.addEventListener('message', (event) => { if (event.data?.type === 'UPDATE_CHART') { // 更新图表数据 pieChart.data.datasets[0].data = [event.data.payload.pass, event.data.payload.reject]; // 触发图表重绘 pieChart.update(); } }); </script> </div>
关键说明
- 变量订阅:使用
TcHmi.Symbol.readEx的持续订阅模式,PLC变量变化时自动触发回调,避免轮询造成的资源浪费 - 跨上下文通信:TcHmiHtmlHost本质是独立iframe,无法直接访问外部TcHmi变量,通过
sendMessage和message事件实现数据传递 - 图表更新:更新Chart数据后必须调用
update()方法,才能触发图表的实时重绘
内容的提问来源于stack exchange,提问作者Heru Prayogo
相关产品推荐
相关产品推荐

