前言
ThingsBoard 是目前 Github 上最风行的开源物联网平台(14.4k Star),能够实现物联网我的项目的疾速开发、治理和扩大, 是中小微企业物联网平台的不二之选。
本文介绍如何在 ThingsBoard 前端我的项目中开发背景图片部件。
产品需要
最近接到产品经理一个需要,在 TB 仪表板中部件的上面能够增加背景图片,实现相似如下的成果:
TB 仪表板整个界面是反对背景图设置的,单个部件只反对背景色彩设置,还不反对背景图片设置,本来想着加个背景图片设置性能就能够解决,后果被告知可能会存在两个部件共用一个背景图片的需要,这就有些麻烦了 …
解决方案
通过我一番斟酌,终于找到了一个正当的解决方案,那就是开发一个可拖拽到其余部件底部的图片部件,将上方的部件背景设置为通明,即可实现预期成果。
开发一个新的部件这个我有教训,难点在于实现拖拽的其余部件下方的部件,这个目前 TB 是不反对的。
在开发者工具中能够查看到,两个部件元素款式 z-index: 1
统一,均在一个层级上,所以无奈重叠。
查看我的项目代码发现,该性能用到了网格布局插件:angular-gridster2,那么就查查看它的官网支不反对重叠性能了。
- github:
https://github.com/tiberiuzuld/angular-gridster2
(1.2k)哎呦,star 还不低的样子。 - 官网文档:
https://tiberiuzuld.github.io/angular-gridster2
官网文档是英文的,在我糟糕的英文浏览程度下,终于找到了该性能:https://tiberiuzuld.github.io/angular-gridster2/multiLayer
,感激官网文档贴心的带 demo 演示性能。
容许我的项目分层显示要害参数:allowMultiLayer:allow items show in layers。
确定计划可行,那就开干!
背景图片部件
部件高级设置
首先我将背景图片部件定义为 Cards 部件库的一种,所以我在 ui-ngx\src\app\modules\home\components\widget\lib\settings\cards
目录下创立部件设置文件 image-widget-settings.component.html
和 image-widget-settings.component.ts
。
其中 image-widget-settings.component.html
代码:
<section class="tb-widget-settings" [formGroup]="imageWidgetSettingsForm">
<fieldset class="fields-group">
<legend class="group-title" translate>widgets.image.settings</legend>
<div fxLayout.xs="column" fxLayout="column" fxLayoutGap="8px">
<!-- 上传图片 -->
<tb-image-input label="{{'widgets.image.imageUrl'| translate}}"
formControlName="imageUrl">
</tb-image-input>
<!-- 是否为背景图片 -->
<mat-slide-toggle formControlName="isUnderLayer" class="slide-block">
{{'widgets.image.isUnderLayer' | translate}}
</mat-slide-toggle>
</div>
</fieldset>
</section>
用 FormGroup 表单控件 imageWidgetSettingsForm
存储数据,数据字段 imageUrl
用存储背景图,应用 TB 的 tb-image-input
上传图片组件。另一个数据字段 isUnderLayer
用来存储是否设定为背景图片,即是否可拖拽到其余部件下方,应用 UI 插件 Material 的滑块开关组件 mat-slide-toggle
来实现。
image-widget-settings.component.ts
代码如下:
import {Component} from '@angular/core';
import {WidgetSettings, WidgetSettingsComponent} from '@shared/models/widget.models';
import {FormBuilder, FormGroup} from '@angular/forms';
import {Store} from '@ngrx/store';
import {AppState} from '@core/core.state';
@Component({
selector: 'tb-image-widget-settings',
templateUrl: './image-widget-settings.component.html',
styleUrls: ['./../widget-settings.scss']
})
export class ImageWidgetSettingsComponent extends WidgetSettingsComponent {
/*FormGroup 表单 */
imageWidgetSettingsForm: FormGroup;
constructor(protected store: Store<AppState>,
private fb: FormBuilder) {super(store);
}
protected settingsForm(): FormGroup {return this.imageWidgetSettingsForm;}
/* 初始化数据字段 */
protected defaultSettings(): WidgetSettings {
return {
imageUrl: '',
isUnderLayer: true,
};
}
/* 数据字段设置 */
protected onSettingsSet(settings: WidgetSettings) {
this.imageWidgetSettingsForm = this.fb.group({imageUrl: [settings.imageUrl, []],
isUnderLayer: [settings.isUnderLayer, []]
});
}
/* 数据字段验证 */
protected updateValidators(emitEvent: boolean) {this.imageWidgetSettingsForm.get('imageUrl').updateValueAndValidity({emitEvent});
this.imageWidgetSettingsForm.get('isUnderLayer').updateValueAndValidity({emitEvent});
}
}
代码并不多,我就都贴上了,定义组件选择器 tb-image-widget-settings
,定义 FormGroup 表单 imageWidgetSettingsForm
,初始化数据字段 imageUrl
和 isUnderLayer
,剩下的数据设置和验证性能和其余的部件设置写法是统一的。
最初记得将 Class ImageWidgetSettingsComponent
在部件设置模块文件 widget-settings.module.ts
中引入申明和导出。
import {ImageWidgetSettingsComponent} from '@home/components/widget/lib/settings/cards/image-widget-settings.component';
@NgModule({
declarations: [
...
ImageWidgetSettingsComponent
],
exports: [
...
ImageWidgetSettingsComponent
]
export class WidgetSettingsModule {
}
export const widgetSettingsComponentsMap: {[key: string]: Type<IWidgetSettingsComponent>} = {
...
'tb-image-widget-settings': ImageWidgetSettingsComponent
};
部件性能展现
创立好部件的高级设置性能,咱们来将部件成果展现进去。
在 ui-ngx\src\app\modules\home\components\widget\lib
目录下创立三个文件 image-widget.component.html
、image-widget.component.ts
和 image-widget.component.css
。
其中 image-widget.component.html
代码如下:
<div class="bg-img" style="background-image: url('{{settings.imageUrl}}')">
</div>
超级简略有木有,因为就是一个背景图成果展现而已,背景图片的门路就是 imageUrl
。
image-widget.component.css
代码如下:
:host {
display: flex;
width: 100%;
height: 100%;
.bg-img{
width: 100%;
height: 100%;
background-repeat: no-repeat;
background-size: 100% 100%;
}
}
Css 用来设置部件的宽高和背景图片的款式,background-size: 100% 100%;
实现背景图片可随着容器拉伸,达到图片全副展现的成果。
image-widget.component.ts
代码如下:
import {ChangeDetectorRef, Component, Input, OnInit} from '@angular/core';
import {PageComponent} from '@shared/components/page.component';
import {WidgetContext} from '@home/models/widget-component.models';
import {Store} from '@ngrx/store';
import {AppState} from '@core/core.state';
interface ImageWidgetSettings {
imageUrl: string;
isUnderLayer: boolean;
}
@Component({
selector: 'tb-image-widget',
templateUrl: './image-widget.component.html',
styleUrls: ['./image-widget.component.css']
})
export class ImageWidgetComponent extends PageComponent implements OnInit {
settings: ImageWidgetSettings;
@Input()
ctx: WidgetContext;
constructor(protected store: Store<AppState>,
protected cd: ChangeDetectorRef) {super(store);
}
ngOnInit(): void {
this.ctx.$scope.imageWidget = this;
this.settings = this.ctx.settings;
}
}
其中的 settings
字段存储部件设置的 imageUrl
和 isUnderLayer
。
和高级设置文件一样,Class ImageWidgetComponent
须要在部件模块文件 widget-components.module.ts
中引入申明和导出。
import {ImageWidgetComponent} from '@home/components/widget/lib/image-widget.component';
@NgModule({
declarations: [
...
ImageWidgetComponent
],
exports: [
...
ImageWidgetComponent
]
export class WidgetComponentsModule {}
设置部件层级
咳咳,敲黑板,接下来是最外围的局部,怎么设置背景图片部件的层级,实现可拖拽到其余部件的底层。
首先找到 angular-gridster2
选项设置的代码,在 dashboard.component.ts
文件中,增加分层选项 allowMultiLayer
:
ngOnInit(): void {
this.dashboardWidgets.parentDashboard = this.parentDashboard;
if (!this.dashboardTimewindow) {this.dashboardTimewindow = this.timeService.defaultTimewindow();
}
this.gridsterOpts = {
gridType: GridType.ScrollVertical,
keepFixedHeightInMobile: true,
disableWarnings: false,
disableAutoPositionOnConflict: false,
pushItems: false,
swap: false,
maxRows: 100,
minCols: this.columns ? this.columns : 24,
maxCols: 3000,
maxItemCols: 1000,
maxItemRows: 1000,
maxItemArea: 1000000,
outerMargin: true,
margin: isDefined(this.margin) ? this.margin : 10,
minItemCols: 1,
minItemRows: 1,
defaultItemCols: 8,
defaultItemRows: 6,
<!-- 新增参数 -->
allowMultiLayer: true,
baseLayerIndex: 1,
defaultLayerIndex: 2,
maxLayerIndex: 10,
resizable: {enabled: this.isEdit},
draggable: {enabled: this.isEdit},
itemChangeCallback: item => this.dashboardWidgets.sortWidgets(),
itemInitCallback: (item, itemComponent) => {(itemComponent.item as DashboardWidget).gridsterItemComponent = itemComponent;
}
};
}
allowMultiLayer: true
设置为容许分层重叠,因为其余部件要在背景图片部件的上方,所以将默认层 defaultLayerIndex
设置 2
,依照官网文档的说法,final z-index should be baseLayerIndex + layerIndex,所以最终部件的层级为 baseLayerIndex + defaultLayerIndex
,也就是层级为 3,关上管制工具查看,正好为 3。
那么问题来了,这是设置整个网格布局的参数,单个部件的层级怎么设置,官网文档 API 并没有给出。
于是,我想到了面向 ChatGPT 编程:
哦?setZIndex()
,原来如此!还好我有 ChatGPT,真是 … 真是胡言乱语啊,试了压根不失效好叭!亏我这么置信你 … 压根没这个办法,真是不苟言笑胡编乱造啊 … 算了,看你之前帮了我那么屡次,这次我就不跟你计较了 …
靠人不如靠己,持续钻研官网文档我发现右上角有查看源码按钮 … 点开浏览源码终于找到如何设置 layerIndex
。
原来将数据设置一个 layerIndex
就能够了,找到循环体数据源打印进去:
果然找到了栅格单元参数 cols, rows, y, x
,咱们只须要找到对应的背景图片部件,设置上 layerIndex
属性即可,那怎么找到呢?对了,就是通过高级设置的字段 isUnderLayer
,在 dashboard.component.ts
文件中 updateWidgets()
办法体中退出判断。
private updateWidgets() {this.dashboardWidgets.setWidgets(this.widgets, this.widgetLayouts);
this.dashboardWidgets.doCheck();
<!-- 背景图片部件层级设置 -->
this.dashboardWidgets.dashboardWidgets.forEach((widget) => {if (widget.widgetContext.widget.config.settings?.isUnderLayer) {widget.layerIndex = 1;}
});
}
因为其余的部件我设置了默认 layerIndex
为 2,背景图片部件在其余部件的上层,所以设置更小的值 1。
最终成果演示
首先咱们须要先将背景图片部件增加到部件库中,登录系统管理员账号 sysadmin@thingsboard.org / sysadmin
,登录系统管理员账号操作是因为增加后会默认显示为零碎部件包。
关上部件库菜单,关上 Cards 部件包,右下角点击增加新的部件类型 -> 创立新的部件类型 -> 动态部件,进行背景图片部件初始化设置:
- 设置部件题目,如“Image”
- 设置 HTML:
<tb-image-widget [ctx]="ctx"></tb-image-widget>
- 清空 JavaScript 内容
- widget.widget-settings 中 widget.settings-form-selector 设置为
tb-image-widget-settings
其中第 2 项中 [ctx]="ctx"
为组件传值必须项,不能省略;第 4 项的 tb-image-widget-settings
为部件高级设置选择器,不能填错。
增加好部件好,咱们在仪表板中增加该部件。
在高级设置中上传一张图片,并将是否为背景图片设置为是,保留后咱们来查看下部件元素的 z-index
。
背景图片部件的 z-index
为 2 失效了,接下来就是见证奇观额时刻!
功败垂成,Nice~
结语
因为 TB 的受众面很小,所以如果你没钻研过 TB 看不懂这篇文章也是很失常的 - -,跳过就好,TB 的相干文章更多的是作为自己的一个工作常识记录,如果能对一小部分人有所帮忙那就更好啦~
好啦,以上就是 ThingsBoard 前端我的项目背景图片部件开发的全部内容,心愿对你有所帮忙,如有问题可通过我的博客 https://echeverra.cn 或微信公众号 echeverra 分割我。
你学“废”了么?
(完)
文章首发于我的博客 https://echeverra.cn/tb3,原创文章,转载请注明出处。
欢送关注我的微信公众号 echeverra,一起学习提高!不定时会有资源和福利相送哦!