@flexem/fc-gui 3.0.0-alpha.180 → 3.0.0-alpha.181

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.
Files changed (37) hide show
  1. package/bundles/@flexem/fc-gui.umd.js +618 -223
  2. package/bundles/@flexem/fc-gui.umd.js.map +1 -1
  3. package/bundles/@flexem/fc-gui.umd.min.js +4 -4
  4. package/bundles/@flexem/fc-gui.umd.min.js.map +1 -1
  5. package/elements/alarm/alarm-element.d.ts +20 -0
  6. package/elements/alarm/alarm-element.js +312 -70
  7. package/elements/alarm/alarm-element.metadata.json +1 -1
  8. package/elements/base/state-control-element.d.ts +10 -0
  9. package/elements/base/state-control-element.js +21 -3
  10. package/elements/base/state-control-element.metadata.json +1 -1
  11. package/elements/character-display/character-display-element.d.ts +9 -0
  12. package/elements/character-display/character-display-element.js +15 -0
  13. package/elements/character-display/character-display-element.metadata.json +1 -1
  14. package/elements/historical-curve/historical-curve.element.d.ts +1 -0
  15. package/elements/historical-curve/historical-curve.element.js +35 -22
  16. package/elements/historical-curve/historical-curve.element.metadata.json +1 -1
  17. package/elements/main-element.js +2 -1
  18. package/elements/numerical-display/numerical-display-element.d.ts +9 -0
  19. package/elements/numerical-display/numerical-display-element.js +15 -0
  20. package/elements/numerical-display/numerical-display-element.metadata.json +1 -1
  21. package/elements/switch-indicator-light/switch-indicator-light-element.d.ts +9 -0
  22. package/elements/switch-indicator-light/switch-indicator-light-element.js +15 -0
  23. package/elements/switch-indicator-light/switch-indicator-light-element.metadata.json +1 -1
  24. package/elements/view-operation/view-operation.element.js +2 -1
  25. package/gui/gui-view.d.ts +15 -1
  26. package/gui/gui-view.js +78 -4
  27. package/gui/gui-view.metadata.json +1 -1
  28. package/model/alarm/alarm.model.d.ts +1 -0
  29. package/model/character-display/character-display.d.ts +1 -0
  30. package/model/historical-curve/historical-curve.display-settings.d.ts +1 -0
  31. package/model/numerical-display/numerical-display.d.ts +1 -0
  32. package/model/settings/popup/view-popup-location-type.d.ts +2 -1
  33. package/model/settings/popup/view-popup-location-type.js +1 -0
  34. package/model/settings/popup/view-popup-location-type.metadata.json +1 -1
  35. package/model/switch-indicator-light/switch-indicator-light.d.ts +1 -0
  36. package/package.json +1 -1
  37. package/view/popup-view.service.d.ts +1 -1
@@ -21923,121 +21923,6 @@ var VariableStateEnum;
21923
21923
 
21924
21924
  "use strict";
21925
21925
 
21926
- // EXTERNAL MODULE: ./.tmp/shared/disposable.ts
21927
- var disposable = __webpack_require__(270);
21928
-
21929
- // CONCATENATED MODULE: ./.tmp/shared/config-is-empty-error.ts
21930
- class ConfigIsEmptyError extends Error {
21931
- constructor() {
21932
- super('The config is empty.');
21933
- // Todo: Only works in Chrome and FireFox, does not work in IE
21934
- Object.setPrototypeOf(this, ConfigIsEmptyError.prototype);
21935
- }
21936
- }
21937
-
21938
- // EXTERNAL MODULE: ./.tmp/model/shared/data-type/fcloud-data-Type.ts
21939
- var fcloud_data_Type = __webpack_require__(7);
21940
-
21941
- // EXTERNAL MODULE: ./node_modules/lodash/lodash.js
21942
- var lodash = __webpack_require__(2);
21943
-
21944
- // CONCATENATED MODULE: ./.tmp/shared/operation-helper.ts
21945
-
21946
-
21947
- class operation_helper_OperationHelper {
21948
- static add(value, operand, dataType, maxValue) {
21949
- if (!dataType) {
21950
- return value + operand;
21951
- }
21952
- if (!Object(lodash["isNil"])(maxValue)) {
21953
- return Math.min(value + operand, maxValue);
21954
- }
21955
- return Math.min(value + operand, operation_helper_OperationHelper.getMax(dataType));
21956
- }
21957
- static subtract(value, operand, dataType, minValue) {
21958
- if (!dataType) {
21959
- return value - operand;
21960
- }
21961
- if (!Object(lodash["isNil"])(minValue)) {
21962
- return Math.max(value - operand, minValue);
21963
- }
21964
- return Math.max(value - operand, operation_helper_OperationHelper.getMin(dataType));
21965
- }
21966
- static getMax(dataType) {
21967
- switch (dataType) {
21968
- case fcloud_data_Type["a" /* FCloudDataType */].Int32:
21969
- return 2147483647;
21970
- case fcloud_data_Type["a" /* FCloudDataType */].Float:
21971
- return 3.402823E+38;
21972
- }
21973
- }
21974
- static getMin(dataType) {
21975
- switch (dataType) {
21976
- case fcloud_data_Type["a" /* FCloudDataType */].Int32:
21977
- return -2147483648;
21978
- case fcloud_data_Type["a" /* FCloudDataType */].Float:
21979
- return -3.402823E+38;
21980
- }
21981
- }
21982
- }
21983
-
21984
- // CONCATENATED MODULE: ./.tmp/shared/gui-consts.ts
21985
- class GuiConsts {
21986
- }
21987
- GuiConsts.components = {
21988
- imageKey: 'Image',
21989
- numericalDisplayKey: 'NumericalDisplay',
21990
- textKey: 'Text',
21991
- hyperlinkKey: 'Hyperlink',
21992
- meterKey: 'Meter',
21993
- pipeKey: 'Pipe',
21994
- switchIndicatorLightKey: 'SwitchIndicatorLight',
21995
- barGraphKey: 'BarGraph',
21996
- /**
21997
- * 切换画面已经改为画面操作
21998
- */
21999
- toggleViewKey: 'ToggleView',
22000
- characterKey: 'Character',
22001
- straightLineKey: 'StraightLine',
22002
- polyLineKey: 'PolyLine',
22003
- rectangleKey: 'Rectangle',
22004
- sectorkey: 'Sector',
22005
- ellipseKey: 'Ellipse',
22006
- datetimeDisplayKey: 'DatetimeDisplay',
22007
- historicalCurveKey: 'HistoricalCurve',
22008
- ringGraphKey: 'RingGraph',
22009
- viewOperationElement: 'ViewOperation',
22010
- polygonKey: 'Polygon',
22011
- videokey: 'Video',
22012
- tableKey: 'Table',
22013
- weatherKey: 'Weather',
22014
- airQualityKey: 'AirQualityIndex',
22015
- alarmKey: 'Alarm',
22016
- scrollAlarmKey: 'ScrollAlarm'
22017
- };
22018
-
22019
- // EXTERNAL MODULE: ./.tmp/shared/graph-extended-style.ts
22020
- var graph_extended_style = __webpack_require__(269);
22021
-
22022
- // CONCATENATED MODULE: ./.tmp/shared/index.ts
22023
- /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "b", function() { return disposable["Disposable"]; });
22024
- /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "a", function() { return ConfigIsEmptyError; });
22025
- /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "e", function() { return operation_helper_OperationHelper; });
22026
- /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "d", function() { return GuiConsts; });
22027
- /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "c", function() { return graph_extended_style["GraphExtendedStyle"]; });
22028
-
22029
-
22030
-
22031
-
22032
-
22033
-
22034
-
22035
- /***/ }),
22036
- /* 6 */
22037
- /***/ (function(module, __webpack_exports__, __webpack_require__) {
22038
-
22039
- "use strict";
22040
-
22041
21926
  // EXTERNAL MODULE: ./.tmp/config/config-store.ts
22042
21927
  var config_store = __webpack_require__(258);
22043
21928
 
@@ -22207,6 +22092,121 @@ class GetAlarmsArgs {
22207
22092
 
22208
22093
 
22209
22094
 
22095
+ /***/ }),
22096
+ /* 6 */
22097
+ /***/ (function(module, __webpack_exports__, __webpack_require__) {
22098
+
22099
+ "use strict";
22100
+
22101
+ // EXTERNAL MODULE: ./.tmp/shared/disposable.ts
22102
+ var disposable = __webpack_require__(270);
22103
+
22104
+ // CONCATENATED MODULE: ./.tmp/shared/config-is-empty-error.ts
22105
+ class ConfigIsEmptyError extends Error {
22106
+ constructor() {
22107
+ super('The config is empty.');
22108
+ // Todo: Only works in Chrome and FireFox, does not work in IE
22109
+ Object.setPrototypeOf(this, ConfigIsEmptyError.prototype);
22110
+ }
22111
+ }
22112
+
22113
+ // EXTERNAL MODULE: ./.tmp/model/shared/data-type/fcloud-data-Type.ts
22114
+ var fcloud_data_Type = __webpack_require__(7);
22115
+
22116
+ // EXTERNAL MODULE: ./node_modules/lodash/lodash.js
22117
+ var lodash = __webpack_require__(2);
22118
+
22119
+ // CONCATENATED MODULE: ./.tmp/shared/operation-helper.ts
22120
+
22121
+
22122
+ class operation_helper_OperationHelper {
22123
+ static add(value, operand, dataType, maxValue) {
22124
+ if (!dataType) {
22125
+ return value + operand;
22126
+ }
22127
+ if (!Object(lodash["isNil"])(maxValue)) {
22128
+ return Math.min(value + operand, maxValue);
22129
+ }
22130
+ return Math.min(value + operand, operation_helper_OperationHelper.getMax(dataType));
22131
+ }
22132
+ static subtract(value, operand, dataType, minValue) {
22133
+ if (!dataType) {
22134
+ return value - operand;
22135
+ }
22136
+ if (!Object(lodash["isNil"])(minValue)) {
22137
+ return Math.max(value - operand, minValue);
22138
+ }
22139
+ return Math.max(value - operand, operation_helper_OperationHelper.getMin(dataType));
22140
+ }
22141
+ static getMax(dataType) {
22142
+ switch (dataType) {
22143
+ case fcloud_data_Type["a" /* FCloudDataType */].Int32:
22144
+ return 2147483647;
22145
+ case fcloud_data_Type["a" /* FCloudDataType */].Float:
22146
+ return 3.402823E+38;
22147
+ }
22148
+ }
22149
+ static getMin(dataType) {
22150
+ switch (dataType) {
22151
+ case fcloud_data_Type["a" /* FCloudDataType */].Int32:
22152
+ return -2147483648;
22153
+ case fcloud_data_Type["a" /* FCloudDataType */].Float:
22154
+ return -3.402823E+38;
22155
+ }
22156
+ }
22157
+ }
22158
+
22159
+ // CONCATENATED MODULE: ./.tmp/shared/gui-consts.ts
22160
+ class GuiConsts {
22161
+ }
22162
+ GuiConsts.components = {
22163
+ imageKey: 'Image',
22164
+ numericalDisplayKey: 'NumericalDisplay',
22165
+ textKey: 'Text',
22166
+ hyperlinkKey: 'Hyperlink',
22167
+ meterKey: 'Meter',
22168
+ pipeKey: 'Pipe',
22169
+ switchIndicatorLightKey: 'SwitchIndicatorLight',
22170
+ barGraphKey: 'BarGraph',
22171
+ /**
22172
+ * 切换画面已经改为画面操作
22173
+ */
22174
+ toggleViewKey: 'ToggleView',
22175
+ characterKey: 'Character',
22176
+ straightLineKey: 'StraightLine',
22177
+ polyLineKey: 'PolyLine',
22178
+ rectangleKey: 'Rectangle',
22179
+ sectorkey: 'Sector',
22180
+ ellipseKey: 'Ellipse',
22181
+ datetimeDisplayKey: 'DatetimeDisplay',
22182
+ historicalCurveKey: 'HistoricalCurve',
22183
+ ringGraphKey: 'RingGraph',
22184
+ viewOperationElement: 'ViewOperation',
22185
+ polygonKey: 'Polygon',
22186
+ videokey: 'Video',
22187
+ tableKey: 'Table',
22188
+ weatherKey: 'Weather',
22189
+ airQualityKey: 'AirQualityIndex',
22190
+ alarmKey: 'Alarm',
22191
+ scrollAlarmKey: 'ScrollAlarm'
22192
+ };
22193
+
22194
+ // EXTERNAL MODULE: ./.tmp/shared/graph-extended-style.ts
22195
+ var graph_extended_style = __webpack_require__(269);
22196
+
22197
+ // CONCATENATED MODULE: ./.tmp/shared/index.ts
22198
+ /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "b", function() { return disposable["Disposable"]; });
22199
+ /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "a", function() { return ConfigIsEmptyError; });
22200
+ /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "e", function() { return operation_helper_OperationHelper; });
22201
+ /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "d", function() { return GuiConsts; });
22202
+ /* concated harmony reexport */__webpack_require__.d(__webpack_exports__, "c", function() { return graph_extended_style["GraphExtendedStyle"]; });
22203
+
22204
+
22205
+
22206
+
22207
+
22208
+
22209
+
22210
22210
  /***/ }),
