@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.
@@ -37367,19 +37367,6 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37367
37367
  item.textContent = updatedTimePeriods[i].name;
37368
37368
  }
37369
37369
  });
37370
- // 文字更新后重新测量宽度,修正首次加载时文字为空导致宽度过小的问题
37371
- const prevDisplay = this.dropdownListEl.style.display;
37372
- const prevVisibility = this.dropdownListEl.style.visibility;
37373
- this.dropdownListEl.style.display = 'block';
37374
- this.dropdownListEl.style.visibility = 'hidden';
37375
- this.dropdownListEl.style.width = '';
37376
- const newWidth = this.dropdownListEl.offsetWidth;
37377
- this.dropdownListEl.style.display = prevDisplay;
37378
- this.dropdownListEl.style.visibility = prevVisibility;
37379
- this.dropdownListEl.style.width = newWidth + 'px';
37380
- if (this.dropdownTriggerEl) {
37381
- this.dropdownTriggerEl.style.width = newWidth + 'px';
37382
- }
37383
37370
  }
37384
37371
  // 更新触发按钮文字(显示当前选中项的最新语言文案)
37385
37372
  if (this.dropdownTriggerEl) {
@@ -37874,9 +37861,7 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37874
37861
  .style('padding', '4px 8px')
37875
37862
  .style('cursor', 'pointer')
37876
37863
  .style('white-space', 'nowrap')
37877
- .style('font-size', (parseFloat(this.displayOption.operationSelectFontSize) * scale) + 'px')
37878
- .style('line-height', (this.displayOption.operationAreaHeight * scale - 8) + 'px')
37879
- .style('min-height', (this.displayOption.operationAreaHeight * scale - 8) + 'px')
37864
+ // 字号/行高在打开时动态根据 trigger 的视口实际尺寸设置,见 dropdownTrigger.on('click') 处理
37880
37865
  .style('background', tp.key === Number(this.currentTimePeriod) ? '#1890ff' : 'transparent')
37881
37866
  .style('color', tp.key === Number(this.currentTimePeriod) ? '#fff' : '#333')
37882
37867
  .text(tp.name)
@@ -37918,15 +37903,6 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37918
37903
  this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
37919
37904
  });
37920
37905
  });
37921
- // 测量下拉列表最大宽度,让 trigger 和列表宽度一致
37922
- dropdownListEl.style.display = 'block';
37923
- dropdownListEl.style.visibility = 'hidden';
37924
- const listContentWidth = dropdownListEl.offsetWidth;
37925
- dropdownListEl.style.display = 'none';
37926
- dropdownListEl.style.visibility = '';
37927
- dropdownListEl.style.width = listContentWidth + 'px';
37928
- dropdownTrigger.node().style.width = listContentWidth + 'px';
37929
- dropdownTrigger.node().style.boxSizing = 'border-box';
37930
37906
  const hideDropdown = () => { dropdownListEl.style.display = 'none'; };
