准备2张SVG图片, open.svg close.svg
在/usr/src/app/FUXA/client/src/app/gauges/controls/路径下,添加我们的html-myswitch目录和文件。 /usr/src/app/FUXA/client/src/app/gauges/controls/html-myswitch/html-myswitch.component.ts
import { Injectable, ViewContainerRef, ComponentFactoryResolver } from '@angular/core';
import { GaugeBaseComponent } from '../../gauge-base/gauge-base.component';
import { GaugeSettings, Variable, GaugeStatus, WindowLink, Event } from '../../../_models/hmi';
import { Utils } from '../../../_helpers/utils';
import { GaugeDialogType } from '../../gauge-property/gauge-property.component';
import { NgxMySwitchComponent } from '../../../gui-helpers/ngx-myswitch/ngx-myswitch.component';
@Injectable()
export class HtmlMySwitchComponent {
static TypeTag = 'svg-ext-own_ctrl-myswitch';
static LabelTag = 'HtmlMySwitch';
static prefix = 'D-OXC_';
constructor() {
}
static getSignals(pro: any) {
let res: string[] = [];
if (pro.variableId) {
res.push(pro.variableId);
}
if (pro.alarmId) {
res.push(pro.alarmId);
}
if (pro.actions) {
pro.actions.forEach(act => {
res.push(act.variableId);
});
}
return res;
}
static getDialogType(): GaugeDialogType {
return GaugeDialogType.Switch;
}
static bindEvents(ga: GaugeSettings, slider?: NgxMySwitchComponent, callback?:any): Event {
if (slider) {
slider.bindUpdate((val) => {
let event = new Event();
event.type = 'on';
event.ga = ga;
event.value = val;
callback(event);
});
}
return null;
}
static processValue(ga: GaugeSettings, svgele: any, sig: Variable, gaugeStatus: GaugeStatus, switcher?: NgxMySwitchComponent) {
try {
if (switcher) {
let val = parseFloat(sig.value);
if (Number.isNaN(val)) {
// maybe boolean
val = Number(sig.value);
} else {
val = parseFloat(val.toFixed(5));
}
switcher.setValue(val);
}
} catch (err) {
console.error(err);
}
}
static initElement(ga: GaugeSettings, resolver: ComponentFactoryResolver, viewContainerRef: ViewContainerRef, options?: any) {
let ele = document.getElementById(ga.id);
if (ele) {
let htmlSwitch = Utils.searchTreeStartWith(ele, this.prefix);
if (htmlSwitch) {
const factory = resolver.resolveComponentFactory(NgxMySwitchComponent);
const componentRef = viewContainerRef.createComponent(factory);
htmlSwitch.innerHTML = '';
componentRef.changeDetectorRef.detectChanges();
const loaderComponentElement = componentRef.location.nativeElement;
htmlSwitch.appendChild(loaderComponentElement);
// var options = {}
// options.height = htmlSwitch.clientHeight;
// options.width = htmlSwitch.clientWidth;
// if (!componentRef.instance.setOptions(options, true)) {
// // componentRef.instance.init();
// }
return componentRef.instance;
}
}
}
static resize(ga: GaugeSettings, resolver: ComponentFactoryResolver, viewContainerRef: ViewContainerRef, options?: any) {
let ele = document.getElementById(ga.id);
if (ele) {
let htmlSwitch = Utils.searchTreeStartWith(ele, this.prefix);
if (htmlSwitch) {
const factory = resolver.resolveComponentFactory(NgxMySwitchComponent);
const componentRef = viewContainerRef.createComponent(factory);
htmlSwitch.innerHTML = '';
componentRef.changeDetectorRef.detectChanges();
const loaderComponentElement = componentRef.location.nativeElement;
htmlSwitch.appendChild(loaderComponentElement);
return componentRef.instance;
}
}
}
static detectChange(ga: GaugeSettings, res: any, ref: any) {
let options;
if (ga.property && ga.property.options) {
options = ga.property.options;
}
return HtmlMySwitchComponent.initElement(ga, res, ref, options);
}
static getSize(ga: GaugeSettings) {
let result = {height: 0, width: 0};
let ele = document.getElementById(ga.id);
if (ele) {
let htmlSwitch = Utils.searchTreeStartWith(ele, this.prefix);
if (htmlSwitch) {
result.height = htmlSwitch.clientHeight;
result.width = htmlSwitch.clientWidth;
}
}
return result;
}
}
类开头的3个变量: static TypeTag = ‘svg-ext-own_ctrl-myswitch’; static LabelTag = ‘HtmlMySwitch’; static prefix = ‘D-OXC_’; TypeTag必须保留svg-ext-own_ctrl-前缀,最后的myswitch可以自己命令 LabelTag正常用。 prefix,这个D-OXC_不能改,必须保持原样。因为svgeditor并没有开源,其内部对自定义控件的前缀做了限制。如果你想改,需要对已经作为混淆的js进行调整。
这个里用到一个NgxMySwitchComponent文件,这个是我们真实的图形。
/usr/src/app/FUXA/client/src/app/gui-helpers/ngx-myswitch
/usr/src/app/FUXA/client/src/app/gui-helpers/ngx-myswitch/ngx-myswitch.component.html
<label class="md-switch" style="width:100%;height:100%;">
<input type="checkbox" (change)="onClick()" #switcher>
<svg #openW width="100%" version="1.1" viewBox="0 0 8.2021 2.6458" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(-1.1811 -.40369)">
<g transform="translate(-29.104,-80.172)">
<g stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<path d="m30.427 82.687h2.6458" fill="none" stroke-width=".265"/>
<path d="m35.719 82.687h2.6458" fill="none" stroke-width=".265"/>
<ellipse cx="33.073" cy="82.687" rx=".40117" ry=".39902" stroke-width=".256" style="paint-order:normal"/>
<ellipse cx="35.719" cy="82.687" rx=".40117" ry=".39902" fill="#fff" stroke-width=".256" style="paint-order:normal"/>
<path d="m33.073 82.687 2.1167-1.8521" fill="none" stroke-width=".265"/>
</g>
</g>
</g>
</svg>
<svg #closeW width="100%" version="1.1" viewBox="0 0 8.2021 2.6458" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(-1.8476 -5.1592)">
<g transform="translate(-28.447 -79.398)">
<g stroke="#000" stroke-linecap="round" stroke-linejoin="round">
<path d="m30.427 86.656h2.6458" fill="none" stroke-width=".265"/>
<path d="m35.719 86.656h2.6458" fill="none" stroke-width=".265"/>
<ellipse cx="33.073" cy="86.656" rx=".40117" ry=".39902" stroke-width=".256" style="paint-order:normal"/>
<ellipse cx="35.719" cy="86.656" rx=".40117" ry=".39902" fill="#fff" stroke-width=".256" style="paint-order:normal"/>
<path d="m33.073 86.656 2.6458-0.52917" fill="none" stroke-width=".265"/>
</g>
</g>
</g>
</svg>
</label>
这里面的2个svg就是我们的open和close,这个文件看起来是标准的angular component html文件,但是ngIf会报错,估计是和创建方式有关系。
然后需要注意的是style=“width:100%;height:100%",这个控制图形会随着外部操作拖拽变大或者变小。
/usr/src/app/FUXA/client/src/app/gui-helpers/ngx-myswitch/ngx-myswitch.component.ts
/* eslint-disable @angular-eslint/component-selector */
import { Component, OnInit, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
@Component({
selector: 'ngx-myswitch',
templateUrl: './ngx-myswitch.component.html',
styleUrls: ['./ngx-myswitch.component.css']
})
export class NgxMySwitchComponent implements AfterViewInit {
@ViewChild('switcher', {static: false}) public switcher: ElementRef;
@ViewChild('openW', {static: false}) public openW: ElementRef;
@ViewChild('closeW', {static: false}) public closeW: ElementRef;
options: SwitchOptions = new SwitchOptions();
checked = false;
onUpdate: any;
isOpen = false;
constructor() {
}
ngAfterViewInit() {
this.onRefresh();
}
onClick() {
this.onRefresh();
if (this.onUpdate) {
this.onUpdate((this.checked) ? this.options.onValue.toString() : this.options.offValue.toString());
}
}
onRefresh() {
this.checked = this.switcher.nativeElement.checked;
if(this.checked)
{
this.openW.nativeElement.style.display = "none";
this.closeW.nativeElement.style.display = "block";
}else{
this.openW.nativeElement.style.display = "block";
this.closeW.nativeElement.style.display = "none";
}
}
setOptions(options: SwitchOptions, force = false): boolean {
if (force) {
this.options = options;
this.onRefresh();
} else {
setTimeout(() => {
this.options = options;
this.onRefresh();
}, 200);
}
return true;
}
setValue(value: number) {
this.switcher.nativeElement.checked = (value) ? true : false;
this.onRefresh();
}
bindUpdate(calback: any) {
this.onUpdate = calback;
}
}
export class SwitchOptions {
offValue = 0;
onValue = 1;
offBackground = '#ccc';
onBackground = '#ccc';
offText = '';
onText = '';
offSliderColor = '#fff';
onSliderColor = '#0CC868';
offTextColor = '#000'
onTextColor = '#fff'
fontSize = 12
fontFamily = ''
radius = 0;
height: number;
width: number;
}
这个里面因此了一个checkbox处理用户的点击,onRefresh根据当前是选中还是未选中,控制2个图型的显示。
L123:
//JGCX 2023-08-08
import { HtmlMySwitchComponent } from './gauges/controls/html-myswitch/html-myswitch.component';
L335:
//JGCX
HtmlMySwitchComponent,
L40:
//JGCX 2023-08-08 Add Our own gauge
import { HtmlMySwitchComponent } from './controls/html-myswitch/html-myswitch.component';
L72:
// list of gauges components
static Gauges = [ValueComponent, HtmlInputComponent, HtmlButtonComponent, HtmlBagComponent,
HtmlSelectComponent, HtmlChartComponent, GaugeProgressComponent, GaugeSemaphoreComponent, ShapesComponent, ProcEngComponent, ApeShapesComponent,
PipeComponent, SliderComponent, HtmlSwitchComponent, HtmlGraphComponent, HtmlIframeComponent, HtmlTableComponent, HtmlMySwitchComponent];
L206:
else if (ga.type.startsWith(HtmlMySwitchComponent.TypeTag)) {
return this.mapGauges[ga.id] = HtmlMySwitchComponent.detectChange(ga, res, ref);
}
L477:
else if (ga.type.startsWith(HtmlMySwitchComponent.TypeTag)) {
let self = this;
HtmlMySwitchComponent.bindEvents(ga, this.mapGauges[ga.id], (event) => {
self.putEvent(event);
});
}
L546:
else if (ga.type.startsWith(HtmlMySwitchComponent.TypeTag)) {
Object.keys(this.memorySigGauges[sig.id]).forEach(k => {
if (k === ga.id && this.mapGauges[k]) {
HtmlMySwitchComponent.processValue(ga, svgele, sig, gaugeStatus, this.mapGauges[k]);
}
});
break;
}
L715:
else if (type.startsWith(HtmlMySwitchComponent.TypeTag)) {
return 'myswitch_';
}
L811:
else if (ga.type.startsWith(HtmlMySwitchComponent.TypeTag)) {
let gauge = HtmlMySwitchComponent.initElement(ga, res, ref, isview);
this.mapGauges[ga.id] = gauge;
return gauge;
}
L185
<!-- JGCX -->
<div class="svg-tool-button" matTooltip="{{'editor.controls-myswitch' | translate}}" [ngClass]="{'svg-tool-active': isModeActive('own_ctrl-myswitch')}"
(click)="setMode('own_ctrl-myswitch')">
<span class="icon-tool icon-myswitch"></span>
</div>
/usr/src/app/FUXA/client/src/app/editor/editor.component.css
.icon-myswitch {
background: url("assets/images/open.svg") no-repeat center center;
}
然后调试好,就可以用了。