22211
22211
  /* 7 */
22212
22212
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
@@ -22291,7 +22291,7 @@ class ConsoleLoggerService {
22291
22291
 
22292
22292
  "use strict";
22293
22293
  /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return VariableUtil; });
22294
- /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(6);
22294
+ /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(5);
22295
22295
 
22296
22296
  class VariableUtil {
22297
22297
  static getConvertedVariableName(variableStore, variable) {
@@ -34485,7 +34485,7 @@ var ViewBackgroundFillType;
34485
34485
  })(ViewBackgroundFillType || (ViewBackgroundFillType = {}));
34486
34486
 
34487
34487
  // EXTERNAL MODULE: ./.tmp/shared/index.ts + 3 modules
34488
- var shared = __webpack_require__(5);
34488
+ var shared = __webpack_require__(6);
34489
34489
 
34490
34490
  // CONCATENATED MODULE: ./.tmp/model/shared/dynamic-display/dynamic-behavior-type.ts
34491
34491
  var DynamicBehaviorType;
@@ -35046,6 +35046,13 @@ class state_control_element_StateControlElement extends conditional_dynamic_disp
35046
35046
  this.isEnable = true;
35047
35047
  this.elementStates = [];
35048
35048
  }
35049
+ /**
35050
+ * 子类可覆盖此方法提供元件当前大小和初始大小,用于状态图标缩放计算
35051
+ * @returns {{ width: number, height: number, initWidth?: number, initHeight?: number }}
35052
+ */
35053
+ getElementSizeForIconScale() {
35054
+ return null;
35055
+ }
35049
35056
  initState() {
35050
35057
  if (!this.elementStates.length) {
35051
35058
  return;
@@ -35196,7 +35203,18 @@ class state_control_element_StateControlElement extends conditional_dynamic_disp
35196
35203
  const imgObj = document.createElementNS('http://www.w3.org/2000/svg', 'image');
35197
35204
  if (imgObj) {
35198
35205
  const currentRectElement = this.currentRect[0];
35199
- let x = Number(currentRectElement.getAttribute('width')) - 20;
35206
+ // 计算图标缩放比例
35207
+ const baseIconSize = 20;
35208
+ let iconSize = baseIconSize;
35209
+ const sizeInfo = this.getElementSizeForIconScale();
35210
+ if (sizeInfo && sizeInfo.initWidth && sizeInfo.initHeight) {
35211
+ const scaleX = sizeInfo.width / sizeInfo.initWidth;
35212
+ const scaleY = sizeInfo.height / sizeInfo.initHeight;
35213
+ // 取较小值,避免图标超出元件边界
35214
+ const scale = Math.min(scaleX, scaleY);
35215
+ iconSize = baseIconSize * scale;
35216
+ }
35217
+ let x = Number(currentRectElement.getAttribute('width')) - iconSize;
35200
35218
  const currentRectX = currentRectElement.getAttribute('x');
35201
35219
  if (currentRectX !== null) {
35202
35220
  x += Number(currentRectX);
@@ -35207,8 +35225,8 @@ class state_control_element_StateControlElement extends conditional_dynamic_disp
35207
35225
  imgObj.setAttributeNS(null, 'id', 'StateImage');
35208
35226
  imgObj.setAttributeNS(null, 'x', x.toString());
35209
35227
  imgObj.setAttributeNS(null, 'y', '0');
35210
- imgObj.setAttributeNS(null, 'height', '20px');
35211
- imgObj.setAttributeNS(null, 'width', '20px');
35228
+ imgObj.setAttributeNS(null, 'height', iconSize + 'px');
35229
+ imgObj.setAttributeNS(null, 'width', iconSize + 'px');
35212
35230
  const titleElement = document.createElementNS('http://www.w3.org/2000/svg', 'title');
35213
35231
  const text = document.createTextNode(title);
35214
35232
  titleElement.appendChild(text);
@@ -35335,7 +35353,7 @@ class conditional_enable_element_ConditionalEnableElement extends state_control_
35335
35353
  }
35336
35354
 
35337
35355
  // EXTERNAL MODULE: ./.tmp/config/index.ts + 12 modules
35338
- var _tmp_config = __webpack_require__(6);
35356
+ var _tmp_config = __webpack_require__(5);
35339
35357
 
35340
35358
  // CONCATENATED MODULE: ./.tmp/elements/base/readable-element.ts
35341
35359
 
@@ -36224,6 +36242,21 @@ class character_display_element_CharacterDisplayElement extends readable_element
36224
36242
  this.rootElement.select('image').attr('xlink:href', null);
36225
36243
  }
36226
36244
  }
36245
+ /**
36246
+ * 提供元件尺寸信息用于状态图标缩放
36247
+ */
36248
+ getElementSizeForIconScale() {
36249
+ var _a, _b;
36250
+ if (this.model.size) {
36251
+ return {
36252
+ width: this.model.size.width,
36253
+ height: this.model.size.height,
36254
+ initWidth: (_a = this.model.initSize) === null || _a === void 0 ? void 0 : _a.width,
36255
+ initHeight: (_b = this.model.initSize) === null || _b === void 0 ? void 0 : _b.height
36256
+ };
36257
+ }
36258
+ return null;
36259
+ }
36227
36260
  }
