ThingsBoard 自定义 Time-Series 时序表格部件开发:Widget Editor 完整实战与订阅数据模型源码解析
发布时间:2026/10/3 20:28:26 作者:尧图编辑部 阅读量:1,286

物联网后端数据可视化消息队列【免费下载链接】thingsboardAll-in-one IoT Platform - Device management, data collection, processing and visualization.项目地址https://gitcode.com/GitHub_Trending/th/thingsboard点击查看免费下载本文以 ThingsBoard 前端仓库ui-ngx内置的官方示例 timeseries_widget.md 为核心手把手讲解如何在Widgets Bundle 视图中从零创建一个自定义Time-Series 时序部件通过 HTML/CSS/JavaScript 三个代码区实现每个数据源一个页签、页签内以表格展示最新时序数据的效果并深入解析部件subscription订阅对象与defaultSubscription的数据结构帮助读者掌握 ThingsBoard 自定义部件的完整开发与调试能力。一、前置认知Widget Editor 与 Time-Series 部件类型ThingsBoard 的自定义部件开发都在Widget Editor部件编辑器中完成它允许开发者用 HTML、CSS、JavaScriptAngular 模板语法定义部件的外观与行为。部件类型决定订阅的数据结构Latest values最新值与Time-Series时序部件订阅对象提供datasources数据源数组与data最新/时序数据数组Alarm告警部件提供alarmSource与alarmsRPC / Static部件订阅对象可选通常不包含必要的数据信息。官方对部件生命周期函数与订阅对象的完整说明见 widget_js_fn.md 与 widget_js_subscription_object.md。本示例聚焦Time-Series类型其最终效果为多个数据源以mat-tab页签切换每个页签内渲染一张时间戳 各数据键dataKey数值的表格。二、创建步骤从 Widgets Bundle 进入 Time-Series 模板打开Widgets Bundle部件库视图点击屏幕右下角的大按钮在弹出的菜单中点击Create new widget type创建新部件类型在Select widget type选择部件类型弹窗中点击Time-Series按钮Widget Editor随即打开并自动填充默认的Time-Series模板部件内容此时Resources区已包含 CSS、HTML 两个标签页JavaScript区已包含默认部件骨架代码。接下来只需分别替换三处代码并点击Run即可看到运行结果。三、替换 CSS定义表格表头左对齐样式将 Resources 区CSS标签页的内容替换为.my-data-table th { text-align: left; }该样式为示例表格定义了my-data-table类使表头th文本左对齐避免默认居中样式影响阅读。四、替换 HTML以页签 表格渲染多数据源时序数据将 Resources 区HTML标签页的内容替换为mat-tab-group styleheight: 100%; mat-tab *ngForlet datasource of datasources; let $dsIndex index label{{datasource.name}} table classmy-data-table stylewidth: 100%; thead tr thTimestamp/th th *ngForlet dataKeyData of datasourceData[$dsIndex]{{dataKeyData.dataKey.label}}/th tr /thead tbody tr *ngForlet data of datasourceData[$dsIndex][0].data; let $dataIndex index td{{data[0] | date : yyyy-MM-dd HH:mm:ss}}/td td *ngForlet dataKeyData of datasourceData[$dsIndex]{{dataKeyData.data[$dataIndex] dataKeyData.data[$dataIndex][1]}}/td /tr /tbody /table /mat-tab /mat-tab-group该模板使用 Angular 结构型指令*ngFor官方参考 Angular NgForOf API外层*ngForlet datasource of datasources; let $dsIndex index遍历当前订阅的所有数据源为每个数据源渲染一个mat-tab页签页签标题为datasource.name表头*ngForlet dataKeyData of datasourceData[$dsIndex]按数据源索引读取$scope.datasourceData将每个dataKeyData的dataKey.label渲染为列标题首列固定为 Timestamp表体*ngForlet data of datasourceData[$dsIndex][0].data以第一个 dataKey 的data数组为行基准data[0]为毫秒级 Unix 时间戳通过 Angulardate管道格式化为yyyy-MM-dd HH:mm:ssdataKeyData.data[$dataIndex][1]为对应时间点的数值最后一行使用Angular 表达式求值短路A B当某 dataKey 在对应索引处无数据点时返回空避免渲染undefined。五、替换 JavaScript初始化订阅数据并响应数据更新将JavaScript区的内容替换为self.onInit function() { self.ctx.widgetTitle My first Time-Series widget; self.ctx.$scope.datasources self.ctx.defaultSubscription.datasources; self.ctx.$scope.data self.ctx.defaultSubscription.data; self.ctx.$scope.datasourceData []; var currentDatasource null; var currentDatasourceIndex -1; for (var i0;iself.ctx.$scope.data.length;i) { var dataKeyData self.ctx.$scope.data[i]; if (dataKeyData.datasource ! currentDatasource) { currentDatasource dataKeyData.datasource currentDatasourceIndex; self.ctx.$scope.datasourceData[currentDatasourceIndex] []; } self.ctx.$scope.datasourceData[currentDatasourceIndex].push(dataKeyData); } self.ctx.updateWidgetParams(); } self.onDataUpdated function() { self.ctx.detectChanges(); }代码要点self是部件实例的内置引用每个部件函数都应定义为self的属性详见 widget_js_fn.mdself.ctx是 WidgetContext 类型引用提供部件所需的全部 API 与数据onInit在部件初始化时调用将defaultSubscription.datasources数据源数组与defaultSubscription.data各 dataKey 的时序数据数组挂载到$scope使其在 HTML 模板中可直接访问$scope.datasourceData是本示例引入的关键重组结构由于data是按datasourcedataKey平铺的见下文订阅结构这里遍历data每当dataKeyData.datasource发生变化就开启一个新的数据源索引把属于同一数据源的所有dataKeyData收集到datasourceData[索引]数组中——HTML 中便可以通过datasourceData[$dsIndex]按数据源索引灵活取用updateWidgetParams()同步部件参数底层实现见下节源码解析onDataUpdated在订阅收到新数据时被调用这里仅执行detectChanges()触发一次新的 Angular 变更检测使表格中的数据及时刷新。六、运行与预览完成上述替换后点击Widget Editor Toolbar上的Run按钮即可在Widget preview部件预览区看到运行结果预览中可以看到每个数据源对应一个页签表格首列展示格式化的时间戳其余列按 dataKey 的 label 展示各数据键的数值。七、源码级解析subscription 订阅对象与 defaultSubscription示例中的核心数据来源是self.ctx.defaultSubscription它是 IWidgetSubscription 的实例源码定义于 widget-api.models.ts包含该订阅的全部信息与当前数据。在 widget-component.models.ts 中WidgetContext声明了defaultSubscription: IWidgetSubscription null部件代码中可随时读取。7.1 datasources数据源数组datasources [ { // datasource type: entity,// type of the datasource. Can be function or entity name: name, // name of the datasource (in case of entity usually Entity name) aliasName: aliasName, // name of the alias used to resolve this particular datasource Entity entityName: entityName, // name of the Entity used as datasource entityType: DEVICE, // datasource Entity type (for ex. DEVICE, ASSET, TENANT, etc.) entityId: 943b8cd0-576a-11e7-824c-0b1cb331ec92, // entity identificator presented as string uuid. dataKeys: [ // array of keys (attributes or timeseries) of the entity used to fetch data { // dataKey name: name, // the name of the particular entity attribute/timeseries type: timeseries, // type of the dataKey. Can be timeseries, attribute or function label: Sin, // label of the dataKey. Used as display value (for ex. in the widget legend section) color: #ffffff, // color of the key. Can be used by widget to set color of the key data. funcBody: , // only applicable for datasource with type function and function key type. settings: {} // dataKey specific settings with structure according to the defined Data key settings form. }, //... ] }, //... ]type为function时代表模拟数据源配合funcBody生成仿真数据为entity时代表真实实体数据源aliasName指向仪表板中配置的实体别名。7.2 data各 dataKey 的时序数据点data [ { datasource: {}, // datasource object of this data. See datasource structure above. dataKey: {}, // dataKey for which the data is held. See dataKey structure above. data: [ // array of data points [ // data point 1498150092317, // unix timestamp of datapoint in milliseconds 1, // value, can be either string, numeric or boolean ], //... ] }, //... ]data的每个元素DatasourceData对应一个数据源 一个 dataKey的组合数据点以[时间戳, 数值]二元数组表示。这也解释了示例 JavaScript 为什么要按dataKeyData.datasource归组data是平铺结构而 HTML 表格需要按数据源聚合datasourceData正是为这种按数据源索引访问而引入的重组视图。7.3 IWidgetSubscription 接口中的相关成员在 IWidgetSubscription 接口中可看到与示例直接对应的成员datasources?: ArrayDatasource—— 订阅使用的数据源数组data?: ArrayDatasourceData—— 订阅范围内收到的数据latestData?: ArrayDatasourceData—— 最新值数据Latest values 部件使用type: widgetType、callbacks: WidgetSubscriptionCallbacks等成员共同支撑订阅的生命周期与回调如onDataUpdated对应接口中的WidgetSubscriptionCallbacks.onDataUpdated。7.4 WidgetContext 的 detectChanges 与 updateWidgetParams 底层实现示例中调用的两个 API 在 widget-component.models.ts 中有明确实现detectChanges()在ngZone内调用changeDetectorValue?.detectChanges()触发 Angular 变更检测带updateWidgetParams可选参数为true时先同步部件参数。这正是示例注释中所说的收到新数据时必须执行新的变更检测周期的底层原因updateWidgetParams()通过setTimeout(..., 0)异步调用dashboardWidget.updateWidgetParams()同步部件参数。八、调试技巧与扩展方向官方文档 widget_js_fn.md 还给出了部件代码的两类调试方法Web 控制台输出在部件 JavaScript 任意位置放置console.log(...)点击Run重启部件代码在浏览器控制台观察输出浏览器调试器在感兴趣的位置放置debugger;语句并点击Run浏览器会自动在断点处暂停可用调试工具逐步分析执行过程。基于本示例的datasourceData重组模式可以进一步扩展把data[0]的毫秒时间戳配合date管道展示更丰富的日期格式参照 latest_values_widget.md 使用latestData实现最新值部件为表格列标题绑定dataKey.color实现图例着色借鉴 widget_js_fn.md 中onResize、onDestroy、getSettingsForm、typeParameters、actionSources等生命周期函数为部件增加设置表单与用户动作。至此一个可运行的多数据源 Time-Series 表格部件已完成创建。整个示例的全部代码与说明均可在仓库 ui-ngx/src/assets/help/en_US/widget/editor/examples/timeseries_widget.md 中查看与复现。赞分享物联网后端数据可视化消息队列【免费下载链接】thingsboardAll-in-one IoT Platform - Device management, data collection, processing and visualization.项目地址https://gitcode.com/GitHub_Trending/th/thingsboard点击查看免费下载相关推荐Neon 怎么把 Postgres 上游小版本合并进 neon postgres 并更新仓库引用Neon 怎么把 Postgres 上游小版本合并进 neon postgres 并更新仓库引用 Neon 把 Postgres 以 forkneondata物联网后端数据可视化消息队列ThingsBoard Alarm Widget 从零到实战基于 Widget Editor 开发自定义告警表格组件ThingsBoard Alarm Widget 从零到实战基于 Widget Editor 开发自定义告警表格组件 本指南以 ThingsBoard 官方示物联网后端数据可视化消息队列ThingsBoard 静态 Widget 开发实战从 Widget Editor 创建无数据源的自定义 UI 组件ThingsBoard 静态 Widget 开发实战从 Widget Editor 创建无数据源的自定义 UI 组件 导读 静态 WidgetStatic物联网后端数据可视化消息队列上一篇终极指南如何使用WandEnhancer免费解锁WeMod高级功能下一篇ColorControl高性能跨设备显示控制与智能协同系统深度解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考