37931
37907
  dropdownTrigger.on('click', () => {
37932
37908
  const isVisible = dropdownListEl.style.display !== 'none';
@@ -37936,10 +37912,19 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37936
37912
  else {
37937
37913
  const triggerNode = dropdownTrigger.node();
37938
37914
  const triggerRect = triggerNode.getBoundingClientRect();
37939
- // 设置宽度至少和 trigger 一样宽
37915
+ // trigger 在视口中的实际高度(已经过画布 transform 缩放),用于对齐下拉项尺寸。
37916
+ // 不能在渲染时写死设计像素,因为下拉挂在 body 上不受画布 transform 影响。
37917
+ const itemHeight = triggerRect.height;
37918
+ // 字号取行高的 60%,保证文字在行内垂直居中且不溢出
37919
+ const itemFontSize = Math.round(itemHeight * 0.6);
37920
+ dropdownList.selectAll('.hc-dropdown-item')
37921
+ .style('font-size', itemFontSize + 'px')
37922
+ .style('line-height', itemHeight + 'px')
37923
+ .style('min-height', itemHeight + 'px');
37924
+ // 设置宽度至少和 trigger 一样宽,先展示再测宽度
37925
+ dropdownListEl.style.display = 'block';
37940
37926
  dropdownListEl.style.minWidth = triggerRect.width + 'px';
37941
37927
  dropdownListEl.style.left = triggerRect.left + 'px';
37942
- dropdownListEl.style.display = 'block';
37943
37928
  const listHeight = dropdownListEl.offsetHeight;
37944
37929
  const spaceBelow = window.innerHeight - triggerRect.bottom;
37945
37930
  if (spaceBelow < listHeight) {
@@ -42502,6 +42487,181 @@ C140,111.8,99.2,158.4,78,178.6z M78,40.4c-17.8,0-32.4,14.4-32.4,32.2s14.5,32.2,3
42502
42487
  }
42503
42488
  }
42504
42489
 
42490
+ // CONCATENATED MODULE: ./.tmp/elements/alarm/alarm-table-scrollbar.ts
42491
+ /** SVG scrollbar kept outside foreignObject so WKWebView applies the canvas scale. */
42492
+ class AlarmTableScrollbar {
42493
+ constructor(parent, x, y, width, height, visibleRows, onChange, onPause, onResume) {
42494
+ this.y = y;
42495
+ this.height = height;
42496
+ this.visibleRows = visibleRows;
42497
+ this.onChange = onChange;
42498
+ this.onPause = onPause;
42499
+ this.onResume = onResume;
42500
+ this.maxStart = 0;
42501
+ this.start = 0;
42502
+ this.thumbHeight = 0;
42503
+ this.thumbTop = 0;
42504
+ this.dragging = false;
42505
+ this.hovered = false;
42506
+ this.focused = false;
42507
+ this.dragStartY = 0;
42508
+ this.dragStartRow = 0;
42509
+ this.handleStart = (event) => {
42510
+ if (!this.maxStart || ('button' in event && event.button !== 0) || ('touches' in event && event.touches.length !== 1))
42511
+ return;
42512
+ event.preventDefault();
42513
+ event.stopPropagation();
42514
+ this.onPause();
42515
+ const localY = this.getLocalY(event);
42516
+ // The full gutter is clickable, including the transparent sides of the thumb.
42517
+ if (localY < this.y + this.thumbTop || localY > this.y + this.thumbTop + this.thumbHeight) {
42518
+ this.onChange(this.start + (localY < this.y + this.thumbTop ? -this.visibleRows : this.visibleRows));
42519
+ this.onResume();
42520
+ return;
42521
+ }
42522
+ this.dragging = true;
42523
+ this.dragStartY = localY;
42524
+ this.dragStartRow = this.start;
42525
+ this.thumb.setAttribute('fill', '#8f99aa');
42526
+ this.thumb.style.cursor = 'grabbing';
42527
+ this.ownerDocument.addEventListener('mousemove', this.handleMove);
42528
+ this.ownerDocument.addEventListener('mouseup', this.handleEnd);
42529
+ this.ownerDocument.addEventListener('touchmove', this.handleMove, { passive: false });
42530
+ this.ownerDocument.addEventListener('touchend', this.handleEnd);
42531
+ this.ownerDocument.addEventListener('touchcancel', this.handleEnd);
42532
+ this.ownerDocument.defaultView.addEventListener('blur', this.handleEnd);
42533
+ };
42534
+ this.handleMove = (event) => {
42535
+ if (!this.dragging || ('touches' in event && event.touches.length !== 1))
42536
+ return;
42537
+ event.preventDefault();
42538
+ event.stopPropagation();
42539
+ const travel = this.height - this.thumbHeight;
42540
+ if (travel <= 0)
42541
+ return;
42542
+ const rowDelta = Math.round((this.getLocalY(event) - this.dragStartY) / travel * this.maxStart);
42543
+ this.onChange(this.dragStartRow + rowDelta);
42544
+ };
42545
+ this.handleEnd = () => {
42546
+ if (!this.dragging)
42547
+ return;
42548
+ this.dragging = false;
42549
+ this.unbindDrag();
42550
+ this.thumb.setAttribute('fill', '#b6bdc9');
42551
+ this.thumb.style.cursor = 'grab';
42552
+ this.onResume();
42553
+ };
42554
+ this.handleLeave = () => {
42555
+ this.hovered = false;
42556
+ this.onResume();
42557
+ };
42558
+ this.handleEnter = () => {
42559
+ this.hovered = true;
42560
+ this.onPause();
42561
+ };
42562
+ this.handleFocus = () => {
42563
+ this.focused = true;
42564
+ this.onPause();
42565
+ };
42566
+ this.handleBlur = () => {
42567
+ this.focused = false;
42568
+ this.onResume();
42569
+ };
42570
+ this.handleKeyDown = (event) => {
42571
+ const targets = {
42572
+ ArrowUp: this.start - 1,
42573
+ ArrowDown: this.start + 1,
42574
+ PageUp: this.start - this.visibleRows,
42575
+ PageDown: this.start + this.visibleRows,
42576
+ Home: 0,
42577
+ End: this.maxStart
42578
+ };
42579
+ if (!(event.key in targets))
42580
+ return;
42581
+ event.preventDefault();
42582
+ event.stopPropagation();
42583
+ this.onChange(targets[event.key]);
42584
+ };
42585
+ this.ownerDocument = parent.ownerDocument;
42586
+ this.group = this.createElement('g');
42587
+ this.group.setAttribute('role', 'scrollbar');
42588
+ this.group.setAttribute('aria-orientation', 'vertical');
42589
+ this.group.setAttribute('aria-valuemin', '0');
42590
+ this.group.setAttribute('tabindex', '0');
42591
+ this.group.style.cursor = 'default';
42592
+ this.track = this.createElement('rect');
42593
+ this.setRect(this.track, x, y, width, height);
42594
+ this.track.setAttribute('fill', '#eef0f4');
42595
+ this.track.setAttribute('rx', String(width / 2));
42596
+ this.thumb = this.createElement('rect');
42597
+ this.setRect(this.thumb, x + width / 4, y, width / 2, height);
42598
+ this.thumb.setAttribute('fill', '#b6bdc9');
42599
+ this.thumb.setAttribute('rx', String(width / 4));
42600
+ this.thumb.style.cursor = 'grab';
42601
+ this.group.appendChild(this.track);
42602
+ this.group.appendChild(this.thumb);
42603
+ parent.appendChild(this.group);
42604
+ this.group.addEventListener('mousedown', this.handleStart);
42605
+ this.group.addEventListener('touchstart', this.handleStart, { passive: false });
42606
+ this.group.addEventListener('keydown', this.handleKeyDown);
42607
+ this.group.addEventListener('mouseenter', this.handleEnter);
42608
+ this.group.addEventListener('mouseleave', this.handleLeave);
42609
+ this.group.addEventListener('focus', this.handleFocus);
42610
+ this.group.addEventListener('blur', this.handleBlur);
42611
+ }
42612
+ get isInteracting() {
42613
+ return this.dragging || this.hovered || this.focused;
42614
+ }
42615
+ update(start, totalRows) {
42616
+ this.maxStart = Math.max(0, totalRows - this.visibleRows);
42617
+ this.start = Math.min(this.maxStart, Math.max(0, start));
42618
+ this.group.setAttribute('display', this.maxStart ? 'inline' : 'none');
42619
+ this.group.setAttribute('aria-valuemax', String(this.maxStart));
42620
+ this.group.setAttribute('aria-valuenow', String(this.start));
42621
+ this.thumbHeight = Math.min(this.height, Math.max(20, this.height * this.visibleRows / Math.max(1, totalRows)));
42622
+ this.thumbTop = this.maxStart ? (this.height - this.thumbHeight) * this.start / this.maxStart : 0;
42623
+ this.thumb.setAttribute('height', String(this.thumbHeight));
42624
+ this.thumb.setAttribute('y', String(this.y + this.thumbTop));
42625
+ }
42626
+ dispose() {
42627
+ this.dragging = false;
42628
+ this.unbindDrag();
42629
+ this.group.removeEventListener('mousedown', this.handleStart);
42630
+ this.group.removeEventListener('touchstart', this.handleStart);
42631
+ this.group.removeEventListener('keydown', this.handleKeyDown);
42632
+ this.group.removeEventListener('mouseenter', this.handleEnter);
42633
+ this.group.removeEventListener('mouseleave', this.handleLeave);
42634
+ this.group.removeEventListener('focus', this.handleFocus);
42635
+ this.group.removeEventListener('blur', this.handleBlur);
42636
+ this.group.remove();
42637
+ }
42638
+ createElement(name) {
42639
+ return this.ownerDocument.createElementNS('http://www.w3.org/2000/svg', name);
42640
+ }
42641
+ setRect(rect, x, y, width, height) {
42642
+ rect.setAttribute('x', String(x));
42643
+ rect.setAttribute('y', String(y));
42644
+ rect.setAttribute('width', String(width));
42645
+ rect.setAttribute('height', String(height));
42646
+ }
42647
+ getLocalY(event) {
42648
+ const pointer = 'touches' in event ? event.touches[0] : event;
42649
+ const point = this.group.ownerSVGElement.createSVGPoint();
42650
+ point.x = pointer.clientX;
42651
+ point.y = pointer.clientY;
42652
+ const matrix = this.group.getScreenCTM();
42653
+ return matrix ? point.matrixTransform(matrix.inverse()).y : point.y;
42654
+ }
42655
+ unbindDrag() {
42656
+ this.ownerDocument.removeEventListener('mousemove', this.handleMove);
42657
+ this.ownerDocument.removeEventListener('mouseup', this.handleEnd);
42658
+ this.ownerDocument.removeEventListener('touchmove', this.handleMove);
42659
+ this.ownerDocument.removeEventListener('touchend', this.handleEnd);
42660
+ this.ownerDocument.removeEventListener('touchcancel', this.handleEnd);
42661
+ this.ownerDocument.defaultView.removeEventListener('blur', this.handleEnd);
42662
+ }
42663
+ }
42664
+
42505
42665
  // CONCATENATED MODULE: ./.tmp/elements/alarm/alarm-element.ts
42506
42666
 
42507
42667
 
@@ -42509,6 +42669,7 @@ C140,111.8,99.2,158.4,78,178.6z M78,40.4c-17.8,0-32.4,14.4-32.4,32.2s14.5,32.2,3
42509
42669
 
42510
42670
 
42511
42671
 
42672
+
42512
42673
  var AlaertElementStatus;
42513
42674
  (function (AlaertElementStatus) {
42514
42675
  AlaertElementStatus[AlaertElementStatus["Normal"] = 0] = "Normal";
@@ -42547,97 +42708,60 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42547
42708
  this.rowHeight = 0;
42548
42709
  this.touchStartY = 0;
42549
42710
  this.touchScrollAccumulator = 0;
42550
- this.thumbDragStartY = 0;
42551
- this.thumbDragStartWindow = 0;
42552
- this.thumbDragging = false;
42711
+ this.scrollHovered = false;
42712
+ this.touchScrolling = false;
42553
42713
  this.isDisposed = false;
42554
42714
  this.handleScrollWheel = (event) => {
42555
- if (!this.rowHeight)
42715
+ if (!this.rowHeight || !this.getMaxWindowStart())
42556
42716
  return;
42557
42717
  event.preventDefault();
42558
- this.touchScrollAccumulator += event.deltaY;
42559
- const rowDelta = Math.trunc(this.touchScrollAccumulator / this.rowHeight);
42718
+ event.stopPropagation();
42719
+ const screenRowHeight = this.getScreenRowHeight();
42720
+ const delta = event.deltaMode === 1 ? event.deltaY * screenRowHeight
42721
+ : event.deltaMode === 2 ? event.deltaY * screenRowHeight * this.maxVisibleRows : event.deltaY;
42722
+ this.touchScrollAccumulator += delta;
42723
+ const rowDelta = Math.trunc(this.touchScrollAccumulator / screenRowHeight);
42560
42724
  if (rowDelta !== 0) {
42561
- this.touchScrollAccumulator -= rowDelta * this.rowHeight;
42725
+ this.touchScrollAccumulator -= rowDelta * screenRowHeight;
42562
42726
  this.moveScrollWindowBy(rowDelta);
42563
42727
  }
42564
42728
  };
42565
42729
  this.handleScrollTouchStart = (event) => {
42730
+ if (event.touches.length !== 1 || !this.getMaxWindowStart())
42731
+ return;
42732
+ this.touchScrolling = true;
42733
+ clearInterval(this.scrollIntervalId);
42734
+ event.stopPropagation();
42566
42735
  this.touchStartY = event.touches[0].clientY;
42567
42736
  this.touchScrollAccumulator = 0;
42568
42737
  };
42569
42738
  this.handleScrollTouchMove = (event) => {
42570
- if (!this.rowHeight)
42739
+ if (!this.touchScrolling || event.touches.length !== 1)
42571
42740
  return;
42572
42741
  event.preventDefault();
42742
+ event.stopPropagation();
42573
42743
  const currentY = event.touches[0].clientY;
42574
42744
  const deltaY = this.touchStartY - currentY;
42575
42745
  this.touchStartY = currentY;
42576
42746
  this.touchScrollAccumulator += deltaY;
42577
- const rowDelta = Math.trunc(this.touchScrollAccumulator / this.rowHeight);
42747
+ const screenRowHeight = this.getScreenRowHeight();
42748
+ const rowDelta = Math.trunc(this.touchScrollAccumulator / screenRowHeight);
42578
42749
  if (rowDelta !== 0) {
42579
- this.touchScrollAccumulator -= rowDelta * this.rowHeight;
42750
+ this.touchScrollAccumulator -= rowDelta * screenRowHeight;
42580
42751
  this.moveScrollWindowBy(rowDelta);
42581
42752
  }
42582
42753
  };
42583
42754
  this.handleScrollMouseEnter = () => {
42755
+ this.scrollHovered = true;
42584
42756
  clearInterval(this.scrollIntervalId);
42585
42757
  };
42586
42758
  this.handleScrollMouseLeave = () => {
42587
- if (!this.thumbDragging)
42588
- this.startAutoScroll();
42589
- };
42590
- // 拖拽滑块时挂全局 mousemove/mouseup,允许拖出滚动条区域也能继续跟手,松开时才解绑
42591
- this.handleThumbDragStart = (event) => {
42592
- event.preventDefault();
42593
- event.stopPropagation();
42594
- this.thumbDragging = true;
42595
- clearInterval(this.scrollIntervalId);
42596
- this.thumbDragStartY = this.getClientY(event);
42597
- this.thumbDragStartWindow = this.scrollWindowStart;
42598
- document.addEventListener('mousemove', this.handleThumbDragMove);
42599
- document.addEventListener('mouseup', this.handleThumbDragEnd);
42600
- document.addEventListener('touchmove', this.handleThumbDragMove, { passive: false });
42601
- document.addEventListener('touchend', this.handleThumbDragEnd);
42602
- };
42603
- this.handleThumbDragMove = (event) => {
42604
- if (!this.thumbDragging || !this.scrollTrack)
42605
- return;
42606
- event.preventDefault();
42607
- const maxWindowStart = Math.max(0, this.pageSize - this.maxVisibleRows);
42608
- if (maxWindowStart <= 0)
42609
- return;
42610
- const trackHeight = this.scrollTrack.clientHeight;
42611
- const thumbHeightRatio = Math.min(1, this.maxVisibleRows / this.pageSize);
42612
- const thumbHeight = Math.max(20, trackHeight * thumbHeightRatio);
42613
- const maxThumbTop = trackHeight - thumbHeight;
42614
- if (maxThumbTop <= 0)
42615
- return;
42616
- const deltaY = this.getClientY(event) - this.thumbDragStartY;
42617
- const deltaWindow = Math.round((deltaY / maxThumbTop) * maxWindowStart);
42618
- const nextStart = Math.min(maxWindowStart, Math.max(0, this.thumbDragStartWindow + deltaWindow));
42619
- if (nextStart === this.scrollWindowStart)
42620
- return;
42621
- this.scrollWindowStart = nextStart;
42622
- this.renderScrollWindow(this.scrollWindowStart);
42623
- };
42624
- this.handleThumbDragEnd = () => {
42625
- this.thumbDragging = false;
42626
- document.removeEventListener('mousemove', this.handleThumbDragMove);
42627
- document.removeEventListener('mouseup', this.handleThumbDragEnd);
42628
- document.removeEventListener('touchmove', this.handleThumbDragMove);
42629
- document.removeEventListener('touchend', this.handleThumbDragEnd);
42759
+ this.scrollHovered = false;
42630
42760
  this.startAutoScroll();
42631
42761
  };
42632
- // 点击轨道空白处(非滑块)时整页跳转,方向取决于点击位置在滑块上方还是下方
42633
- this.handleTrackClick = (event) => {
42634
- if (event.target !== this.scrollTrack || !this.scrollTrack)
42635
- return;
42636
- const trackRect = this.scrollTrack.getBoundingClientRect();
42637
- const clickTop = event.clientY - trackRect.top;
42638
- const thumbTop = parseFloat(this.scrollThumb.style.top) || 0;
42639
- const rowDelta = clickTop < thumbTop ? -this.maxVisibleRows : this.maxVisibleRows;
42640
- this.moveScrollWindowBy(rowDelta);
42762
+ this.handleScrollTouchEnd = () => {
42763
+ this.touchScrolling = false;
42764
+ this.startAutoScroll();
42641
42765
  };
42642
42766
  this.rootElement.selectAll('*').remove();
42643
42767
  this.setStatusAsLoading();
@@ -42920,7 +43044,7 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42920
43044
  if (useScroll) {
42921
43045
  if (!this.scrollContent)
42922
43046
  return;
42923
- this.scrollWindowStart = Math.min(this.scrollWindowStart, Math.max(0, this.pageSize - this.maxVisibleRows));
43047
+ this.scrollWindowStart = Math.min(this.scrollWindowStart, this.getMaxWindowStart());
42924
43048
  this.renderScrollWindow(this.scrollWindowStart);
42925
43049
  return;
42926
43050
  }
@@ -42955,24 +43079,12 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42955
43079
  }
42956
43080
  this.updateScrollThumb();
42957
43081
  }
42958
- // 滑块高度按"可见行数/总行数"的比例算,位置按当前窗口起始行占可滚动范围的比例算,
42959
- // 只用 top/height 两个数值属性更新,不涉及 transform,不会触发合成层
42960
43082
  updateScrollThumb() {
42961
- if (!this.scrollTrack || !this.scrollThumb)
42962
- return;
42963
- const maxWindowStart = Math.max(0, this.pageSize - this.maxVisibleRows);
42964
- if (maxWindowStart <= 0) {
42965
- this.scrollThumb.style.display = 'none';
42966
- return;
42967
- }
42968
- this.scrollThumb.style.display = 'block';
42969
- const trackHeight = this.scrollTrack.clientHeight;
42970
- const thumbHeightRatio = Math.min(1, this.maxVisibleRows / this.pageSize);
42971
- const thumbHeight = Math.max(20, trackHeight * thumbHeightRatio);
42972
- const maxThumbTop = trackHeight - thumbHeight;
42973
- const thumbTop = maxThumbTop * (this.scrollWindowStart / maxWindowStart);
42974
- this.scrollThumb.style.height = `${thumbHeight}px`;
42975
- this.scrollThumb.style.top = `${thumbTop}px`;
43083
+ if (this.scrollbar)
43084
+ this.scrollbar.update(this.scrollWindowStart, this.alarmList.length);
43085
+ }
43086
+ getMaxWindowStart() {
43087
+ return Math.max(0, this.alarmList.length - this.maxVisibleRows);
42976
43088
  }
42977
43089
  getIconScale() {
42978
43090
  const initSize = this.model.initSize;
@@ -43021,7 +43133,7 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43021
43133
  vertical-align: middle;`;
43022
43134
  for (let col = 0; col < 4; col++) {
43023
43135
  const th = document.createElement('th');
43024
- th.innerHTML = this.getHeaderTextByColumn(col);
43136
+ th.textContent = this.getHeaderTextByColumn(col);
43025
43137
  th.style.cssText = `width: ${this.model.widths[col] / this.model.size.width * 100}%;
43026
43138
  border-style: solid;
43027
43139
  border-color: ${this.model.generalSetting.splitLine};
@@ -43048,7 +43160,7 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43048
43160
  border-left-width: ${!col || this.model.generalSetting.isHiddenColumnSplitLine ? 0 : 1}px;`;
43049
43161
  if (this.alarmList[row]) {
43050
43162
  if (col !== 2) {
43051
- td.innerHTML = this.alarmList[row][col];
43163
+ td.textContent = this.alarmList[row][col];
43052
43164
  td.style.cssText += `${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
43053
43165
  }
43054
43166
  else {
@@ -43067,14 +43179,14 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43067
43179
  border-radius: 5px;
43068
43180
  background: ${levelColors[this.alarmList[row][col]]};
43069
43181
  color: #ffffff;
43070
- width: ${this.model.widths[col] - 30}px;
43182
+ width: calc(100% - 30px);
43071
43183
  height: ${alarmHeight}px;
43072
43184
  max-height: ${rowHeight}px;
43073
43185
  display: flex;
43074
43186
  justify-content: center;
43075
43187
  align-items: center;
43076
43188
  ${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
43077
- alarmLevel.innerHTML = this.model.levelText[this.alarmList[row][col]];
43189
+ alarmLevel.textContent = this.model.levelText[this.alarmList[row][col]];
43078
43190
  td.appendChild(alarmLevel);
43079
43191
  }
43080
43192
  }
@@ -43114,40 +43226,25 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43114
43226
  const dataRowHeight = this.model.heights[1] || this.model.heights[0];
43115
43227
  this.rowHeight = dataRowHeight;
43116
43228
  this.scrollWindowStart = 0;
43117
- // 之前用"表头/表体分两个 table + flex 包裹容器 + overflow/transform 滚动"的结构,
43118
- // 在 iOS WKWebView 上表体会明显放大错位,换了两种滚动实现方式(原生 overflow:auto、
43119
- // JS transform 平移)都复现同样的问题,怀疑是这套多层 div + 双 table 结构本身的问题。
43120
- // 这里改成和 renderPlainTable() 完全同构的单 table 结构(已验证在所有平台上都正常),
43121
- // DOM 里始终只保留 maxVisibleRows 行数据,滚动时只增删 <tr> 内容,不做任何位移/滚动。
43122
- // 自定义滚动条(轨道+滑块)只用 position + top/height 定位,不用 overflow/transform/
43123
- // will-change,这些属性都不会触发 WebKit 合成层提升,不会重新引入 iOS 缩放错位问题。
43124
- const scrollbarWidth = 6;
43125
- const wrapper = document.createElement('div');
43126
- wrapper.style.cssText = `position: relative; width: ${this.model.size.width}px;
43127
- height: ${elementHeight - operationAreaReservedHeight}px;`;
43229
+ // WKWebView can paint positioned HTML descendants outside the SVG scale.
43230
+ // Keep a single unpositioned table directly in foreignObject; the scrollbar
43231
+ // is a sibling SVG group, never an HTML overlay or native scrolling layer.
43232
+ const scrollbarWidth = Math.min(12, this.model.size.width * 0.04);
43233
+ const tableHeight = elementHeight - operationAreaReservedHeight;
43128
43234
  const table = document.createElement('table');
43129
43235
  table.style.cssText = `border: 2px solid ${this.model.generalSetting.stroke};
43130
- height: ${elementHeight - operationAreaReservedHeight}px;
43131
- width: calc(100% - ${scrollbarWidth}px);`;
43236
+ height: ${tableHeight}px; width: 100%; table-layout: fixed;
43237
+ overflow-wrap: break-word; -webkit-text-size-adjust: none; text-size-adjust: none;`;
43132
43238
  table.appendChild(this.buildHeaderRow());
43133
- wrapper.appendChild(table);
43134
- const track = document.createElement('div');
43135
- track.style.cssText = `position: absolute; top: 0; right: 0; width: ${scrollbarWidth}px;
43136
- height: 100%; background: rgba(0,0,0,0.06); border-radius: ${scrollbarWidth / 2}px;`;
43137
- const thumb = document.createElement('div');
43138
- thumb.style.cssText = `position: absolute; left: 0; width: 100%;
43139
- background: rgba(0,0,0,0.35); border-radius: ${scrollbarWidth / 2}px; cursor: pointer;`;
43140
- track.appendChild(thumb);
43141
- wrapper.appendChild(track);
43142
- this.element.appendChild(wrapper);
43239
+ this.element.setAttribute('width', String(this.model.size.width - scrollbarWidth));
43240
+ this.element.appendChild(table);
43143
43241
  this.scrollContent = table;
43144
- this.scrollTrack = track;
43145
- this.scrollThumb = thumb;
43146
43242
  this.renderScrollWindow(0);
43243
+ const headerHeight = Math.min(tableHeight, table.rows[0].getBoundingClientRect().height / this.getCanvasScaleY());
43244
+ 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());
43147
43245
  this.updateScrollThumb();
43148
43246
  this.hoverTarget = table;
43149
43247
  this.bindScrollHoverEvents();
43150
- this.bindScrollbarEvents();
43151
43248
  this.startAutoScroll();
43152
43249
  }
43153
43250
  bindScrollHoverEvents() {
@@ -43159,10 +43256,16 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43159
43256
  this.hoverTarget.addEventListener('wheel', this.handleScrollWheel, { passive: false });
43160
43257
  this.hoverTarget.addEventListener('touchstart', this.handleScrollTouchStart, { passive: true });
43161
43258
  this.hoverTarget.addEventListener('touchmove', this.handleScrollTouchMove, { passive: false });
43259
+ this.hoverTarget.addEventListener('touchend', this.handleScrollTouchEnd);
43260
+ this.hoverTarget.addEventListener('touchcancel', this.handleScrollTouchEnd);
43162
43261
  }
43163
43262
  }
43164
43263
  unbindScrollHoverEvents() {
43165
- this.unbindScrollbarEvents();
43264
+ if (this.scrollbar)
43265
+ this.scrollbar.dispose();
43266
+ this.scrollbar = null;
43267
+ this.scrollHovered = false;
43268
+ this.touchScrolling = false;
43166
43269
  if (!this.hoverTarget)
43167
43270
  return;
43168
43271
  this.hoverTarget.removeEventListener('mouseenter', this.handleScrollMouseEnter);
@@ -43170,6 +43273,8 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43170
43273
  this.hoverTarget.removeEventListener('wheel', this.handleScrollWheel);
43171
43274
  this.hoverTarget.removeEventListener('touchstart', this.handleScrollTouchStart);
43172
43275
  this.hoverTarget.removeEventListener('touchmove', this.handleScrollTouchMove);
43276
+ this.hoverTarget.removeEventListener('touchend', this.handleScrollTouchEnd);
43277
+ this.hoverTarget.removeEventListener('touchcancel', this.handleScrollTouchEnd);
43173
43278
  this.hoverTarget = null;
43174
43279
  }
43175
43280
  // 手动滚动只在当前可见窗口范围内移动(不触发翻页),到顶/到底停住,
@@ -43177,41 +43282,26 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43177
43282
  moveScrollWindowBy(rowDelta) {
43178
43283
  if (!this.scrollContent)
43179
43284
  return;
43180
- const maxWindowStart = Math.max(0, this.pageSize - this.maxVisibleRows);
43285
+ const maxWindowStart = this.getMaxWindowStart();
43181
43286
  const nextStart = Math.min(maxWindowStart, Math.max(0, this.scrollWindowStart + rowDelta));
43182
43287
  if (nextStart === this.scrollWindowStart)
43183
43288
  return;
43184
43289
  this.scrollWindowStart = nextStart;
43185
43290
  this.renderScrollWindow(this.scrollWindowStart);
43186
43291
  }
43187
- bindScrollbarEvents() {
43188
- if (!this.scrollTrack || !this.scrollThumb)
43189
- return;
43190
- this.scrollThumb.addEventListener('mousedown', this.handleThumbDragStart);
43191
- this.scrollThumb.addEventListener('touchstart', this.handleThumbDragStart, { passive: true });
43192
- this.scrollTrack.addEventListener('mousedown', this.handleTrackClick);
43193
- }
43194
- unbindScrollbarEvents() {
43195
- if (this.scrollThumb) {
43196
- this.scrollThumb.removeEventListener('mousedown', this.handleThumbDragStart);
43197
- this.scrollThumb.removeEventListener('touchstart', this.handleThumbDragStart);
43198
- }
43199
- if (this.scrollTrack) {
43200
- this.scrollTrack.removeEventListener('mousedown', this.handleTrackClick);
43201
- }
43202
- document.removeEventListener('mousemove', this.handleThumbDragMove);
43203
- document.removeEventListener('mouseup', this.handleThumbDragEnd);
43204
- document.removeEventListener('touchmove', this.handleThumbDragMove);
43205
- document.removeEventListener('touchend', this.handleThumbDragEnd);
43206
- this.scrollTrack = null;
43207
- this.scrollThumb = null;
43292
+ getCanvasScaleY() {
43293
+ const matrix = this.element.getScreenCTM();
43294
+ return matrix ? Math.sqrt(matrix.c * matrix.c + matrix.d * matrix.d) || 1 : 1;
43208
43295
  }
43209
- getClientY(event) {
43210
- return 'touches' in event ? event.touches[0].clientY : event.clientY;
43296
+ getScreenRowHeight() {
43297
+ var _a;
43298
+ const row = (_a = this.scrollContent) === null || _a === void 0 ? void 0 : _a.querySelectorAll('tr')[1];
43299
+ return (row === null || row === void 0 ? void 0 : row.getBoundingClientRect().height) || this.rowHeight * this.getCanvasScaleY();
43211
43300
  }
43212
43301
  startAutoScroll() {
43302
+ var _a;
43213
43303
  clearInterval(this.scrollIntervalId);
43214
- if (!this.model.generalSetting.autoScroll)
43304
+ if (this.isDisposed || this.scrollHovered || this.touchScrolling || ((_a = this.scrollbar) === null || _a === void 0 ? void 0 : _a.isInteracting) || !this.model.generalSetting.autoScroll)
43215
43305
  return;
43216
43306
  const totalPages = Math.max(1, Math.ceil(this.totalCount / this.pageSize));
43217
43307
  if (totalPages <= 1 && !this.scrollContent)
@@ -43224,7 +43314,7 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
43224
43314
  this.autoNextPage();
43225
43315
  return;
43226
43316
  }
43227
- const maxWindowStart = this.pageSize - this.maxVisibleRows;
43317
+ const maxWindowStart = this.getMaxWindowStart();
43228
43318
  if (maxWindowStart <= 0 || this.scrollWindowStart >= maxWindowStart) {
43229
43319
  this.autoNextPage();
43230
43320
  return;
@@ -45135,7 +45225,7 @@ var shared = __webpack_require__(6);
45135
45225
  // EXTERNAL MODULE: ./.tmp/view/view.service.ts
45136
45226
  var view_service = __webpack_require__(27);
45137
45227
 
45138
- // EXTERNAL MODULE: ./.tmp/gui/gui-view.ts + 126 modules
45228
+ // EXTERNAL MODULE: ./.tmp/gui/gui-view.ts + 127 modules
45139
45229
  var gui_view = __webpack_require__(32);
45140
45230
 
45141
45231
  // EXTERNAL MODULE: external "rxjs/operators"