36228
36261
 
36229
36262
  // EXTERNAL MODULE: ./node_modules/moment/moment.js
@@ -37228,6 +37261,16 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37228
37261
  // 订阅语种变化事件 和 文本库缓存更新事件
37229
37262
  this.subscribeLanguageChange();
37230
37263
  }
37264
+ getIconScale() {
37265
+ const initSize = this.model.displaySetting.initSize;
37266
+ const size = this.model.displaySetting.size;
37267
+ if (!initSize || !initSize.width || !initSize.height) {
37268
+ return 1;
37269
+ }
37270
+ const scaleX = size.width / initSize.width;
37271
+ const scaleY = size.height / initSize.height;
37272
+ return Math.min(scaleX, scaleY);
37273
+ }
37231
37274
  dispose() {
37232
37275
  clearInterval(this.refreshIntervalId);
37233
37276
  if (this.chartElement) {
@@ -37493,7 +37536,10 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37493
37536
  }
37494
37537
  renderChart(result) {
37495
37538
  const chartWidth = this.model.displaySetting.size.width;
37496
- const chartHeight = this.model.displaySetting.size.height - this.displayOption.operationAreaHeight - this.displayOption.operationAreaMarginTop;
37539
+ const scale = this.getIconScale();
37540
+ // 图表主体与底部操作区之间的预留高度,需要与操作区渲染时使用的同一个 scale 保持一致,
37541
+ // 否则图表按未缩放高度占满后,缩放后的操作区会超出元件整体高度
37542
+ const chartHeight = this.model.displaySetting.size.height - (this.displayOption.operationAreaHeight + this.displayOption.operationAreaMarginTop) * scale;
37497
37543
  const data = new Array();
37498
37544
  Object(lodash["each"])(this.model.dataSetting.channels, (channel, key) => {
37499
37545
  const values = new Array();
@@ -37503,10 +37549,10 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37503
37549
  this.data = data;
37504
37550
  let chart;
37505
37551
  if (this.model.displaySetting.curveType === CurveType.BarGroup || this.model.displaySetting.curveType === CurveType.BarStack) {
37506
- chart = this.getMultiBarWithFocusChart(chartWidth, chartHeight, data);
37552
+ chart = this.getMultiBarWithFocusChart(chartWidth, chartHeight, data, scale);
37507
37553
  }
37508
37554
  else {
37509
- chart = this.getLineChart(chartWidth, chartHeight, data);
37555
+ chart = this.getLineChart(chartWidth, chartHeight, data, scale);
37510
37556
  }
37511
37557
  // 设置 tooltip 自动隐藏逻辑
37512
37558
  this.setupTooltipAutoHide(chart);
@@ -37556,7 +37602,7 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37556
37602
  console.log(e);
37557
37603
  }
37558
37604
  }
37559
- getLineChart(chartWidth, chartHeight, data) {
37605
+ getLineChart(chartWidth, chartHeight, data, scale = 1) {
37560
37606
  const chart = nv_d3["models"].lineChart().showLegend(true)
37561
37607
  .margin({ top: 0, bottom: 0, left: this.displayOption.marginLeft, right: this.displayOption.marginRight })
37562
37608
  .noData(this.localization.chartNoData);
@@ -37570,7 +37616,7 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37570
37616
  chart.focus.showXAxis(false);
37571
37617
  }
37572
37618
  this.renderCommonProperty(chart, chartWidth, chartHeight, data);
37573
- this.renderOperationArea(chartWidth, chartHeight);
37619
+ this.renderOperationArea(chartWidth, chartHeight, scale);
37574
37620
  this.initPoint();
37575
37621
  chart.legend.dispatch.on('legendClick', () => {
37576
37622
  setTimeout(() => {
@@ -37586,7 +37632,7 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37586
37632
  });
37587
37633
  return chart;
37588
37634
  }
37589
- getMultiBarWithFocusChart(chartWidth, chartHeight, data) {
37635
+ getMultiBarWithFocusChart(chartWidth, chartHeight, data, scale = 1) {
37590
37636
  const chart = nv_d3["models"].multiBarWithFocusChart()
37591
37637
  .margin({
37592
37638
  top: 0, bottom: 0, left: this.displayOption.marginLeft, right: this.displayOption.marginRight
@@ -37609,7 +37655,7 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37609
37655
  }
37610
37656
  chart.xAxis.tickFormat(d => this.timeFormat(d, '%x %X'));
37611
37657
  this.renderCommonProperty(chart, chartWidth, chartHeight, data);
37612
- this.renderOperationArea(chartWidth, chartHeight);
37658
+ this.renderOperationArea(chartWidth, chartHeight, scale);
37613
37659
  const focusContext = this.rootElement.select('.nv-context');
37614
37660
  focusContext.select('.nv-barsWrap.nvd3-svg').attr('transform', 'translate(0,30)');
37615
37661
  focusContext.select('.nv-brushBackground').attr('transform', 'translate(0,30)');
@@ -37770,17 +37816,17 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37770
37816
  .remove();
37771
37817
  }
37772
37818
  }
37773
- renderOperationArea(chartWidth, chartHeight) {
37819
+ renderOperationArea(chartWidth, chartHeight, scale = 1) {
37774
37820
  const backgroundColor = this.model.displaySetting.axisSetting.filterBackgroudColor || 'inherit';
37775
- const operationArea = this.rootElement.append('g').attr('transform', `translate(0,${chartHeight + this.displayOption.operationAreaMarginTop})`)
37776
- .append('foreignObject').attr('width', chartWidth).attr('height', this.displayOption.operationAreaHeight).attr('fill', 'none')
37777
- .append('xhtml:div').style('height', (this.displayOption.operationAreaHeight - 4) + 'px').style('overflow', 'hidden').style('margin-top', '4px');
37821
+ const operationArea = this.rootElement.append('g').attr('transform', `translate(0,${chartHeight + this.displayOption.operationAreaMarginTop * scale})`)
37822
+ .append('foreignObject').attr('width', chartWidth).attr('height', this.displayOption.operationAreaHeight * scale).attr('fill', 'none')
37823
+ .append('xhtml:div').style('height', (this.displayOption.operationAreaHeight * scale - 4) + 'px').style('overflow', 'hidden').style('margin-top', '4px');
37778
37824
  const rect = this.$element.parent().parent().find('rect');
37779
37825
  const fillColor = rect.attr('fill');
37780
37826
  const dropdownBg = this.model.displaySetting.axisSetting.filterBackgroudColor || fillColor || '#fff';
37781
37827
  const dropdownWrapper = operationArea.append('div')
37782
37828
  .style('display', 'inline-block')
37783
- .style('margin-left', this.displayOption.marginLeft + 'px')
37829
+ .style('margin-left', (this.displayOption.marginLeft * scale) + 'px')
37784
37830
  .style('vertical-align', 'middle');
37785
37831
  const selectedText = this.timePeriods.find(t => t.key === Number(this.currentTimePeriod));
37786
37832
  const arrowIconUrl = 'url("data:image/svg+xml,'
@@ -37792,14 +37838,14 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37792
37838
  .style('background-image', arrowIconUrl)
37793
37839
  .style('background-repeat', 'no-repeat')
37794
37840
  .style('background-position', 'right 4px center')
37795
- .style('font-size', this.displayOption.operationSelectFontSize)
37841
+ .style('font-size', (parseFloat(this.displayOption.operationSelectFontSize) * scale) + 'px')
37796
37842
  .style('cursor', 'pointer')
37797
37843
  .style('padding', '0 18px 0 4px')
37798
37844
  .style('border', '1px solid #ccc')
37799
37845
  .style('border-radius', '2px')
37800
37846
  .style('white-space', 'nowrap')
37801
- .style('line-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37802
- .style('min-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37847
+ .style('line-height', (this.displayOption.operationAreaHeight * scale - 8) + 'px')
37848
+ .style('min-height', (this.displayOption.operationAreaHeight * scale - 8) + 'px')
37803
37849
  .text(selectedText ? selectedText.name : '');
37804
37850
  const dropdownListEl = document.createElement('div');
37805
37851
  dropdownListEl.style.cssText = 'display:none;position:fixed;background:' + dropdownBg
@@ -37814,9 +37860,9 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37814
37860
  .style('padding', '4px 8px')
37815
37861
  .style('cursor', 'pointer')
37816
37862
  .style('white-space', 'nowrap')
37817
- .style('font-size', this.displayOption.operationSelectFontSize)
37818
- .style('line-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37819
- .style('min-height', (this.displayOption.operationAreaHeight - 8) + 'px')
37863
+ .style('font-size', (parseFloat(this.displayOption.operationSelectFontSize) * scale) + 'px')
37864
+ .style('line-height', (this.displayOption.operationAreaHeight * scale - 8) + 'px')
37865
+ .style('min-height', (this.displayOption.operationAreaHeight * scale - 8) + 'px')
37820
37866
  .style('background', tp.key === Number(this.currentTimePeriod) ? '#1890ff' : 'transparent')
37821
37867
  .style('color', tp.key === Number(this.currentTimePeriod) ? '#fff' : '#333')
37822
37868
  .text(tp.name)
@@ -37911,24 +37957,24 @@ class historical_curve_element_HistoricalCurveElement extends conditional_displa
37911
37957
  window.addEventListener('resize', this._resizeHideHandler);
37912
37958
  // 滚动时收起
37913
37959
  document.addEventListener('scroll', hideDropdown, true);
37914
- const buttonWidth = this.displayOption.operationButtonWidth + 'px', buttonHeight = this.displayOption.operationButtonHeight + 'px';
37960
+ const buttonWidth = (this.displayOption.operationButtonWidth * scale) + 'px', buttonHeight = (this.displayOption.operationButtonHeight * scale) + 'px';
37915
37961
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
37916
37962
  .style('float', 'right').style('background-image', 'url(assets/img/black_last_page.png)')
37917
37963
  .style('background-color', backgroundColor).style('background-size', 'cover')
37918
37964
  .on('click', () => { this.loadLastPage(); });
37919
37965
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
37920
37966
  .style('float', 'right').style('background-image', 'url(assets/img/black_next_page.png)')
37921
- .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
37967
+ .style('margin', `0 ${this.displayOption.operationButtonMargin * scale}px 0 0`)
37922
37968
  .style('background-color', backgroundColor).style('background-size', 'cover')
37923
37969
  .on('click', () => { this.loadNextPage(); });
37924
37970
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
37925
37971
  .style('float', 'right').style('background-image', 'url(assets/img/black_previous_page.png)')
37926
- .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
37972
+ .style('margin', `0 ${this.displayOption.operationButtonMargin * scale}px 0 0`)
37927
37973
  .style('background-color', backgroundColor).style('background-size', 'cover')
37928
37974
  .on('click', () => { this.loadPreviousPage(); });
37929
37975
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
37930
37976
  .style('float', 'right').style('background-image', 'url(assets/img/black_first_page.png)')
37931
- .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
37977
+ .style('margin', `0 ${this.displayOption.operationButtonMargin * scale}px 0 0`)
37932
37978
  .style('background-color', backgroundColor).style('background-size', 'cover')
37933
37979
  .on('click', () => { this.loadFirstPage(); });
37934
37980
  }
@@ -38840,6 +38886,21 @@ class numerical_display_element_NumericalDisplayElement extends readable_element
38840
38886
  }
38841
38887
  return displayText;
38842
38888
  }
38889
+ /**
38890
+ * 提供元件尺寸信息用于状态图标缩放
38891
+ */
38892
+ getElementSizeForIconScale() {
38893
+ var _a, _b;
38894
+ if (this.model.size) {
38895
+ return {
38896
+ width: this.model.size.width,
38897
+ height: this.model.size.height,
38898
+ initWidth: (_a = this.model.initSize) === null || _a === void 0 ? void 0 : _a.width,
38899
+ initHeight: (_b = this.model.initSize) === null || _b === void 0 ? void 0 : _b.height
38900
+ };
38901
+ }
38902
+ return null;
38903
+ }
38843
38904
  }
38844
38905
 
38845
38906
  // EXTERNAL MODULE: ./.tmp/model/shared/condition/condition-type.ts
@@ -40663,6 +40724,21 @@ class switch_indicator_light_element_SwitchIndicatorLightElement extends conditi
40663
40724
  this.textStateElement = new text_state_element_TextStateElement(this.model.states, width, height, this.logger, this.model.version, this.model.states, this.model.textLibrary, this.textLibraryService, this.languageService, this.guiContext, true, this.model.fontStyleCultures);
40664
40725
  this.$element.append(this.textStateElement.Element);
40665
40726
  }
40727
+ /**
40728
+ * 提供元件尺寸信息用于状态图标缩放
40729
+ */
40730
+ getElementSizeForIconScale() {
40731
+ var _a, _b;
40732
+ if (this.model.size) {
40733
+ return {
40734
+ width: this.model.size.width,
40735
+ height: this.model.size.height,
40736
+ initWidth: (_a = this.model.initSize) === null || _a === void 0 ? void 0 : _a.width,
40737
+ initHeight: (_b = this.model.initSize) === null || _b === void 0 ? void 0 : _b.height
40738
+ };
40739
+ }
40740
+ return null;
40741
+ }
40666
40742
  /**
40667
40743
  * 释放资源
40668
40744
  */
@@ -41245,7 +41321,8 @@ class view_operation_element_ViewOperationElement extends conditional_enable_ele
41245
41321
  popView() {
41246
41322
  const viewIndex = this.model.viewIndex;
41247
41323
  if (null != viewIndex) {
41248
- this.popupViewService.popView(viewIndex, this.hostContainerId, this.el).subscribe(() => this.recordViewOperation(), error => this.logger.error(`ToggleView(${viewIndex}) failed. ${error}`));
41324
+ const triggerRect = this.$element[0].getBoundingClientRect();
41325
+ this.popupViewService.popView(viewIndex, this.hostContainerId, this.el, triggerRect).subscribe(() => this.recordViewOperation(), error => this.logger.error(`ToggleView(${viewIndex}) failed. ${error}`));
41249
41326
  $(`#${this.hostContainerId} video`)
41250
41327
  .addClass('video-hidden')
41251
41328
  .css('visibility', 'hidden');
@@ -42440,6 +42517,15 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42440
42517
  this.page = 0;
42441
42518
  this.totalCount = 0;
42442
42519
  this.pageSize = 5;
42520
+ this.maxVisibleRows = 15;
42521
+ this.rowHeight = 0;
42522
+ this.isDisposed = false;
42523
+ this.handleScrollMouseEnter = () => {
42524
+ clearInterval(this.scrollIntervalId);
42525
+ };
42526
+ this.handleScrollMouseLeave = () => {
42527
+ this.startAutoScroll();
42528
+ };
42443
42529
  this.rootElement.selectAll('*').remove();
42444
42530
  this.setStatusAsLoading();
42445
42531
  this.logger = injector.get(logger["b" /* LOGGER_SERVICE_TOKEN */]);
@@ -42454,7 +42540,14 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42454
42540
  this.updateQueryTimeRange();
42455
42541
  if (this.model.filterSetting.alarmType) {
42456
42542
  this.refreshIntervalId = setInterval(() => {
42457
- this.loadFirstPage();
42543
+ if (this.model.generalSetting.autoScroll) {
42544
+ // 开启滚动时,仅更新数据不重渲染,保持滚动进度
42545
+ this.refreshCurrentPageData();
42546
+ }
42547
+ else {
42548
+ // 未开启滚动时,返回第一页
42549
+ this.loadFirstPage();
42550
+ }
42458
42551
  this.logger.debug(`[GUI]Refresh Alarm Table:${d3["time"].format('%x %X')(new Date())}`);
42459
42552
  }, this.model.filterSetting.refreshCycle * 60 * 1000);
42460
42553
  }
@@ -42462,7 +42555,14 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42462
42555
  variableCommunicator.subscribeUserDeviceAlarms(signalRAppId).subscribe(alarms => {
42463
42556
  alarms.forEach(alarm => {
42464
42557
  if (this.alarmNames.indexOf(alarm.name) !== -1) {
42465
- this.getAlarmData();
42558
+ if (this.model.generalSetting.autoScroll) {
42559
+ // 开启滚动时,刷新当前页并保持滚动进度
42560
+ this.refreshCurrentPageData();
42561
+ }
42562
+ else {
42563
+ // 未开启滚动时,刷新当前页(原有逻辑)
42564
+ this.getAlarmData();
42565
+ }
42466
42566
  return;
42467
42567
  }
42468
42568
  });
@@ -42477,10 +42577,11 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42477
42577
  }
42478
42578
  }
42479
42579
  dispose() {
42580
+ this.isDisposed = true;
42480
42581
  clearInterval(this.refreshIntervalId);
42481
- if (this.element) {
42482
- this.element.tooltip.hidden(true);
42483
- }
42582
+ clearInterval(this.scrollIntervalId);
42583
+ clearTimeout(this.getAlarmDataId);
42584
+ this.unbindScrollHoverEvents();
42484
42585
  // 取消语种变化订阅
42485
42586
  if (this.languageChangeSubscription) {
42486
42587
  this.languageChangeSubscription.unsubscribe();
@@ -42602,15 +42703,21 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42602
42703
  return '';
42603
42704
  }
42604
42705
  getAlarmData() {
42706
+ clearInterval(this.scrollIntervalId);
42707
+ this.unbindScrollHoverEvents();
42605
42708
  this.rootElement.selectAll('*').remove();
42606
42709
  this.setStatusAsLoading();
42607
42710
  clearTimeout(this.getAlarmDataId);
42608
42711
  this.getAlarmDataId = setTimeout(() => {
42712
+ if (this.isDisposed)
42713
+ return;
42609
42714
  this.timePeriods = this.getValidTimePeriods();
42610
42715
  if (this.model.filterSetting.alarmType) {
42611
42716
  this.updateQueryTimeRange();
42612
42717
  const input = new _tmp_config["c" /* GetAlarmsArgs */](this.alarmNames, this.startTime, this.endTime, this.pageSize, this.page * this.pageSize);
42613
42718
  this.alarmsStore.getHistoryAlarms(input).subscribe(result => {
42719
+ if (this.isDisposed)
42720
+ return;
42614
42721
  if (!result.error) {
42615
42722
  this.totalCount = result.totalCount;
42616
42723
  this.alarmList = result.items.map(item => [
@@ -42626,6 +42733,8 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42626
42733
  else {
42627
42734
  const input = new _tmp_config["c" /* GetAlarmsArgs */](this.alarmNames, undefined, undefined, this.pageSize, this.page * this.pageSize);
42628
42735
  this.alarmsStore.getCurrentAlarms(input).subscribe(result => {
42736
+ if (this.isDisposed)
42737
+ return;
42629
42738
  if (!result.error) {
42630
42739
  this.totalCount = result.totalCount;
42631
42740
  this.currentAlarmList = result.items;
@@ -42646,16 +42755,124 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42646
42755
  }
42647
42756
  }, 500);
42648
42757
  }
42758
+ refreshCurrentPageData() {
42759
+ var _a;
42760
+ if (this.isDisposed)
42761
+ return;
42762
+ const currentScrollTop = ((_a = this.scrollContainer) === null || _a === void 0 ? void 0 : _a.scrollTop) || 0;
42763
+ if (this.model.filterSetting.alarmType) {
42764
+ this.updateQueryTimeRange();
42765
+ const input = new _tmp_config["c" /* GetAlarmsArgs */](this.alarmNames, this.startTime, this.endTime, this.pageSize, this.page * this.pageSize);
42766
+ this.alarmsStore.getHistoryAlarms(input).subscribe(result => {
42767
+ if (this.isDisposed)
42768
+ return;
42769
+ if (!result.error) {
42770
+ this.totalCount = result.totalCount;
42771
+ this.alarmList = result.items.map(item => [
42772
+ item.name,
42773
+ item.message,
42774
+ item.alarmLevel,
42775
+ item.triggeredTime.format('YYYY-MM-DD HH:mm:ss')
42776
+ ]);
42777
+ this.updateTableContent();
42778
+ if (this.scrollContainer) {
42779
+ this.scrollContainer.scrollTop = currentScrollTop;
42780
+ }
42781
+ }
42782
+ });
42783
+ }
42784
+ else {
42785
+ const input = new _tmp_config["c" /* GetAlarmsArgs */](this.alarmNames, undefined, undefined, this.pageSize, this.page * this.pageSize);
42786
+ this.alarmsStore.getCurrentAlarms(input).subscribe(result => {
42787
+ if (this.isDisposed)
42788
+ return;
42789
+ if (!result.error) {
42790
+ this.totalCount = result.totalCount;
42791
+ this.currentAlarmList = result.items;
42792
+ if (!result.items.length && result.totalCount) {
42793
+ this.page = 0;
42794
+ this.refreshCurrentPageData();
42795
+ return;
42796
+ }
42797
+ this.alarmList = this.currentAlarmList.map(item => [
42798
+ item.name,
42799
+ item.message,
42800
+ item.alarmLevel,
42801
+ item.triggeredTime.format('YYYY-MM-DD HH:mm:ss')
42802
+ ]);
42803
+ this.updateTableContent();
42804
+ if (this.scrollContainer) {
42805
+ this.scrollContainer.scrollTop = currentScrollTop;
42806
+ }
42807
+ }
42808
+ });
42809
+ }
42810
+ }
42811
+ updateTableContent() {
42812
+ if (!this.element)
42813
+ return;
42814
+ const useScroll = this.pageSize > this.maxVisibleRows;
42815
+ const dataRowHeight = this.model.heights[1] || this.model.heights[0];
42816
+ // 查找表格主体
42817
+ let tbody;
42818
+ if (useScroll) {
42819
+ const bodyContainer = this.element.querySelector('div > div:nth-child(2)');
42820
+ if (!bodyContainer)
42821
+ return;
42822
+ const bodyTable = bodyContainer.querySelector('table');
42823
+ if (!bodyTable)
42824
+ return;
42825
+ tbody = bodyTable;
42826
+ }
42827
+ else {
42828
+ const table = this.element.querySelector('table');
42829
+ if (!table)
42830
+ return;
42831
+ tbody = table;
42832
+ }
42833
+ // 清除现有数据行(保留表头)
42834
+ const rows = Array.from(tbody.querySelectorAll('tr'));
42835
+ rows.forEach((row, index) => {
42836
+ if (index > 0 || useScroll) { // 对于 scrollable 模式,表头在另一个 table,所以这里全部清除
42837
+ row.remove();
42838
+ }
42839
+ });
42840
+ // 重新生成数据行
42841
+ for (let row = 0; row < this.pageSize; row++) {
42842
+ const rowHeight = useScroll ? dataRowHeight : this.model.heights[row + 1];
42843
+ tbody.appendChild(this.buildDataRow(row, rowHeight));
42844
+ }
42845
+ }
42846
+ getIconScale() {
42847
+ const initSize = this.model.initSize;
42848
+ if (!initSize || !initSize.width || !initSize.height) {
42849
+ return 1;
42850
+ }
42851
+ const scaleX = this.model.size.width / initSize.width;
42852
+ const scaleY = this.model.size.height / initSize.height;
42853
+ return Math.min(scaleX, scaleY);
42854
+ }
42649
42855
  renderElement() {
42650
42856
  const elementHeight = this.model.size.height;
42651
42857
  this.element = document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject');
42652
42858
  this.element.setAttribute('width', this.model.size.width.toString());
42653
42859
  this.element.setAttribute('height', elementHeight.toString());
42654
42860
  this.$element.append(this.element);
42655
- const table = document.createElement('table');
42656
- table.style.cssText = `border: 2px solid ${this.model.generalSetting.stroke};
42657
- height: ${elementHeight - 39}`;
42658
- let tr = document.createElement('tr');
42861
+ const scale = this.getIconScale();
42862
+ // 表格与底部操作区之间的预留高度,需要与操作区渲染时使用的同一个 scale 保持一致,
42863
+ // 否则表格按未缩放高度占满后,缩放后的操作区会超出元件整体高度
42864
+ const operationAreaReservedHeight = 39 * scale;
42865
+ const useScroll = this.pageSize > this.maxVisibleRows;
42866
+ if (useScroll) {
42867
+ this.renderScrollableTable(elementHeight, operationAreaReservedHeight);
42868
+ }
42869
+ else {
42870
+ this.renderPlainTable(elementHeight, operationAreaReservedHeight);
42871
+ }
42872
+ this.renderOperationArea(this.model.size.width, elementHeight - operationAreaReservedHeight, scale);
42873
+ }
42874
+ buildHeaderRow() {
42875
+ const tr = document.createElement('tr');
42659
42876
  let fontString = '';
42660
42877
  if (this.model.generalSetting.headerFont.isItalic) {
42661
42878
  fontString += 'italic ';
@@ -42680,56 +42897,34 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42680
42897
  border-left-width: ${!col || this.model.generalSetting.isHiddenColumnSplitLine ? 0 : 1}px;`;
42681
42898
  tr.appendChild(th);
42682
42899
  }
42683
- table.appendChild(tr);
42900
+ return tr;
42901
+ }
42902
+ buildDataRow(row, rowHeight) {
42684
42903
  const levelColors = ['#3695FF', '#FFE900', '#FFA800', '#E84F4F'];
42685
- for (let row = 0; row < this.pageSize; row++) {
42686
- tr = document.createElement('tr');
42687
- tr.style.cssText = `height: ${this.model.heights[row + 1]}px;
42688
- background: ${this.model.generalSetting.tableFillColor};
42689
- font: ${this.model.generalSetting.fontStyle};
42690
- color: ${this.model.generalSetting.fontColor};
42691
- text-align: ${this.model.generalSetting.textAlign};
42692
- vertical-align: middle;`;
42693
- for (let col = 0; col < 4; col++) {
42694
- const td = document.createElement('td');
42695
- td.style.cssText = `border-style: solid;
42696
- border-color: ${this.model.generalSetting.splitLine};
42697
- border-top-width: ${this.model.generalSetting.isHiddenColumnSplitLine ? 0 : 1}px;
42698
- border-left-width: ${!col || this.model.generalSetting.isHiddenColumnSplitLine ? 0 : 1}px;`;
42699
- if (this.alarmList[row]) {
42700
- if (col !== 2) {
42701
- td.innerHTML = this.alarmList[row][col];
42702
- td.style.cssText += `${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
42703
- }
42704
- else {
42705
- const alarmLevel = document.createElement('div');
42706
- let alarmHeight = parseInt(this.model.generalSetting.fontSize) + 15;
42707
- if (alarmHeight > this.model.heights[row + 1])
42708
- alarmHeight = this.model.heights[row + 1];
42709
- let margin = '0 15px';
42710
- if (this.model.generalSetting.textAlign === 'left') {
42711
- margin = '0 30px 0 0';
42712
- }
42713
- else if (this.model.generalSetting.textAlign === 'right') {
42714
- margin = '0 0 0 30px';
42715
- }
42716
- alarmLevel.style.cssText = `margin: ${margin};
42717
- border-radius: 5px;
42718
- background: ${levelColors[this.alarmList[row][col]]};
42719
- color: #ffffff;
42720
- width: ${this.model.widths[col] - 30}px;
42721
- height: ${alarmHeight}px;
42722
- max-height: ${this.model.heights[row + 1]}px;
42723
- display: flex;
42724
- justify-content: center;
42725
- align-items: center;
42726
- ${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
42727
- alarmLevel.innerHTML = this.model.levelText[this.alarmList[row][col]];
42728
- td.appendChild(alarmLevel);
42729
- }
42904
+ const tr = document.createElement('tr');
42905
+ tr.style.cssText = `height: ${rowHeight}px;
42906
+ background: ${this.model.generalSetting.tableFillColor};
42907
+ font: ${this.model.generalSetting.fontStyle};
42908
+ color: ${this.model.generalSetting.fontColor};
42909
+ text-align: ${this.model.generalSetting.textAlign};
42910
+ vertical-align: middle;`;
42911
+ for (let col = 0; col < 4; col++) {
42912
+ const td = document.createElement('td');
42913
+ td.style.cssText = `width: ${this.model.widths[col] / this.model.size.width * 100}%;
42914
+ border-style: solid;
42915
+ border-color: ${this.model.generalSetting.splitLine};
42916
+ border-top-width: ${this.model.generalSetting.isHiddenColumnSplitLine ? 0 : 1}px;
42917
+ border-left-width: ${!col || this.model.generalSetting.isHiddenColumnSplitLine ? 0 : 1}px;`;
42918
+ if (this.alarmList[row]) {
42919
+ if (col !== 2) {
42920
+ td.innerHTML = this.alarmList[row][col];
42921
+ td.style.cssText += `${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
42730
42922
  }
42731
- else if (col === 2) {
42923
+ else {
42732
42924
  const alarmLevel = document.createElement('div');
42925
+ let alarmHeight = parseInt(this.model.generalSetting.fontSize) + 15;
42926
+ if (alarmHeight > rowHeight)
42927
+ alarmHeight = rowHeight;
42733
42928
  let margin = '0 15px';
42734
42929
  if (this.model.generalSetting.textAlign === 'left') {
42735
42930
  margin = '0 30px 0 0';
@@ -42738,24 +42933,144 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42738
42933
  margin = '0 0 0 30px';
42739
42934
  }
42740
42935
  alarmLevel.style.cssText = `margin: ${margin};
42741
- width: ${this.model.widths[col] - 30}px;`;
42936
+ border-radius: 5px;
42937
+ background: ${levelColors[this.alarmList[row][col]]};
42938
+ color: #ffffff;
42939
+ width: ${this.model.widths[col] - 30}px;
42940
+ height: ${alarmHeight}px;
42941
+ max-height: ${rowHeight}px;
42942
+ display: flex;
42943
+ justify-content: center;
42944
+ align-items: center;
42945
+ ${this.model.generalSetting.isUnderline ? 'text-decoration: underline' : ''};`;
42946
+ alarmLevel.innerHTML = this.model.levelText[this.alarmList[row][col]];
42742
42947
  td.appendChild(alarmLevel);
42743
42948
  }
42744
- tr.appendChild(td);
42745
42949
  }
42746
- table.appendChild(tr);
42950
+ else if (col === 2) {
42951
+ const alarmLevel = document.createElement('div');
42952
+ let margin = '0 15px';
42953
+ if (this.model.generalSetting.textAlign === 'left') {
42954
+ margin = '0 30px 0 0';
42955
+ }
42956
+ else if (this.model.generalSetting.textAlign === 'right') {
42957
+ margin = '0 0 0 30px';
42958
+ }
42959
+ alarmLevel.style.cssText = `margin: ${margin};
42960
+ width: ${this.model.widths[col] - 30}px;`;
42961
+ td.appendChild(alarmLevel);
42962
+ }
42963
+ tr.appendChild(td);
42964
+ }
42965
+ return tr;
42966
+ }
42967
+ renderPlainTable(elementHeight, operationAreaReservedHeight) {
42968
+ this.scrollContainer = null;
42969
+ const table = document.createElement('table');
42970
+ table.style.cssText = `border: 2px solid ${this.model.generalSetting.stroke};
42971
+ height: ${elementHeight - operationAreaReservedHeight}px;`;
42972
+ table.appendChild(this.buildHeaderRow());
42973
+ for (let row = 0; row < this.pageSize; row++) {
42974
+ table.appendChild(this.buildDataRow(row, this.model.heights[row + 1]));
42747
42975
  }
42748
42976
  this.element.appendChild(table);
42749
- this.renderOperationArea(this.model.size.width, elementHeight - 39);
42977
+ this.hoverTarget = table;
42978
+ this.bindScrollHoverEvents();
42979
+ this.startAutoScroll();
42980
+ }
42981
+ renderScrollableTable(elementHeight, operationAreaReservedHeight) {
42982
+ const dataRowHeight = this.model.heights[1] || this.model.heights[0];
42983
+ this.rowHeight = dataRowHeight;
42984
+ const wrapper = document.createElement('div');
42985
+ wrapper.style.cssText = `display: flex;
42986
+ flex-direction: column;
42987
+ box-sizing: border-box;
42988
+ border: 2px solid ${this.model.generalSetting.stroke};
42989
+ height: ${elementHeight - operationAreaReservedHeight}px;
42990
+ overflow: hidden;`;
42991
+ const headerWrapper = document.createElement('div');
42992
+ headerWrapper.style.cssText = 'flex: none; box-sizing: border-box; overflow: hidden;';
42993
+ const headerTable = document.createElement('table');
42994
+ headerTable.style.cssText = 'width: 100%; table-layout: fixed;';
42995
+ headerTable.appendChild(this.buildHeaderRow());
42996
+ headerWrapper.appendChild(headerTable);
42997
+ const bodyContainer = document.createElement('div');
42998
+ bodyContainer.style.cssText = `flex: none;
42999
+ overflow-y: auto;
43000
+ overflow-x: hidden;
43001
+ height: ${dataRowHeight * this.maxVisibleRows}px;`;
43002
+ const bodyTable = document.createElement('table');
43003
+ bodyTable.style.cssText = 'width: 100%; table-layout: fixed;';
43004
+ for (let row = 0; row < this.pageSize; row++) {
43005
+ bodyTable.appendChild(this.buildDataRow(row, dataRowHeight));
43006
+ }
43007
+ bodyContainer.appendChild(bodyTable);
43008
+ wrapper.appendChild(headerWrapper);
43009
+ wrapper.appendChild(bodyContainer);
43010
+ this.element.appendChild(wrapper);
43011
+ this.scrollContainer = bodyContainer;
43012
+ requestAnimationFrame(() => {
43013
+ const scrollbarWidth = bodyContainer.offsetWidth - bodyContainer.clientWidth;
43014
+ if (scrollbarWidth > 0) {
43015
+ headerWrapper.style.paddingRight = scrollbarWidth + 'px';
43016
+ }
43017
+ });
43018
+ this.hoverTarget = bodyContainer;
43019
+ this.bindScrollHoverEvents();
43020
+ this.startAutoScroll();
43021
+ }
43022
+ bindScrollHoverEvents() {
43023
+ if (!this.hoverTarget)
43024
+ return;
43025
+ this.hoverTarget.addEventListener('mouseenter', this.handleScrollMouseEnter);
43026
+ this.hoverTarget.addEventListener('mouseleave', this.handleScrollMouseLeave);
43027
+ }
43028
+ unbindScrollHoverEvents() {
43029
+ if (!this.hoverTarget)
43030
+ return;
43031
+ this.hoverTarget.removeEventListener('mouseenter', this.handleScrollMouseEnter);
43032
+ this.hoverTarget.removeEventListener('mouseleave', this.handleScrollMouseLeave);
43033
+ this.hoverTarget = null;
42750
43034
  }
42751
- renderOperationArea(chartWidth, chartHeight) {
43035
+ startAutoScroll() {
43036
+ clearInterval(this.scrollIntervalId);
43037
+ if (!this.model.generalSetting.autoScroll)
43038
+ return;
43039
+ const totalPages = Math.max(1, Math.ceil(this.totalCount / this.pageSize));
43040
+ if (totalPages <= 1 && !this.scrollContainer)
43041
+ return;
43042
+ const duration = (this.model.generalSetting.scrollDuration || 10) * 1000;
43043
+ this.scrollIntervalId = setInterval(() => this.scrollOneRow(), duration);
43044
+ }
43045
+ scrollOneRow() {
43046
+ const el = this.scrollContainer;
43047
+ if (!el) {
43048
+ this.autoNextPage();
43049
+ return;
43050
+ }
43051
+ const maxScrollTop = el.scrollHeight - el.clientHeight;
43052
+ if (maxScrollTop <= 1 || el.scrollTop >= maxScrollTop - 1) {
43053
+ this.autoNextPage();
43054
+ return;
43055
+ }
43056
+ el.scrollTop = Math.min(el.scrollTop + this.rowHeight, maxScrollTop);
43057
+ }
43058
+ autoNextPage() {
43059
+ const totalPages = Math.max(1, Math.ceil(this.totalCount / this.pageSize));
43060
+ if (totalPages <= 1)
43061
+ return;
43062
+ const lastPage = totalPages - 1;
43063
+ this.page = this.page < lastPage ? this.page + 1 : 0;
43064
+ this.getAlarmData();
43065
+ }
43066
+ renderOperationArea(chartWidth, chartHeight, scale = 1) {
42752
43067
  var _a;
42753
- const operationArea = this.rootElement.append('g').attr('transform', `translate(0,${chartHeight + this.displayOption.operationAreaMarginTop})`)
42754
- .append('foreignObject').attr('width', chartWidth).attr('height', this.displayOption.operationAreaHeight).attr('fill', 'none')
42755
- .append('xhtml:div').style('height', (this.displayOption.operationAreaHeight - 4) + 'px').style('overflow', 'hidden').style('margin-top', '4px');
43068
+ const operationArea = this.rootElement.append('g').attr('transform', `translate(0,${chartHeight + this.displayOption.operationAreaMarginTop * scale})`)
43069
+ .append('foreignObject').attr('width', chartWidth).attr('height', this.displayOption.operationAreaHeight * scale).attr('fill', 'none')
43070
+ .append('xhtml:div').style('height', (this.displayOption.operationAreaHeight * scale - 4) + 'px').style('overflow', 'hidden').style('margin-top', '4px');
42756
43071
  if ((_a = this.model.filterSetting) === null || _a === void 0 ? void 0 : _a.alarmType) {
42757
- const selectElement = operationArea.append('select').style('margin-left', this.displayOption.marginLeft + 'px')
42758
- .style('font-size', this.displayOption.operationSelectFontSize).on('change', () => {
43072
+ const selectElement = operationArea.append('select').style('margin-left', (this.displayOption.marginLeft * scale) + 'px')
43073
+ .style('font-size', (parseFloat(this.displayOption.operationSelectFontSize) * scale) + 'px').on('change', () => {
42759
43074
  const displayTimePeriod = this.rootElement.select('select').property('value');
42760
43075
  this.updateTimeRange(displayTimePeriod);
42761
43076
  this.getAlarmData();
@@ -42763,24 +43078,28 @@ class alarm_element_AlarmElement extends conditional_display_element_Conditional
42763
43078
  const options = selectElement.selectAll('option').data(this.timePeriods).enter().append('option');
42764
43079
  options.text(d => d.name).attr('value', d => d.key).property('selected', d => d.key === Number(this.currentTimePeriod));
42765
43080
  }
42766
- const buttonWidth = this.displayOption.operationButtonWidth + 'px', buttonHeight = this.displayOption.operationButtonHeight + 'px';
43081
+ const buttonWidth = (this.displayOption.operationButtonWidth * scale) + 'px', buttonHeight = (this.displayOption.operationButtonHeight * scale) + 'px';
42767
43082
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
42768
43083
  .style('float', 'right').style('background-image', 'url(assets/img/last_page.svg)')
43084
+ .style('background-size', 'contain').style('background-repeat', 'no-repeat').style('background-position', 'center')
42769
43085
  .style('background-color', 'inherit')
42770
43086
  .on('click', () => { this.loadLastPage(); });
42771
43087
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
42772
43088
  .style('float', 'right').style('background-image', 'url(assets/img/next_page.svg)')
42773
- .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
43089
+ .style('background-size', 'contain').style('background-repeat', 'no-repeat').style('background-position', 'center')
43090
+ .style('margin', `0 ${this.displayOption.operationButtonMargin * scale}px 0 0`)
42774
43091
  .style('background-color', 'inherit')
42775
43092
  .on('click', () => { this.loadNextPage(); });
42776
43093
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
42777
43094
  .style('float', 'right').style('background-image', 'url(assets/img/previous_page.svg)')
42778
- .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
43095
+ .style('background-size', 'contain').style('background-repeat', 'no-repeat').style('background-position', 'center')
43096
+ .style('margin', `0 ${this.displayOption.operationButtonMargin * scale}px 0 0`)
42779
43097
  .style('background-color', 'inherit')
42780
43098
  .on('click', () => { this.loadPreviousPage(); });
42781
43099
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
42782
43100
  .style('float', 'right').style('background-image', 'url(assets/img/first_page.svg)')
42783
- .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
43101
+ .style('background-size', 'contain').style('background-repeat', 'no-repeat').style('background-position', 'center')
43102
+ .style('margin', `0 ${this.displayOption.operationButtonMargin * scale}px 0 0`)
42784
43103
  .style('background-color', 'inherit')
42785
43104
  .on('click', () => { this.loadFirstPage(); });
42786
43105
  this.setStatusAsNormal();
@@ -44067,7 +44386,8 @@ class main_element_MainElement {
44067
44386
  Object(lodash["each"])(this.elements, e => {
44068
44387
  if (e instanceof historical_curve_element_HistoricalCurveElement || e instanceof video_element_VideoElement
44069
44388
  || e instanceof weater_element_WeatherElement || e instanceof numerical_display_element_NumericalDisplayElement || e instanceof text_element_TextElement
44070
- || e instanceof air_quality_element_AirQualityElement || e instanceof switch_indicator_light_element_SwitchIndicatorLightElement || e instanceof scroll_alarm_element_ScrollAlarmElement) {
44389
+ || e instanceof air_quality_element_AirQualityElement || e instanceof switch_indicator_light_element_SwitchIndicatorLightElement || e instanceof scroll_alarm_element_ScrollAlarmElement
44390
+ || e instanceof alarm_element_AlarmElement) {
44071
44391
  e.dispose();
44072
44392
  }
44073
44393
  });
@@ -44336,7 +44656,7 @@ class gui_view_GuiView {
44336
44656
  }
44337
44657
  });
44338
44658
  }
44339
- popView(viewIndex, hostContainerId, el) {
44659
+ popView(viewIndex, hostContainerId, el, triggerRect) {
44340
44660
  return this.context.configStore.viewStore.getViewConfig(viewIndex).pipe(Object(operators_["map"])(view => {
44341
44661
  if (!view.config || !view.config.length) {
44342
44662
  throw new shared["a" /* ConfigIsEmptyError */]();
@@ -44357,6 +44677,10 @@ class gui_view_GuiView {
44357
44677
  x = settings.popup.location.x;
44358
44678
  y = settings.popup.location.y;
44359
44679
  }
44680
+ else if (settings.popup.locationType === _tmp_model["ViewPopupLocationType"].NearButton && triggerRect) {
44681
+ const hasShadow = settings.popup.backdropType === _tmp_model["ViewPopupBackdropType"].Shadow && !this.isMobileMode;
44682
+ ({ x, y } = this.getNearButtonPosition(popView, triggerRect, hasShadow));
44683
+ }
44360
44684
  else {
44361
44685
  x = (this.rawWidth - popView.rawWidth) / 2;
44362
44686
  y = (this.rawHeight - popView.rawHeight) / 2;
@@ -44376,6 +44700,73 @@ class gui_view_GuiView {
44376
44700
  this.element.appendChild(popView.element);
44377
44701
  }));
44378
44702
  }
44703
+ /**
44704
+ * 把屏幕像素矩形(如按钮的 getBoundingClientRect)换算为当前画面 SVG 坐标系下的矩形。
44705
+ * 用 getScreenCTM 而不是简单的宽高比换算,因为画面容器宽高比与 rawWidth/rawHeight 不一致时
44706
+ * SVG 会按 preserveAspectRatio 留白(letterbox),线性比例换算会有偏差。
44707
+ */
44708
+ toLocalRect(rect) {
44709
+ const svgRoot = this.element;
44710
+ const ctm = svgRoot.getScreenCTM && svgRoot.getScreenCTM();
44711
+ if (ctm) {
44712
+ const inverse = ctm.inverse();
44713
+ const toLocal = (clientX, clientY) => {
44714
+ const pt = svgRoot.createSVGPoint();
44715
+ pt.x = clientX;
44716
+ pt.y = clientY;
44717
+ return pt.matrixTransform(inverse);
44718
+ };
44719
+ const topLeft = toLocal(rect.left, rect.top);
44720
+ const bottomRight = toLocal(rect.right, rect.bottom);
44721
+ return {
44722
+ x: topLeft.x,
44723
+ y: topLeft.y,
44724
+ width: bottomRight.x - topLeft.x,
44725
+ height: bottomRight.y - topLeft.y
44726
+ };
44727
+ }
44728
+ const viewRect = this.element.getBoundingClientRect();
44729
+ const scaleX = viewRect.width ? this.rawWidth / viewRect.width : 1;
44730
+ const scaleY = viewRect.height ? this.rawHeight / viewRect.height : 1;
44731
+ return {
44732
+ x: (rect.left - viewRect.left) * scaleX,
44733
+ y: (rect.top - viewRect.top) * scaleY,
44734
+ width: rect.width * scaleX,
44735
+ height: rect.height * scaleY
44736
+ };
44737
+ }
44738
+ /**
44739
+ * 按钮附近:按钮与弹出画面之间留缝隙,两侧都放得下时默认放右侧,放不下时放在放得下的一侧;
44740
+ * 竖直方向默认与按钮顶部对齐,下方放不下时改为与按钮底部对齐;
44741
+ * 左右两侧都放不下(弹窗比画面还宽)时直接退化为画面居中,不再跟随按钮
44742
+ */
44743
+ getNearButtonPosition(popView, triggerRect, hasShadow) {
44744
+ const gap = 20;
44745
+ const { x: buttonX, y: buttonY, width: buttonWidth, height: buttonHeight } = this.toLocalRect(triggerRect);
44746
+ const rightX = buttonX + buttonWidth + gap;
44747
+ const leftX = buttonX - gap - popView.rawWidth;
44748
+ const fitsRight = rightX + popView.rawWidth <= this.rawWidth;
44749
+ const fitsLeft = leftX >= 0;
44750
+ let x;
44751
+ let y;
44752
+ if (!fitsRight && !fitsLeft) {
44753
+ x = (this.rawWidth - popView.rawWidth) / 2;
44754
+ y = (this.rawHeight - popView.rawHeight) / 2;
44755
+ }
44756
+ else {
44757
+ x = fitsRight ? rightX : leftX;
44758
+ const fitsBelow = buttonY + popView.rawHeight <= this.rawHeight;
44759
+ y = fitsBelow ? buttonY : buttonY + buttonHeight - popView.rawHeight;
44760
+ if (hasShadow) {
44761
+ // 阴影会把可见内容整体右下偏移 SHADOW_INSET,这里反向补偏移让可见内容而不是容器本身对齐按钮
44762
+ x -= gui_view_GuiView.SHADOW_INSET;
44763
+ y -= gui_view_GuiView.SHADOW_INSET;
44764
+ }
44765
+ }
44766
+ x = Math.max(0, Math.min(x, this.rawWidth - popView.rawWidth));
44767
+ y = Math.max(0, Math.min(y, this.rawHeight - popView.rawHeight));
44768
+ return { x, y };
44769
+ }
44379
44770
  closeView() {
44380
44771
  if (!this.parentView) {
44381
44772
  return;
@@ -44413,10 +44804,11 @@ class gui_view_GuiView {
44413
44804
  if (!container) {
44414
44805
  return;
44415
44806
  }
44807
+ const inset = gui_view_GuiView.SHADOW_INSET;
44416
44808
  container.setAttribute('filter', `url(#${filterId})`);
44417
- container.setAttribute('x', '6');
44418
- container.setAttribute('y', '6');
44419
- $(this.element).children('g').attr('transform', 'matrix(1, 0, 0, 1, 6, 6)');
44809
+ container.setAttribute('x', String(inset));
44810
+ container.setAttribute('y', String(inset));
44811
+ $(this.element).children('g').attr('transform', `matrix(1, 0, 0, 1, ${inset}, ${inset})`);
44420
44812
  }
44421
44813
  hideMusk() {
44422
44814
  if (this.muskElement) {
@@ -44458,6 +44850,8 @@ class gui_view_GuiView {
44458
44850
  }
44459
44851
  }
44460
44852
  }
44853
+ /** showShadow() 给阴影留白,内容整体右下偏移的量,"按钮附近"定位需要据此修正才能让可见内容与按钮对齐 */
44854
+ gui_view_GuiView.SHADOW_INSET = 5;
44461
44855
 
44462
44856
 
44463
44857
  /***/ }),
@@ -44553,7 +44947,7 @@ var settings = __webpack_require__(15);
44553
44947
  var logger = __webpack_require__(8);
44554
44948
 
44555
44949
  // EXTERNAL MODULE: ./.tmp/shared/index.ts + 3 modules
44556
- var shared = __webpack_require__(5);
44950
+ var shared = __webpack_require__(6);
44557
44951
 
44558
44952
  // EXTERNAL MODULE: ./.tmp/view/view.service.ts
44559
44953
  var view_service = __webpack_require__(27);
@@ -66447,6 +66841,7 @@ var ViewPopupLocationType;
66447
66841
  (function (ViewPopupLocationType) {
66448
66842
  ViewPopupLocationType[ViewPopupLocationType["Center"] = 0] = "Center";
66449
66843
  ViewPopupLocationType[ViewPopupLocationType["Custom"] = 1] = "Custom";
66844
+ ViewPopupLocationType[ViewPopupLocationType["NearButton"] = 2] = "NearButton";
66450
66845
  })(ViewPopupLocationType || (ViewPopupLocationType = {}));
66451
66846
 
66452
66847
  // CONCATENATED MODULE: ./.tmp/model/settings/popup/view-popup-backdrop-type.ts
@@ -66560,7 +66955,7 @@ var Subject = __webpack_require__(39);
66560
66955
  var operators_ = __webpack_require__(17);
66561
66956
 
66562
66957
  // EXTERNAL MODULE: ./.tmp/config/index.ts + 12 modules
66563
- var _tmp_config = __webpack_require__(6);
66958
+ var _tmp_config = __webpack_require__(5);
66564
66959
 
66565
66960
  // EXTERNAL MODULE: ./.tmp/core/stringifying-map.ts
66566
66961
  var stringifying_map = __webpack_require__(30);
@@ -87514,7 +87909,7 @@ __webpack_require__.r(__webpack_exports__);
87514
87909
  /* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(43);
87515
87910
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "StringifyingMap", function() { return _core__WEBPACK_IMPORTED_MODULE_3__["a"]; });
87516
87911
 
87517
- /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(6);
87912
+ /* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5);
87518
87913
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ConfigStore", function() { return _config__WEBPACK_IMPORTED_MODULE_4__["b"]; });
87519
87914
 
87520
87915
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "GuiFeatureConfig", function() { return _config__WEBPACK_IMPORTED_MODULE_4__["j"]; });
@@ -87574,7 +87969,7 @@ __webpack_require__.r(__webpack_exports__);
87574
87969
  /* harmony import */ var _security__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(77);
87575
87970
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "SecurityChecker", function() { return _security__WEBPACK_IMPORTED_MODULE_8__["a"]; });
87576
87971
 
87577
- /* harmony import */ var _shared__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(5);
87972
+ /* harmony import */ var _shared__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(6);
87578
87973
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Disposable", function() { return _shared__WEBPACK_IMPORTED_MODULE_9__["b"]; });
87579
87974
 
87580
87975
  /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ConfigIsEmptyError", function() { return _shared__WEBPACK_IMPORTED_MODULE_9__["a"]; });