@flexem/fc-gui 3.0.0-alpha.185 → 3.0.0-alpha.188
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundles/@flexem/fc-gui.umd.js +255 -165
- package/bundles/@flexem/fc-gui.umd.js.map +1 -1
- package/bundles/@flexem/fc-gui.umd.min.js +1 -1
- package/bundles/@flexem/fc-gui.umd.min.js.map +1 -1
- package/elements/alarm/alarm-element.d.ts +7 -12
- package/elements/alarm/alarm-element.js +67 -137
- package/elements/alarm/alarm-element.metadata.json +1 -1
- package/elements/alarm/alarm-table-scrollbar.d.ts +38 -0
- package/elements/alarm/alarm-table-scrollbar.js +173 -0
- package/elements/alarm/alarm-table-scrollbar.metadata.json +1 -0
- package/elements/historical-curve/historical-curve.element.js +12 -27
- package/package.json +1 -1
|
@@ -37,11 +37,9 @@ export declare class AlarmElement extends ConditionalDisplayElement {
|
|
|
37
37
|
private rowHeight;
|
|
38
38
|
private touchStartY;
|
|
39
39
|
private touchScrollAccumulator;
|
|
40
|
-
private
|
|
41
|
-
private
|
|
42
|
-
private
|
|
43
|
-
private thumbDragStartWindow;
|
|
44
|
-
private thumbDragging;
|
|
40
|
+
private scrollbar;
|
|
41
|
+
private scrollHovered;
|
|
42
|
+
private touchScrolling;
|
|
45
43
|
private isDisposed;
|
|
46
44
|
constructor(element: HTMLElement, injector: Injector, permissionChecker: PermissionChecker, variableCommunicator: VariableCommunicator, variableStore: VariableStore, alarmsStore: AlarmsStore, signalRAppId: string, systemTextLibraryService?: SystemTextLibraryService, languageService?: LanguageService, guiContext?: GuiContext);
|
|
47
45
|
dispose(): void;
|
|
@@ -72,6 +70,7 @@ export declare class AlarmElement extends ConditionalDisplayElement {
|
|
|
72
70
|
private updateTableContent;
|
|
73
71
|
private renderScrollWindow;
|
|
74
72
|
private updateScrollThumb;
|
|
73
|
+
private getMaxWindowStart;
|
|
75
74
|
private getIconScale;
|
|
76
75
|
private renderElement;
|
|
77
76
|
private buildHeaderRow;
|
|
@@ -86,13 +85,9 @@ export declare class AlarmElement extends ConditionalDisplayElement {
|
|
|
86
85
|
private readonly handleScrollTouchMove;
|
|
87
86
|
private readonly handleScrollMouseEnter;
|
|
88
87
|
private readonly handleScrollMouseLeave;
|
|
89
|
-
private
|
|
90
|
-
private
|
|
91
|
-
private
|
|
92
|
-
private readonly handleThumbDragStart;
|
|
93
|
-
private readonly handleThumbDragMove;
|
|
94
|
-
private readonly handleThumbDragEnd;
|
|
95
|
-
private readonly handleTrackClick;
|
|
88
|
+
private readonly handleScrollTouchEnd;
|
|
89
|
+
private getCanvasScaleY;
|
|
90
|
+
private getScreenRowHeight;
|
|
96
91
|
private startAutoScroll;
|
|
97
92
|
private scrollOneRow;
|
|
98
93
|
private autoNextPage;
|
|
@@ -4,6 +4,7 @@ import { ConditionalDisplayElement } from '../base/conditional-display-element';
|
|
|
4
4
|
import { GetAlarmsArgs } from '../../config';
|
|
5
5
|
import * as moment from 'moment';
|
|
6
6
|
import { LOGGER_SERVICE_TOKEN } from '../../logger';
|
|
7
|
+
import { AlarmTableScrollbar } from './alarm-table-scrollbar';
|
|
7
8
|
var AlaertElementStatus;
|
|
8
9
|
(function (AlaertElementStatus) {
|
|
9
10
|
AlaertElementStatus[AlaertElementStatus["Normal"] = 0] = "Normal";
|
|
@@ -42,97 +43,60 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
42
43
|
this.rowHeight = 0;
|
|
43
44
|
this.touchStartY = 0;
|
|
44
45
|
this.touchScrollAccumulator = 0;
|
|
45
|
-
this.
|
|
46
|
-
this.
|
|
47
|
-
this.thumbDragging = false;
|
|
46
|
+
this.scrollHovered = false;
|
|
47
|
+
this.touchScrolling = false;
|
|
48
48
|
this.isDisposed = false;
|
|
49
49
|
this.handleScrollWheel = (event) => {
|
|
50
|
-
if (!this.rowHeight)
|
|
50
|
+
if (!this.rowHeight || !this.getMaxWindowStart())
|
|
51
51
|
return;
|
|
52
52
|
event.preventDefault();
|
|
53
|
-
|
|
54
|
-
const
|
|
53
|
+
event.stopPropagation();
|
|
54
|
+
const screenRowHeight = this.getScreenRowHeight();
|
|
55
|
+
const delta = event.deltaMode === 1 ? event.deltaY * screenRowHeight
|
|
56
|
+
: event.deltaMode === 2 ? event.deltaY * screenRowHeight * this.maxVisibleRows : event.deltaY;
|
|
57
|
+
this.touchScrollAccumulator += delta;
|
|
58
|
+
const rowDelta = Math.trunc(this.touchScrollAccumulator / screenRowHeight);
|
|
55
59
|
if (rowDelta !== 0) {
|
|
56
|
-
this.touchScrollAccumulator -= rowDelta *
|
|
60
|
+
this.touchScrollAccumulator -= rowDelta * screenRowHeight;
|
|
57
61
|
this.moveScrollWindowBy(rowDelta);
|
|
58
62
|
}
|
|
59
63
|
};
|
|
60
64
|
this.handleScrollTouchStart = (event) => {
|
|
65
|
+
if (event.touches.length !== 1 || !this.getMaxWindowStart())
|
|
66
|
+
return;
|
|
67
|
+
this.touchScrolling = true;
|
|
68
|
+
clearInterval(this.scrollIntervalId);
|
|
69
|
+
event.stopPropagation();
|
|
61
70
|
this.touchStartY = event.touches[0].clientY;
|
|
62
71
|
this.touchScrollAccumulator = 0;
|
|
63
72
|
};
|
|
64
73
|
this.handleScrollTouchMove = (event) => {
|
|
65
|
-
if (!this.
|
|
74
|
+
if (!this.touchScrolling || event.touches.length !== 1)
|
|
66
75
|
return;
|
|
67
76
|
event.preventDefault();
|
|
77
|
+
event.stopPropagation();
|
|
68
78
|
const currentY = event.touches[0].clientY;
|
|
69
79
|
const deltaY = this.touchStartY - currentY;
|
|
70
80
|
this.touchStartY = currentY;
|
|
71
81
|
this.touchScrollAccumulator += deltaY;
|
|
72
|
-
const
|
|
82
|
+
const screenRowHeight = this.getScreenRowHeight();
|
|
83
|
+
const rowDelta = Math.trunc(this.touchScrollAccumulator / screenRowHeight);
|
|
73
84
|
if (rowDelta !== 0) {
|
|
74
|
-
this.touchScrollAccumulator -= rowDelta *
|
|
85
|
+
this.touchScrollAccumulator -= rowDelta * screenRowHeight;
|
|
75
86
|
this.moveScrollWindowBy(rowDelta);
|
|
76
87
|
}
|
|
77
88
|
};
|
|
78
89
|
this.handleScrollMouseEnter = () => {
|
|
90
|
+
this.scrollHovered = true;
|
|
79
91
|
clearInterval(this.scrollIntervalId);
|
|
80
92
|
};
|
|
81
93
|
this.handleScrollMouseLeave = () => {
|
|
82
|
-
|
|
83
|
-
this.startAutoScroll();
|
|
84
|
-
};
|
|
85
|
-
// 拖拽滑块时挂全局 mousemove/mouseup,允许拖出滚动条区域也能继续跟手,松开时才解绑
|
|
86
|
-
this.handleThumbDragStart = (event) => {
|
|
87
|
-
event.preventDefault();
|
|
88
|
-
event.stopPropagation();
|
|
89
|
-
this.thumbDragging = true;
|
|
90
|
-
clearInterval(this.scrollIntervalId);
|
|
91
|
-
this.thumbDragStartY = this.getClientY(event);
|
|
92
|
-
this.thumbDragStartWindow = this.scrollWindowStart;
|
|
93
|
-
document.addEventListener('mousemove', this.handleThumbDragMove);
|
|
94
|
-
document.addEventListener('mouseup', this.handleThumbDragEnd);
|
|
95
|
-
document.addEventListener('touchmove', this.handleThumbDragMove, { passive: false });
|
|
96
|
-
document.addEventListener('touchend', this.handleThumbDragEnd);
|
|
97
|
-
};
|
|
98
|
-
this.handleThumbDragMove = (event) => {
|
|
99
|
-
if (!this.thumbDragging || !this.scrollTrack)
|
|
100
|
-
return;
|
|
101
|
-
event.preventDefault();
|
|
102
|
-
const maxWindowStart = Math.max(0, this.pageSize - this.maxVisibleRows);
|
|
103
|
-
if (maxWindowStart <= 0)
|
|
104
|
-
return;
|
|
105
|
-
const trackHeight = this.scrollTrack.clientHeight;
|
|
106
|
-
const thumbHeightRatio = Math.min(1, this.maxVisibleRows / this.pageSize);
|
|
107
|
-
const thumbHeight = Math.max(20, trackHeight * thumbHeightRatio);
|
|
108
|
-
const maxThumbTop = trackHeight - thumbHeight;
|
|
109
|
-
if (maxThumbTop <= 0)
|
|
110
|
-
return;
|
|
111
|
-
const deltaY = this.getClientY(event) - this.thumbDragStartY;
|
|
112
|
-
const deltaWindow = Math.round((deltaY / maxThumbTop) * maxWindowStart);
|
|
113
|
-
const nextStart = Math.min(maxWindowStart, Math.max(0, this.thumbDragStartWindow + deltaWindow));
|
|
114
|
-
if (nextStart === this.scrollWindowStart)
|
|
115
|
-
return;
|
|
116
|
-
this.scrollWindowStart = nextStart;
|
|
117
|
-
this.renderScrollWindow(this.scrollWindowStart);
|
|
118
|
-
};
|
|
119
|
-
this.handleThumbDragEnd = () => {
|
|
120
|
-
this.thumbDragging = false;
|
|
121
|
-
document.removeEventListener('mousemove', this.handleThumbDragMove);
|
|
122
|
-
document.removeEventListener('mouseup', this.handleThumbDragEnd);
|
|
123
|
-
document.removeEventListener('touchmove', this.handleThumbDragMove);
|
|
124
|
-
document.removeEventListener('touchend', this.handleThumbDragEnd);
|
|
94
|
+
this.scrollHovered = false;
|
|
125
95
|
this.startAutoScroll();
|
|
126
96
|
};
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return;
|
|
131
|
-
const trackRect = this.scrollTrack.getBoundingClientRect();
|
|
132
|
-
const clickTop = event.clientY - trackRect.top;
|
|
133
|
-
const thumbTop = parseFloat(this.scrollThumb.style.top) || 0;
|
|
134
|
-
const rowDelta = clickTop < thumbTop ? -this.maxVisibleRows : this.maxVisibleRows;
|
|
135
|
-
this.moveScrollWindowBy(rowDelta);
|
|
97
|
+
this.handleScrollTouchEnd = () => {
|
|
98
|
+
this.touchScrolling = false;
|
|
99
|
+
this.startAutoScroll();
|
|
136
100
|
};
|
|
137
101
|
this.rootElement.selectAll('*').remove();
|
|
138
102
|
this.setStatusAsLoading();
|
|
@@ -415,7 +379,7 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
415
379
|
if (useScroll) {
|
|
416
380
|
if (!this.scrollContent)
|
|
417
381
|
return;
|
|
418
|
-
this.scrollWindowStart = Math.min(this.scrollWindowStart,
|
|
382
|
+
this.scrollWindowStart = Math.min(this.scrollWindowStart, this.getMaxWindowStart());
|
|
419
383
|
this.renderScrollWindow(this.scrollWindowStart);
|
|
420
384
|
return;
|
|
421
385
|
}
|
|
@@ -450,24 +414,12 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
450
414
|
}
|
|
451
415
|
this.updateScrollThumb();
|
|
452
416
|
}
|
|
453
|
-
// 滑块高度按"可见行数/总行数"的比例算,位置按当前窗口起始行占可滚动范围的比例算,
|
|
454
|
-
// 只用 top/height 两个数值属性更新,不涉及 transform,不会触发合成层
|
|
455
417
|
updateScrollThumb() {
|
|
456
|
-
if (
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
return;
|
|
462
|
-
}
|
|
463
|
-
this.scrollThumb.style.display = 'block';
|
|
464
|
-
const trackHeight = this.scrollTrack.clientHeight;
|
|
465
|
-
const thumbHeightRatio = Math.min(1, this.maxVisibleRows / this.pageSize);
|
|
466
|
-
const thumbHeight = Math.max(20, trackHeight * thumbHeightRatio);
|
|
467
|
-
const maxThumbTop = trackHeight - thumbHeight;
|
|
468
|
-
const thumbTop = maxThumbTop * (this.scrollWindowStart / maxWindowStart);
|
|
469
|
-
this.scrollThumb.style.height = `${thumbHeight}px`;
|
|
470
|
-
this.scrollThumb.style.top = `${thumbTop}px`;
|
|
418
|
+
if (this.scrollbar)
|
|
419
|
+
this.scrollbar.update(this.scrollWindowStart, this.alarmList.length);
|
|
420
|
+
}
|
|
421
|
+
getMaxWindowStart() {
|
|
422
|
+
return Math.max(0, this.alarmList.length - this.maxVisibleRows);
|
|
471
423
|
}
|
|
472
424
|
getIconScale() {
|
|
473
425
|
const initSize = this.model.initSize;
|
|
@@ -516,7 +468,7 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
516
468
|
vertical-align: middle;`;
|
|
517
469
|
for (let col = 0; col < 4; col++) {
|
|
518
470
|
const th = document.createElement('th');
|
|
519
|
-
th.
|
|
471
|
+
th.textContent = this.getHeaderTextByColumn(col);
|
|
520
472
|
th.style.cssText = `width: ${this.model.widths[col] / this.model.size.width * 100}%;
|
|
521
473
|
border-style: solid;
|
|
522
474
|
border-color: ${this.model.generalSetting.splitLine};
|
|
@@ -543,7 +495,7 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
543
495
|
border-left-width: ${!col || this.model.generalSetting.isHiddenColumnSplitLine ? 0 : 1}px;`;
|
|
544
496
|
if (this.alarmList[row]) {
|
|
545
497
|
if (col !== 2) {
|
|
546
|
-
td.
|
|
498
|
+
td.textContent = this.alarmList[row][col];
|
|
547
499
|
td.style.cssText += `${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
|
|
548
500
|
}
|
|
549
501
|
else {
|
|
@@ -562,14 +514,14 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
562
514
|
border-radius: 5px;
|
|
563
515
|
background: ${levelColors[this.alarmList[row][col]]};
|
|
564
516
|
color: #ffffff;
|
|
565
|
-
width:
|
|
517
|
+
width: calc(100% - 30px);
|
|
566
518
|
height: ${alarmHeight}px;
|
|
567
519
|
max-height: ${rowHeight}px;
|
|
568
520
|
display: flex;
|
|
569
521
|
justify-content: center;
|
|
570
522
|
align-items: center;
|
|
571
523
|
${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
|
|
572
|
-
alarmLevel.
|
|
524
|
+
alarmLevel.textContent = this.model.levelText[this.alarmList[row][col]];
|
|
573
525
|
td.appendChild(alarmLevel);
|
|
574
526
|
}
|
|
575
527
|
}
|
|
@@ -609,40 +561,25 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
609
561
|
const dataRowHeight = this.model.heights[1] || this.model.heights[0];
|
|
610
562
|
this.rowHeight = dataRowHeight;
|
|
611
563
|
this.scrollWindowStart = 0;
|
|
612
|
-
//
|
|
613
|
-
//
|
|
614
|
-
//
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
// 自定义滚动条(轨道+滑块)只用 position + top/height 定位,不用 overflow/transform/
|
|
618
|
-
// will-change,这些属性都不会触发 WebKit 合成层提升,不会重新引入 iOS 缩放错位问题。
|
|
619
|
-
const scrollbarWidth = 6;
|
|
620
|
-
const wrapper = document.createElement('div');
|
|
621
|
-
wrapper.style.cssText = `position: relative; width: ${this.model.size.width}px;
|
|
622
|
-
height: ${elementHeight - operationAreaReservedHeight}px;`;
|
|
564
|
+
// WKWebView can paint positioned HTML descendants outside the SVG scale.
|
|
565
|
+
// Keep a single unpositioned table directly in foreignObject; the scrollbar
|
|
566
|
+
// is a sibling SVG group, never an HTML overlay or native scrolling layer.
|
|
567
|
+
const scrollbarWidth = Math.min(12, this.model.size.width * 0.04);
|
|
568
|
+
const tableHeight = elementHeight - operationAreaReservedHeight;
|
|
623
569
|
const table = document.createElement('table');
|
|
624
570
|
table.style.cssText = `border: 2px solid ${this.model.generalSetting.stroke};
|
|
625
|
-
height: ${
|
|
626
|
-
|
|
571
|
+
height: ${tableHeight}px; width: 100%; table-layout: fixed;
|
|
572
|
+
overflow-wrap: break-word; -webkit-text-size-adjust: none; text-size-adjust: none;`;
|
|
627
573
|
table.appendChild(this.buildHeaderRow());
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
track.style.cssText = `position: absolute; top: 0; right: 0; width: ${scrollbarWidth}px;
|
|
631
|
-
height: 100%; background: rgba(0,0,0,0.06); border-radius: ${scrollbarWidth / 2}px;`;
|
|
632
|
-
const thumb = document.createElement('div');
|
|
633
|
-
thumb.style.cssText = `position: absolute; left: 0; width: 100%;
|
|
634
|
-
background: rgba(0,0,0,0.35); border-radius: ${scrollbarWidth / 2}px; cursor: pointer;`;
|
|
635
|
-
track.appendChild(thumb);
|
|
636
|
-
wrapper.appendChild(track);
|
|
637
|
-
this.element.appendChild(wrapper);
|
|
574
|
+
this.element.setAttribute('width', String(this.model.size.width - scrollbarWidth));
|
|
575
|
+
this.element.appendChild(table);
|
|
638
576
|
this.scrollContent = table;
|
|
639
|
-
this.scrollTrack = track;
|
|
640
|
-
this.scrollThumb = thumb;
|
|
641
577
|
this.renderScrollWindow(0);
|
|
578
|
+
const headerHeight = Math.min(tableHeight, table.rows[0].getBoundingClientRect().height / this.getCanvasScaleY());
|
|
579
|
+
this.scrollbar = new AlarmTableScrollbar(this.element.parentNode, this.model.size.width - scrollbarWidth, headerHeight, scrollbarWidth, Math.max(0, tableHeight - headerHeight), this.maxVisibleRows, start => this.moveScrollWindowBy(start - this.scrollWindowStart), () => clearInterval(this.scrollIntervalId), () => this.startAutoScroll());
|
|
642
580
|
this.updateScrollThumb();
|
|
643
581
|
this.hoverTarget = table;
|
|
644
582
|
this.bindScrollHoverEvents();
|
|
645
|
-
this.bindScrollbarEvents();
|
|
646
583
|
this.startAutoScroll();
|
|
647
584
|
}
|
|
648
585
|
bindScrollHoverEvents() {
|
|
@@ -654,10 +591,16 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
654
591
|
this.hoverTarget.addEventListener('wheel', this.handleScrollWheel, { passive: false });
|
|
655
592
|
this.hoverTarget.addEventListener('touchstart', this.handleScrollTouchStart, { passive: true });
|
|
656
593
|
this.hoverTarget.addEventListener('touchmove', this.handleScrollTouchMove, { passive: false });
|
|
594
|
+
this.hoverTarget.addEventListener('touchend', this.handleScrollTouchEnd);
|
|
595
|
+
this.hoverTarget.addEventListener('touchcancel', this.handleScrollTouchEnd);
|
|
657
596
|
}
|
|
658
597
|
}
|
|
659
598
|
unbindScrollHoverEvents() {
|
|
660
|
-
this.
|
|
599
|
+
if (this.scrollbar)
|
|
600
|
+
this.scrollbar.dispose();
|
|
601
|
+
this.scrollbar = null;
|
|
602
|
+
this.scrollHovered = false;
|
|
603
|
+
this.touchScrolling = false;
|
|
661
604
|
if (!this.hoverTarget)
|
|
662
605
|
return;
|
|
663
606
|
this.hoverTarget.removeEventListener('mouseenter', this.handleScrollMouseEnter);
|
|
@@ -665,6 +608,8 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
665
608
|
this.hoverTarget.removeEventListener('wheel', this.handleScrollWheel);
|
|
666
609
|
this.hoverTarget.removeEventListener('touchstart', this.handleScrollTouchStart);
|
|
667
610
|
this.hoverTarget.removeEventListener('touchmove', this.handleScrollTouchMove);
|
|
611
|
+
this.hoverTarget.removeEventListener('touchend', this.handleScrollTouchEnd);
|
|
612
|
+
this.hoverTarget.removeEventListener('touchcancel', this.handleScrollTouchEnd);
|
|
668
613
|
this.hoverTarget = null;
|
|
669
614
|
}
|
|
670
615
|
// 手动滚动只在当前可见窗口范围内移动(不触发翻页),到顶/到底停住,
|
|
@@ -672,41 +617,26 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
672
617
|
moveScrollWindowBy(rowDelta) {
|
|
673
618
|
if (!this.scrollContent)
|
|
674
619
|
return;
|
|
675
|
-
const maxWindowStart =
|
|
620
|
+
const maxWindowStart = this.getMaxWindowStart();
|
|
676
621
|
const nextStart = Math.min(maxWindowStart, Math.max(0, this.scrollWindowStart + rowDelta));
|
|
677
622
|
if (nextStart === this.scrollWindowStart)
|
|
678
623
|
return;
|
|
679
624
|
this.scrollWindowStart = nextStart;
|
|
680
625
|
this.renderScrollWindow(this.scrollWindowStart);
|
|
681
626
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
this.scrollThumb.addEventListener('mousedown', this.handleThumbDragStart);
|
|
686
|
-
this.scrollThumb.addEventListener('touchstart', this.handleThumbDragStart, { passive: true });
|
|
687
|
-
this.scrollTrack.addEventListener('mousedown', this.handleTrackClick);
|
|
627
|
+
getCanvasScaleY() {
|
|
628
|
+
const matrix = this.element.getScreenCTM();
|
|
629
|
+
return matrix ? Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d) || 1 : 1;
|
|
688
630
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
}
|
|
694
|
-
if (this.scrollTrack) {
|
|
695
|
-
this.scrollTrack.removeEventListener('mousedown', this.handleTrackClick);
|
|
696
|
-
}
|
|
697
|
-
document.removeEventListener('mousemove', this.handleThumbDragMove);
|
|
698
|
-
document.removeEventListener('mouseup', this.handleThumbDragEnd);
|
|
699
|
-
document.removeEventListener('touchmove', this.handleThumbDragMove);
|
|
700
|
-
document.removeEventListener('touchend', this.handleThumbDragEnd);
|
|
701
|
-
this.scrollTrack = null;
|
|
702
|
-
this.scrollThumb = null;
|
|
703
|
-
}
|
|
704
|
-
getClientY(event) {
|
|
705
|
-
return 'touches' in event ? event.touches[0].clientY : event.clientY;
|
|
631
|
+
getScreenRowHeight() {
|
|
632
|
+
var _a;
|
|
633
|
+
const row = (_a = this.scrollContent) === null || _a === void 0 ? void 0 : _a.querySelectorAll('tr')[1];
|
|
634
|
+
return (row === null || row === void 0 ? void 0 : row.getBoundingClientRect().height) || this.rowHeight * this.getCanvasScaleY();
|
|
706
635
|
}
|
|
707
636
|
startAutoScroll() {
|
|
637
|
+
var _a;
|
|
708
638
|
clearInterval(this.scrollIntervalId);
|
|
709
|
-
if (!this.model.generalSetting.autoScroll)
|
|
639
|
+
if (this.isDisposed || this.scrollHovered || this.touchScrolling || ((_a = this.scrollbar) === null || _a === void 0 ? void 0 : _a.isInteracting) || !this.model.generalSetting.autoScroll)
|
|
710
640
|
return;
|
|
711
641
|
const totalPages = Math.max(1, Math.ceil(this.totalCount / this.pageSize));
|
|
712
642
|
if (totalPages <= 1 && !this.scrollContent)
|
|
@@ -719,7 +649,7 @@ export class AlarmElement extends ConditionalDisplayElement {
|
|
|
719
649
|
this.autoNextPage();
|
|
720
650
|
return;
|
|
721
651
|
}
|
|
722
|
-
const maxWindowStart = this.
|
|
652
|
+
const maxWindowStart = this.getMaxWindowStart();
|
|
723
653
|
if (maxWindowStart <= 0 || this.scrollWindowStart >= maxWindowStart) {
|
|
724
654
|
this.autoNextPage();
|
|
725
655
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"__symbolic":"module","version":4,"metadata":{"AlarmElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":
|
|
1
|
+
[{"__symbolic":"module","version":4,"metadata":{"AlarmElement":{"__symbolic":"class","extends":{"__symbolic":"reference","module":"../base/conditional-display-element","name":"ConditionalDisplayElement","line":22,"character":34},"members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":68,"character":25,"context":{"typeName":"HTMLElement"}},{"__symbolic":"reference","module":"@angular/core","name":"Injector","line":69,"character":18},{"__symbolic":"reference","module":"../../service","name":"PermissionChecker","line":70,"character":27},{"__symbolic":"reference","module":"../../communication","name":"VariableCommunicator","line":71,"character":30},{"__symbolic":"reference","module":"../../config","name":"VariableStore","line":72,"character":23},{"__symbolic":"reference","module":"../../config","name":"AlarmsStore","line":73,"character":38},{"__symbolic":"reference","name":"string"},{"__symbolic":"reference","module":"../../service","name":"SystemTextLibraryService","line":75,"character":52},{"__symbolic":"reference","module":"../../service","name":"LanguageService","line":76,"character":43},{"__symbolic":"reference","module":"../../gui/gui-context","name":"GuiContext","line":77,"character":38}]}],"dispose":[{"__symbolic":"method"}],"subscribeLanguageChange":[{"__symbolic":"method"}],"updateLanguageTexts":[{"__symbolic":"method"}],"getCurrentCulture":[{"__symbolic":"method"}],"getHeaderTextByColumn":[{"__symbolic":"method"}],"getValidTimePeriods":[{"__symbolic":"method"}],"getTimePeriodText":[{"__symbolic":"method"}],"getAlarmData":[{"__symbolic":"method"}],"refreshCurrentPageData":[{"__symbolic":"method"}],"updateTableContent":[{"__symbolic":"method"}],"renderScrollWindow":[{"__symbolic":"method"}],"updateScrollThumb":[{"__symbolic":"method"}],"getMaxWindowStart":[{"__symbolic":"method"}],"getIconScale":[{"__symbolic":"method"}],"renderElement":[{"__symbolic":"method"}],"buildHeaderRow":[{"__symbolic":"method"}],"buildDataRow":[{"__symbolic":"method"}],"renderPlainTable":[{"__symbolic":"method"}],"renderScrollableTable":[{"__symbolic":"method"}],"bindScrollHoverEvents":[{"__symbolic":"method"}],"unbindScrollHoverEvents":[{"__symbolic":"method"}],"moveScrollWindowBy":[{"__symbolic":"method"}],"getCanvasScaleY":[{"__symbolic":"method"}],"getScreenRowHeight":[{"__symbolic":"method"}],"startAutoScroll":[{"__symbolic":"method"}],"scrollOneRow":[{"__symbolic":"method"}],"autoNextPage":[{"__symbolic":"method"}],"renderOperationArea":[{"__symbolic":"method"}],"updateTimeRange":[{"__symbolic":"method"}],"updateQueryTimeRange":[{"__symbolic":"method"}],"loadFirstPage":[{"__symbolic":"method"}],"loadNextPage":[{"__symbolic":"method"}],"loadPreviousPage":[{"__symbolic":"method"}],"loadLastPage":[{"__symbolic":"method"}],"setStatusAsNormal":[{"__symbolic":"method"}],"setStatusAsLoading":[{"__symbolic":"method"}],"renderStatus":[{"__symbolic":"method"}],"clearStatus":[{"__symbolic":"method"}]}}}}]
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** SVG scrollbar kept outside foreignObject so WKWebView applies the canvas scale. */
|
|
2
|
+
export declare class AlarmTableScrollbar {
|
|
3
|
+
private readonly y;
|
|
4
|
+
private readonly height;
|
|
5
|
+
private readonly visibleRows;
|
|
6
|
+
private readonly onChange;
|
|
7
|
+
private readonly onPause;
|
|
8
|
+
private readonly onResume;
|
|
9
|
+
private readonly group;
|
|
10
|
+
private readonly track;
|
|
11
|
+
private readonly thumb;
|
|
12
|
+
private readonly ownerDocument;
|
|
13
|
+
private maxStart;
|
|
14
|
+
private start;
|
|
15
|
+
private thumbHeight;
|
|
16
|
+
private thumbTop;
|
|
17
|
+
private dragging;
|
|
18
|
+
private hovered;
|
|
19
|
+
private focused;
|
|
20
|
+
private dragStartY;
|
|
21
|
+
private dragStartRow;
|
|
22
|
+
constructor(parent: SVGElement, x: number, y: number, width: number, height: number, visibleRows: number, onChange: (start: number) => void, onPause: () => void, onResume: () => void);
|
|
23
|
+
get isInteracting(): boolean;
|
|
24
|
+
update(start: number, totalRows: number): void;
|
|
25
|
+
dispose(): void;
|
|
26
|
+
private createElement;
|
|
27
|
+
private setRect;
|
|
28
|
+
private getLocalY;
|
|
29
|
+
private readonly handleStart;
|
|
30
|
+
private readonly handleMove;
|
|
31
|
+
private readonly handleEnd;
|
|
32
|
+
private readonly handleLeave;
|
|
33
|
+
private readonly handleEnter;
|
|
34
|
+
private readonly handleFocus;
|
|
35
|
+
private readonly handleBlur;
|
|
36
|
+
private readonly handleKeyDown;
|
|
37
|
+
private unbindDrag;
|
|
38
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/** SVG scrollbar kept outside foreignObject so WKWebView applies the canvas scale. */
|
|
2
|
+
export class AlarmTableScrollbar {
|
|
3
|
+
constructor(parent, x, y, width, height, visibleRows, onChange, onPause, onResume) {
|
|
4
|
+
this.y = y;
|
|
5
|
+
this.height = height;
|
|
6
|
+
this.visibleRows = visibleRows;
|
|
7
|
+
this.onChange = onChange;
|
|
8
|
+
this.onPause = onPause;
|
|
9
|
+
this.onResume = onResume;
|
|
10
|
+
this.maxStart = 0;
|
|
11
|
+
this.start = 0;
|
|
12
|
+
this.thumbHeight = 0;
|
|
13
|
+
this.thumbTop = 0;
|
|
14
|
+
this.dragging = false;
|
|
15
|
+
this.hovered = false;
|
|
16
|
+
this.focused = false;
|
|
17
|
+
this.dragStartY = 0;
|
|
18
|
+
this.dragStartRow = 0;
|
|
19
|
+
this.handleStart = (event) => {
|
|
20
|
+
if (!this.maxStart || ('button' in event && event.button !== 0) || ('touches' in event && event.touches.length !== 1))
|
|
21
|
+
return;
|
|
22
|
+
event.preventDefault();
|
|
23
|
+
event.stopPropagation();
|
|
24
|
+
this.onPause();
|
|
25
|
+
const localY = this.getLocalY(event);
|
|
26
|
+
// The full gutter is clickable, including the transparent sides of the thumb.
|
|
27
|
+
if (localY < this.y + this.thumbTop || localY > this.y + this.thumbTop + this.thumbHeight) {
|
|
28
|
+
this.onChange(this.start + (localY < this.y + this.thumbTop ? -this.visibleRows : this.visibleRows));
|
|
29
|
+
this.onResume();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
this.dragging = true;
|
|
33
|
+
this.dragStartY = localY;
|
|
34
|
+
this.dragStartRow = this.start;
|
|
35
|
+
this.thumb.setAttribute('fill', '#8f99aa');
|
|
36
|
+
this.thumb.style.cursor = 'grabbing';
|
|
37
|
+
this.ownerDocument.addEventListener('mousemove', this.handleMove);
|
|
38
|
+
this.ownerDocument.addEventListener('mouseup', this.handleEnd);
|
|
39
|
+
this.ownerDocument.addEventListener('touchmove', this.handleMove, { passive: false });
|
|
40
|
+
this.ownerDocument.addEventListener('touchend', this.handleEnd);
|
|
41
|
+
this.ownerDocument.addEventListener('touchcancel', this.handleEnd);
|
|
42
|
+
this.ownerDocument.defaultView.addEventListener('blur', this.handleEnd);
|
|
43
|
+
};
|
|
44
|
+
this.handleMove = (event) => {
|
|
45
|
+
if (!this.dragging || ('touches' in event && event.touches.length !== 1))
|
|
46
|
+
return;
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
event.stopPropagation();
|
|
49
|
+
const travel = this.height - this.thumbHeight;
|
|
50
|
+
if (travel <= 0)
|
|
51
|
+
return;
|
|
52
|
+
const rowDelta = Math.round((this.getLocalY(event) - this.dragStartY) / travel * this.maxStart);
|
|
53
|
+
this.onChange(this.dragStartRow + rowDelta);
|
|
54
|
+
};
|
|
55
|
+
this.handleEnd = () => {
|
|
56
|
+
if (!this.dragging)
|
|
57
|
+
return;
|
|
58
|
+
this.dragging = false;
|
|
59
|
+
this.unbindDrag();
|
|
60
|
+
this.thumb.setAttribute('fill', '#b6bdc9');
|
|
61
|
+
this.thumb.style.cursor = 'grab';
|
|
62
|
+
this.onResume();
|
|
63
|
+
};
|
|
64
|
+
this.handleLeave = () => {
|
|
65
|
+
this.hovered = false;
|
|
66
|
+
this.onResume();
|
|
67
|
+
};
|
|
68
|
+
this.handleEnter = () => {
|
|
69
|
+
this.hovered = true;
|
|
70
|
+
this.onPause();
|
|
71
|
+
};
|
|
72
|
+
this.handleFocus = () => {
|
|
73
|
+
this.focused = true;
|
|
74
|
+
this.onPause();
|
|
75
|
+
};
|
|
76
|
+
this.handleBlur = () => {
|
|
77
|
+
this.focused = false;
|
|
78
|
+
this.onResume();
|
|
79
|
+
};
|
|
80
|
+
this.handleKeyDown = (event) => {
|
|
81
|
+
const targets = {
|
|
82
|
+
ArrowUp: this.start - 1,
|
|
83
|
+
ArrowDown: this.start + 1,
|
|
84
|
+
PageUp: this.start - this.visibleRows,
|
|
85
|
+
PageDown: this.start + this.visibleRows,
|
|
86
|
+
Home: 0,
|
|
87
|
+
End: this.maxStart
|
|
88
|
+
};
|
|
89
|
+
if (!(event.key in targets))
|
|
90
|
+
return;
|
|
91
|
+
event.preventDefault();
|
|
92
|
+
event.stopPropagation();
|
|
93
|
+
this.onChange(targets[event.key]);
|
|
94
|
+
};
|
|
95
|
+
this.ownerDocument = parent.ownerDocument;
|
|
96
|
+
this.group = this.createElement('g');
|
|
97
|
+
this.group.setAttribute('role', 'scrollbar');
|
|
98
|
+
this.group.setAttribute('aria-orientation', 'vertical');
|
|
99
|
+
this.group.setAttribute('aria-valuemin', '0');
|
|
100
|
+
this.group.setAttribute('tabindex', '0');
|
|
101
|
+
this.group.style.cursor = 'default';
|
|
102
|
+
this.track = this.createElement('rect');
|
|
103
|
+
this.setRect(this.track, x, y, width, height);
|
|
104
|
+
this.track.setAttribute('fill', '#eef0f4');
|
|
105
|
+
this.track.setAttribute('rx', String(width / 2));
|
|
106
|
+
this.thumb = this.createElement('rect');
|
|
107
|
+
this.setRect(this.thumb, x + width / 4, y, width / 2, height);
|
|
108
|
+
this.thumb.setAttribute('fill', '#b6bdc9');
|
|
109
|
+
this.thumb.setAttribute('rx', String(width / 4));
|
|
110
|
+
this.thumb.style.cursor = 'grab';
|
|
111
|
+
this.group.appendChild(this.track);
|
|
112
|
+
this.group.appendChild(this.thumb);
|
|
113
|
+
parent.appendChild(this.group);
|
|
114
|
+
this.group.addEventListener('mousedown', this.handleStart);
|
|
115
|
+
this.group.addEventListener('touchstart', this.handleStart, { passive: false });
|
|
116
|
+
this.group.addEventListener('keydown', this.handleKeyDown);
|
|
117
|
+
this.group.addEventListener('mouseenter', this.handleEnter);
|
|
118
|
+
this.group.addEventListener('mouseleave', this.handleLeave);
|
|
119
|
+
this.group.addEventListener('focus', this.handleFocus);
|
|
120
|
+
this.group.addEventListener('blur', this.handleBlur);
|
|
121
|
+
}
|
|
122
|
+
get isInteracting() {
|
|
123
|
+
return this.dragging || this.hovered || this.focused;
|
|
124
|
+
}
|
|
125
|
+
update(start, totalRows) {
|
|
126
|
+
this.maxStart = Math.max(0, totalRows - this.visibleRows);
|
|
127
|
+
this.start = Math.min(this.maxStart, Math.max(0, start));
|
|
128
|
+
this.group.setAttribute('display', this.maxStart ? 'inline' : 'none');
|
|
129
|
+
this.group.setAttribute('aria-valuemax', String(this.maxStart));
|
|
130
|
+
this.group.setAttribute('aria-valuenow', String(this.start));
|
|
131
|
+
this.thumbHeight = Math.min(this.height, Math.max(20, this.height * this.visibleRows / Math.max(1, totalRows)));
|
|
132
|
+
this.thumbTop = this.maxStart ? (this.height - this.thumbHeight) * this.start / this.maxStart : 0;
|
|
133
|
+
this.thumb.setAttribute('height', String(this.thumbHeight));
|
|
134
|
+
this.thumb.setAttribute('y', String(this.y + this.thumbTop));
|
|
135
|
+
}
|
|
136
|
+
dispose() {
|
|
137
|
+
this.dragging = false;
|
|
138
|
+
this.unbindDrag();
|
|
139
|
+
this.group.removeEventListener('mousedown', this.handleStart);
|
|
140
|
+
this.group.removeEventListener('touchstart', this.handleStart);
|
|
141
|
+
this.group.removeEventListener('keydown', this.handleKeyDown);
|
|
142
|
+
this.group.removeEventListener('mouseenter', this.handleEnter);
|
|
143
|
+
this.group.removeEventListener('mouseleave', this.handleLeave);
|
|
144
|
+
this.group.removeEventListener('focus', this.handleFocus);
|
|
145
|
+
this.group.removeEventListener('blur', this.handleBlur);
|
|
146
|
+
this.group.remove();
|
|
147
|
+
}
|
|
148
|
+
createElement(name) {
|
|
149
|
+
return this.ownerDocument.createElementNS('http://www.w3.org/2000/svg', name);
|
|
150
|
+
}
|
|
151
|
+
setRect(rect, x, y, width, height) {
|
|
152
|
+
rect.setAttribute('x', String(x));
|
|
153
|
+
rect.setAttribute('y', String(y));
|
|
154
|
+
rect.setAttribute('width', String(width));
|
|
155
|
+
rect.setAttribute('height', String(height));
|
|
156
|
+
}
|
|
157
|
+
getLocalY(event) {
|
|
158
|
+
const pointer = 'touches' in event ? event.touches[0] : event;
|
|
159
|
+
const point = this.group.ownerSVGElement.createSVGPoint();
|
|
160
|
+
point.x = pointer.clientX;
|
|
161
|
+
point.y = pointer.clientY;
|
|
162
|
+
const matrix = this.group.getScreenCTM();
|
|
163
|
+
return matrix ? point.matrixTransform(matrix.inverse()).y : point.y;
|
|
164
|
+
}
|
|
165
|
+
unbindDrag() {
|
|
166
|
+
this.ownerDocument.removeEventListener('mousemove', this.handleMove);
|
|
167
|
+
this.ownerDocument.removeEventListener('mouseup', this.handleEnd);
|
|
168
|
+
this.ownerDocument.removeEventListener('touchmove', this.handleMove);
|
|
169
|
+
this.ownerDocument.removeEventListener('touchend', this.handleEnd);
|
|
170
|
+
this.ownerDocument.removeEventListener('touchcancel', this.handleEnd);
|
|
171
|
+
this.ownerDocument.defaultView.removeEventListener('blur', this.handleEnd);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"__symbolic":"module","version":4,"metadata":{"AlarmTableScrollbar":{"__symbolic":"class","members":{"__ctor__":[{"__symbolic":"constructor","parameters":[{"__symbolic":"error","message":"Could not resolve type","line":17,"character":16,"context":{"typeName":"SVGElement"}},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"number"},{"__symbolic":"reference","name":"number"},{"__symbolic":"error","message":"Expression form not supported","line":23,"character":35},{"__symbolic":"error","message":"Expression form not supported","line":24,"character":34},{"__symbolic":"error","message":"Expression form not supported","line":25,"character":35}]}],"update":[{"__symbolic":"method"}],"dispose":[{"__symbolic":"method"}],"createElement":[{"__symbolic":"method"}],"setRect":[{"__symbolic":"method"}],"getLocalY":[{"__symbolic":"method"}],"unbindDrag":[{"__symbolic":"method"}]}}}}]
|