@flexem/fc-gui 3.0.0-alpha.13 → 3.0.0-alpha.131

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 (184) hide show
  1. package/CHANGELOG.md +439 -1
  2. package/assets/img/black_first_page.png +0 -0
  3. package/assets/img/black_last_page.png +0 -0
  4. package/assets/img/black_next_page.png +0 -0
  5. package/assets/img/black_previous_page.png +0 -0
  6. package/bundles/@flexem/fc-gui.umd.js +38522 -34542
  7. package/bundles/@flexem/fc-gui.umd.js.map +1 -1
  8. package/bundles/@flexem/fc-gui.umd.min.js +5 -5
  9. package/bundles/@flexem/fc-gui.umd.min.js.map +1 -1
  10. package/communication/variable/variable-communicator.d.ts +4 -0
  11. package/communication/variable/variable-value.d.ts +4 -1
  12. package/communication/variable/variable-value.js +4 -1
  13. package/communication/variable/variable-value.metadata.json +1 -1
  14. package/config/alarm/alarm.store.d.ts +6 -0
  15. package/config/alarm/alarm.store.js +0 -0
  16. package/config/alarm/alarm.store.metadata.json +1 -0
  17. package/config/alarm/get-alarms-args.d.ts +12 -0
  18. package/config/alarm/get-alarms-args.js +13 -0
  19. package/config/alarm/get-alarms-args.metadata.json +1 -0
  20. package/config/alarm/index.d.ts +2 -0
  21. package/config/alarm/index.js +1 -0
  22. package/config/alarm/index.metadata.json +1 -0
  23. package/config/config-store.d.ts +2 -0
  24. package/config/history-data/get-history-data-args.d.ts +14 -3
  25. package/config/history-data/get-history-data-args.js +5 -3
  26. package/config/history-data/get-history-data-args.metadata.json +1 -1
  27. package/config/history-data/history-data.model.d.ts +7 -1
  28. package/config/history-data/history-data.model.js +9 -1
  29. package/config/history-data/history-data.model.metadata.json +1 -1
  30. package/config/history-data/index.d.ts +1 -1
  31. package/config/history-data/index.js +1 -1
  32. package/config/history-data/index.metadata.json +1 -1
  33. package/config/index.d.ts +1 -0
  34. package/config/index.js +1 -0
  35. package/config/index.metadata.json +1 -1
  36. package/elements/air-quality/air-quality-element.d.ts +31 -0
  37. package/elements/air-quality/air-quality-element.js +194 -0
  38. package/elements/air-quality/air-quality-element.metadata.json +1 -0
  39. package/elements/alarm/alarm-element.d.ts +69 -0
  40. package/elements/alarm/alarm-element.js +497 -0
  41. package/elements/alarm/alarm-element.metadata.json +1 -0
  42. package/elements/bar-graph-element.d.ts +10 -2
  43. package/elements/bar-graph-element.js +135 -5
  44. package/elements/bar-graph-element.metadata.json +1 -1
  45. package/elements/base/readable-element.d.ts +6 -1
  46. package/elements/base/readable-element.js +64 -2
  47. package/elements/base/readable-element.metadata.json +1 -1
  48. package/elements/base/state-control-element.d.ts +3 -1
  49. package/elements/base/state-control-element.js +3 -0
  50. package/elements/datetime-display/datetime-display-element.d.ts +1 -0
  51. package/elements/datetime-display/datetime-display-element.js +10 -2
  52. package/elements/datetime-display/datetime-display-element.metadata.json +1 -1
  53. package/elements/datetime-display/time-zone-select-json.d.ts +8 -0
  54. package/elements/datetime-display/time-zone-select-json.js +558 -0
  55. package/elements/historical-curve/historical-curve.element.d.ts +39 -3
  56. package/elements/historical-curve/historical-curve.element.js +509 -43
  57. package/elements/historical-curve/historical-curve.element.metadata.json +1 -1
  58. package/elements/main-element.d.ts +1 -0
  59. package/elements/main-element.js +59 -9
  60. package/elements/main-element.metadata.json +1 -1
  61. package/elements/meter-element.d.ts +7 -1
  62. package/elements/meter-element.js +76 -7
  63. package/elements/meter-element.metadata.json +1 -1
  64. package/elements/numerical-display/numerical-display-element.d.ts +16 -3
  65. package/elements/numerical-display/numerical-display-element.js +83 -11
  66. package/elements/numerical-display/numerical-display-element.metadata.json +1 -1
  67. package/elements/per-view-variable-communicator.d.ts +3 -0
  68. package/elements/per-view-variable-communicator.js +11 -0
  69. package/elements/per-view-variable-communicator.metadata.json +1 -1
  70. package/elements/ring-graph/ring-graph-element.d.ts +13 -1
  71. package/elements/ring-graph/ring-graph-element.js +164 -3
  72. package/elements/ring-graph/ring-graph-element.metadata.json +1 -1
  73. package/elements/scroll-alarm/scroll-alarm-element.d.ts +67 -0
  74. package/elements/scroll-alarm/scroll-alarm-element.js +663 -0
  75. package/elements/scroll-alarm/scroll-alarm-element.metadata.json +1 -0
  76. package/elements/shared/graph/graph-state-element.js +0 -3
  77. package/elements/shared/text/text-element.d.ts +9 -0
  78. package/elements/shared/text/text-element.js +33 -2
  79. package/elements/shared/text/text-element.metadata.json +1 -1
  80. package/elements/shared/text/text-state-element.d.ts +25 -2
  81. package/elements/shared/text/text-state-element.js +138 -63
  82. package/elements/shared/text/text-state-element.metadata.json +1 -1
  83. package/elements/static-elements/hyperlink-element.d.ts +24 -2
  84. package/elements/static-elements/hyperlink-element.js +101 -3
  85. package/elements/static-elements/hyperlink-element.metadata.json +1 -1
  86. package/elements/static-elements/text-element.d.ts +23 -2
  87. package/elements/static-elements/text-element.js +96 -3
  88. package/elements/static-elements/text-element.metadata.json +1 -1
  89. package/elements/switch-indicator-light/bit-switch-operator.d.ts +1 -0
  90. package/elements/switch-indicator-light/bit-switch-operator.js +19 -0
  91. package/elements/switch-indicator-light/bit-switch-operator.metadata.json +1 -1
  92. package/elements/switch-indicator-light/switch-indicator-light-element.d.ts +18 -2
  93. package/elements/switch-indicator-light/switch-indicator-light-element.js +120 -25
  94. package/elements/switch-indicator-light/switch-indicator-light-element.metadata.json +1 -1
  95. package/elements/switch-indicator-light/switch-operator.d.ts +1 -0
  96. package/elements/switch-indicator-light/word-switch-operator.d.ts +1 -0
  97. package/elements/switch-indicator-light/word-switch-operator.js +6 -0
  98. package/elements/switch-indicator-light/word-switch-operator.metadata.json +1 -1
  99. package/elements/video/video-element.d.ts +4 -0
  100. package/elements/video/video-element.js +81 -21
  101. package/elements/video/video-element.metadata.json +1 -1
  102. package/elements/view-operation/view-operation.element.d.ts +23 -2
  103. package/elements/view-operation/view-operation.element.js +103 -1
  104. package/elements/view-operation/view-operation.element.metadata.json +1 -1
  105. package/elements/weather/weater-element.js +0 -1
  106. package/gui/gui-context.d.ts +12 -2
  107. package/gui/gui-host.d.ts +1 -1
  108. package/gui/gui-view.d.ts +2 -0
  109. package/gui/gui-view.js +38 -2
  110. package/gui/gui-view.metadata.json +1 -1
  111. package/gui/gui.component.d.ts +3 -0
  112. package/gui/gui.component.js +15 -2
  113. package/gui/gui.component.metadata.json +1 -1
  114. package/localization/localization.service.d.ts +7 -0
  115. package/localization/localization.service.js +10 -3
  116. package/localization/localization.service.metadata.json +1 -1
  117. package/localization/localization.service.zh_CN.js +8 -1
  118. package/localization/localization.service.zh_CN.metadata.json +1 -1
  119. package/modal/write-value/write-value-modal-args.d.ts +5 -1
  120. package/modal/write-value/write-value-modal-args.js +3 -1
  121. package/modal/write-value/write-value-modal-args.metadata.json +1 -1
  122. package/modal/write-value/write-value-modal.component.d.ts +12 -7
  123. package/modal/write-value/write-value-modal.component.html +9 -4
  124. package/modal/write-value/write-value-modal.component.js +73 -15
  125. package/modal/write-value/write-value-modal.component.metadata.json +1 -1
  126. package/model/air-quality/air-quality-info.d.ts +23 -0
  127. package/model/air-quality/air-quality-info.js +4 -0
  128. package/model/air-quality/air-quality-info.metadata.json +1 -0
  129. package/model/air-quality/air-quality.model.d.ts +7 -0
  130. package/model/air-quality/air-quality.model.js +0 -0
  131. package/model/air-quality/air-quality.model.metadata.json +1 -0
  132. package/model/alarm/alarm.model.d.ts +13 -0
  133. package/model/alarm/alarm.model.js +0 -0
  134. package/model/alarm/alarm.model.metadata.json +1 -0
  135. package/model/bar-graph/bar-graph.d.ts +4 -0
  136. package/model/base/font-setting-model.d.ts +6 -0
  137. package/model/base/font-setting-model.metadata.json +1 -1
  138. package/model/base/readable-model.d.ts +4 -0
  139. package/model/datetime-display/datetime-display.d.ts +1 -0
  140. package/model/historical-curve/historical-curve-axis-settings.d.ts +11 -0
  141. package/model/historical-curve/historical-curve-axis-settings.js +5 -0
  142. package/model/historical-curve/historical-curve-axis-settings.metadata.json +1 -1
  143. package/model/historical-curve/historical-curve-chanel.model.d.ts +8 -0
  144. package/model/historical-curve/historical-curve.data-settings.d.ts +18 -1
  145. package/model/historical-curve/historical-curve.data-settings.metadata.json +1 -1
  146. package/model/meter/meter.d.ts +4 -0
  147. package/model/ring-graph/ring-graph.model.d.ts +8 -0
  148. package/model/scroll-alarm/scroll-alarm.model.d.ts +21 -0
  149. package/model/scroll-alarm/scroll-alarm.model.js +0 -0
  150. package/model/scroll-alarm/scroll-alarm.model.metadata.json +1 -0
  151. package/model/switch-indicator-light/bit-switch-operation.d.ts +2 -1
  152. package/model/switch-indicator-light/bit-switch-operation.js +1 -0
  153. package/model/switch-indicator-light/bit-switch-operation.metadata.json +1 -1
  154. package/model/switch-indicator-light/switch-indicator-light.d.ts +2 -0
  155. package/model/view-operation/view-operation-element.model.d.ts +7 -1
  156. package/package.json +1 -1
  157. package/public_api.js +1 -0
  158. package/remote/communication/variable/remote-variable-communicator.d.ts +22 -0
  159. package/remote/communication/variable/remote-variable-communicator.js +122 -2
  160. package/remote/communication/variable/remote-variable-communicator.metadata.json +1 -1
  161. package/remote/communication/variable/remote-variable-protocol.d.ts +5 -0
  162. package/service/index.d.ts +4 -0
  163. package/service/index.js +1 -0
  164. package/service/index.metadata.json +1 -1
  165. package/service/language.service.d.ts +37 -0
  166. package/service/language.service.js +0 -0
  167. package/service/language.service.metadata.json +1 -0
  168. package/service/released-variable/index.d.ts +1 -0
  169. package/service/released-variable/index.js +0 -0
  170. package/service/released-variable/index.metadata.json +1 -0
  171. package/service/released-variable/released-variable.service.d.ts +4 -0
  172. package/service/released-variable/released-variable.service.js +0 -0
  173. package/service/released-variable/released-variable.service.metadata.json +1 -0
  174. package/service/system-text-library.service.d.ts +76 -0
  175. package/service/system-text-library.service.js +28 -0
  176. package/service/system-text-library.service.metadata.json +1 -0
  177. package/service/text-library.service.d.ts +49 -0
  178. package/service/text-library.service.js +0 -0
  179. package/service/text-library.service.metadata.json +1 -0
  180. package/service/weather.service.d.ts +1 -0
  181. package/shared/gui-consts.d.ts +3 -0
  182. package/shared/gui-consts.js +3 -0
  183. package/shared/gui-consts.metadata.json +1 -1
  184. package/utils/data-type/fbox-data-type.service.js +40 -0
@@ -5,15 +5,20 @@ import * as nv from 'nvd3';
5
5
  import { GetHistoryDataArgs } from '../../config';
6
6
  import { HistoricalCurveTimeRange } from '../../config/history-data/historical-curve.time-range';
7
7
  import { LOCALIZATION } from '../../localization';
8
+ import { SYSTEM_TEXT_LIBRARY_TYPES, TIME_PERIOD_KEYS } from '../../service';
8
9
  import { ConditionalDisplayElement } from '../base/conditional-display-element';
9
10
  import { HistoricalCurveElementStatus } from './historical-curve-element-status';
10
11
  import { LOGGER_SERVICE_TOKEN } from '../../logger';
11
12
  import { GlobalSettings, DisplayMode } from '../../settings';
12
13
  import { CurveType } from '../../model/historical-curve/curve-type';
14
+ import { AxisRangeType } from '../../model/historical-curve/historical-curve-axis-settings';
13
15
  export class HistoricalCurveElement extends ConditionalDisplayElement {
14
- constructor(element, injector, permissionChecker, variableCommunicator, variableStore, historyDataStore, signalRAppId) {
16
+ constructor(element, injector, permissionChecker, variableCommunicator, variableStore, historyDataStore, signalRAppId, systemTextLibraryService, languageService, guiContext) {
15
17
  super(element, permissionChecker, variableCommunicator, variableStore, signalRAppId);
16
18
  this.historyDataStore = historyDataStore;
19
+ this.systemTextLibraryService = systemTextLibraryService;
20
+ this.languageService = languageService;
21
+ this.guiContext = guiContext;
17
22
  this.displayOption = {
18
23
  dataLimit: 500,
19
24
  dataZoomHeight: 32,
@@ -21,16 +26,21 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
21
26
  marginRight: 20,
22
27
  mobileMinWidth: 450,
23
28
  operationAreaHeight: 32,
24
- operationAreaMarginTop: 10,
29
+ operationAreaMarginTop: 25,
25
30
  operationSelectFontSize: '16px',
26
31
  operationButtonWidth: 24,
27
32
  operationButtonHeight: 24,
28
33
  operationButtonMargin: 4
29
34
  };
30
35
  this.elementStatus = HistoricalCurveElementStatus.Loading;
36
+ this.data = [];
37
+ this.needResize = true;
38
+ this.setNeedResize = () => {
39
+ this.needResize = false;
40
+ setTimeout(() => this.needResize = true, 500);
41
+ };
31
42
  this.logger = injector.get(LOGGER_SERVICE_TOKEN);
32
43
  this.localization = injector.get(LOCALIZATION);
33
- this.timePeriods = this.getValidTimePeriods();
34
44
  this.updateTimeRange(this.model.displaySetting.displayTimePeriod);
35
45
  this.refreshIntervalId = setInterval(() => {
36
46
  this.loadFirstPage();
@@ -38,7 +48,7 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
38
48
  }, this.model.displaySetting.refreshInterval * 1000);
39
49
  this.isMobileMode = DisplayMode.Mobile === injector.get(GlobalSettings).displayMode;
40
50
  if (this.isMobileMode) {
41
- this.displayOption.operationAreaMarginTop = 20;
51
+ this.displayOption.operationAreaMarginTop = 35;
42
52
  if (this.model.displaySetting.size.width >= this.displayOption.mobileMinWidth) {
43
53
  this.displayOption.operationAreaHeight = 68;
44
54
  this.displayOption.operationSelectFontSize = '24px';
@@ -48,23 +58,115 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
48
58
  }
49
59
  }
50
60
  this.loadFirstPage();
61
+ this.initKeyboardListener();
62
+ // 订阅语种变化事件
63
+ this.subscribeLanguageChange();
51
64
  }
52
65
  dispose() {
53
66
  clearInterval(this.refreshIntervalId);
54
67
  if (this.chartElement) {
55
68
  this.chartElement.tooltip.hidden(true);
56
69
  }
70
+ if (this.resizeEventListener) {
71
+ this.resizeEventListener.clear();
72
+ }
73
+ if (this.isAndroid) {
74
+ window.removeEventListener('native.keyboardshow', this.setNeedResize);
75
+ window.removeEventListener('native.keyboardhide', this.setNeedResize);
76
+ }
77
+ // 取消语种变化订阅
78
+ if (this.languageChangeSubscription) {
79
+ this.languageChangeSubscription.unsubscribe();
80
+ this.languageChangeSubscription = undefined;
81
+ }
57
82
  this.logger.debug(`[GUI]Dispose Histoical Curve Refresh Interval:${d3.time.format('%x %X')(new Date())}`);
58
83
  }
84
+ initKeyboardListener() {
85
+ this.isAndroid = !!navigator.userAgent.match(/(Android)/i);
86
+ if (this.isAndroid) {
87
+ window.addEventListener('native.keyboardshow', this.setNeedResize);
88
+ window.addEventListener('native.keyboardhide', this.setNeedResize);
89
+ }
90
+ }
91
+ /**
92
+ * 订阅语种变化事件
93
+ */
94
+ subscribeLanguageChange() {
95
+ if (this.guiContext && this.guiContext.languageChanged$) {
96
+ this.languageChangeSubscription = this.guiContext.languageChanged$.subscribe(() => {
97
+ // 只更新时间段选择器的文案,不重新查询数据
98
+ this.updateLanguageTexts();
99
+ });
100
+ }
101
+ }
102
+ /**
103
+ * 更新语种相关的文案(时间段选择器)
104
+ */
105
+ updateLanguageTexts() {
106
+ const selectElement = this.rootElement.select('select');
107
+ if (!selectElement.empty()) {
108
+ // 重新生成时间段数据
109
+ const updatedTimePeriods = this.getValidTimePeriods();
110
+ this.timePeriods = updatedTimePeriods;
111
+ // 更新选项文本
112
+ const options = selectElement.selectAll('option');
113
+ options.each(function (_d, i) {
114
+ if (i < updatedTimePeriods.length) {
115
+ d3.select(this).text(updatedTimePeriods[i].name);
116
+ }
117
+ });
118
+ }
119
+ }
120
+ /**
121
+ * 获取当前语种的 culture 代码
122
+ */
123
+ getCurrentCulture() {
124
+ var _a, _b, _c, _e, _f, _g;
125
+ // 获取当前语种ID
126
+ const currentLanguageId = (_c = (_b = (_a = this.guiContext) === null || _a === void 0 ? void 0 : _a.getCurrentLanguageId) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : null;
127
+ // 确定要使用的语种代码(culture)
128
+ const defaultLanguage = ((_e = this.languageService) === null || _e === void 0 ? void 0 : _e.getDefaultLanguage()) || 'zh-CN';
129
+ if (currentLanguageId === null || currentLanguageId === undefined) {
130
+ // 设备未设置当前语种,使用默认语种
131
+ return defaultLanguage;
132
+ }
133
+ else {
134
+ // 设备已设置当前语种,获取对应的语种代码
135
+ const currentLanguage = (_g = (_f = this.guiContext) === null || _f === void 0 ? void 0 : _f.getLanguageCultureById) === null || _g === void 0 ? void 0 : _g.call(_f, currentLanguageId);
136
+ if (currentLanguage) {
137
+ return currentLanguage;
138
+ }
139
+ else {
140
+ // 无法获取语种代码,使用默认语种
141
+ return defaultLanguage;
142
+ }
143
+ }
144
+ }
59
145
  getValidTimePeriods() {
60
146
  const timePeriods = new Array();
61
- timePeriods.push({ key: 1, name: this.localization.lastOneHour });
62
- timePeriods.push({ key: 2, name: this.localization.lastTwentyFourHours });
63
- timePeriods.push({ key: 3, name: this.localization.lastSevenDays });
64
- timePeriods.push({ key: 4, name: this.localization.lastThirtyDays });
65
- timePeriods.push({ key: 5, name: this.localization.lastOneYear });
147
+ timePeriods.push({ key: 6, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_THIRTY_MINUTES) });
148
+ timePeriods.push({ key: 1, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_ONE_HOUR) });
149
+ timePeriods.push({ key: 7, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_EIGHT_HOURS) });
150
+ timePeriods.push({ key: 2, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_TWENTY_FOUR_HOURS) });
151
+ timePeriods.push({ key: 3, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_SEVEN_DAYS) });
152
+ timePeriods.push({ key: 4, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_THIRTY_DAYS) });
153
+ timePeriods.push({ key: 5, name: this.getTimePeriodText(TIME_PERIOD_KEYS.LAST_ONE_YEAR) });
66
154
  return timePeriods;
67
155
  }
156
+ /**
157
+ * 获取时间段文案(从系统文本库获取多语种翻译)
158
+ */
159
+ getTimePeriodText(textKey) {
160
+ const currentCulture = this.getCurrentCulture();
161
+ const systemType = SYSTEM_TEXT_LIBRARY_TYPES.COMPONENT_BUILTIN;
162
+ if (this.systemTextLibraryService) {
163
+ const translation = this.systemTextLibraryService.getSystemTextValue(systemType, textKey, currentCulture);
164
+ if (translation) {
165
+ return translation;
166
+ }
167
+ }
168
+ return '';
169
+ }
68
170
  updateTimeRange(timePeriodType) {
69
171
  this.currentTimePeriod = +timePeriodType;
70
172
  this.updateQueryTimeRange();
@@ -84,66 +186,281 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
84
186
  case 5:
85
187
  this.startTime = moment().subtract(1, 'years');
86
188
  break;
189
+ case 6:
190
+ this.startTime = moment().subtract(30, 'minutes');
191
+ break;
192
+ case 7:
193
+ this.startTime = moment().subtract(8, 'hours');
194
+ break;
87
195
  default:
88
196
  this.startTime = moment().subtract(1, 'days');
89
197
  }
90
198
  }
91
199
  reRenderElement(startTime, endTime, limit, rangeType) {
200
+ // 清理图表实例
201
+ if (this.chartElement) {
202
+ // 隐藏 tooltip
203
+ if (this.chartElement.tooltip) {
204
+ this.chartElement.tooltip.hidden(true);
205
+ }
206
+ // 清理图表引用
207
+ this.chartElement = null;
208
+ }
209
+ // 清除 DOM 元素
92
210
  this.rootElement.selectAll('*').remove();
93
- this.chartElement = null;
211
+ // 重新渲染
94
212
  this.renderElement(startTime, endTime, limit, rangeType);
95
213
  }
96
214
  renderElement(startTime, endTime, limit, rangeType) {
97
215
  if (!this.model.dataSetting) {
98
216
  return;
99
217
  }
100
- const dataItemName = this.model.dataSetting.dataName;
101
218
  const dataSourceCode = this.model.dataSetting.dataSourceCode;
102
- const channelNames = this.model.dataSetting.channels.map(c => c.name);
103
219
  this.updateElementStatus(HistoricalCurveElementStatus.Loading);
104
- const input = new GetHistoryDataArgs(dataSourceCode, dataItemName, channelNames, startTime, endTime, limit, rangeType);
105
- this.historyDataStore.getHistoryData(input).subscribe(result => {
106
- if (result.error) {
107
- this.updateElementStatus(HistoricalCurveElementStatus.LoadFailed, result.error);
220
+ // 【新格式】如果有多条目配置,使用多条目查询
221
+ if (this.model.dataSetting.dataItems && this.model.dataSetting.dataItems.length > 0) {
222
+ const historyDataItems = this.model.dataSetting.dataItems.map(item => ({
223
+ dataItemName: item.dataName,
224
+ channelNames: item.channels.map(c => c.name)
225
+ }));
226
+ // 使用第一个条目的信息作为兼容参数
227
+ const firstItem = this.model.dataSetting.dataItems[0];
228
+ const input = new GetHistoryDataArgs(dataSourceCode, firstItem.dataName, firstItem.channels.map(c => c.name), startTime, endTime, limit, rangeType, historyDataItems // 传递多条目参数
229
+ );
230
+ this.historyDataStore.getHistoryData(input).subscribe(result => {
231
+ this.handleQueryResult(result);
232
+ });
233
+ }
234
+ // 【旧格式】单条目模式
235
+ else {
236
+ const dataItemName = this.model.dataSetting.dataName;
237
+ const channelNames = this.model.dataSetting.channels.map(c => c.name);
238
+ const input = new GetHistoryDataArgs(dataSourceCode, dataItemName, channelNames, startTime, endTime, limit, rangeType);
239
+ this.historyDataStore.getHistoryData(input).subscribe(result => {
240
+ this.handleQueryResult(result);
241
+ });
242
+ }
243
+ }
244
+ handleQueryResult(result) {
245
+ this.timePeriods = this.getValidTimePeriods();
246
+ // 【新格式】多条目模式下的错误处理
247
+ if (result.historyDataItems && result.historyDataItems.length > 0) {
248
+ // 只要有条目正常返回(即使没有数据),就走正常逻辑
249
+ // 这样可以确保即使部分条目失败,只要有条目成功返回,就显示正常状态
250
+ this.clearStatus();
251
+ if (result.isUnbind) {
252
+ this.updateElementStatus(HistoricalCurveElementStatus.Unbound);
108
253
  }
109
254
  else {
110
- this.clearStatus();
111
- if (result.isUnbind) {
112
- this.updateElementStatus(HistoricalCurveElementStatus.Unbound);
113
- }
114
- else {
115
- this.updateElementStatus(HistoricalCurveElementStatus.Normal);
116
- }
117
- if (result.values.length) {
118
- this.currentStartTime = moment(first(result.values).time);
119
- this.currentEndTime = moment(last(result.values).time);
255
+ this.updateElementStatus(HistoricalCurveElementStatus.Normal);
256
+ }
257
+ // 如果有错误信息,在控制台输出警告
258
+ if (result.error) {
259
+ this.logger.warn(`[历史曲线] 部分条目查询失败: ${result.error}`);
260
+ }
261
+ // 检查是否有任何条目有数据
262
+ const hasAnyData = result.historyDataItems.some(item => item.rows && item.rows.length > 0);
263
+ if (hasAnyData) {
264
+ // 有数据,计算所有条目的最小和最大时间,确保时间轴覆盖所有数据
265
+ let globalMinTime = null;
266
+ let globalMaxTime = null;
267
+ result.historyDataItems.forEach(item => {
268
+ if (item.rows && item.rows.length > 0) {
269
+ const itemMinTime = moment(first(item.rows).time);
270
+ const itemMaxTime = moment(last(item.rows).time);
271
+ if (!globalMinTime || itemMinTime.isBefore(globalMinTime)) {
272
+ globalMinTime = itemMinTime;
273
+ }
274
+ if (!globalMaxTime || itemMaxTime.isAfter(globalMaxTime)) {
275
+ globalMaxTime = itemMaxTime;
276
+ }
277
+ }
278
+ });
279
+ // 设置全局时间范围
280
+ if (globalMinTime && globalMaxTime) {
281
+ this.currentStartTime = globalMinTime;
282
+ this.currentEndTime = globalMaxTime;
120
283
  }
121
- this.chartElement = this.renderChart(result.values);
122
284
  }
285
+ // 无论是否有数据,都渲染曲线(没有数据会显示空曲线)
286
+ this.chartElement = this.renderChartWithMultiItems(result.historyDataItems);
287
+ }
288
+ // 【旧格式】单条目模式的错误处理
289
+ else if (result.error) {
290
+ this.updateElementStatus(HistoricalCurveElementStatus.LoadFailed, result.error);
291
+ }
292
+ else {
293
+ this.clearStatus();
294
+ if (result.isUnbind) {
295
+ this.updateElementStatus(HistoricalCurveElementStatus.Unbound);
296
+ }
297
+ else {
298
+ this.updateElementStatus(HistoricalCurveElementStatus.Normal);
299
+ }
300
+ // 【旧格式】单条目数据,使用原有渲染方式
301
+ if (result.values.length) {
302
+ this.currentStartTime = moment(first(result.values).time);
303
+ this.currentEndTime = moment(last(result.values).time);
304
+ }
305
+ this.chartElement = this.renderChart(result.values);
306
+ }
307
+ }
308
+ setupTooltipAutoHide(chart) {
309
+ const chartContainer = this.rootElement.select('.nv-focus').node();
310
+ if (!chartContainer || !chart)
311
+ return;
312
+ let timeoutId;
313
+ // 鼠标移入图表时显示 tooltip
314
+ chartContainer.addEventListener('mouseover', () => {
315
+ hideTooltipAfterDelay();
123
316
  });
317
+ const clearTooltipTimeout = () => {
318
+ if (timeoutId) {
319
+ clearTimeout(timeoutId);
320
+ timeoutId = null;
321
+ }
322
+ };
323
+ const hideTooltipAfterDelay = () => {
324
+ clearTooltipTimeout();
325
+ timeoutId = setTimeout(() => {
326
+ chart.tooltip.hidden(true);
327
+ }, 2000); // 2秒延迟
328
+ };
124
329
  }
125
330
  renderChart(result) {
126
331
  const chartWidth = this.model.displaySetting.size.width;
127
332
  const chartHeight = this.model.displaySetting.size.height - this.displayOption.operationAreaHeight - this.displayOption.operationAreaMarginTop;
128
333
  const data = new Array();
334
+ // 【旧格式】单条目模式:只显示通道名
129
335
  each(this.model.dataSetting.channels, (channel, key) => {
130
336
  const values = new Array();
131
337
  each(result, v => values.push({ x: moment(v.time).local().toDate().valueOf(), y: v.values[key] }));
132
- data.push({ key: channel.name, area: channel.projectEnabled, values: values });
338
+ const displayName = channel.name;
339
+ data.push({ key: displayName, area: channel.projectEnabled, values: values });
133
340
  });
134
- nv.addGraph(() => {
135
- if (this.model.displaySetting.curveType === CurveType.BarGroup || this.model.displaySetting.curveType === CurveType.BarStack) {
136
- return this.getMultiBarWithFocusChart(chartWidth, chartHeight, data);
341
+ this.data = data;
342
+ let chart;
343
+ if (this.model.displaySetting.curveType === CurveType.BarGroup || this.model.displaySetting.curveType === CurveType.BarStack) {
344
+ chart = this.getMultiBarWithFocusChart(chartWidth, chartHeight, data);
345
+ }
346
+ else {
347
+ chart = this.getLineChart(chartWidth, chartHeight, data);
348
+ }
349
+ // 设置 tooltip 自动隐藏逻辑
350
+ this.setupTooltipAutoHide(chart);
351
+ return chart;
352
+ }
353
+ /**
354
+ * 【新格式】多条目独立数据的曲线渲染
355
+ * 每个条目独立保持自己的时间戳,不会出现时间戳混乱的问题
356
+ */
357
+ renderChartWithMultiItems(historyDataItems) {
358
+ const chartWidth = this.model.displaySetting.size.width;
359
+ const chartHeight = this.model.displaySetting.size.height - this.displayOption.operationAreaHeight - this.displayOption.operationAreaMarginTop;
360
+ const data = new Array();
361
+ // 创建一个 Map 用于快速查找条目数据
362
+ const itemDataMap = new Map();
363
+ each(historyDataItems, item => {
364
+ if (item && item.itemName) {
365
+ itemDataMap.set(item.itemName, item.rows || []);
366
+ }
367
+ });
368
+ // 判断是否只有一个条目
369
+ const isSingleItem = this.model.dataSetting.dataItems && this.model.dataSetting.dataItems.length === 1;
370
+ // 为每个条目的每个通道创建独立的曲线
371
+ each(this.model.dataSetting.dataItems, (dataItem) => {
372
+ const itemName = dataItem.dataName;
373
+ // 通过 itemName 匹配数据,而不是通过索引
374
+ const itemRows = itemDataMap.get(itemName) || [];
375
+ each(dataItem.channels, (channel, channelIdx) => {
376
+ const values = new Array();
377
+ // 每个条目使用自己的时间戳和数据
378
+ each(itemRows, row => {
379
+ const value = row.values && row.values[channelIdx] !== undefined ? row.values[channelIdx] : null;
380
+ values.push({ x: moment(row.time).local().toDate().valueOf(), y: value });
381
+ });
382
+ // 只有多个条目时才使用"条目名-通道名"格式,单条目时只显示通道名
383
+ const displayName = isSingleItem ? channel.name : `${itemName}-${channel.name}`;
384
+ data.push({ key: displayName, area: channel.projectEnabled, values: values });
385
+ });
386
+ });
387
+ this.data = data;
388
+ let chart;
389
+ if (this.model.displaySetting.curveType === CurveType.BarGroup || this.model.displaySetting.curveType === CurveType.BarStack) {
390
+ chart = this.getMultiBarWithFocusChart(chartWidth, chartHeight, data);
391
+ }
392
+ else {
393
+ chart = this.getLineChart(chartWidth, chartHeight, data);
394
+ }
395
+ // 设置 tooltip 自动隐藏逻辑
396
+ this.setupTooltipAutoHide(chart);
397
+ return chart;
398
+ }
399
+ initPoint() {
400
+ try {
401
+ const legendList = this.$element
402
+ .find('.nv-legend')
403
+ .find('.nv-series');
404
+ let hiddenCount = 0;
405
+ // 获取所有通道(支持多条目和单条目模式)
406
+ const allChannels = [];
407
+ if (this.model.dataSetting.dataItems && this.model.dataSetting.dataItems.length > 0) {
408
+ // 【新格式】多条目模式:收集所有条目的所有通道
409
+ each(this.model.dataSetting.dataItems, dataItem => {
410
+ each(dataItem.channels, channel => {
411
+ allChannels.push(channel);
412
+ });
413
+ });
137
414
  }
138
415
  else {
139
- return this.getLineChart(chartWidth, chartHeight, data);
416
+ // 【旧格式】单条目模式
417
+ allChannels.push(...this.model.dataSetting.channels);
140
418
  }
141
- });
419
+ for (let i = 0; i < this.data.length; i++) {
420
+ const channel = allChannels[i];
421
+ if (legendList.eq(i).children().eq(0).css('fill-opacity') === '1') {
422
+ const pointList = this.$element
423
+ .find('.nv-scatterWrap')
424
+ .find('.nv-series-' + (i - hiddenCount))
425
+ .find('.nv-point');
426
+ if (pointList && pointList.length) {
427
+ for (let j = 0; j < pointList.length; j++) {
428
+ const point = pointList.eq(j);
429
+ const previousPoint = pointList.eq(j - 1);
430
+ if (j && point.attr('transform').split(',')[1] !== previousPoint.attr('transform').split(',')[1]) {
431
+ if (channel.enablePoint && channel.pointColor) {
432
+ const pointStyle = {
433
+ 'stroke-opacity': 1,
434
+ 'stroke-width': '2px',
435
+ 'stroke': channel.pointColor,
436
+ 'fill-opacity': 1,
437
+ 'fill': channel.pointColor
438
+ };
439
+ point.addClass('nv-mark-point');
440
+ point.css(pointStyle);
441
+ previousPoint.addClass('nv-mark-point');
442
+ previousPoint.css(pointStyle);
443
+ }
444
+ }
445
+ }
446
+ }
447
+ }
448
+ else {
449
+ hiddenCount++;
450
+ }
451
+ }
452
+ }
453
+ catch (e) {
454
+ console.log(e);
455
+ }
142
456
  }
143
457
  getLineChart(chartWidth, chartHeight, data) {
144
458
  const chart = nv.models.lineChart().showLegend(true)
145
459
  .margin({ top: 0, bottom: 0, left: this.displayOption.marginLeft, right: this.displayOption.marginRight })
146
460
  .noData(this.localization.chartNoData);
461
+ if (this.model.displaySetting.axisSetting.yAxisRangeType === AxisRangeType.Custom) {
462
+ chart.yDomain([this.model.displaySetting.axisSetting.yAxisMin, this.model.displaySetting.axisSetting.yAxisMax]);
463
+ }
147
464
  if (!this.isMobileMode) {
148
465
  chart.focusEnable(true);
149
466
  chart.focus.margin({ top: 10, right: 0, bottom: 0, left: 0 });
@@ -152,6 +469,19 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
152
469
  }
153
470
  this.renderCommonProperty(chart, chartWidth, chartHeight, data);
154
471
  this.renderOperationArea(chartWidth, chartHeight);
472
+ this.initPoint();
473
+ chart.legend.dispatch.on('legendClick', () => {
474
+ setTimeout(() => {
475
+ this.$element.find('.nv-mark-point').css({
476
+ 'stroke-opacity': 0,
477
+ 'stroke-width': 0,
478
+ 'stroke': 'unset',
479
+ 'fill-opacity': 0,
480
+ 'fill': 'unset'
481
+ }).removeClass('nv-mark-point');
482
+ this.initPoint();
483
+ }, 1);
484
+ });
155
485
  return chart;
156
486
  }
157
487
  getMultiBarWithFocusChart(chartWidth, chartHeight, data) {
@@ -168,6 +498,9 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
168
498
  chart.multibar.stacked(true);
169
499
  chart.multibar2.stacked(true);
170
500
  }
501
+ if (this.model.displaySetting.axisSetting.yAxisRangeType === AxisRangeType.Custom) {
502
+ chart.yDomain([this.model.displaySetting.axisSetting.yAxisMin, this.model.displaySetting.axisSetting.yAxisMax]);
503
+ }
171
504
  if (!this.isMobileMode) {
172
505
  chart.focusEnable(true);
173
506
  chart.focusShowAxisX(false);
@@ -188,9 +521,27 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
188
521
  return chart;
189
522
  }
190
523
  renderCommonProperty(chart, chartWidth, chartHeight, data) {
524
+ var _a, _b;
191
525
  chart.tooltip.headerFormatter(d => this.timeFormat(d, '%x %X'));
192
526
  if (this.model.displaySetting.showAxis) {
193
- chart.xAxis.showMaxMin(true).tickFormat(d => this.timeFormat(d, '%X'));
527
+ chart.xAxis.showMaxMin(true).tickFormat(d => {
528
+ this.$element.find('.nv-mark-point').css({
529
+ 'stroke-opacity': 0,
530
+ 'stroke-width': 0,
531
+ 'stroke': 'unset',
532
+ 'fill-opacity': 0,
533
+ 'fill': 'unset'
534
+ }).removeClass('nv-mark-point');
535
+ clearTimeout(this.timer);
536
+ this.timer = undefined;
537
+ this.timer = setTimeout(() => {
538
+ this.initPoint();
539
+ }, 100);
540
+ if (this.currentTimePeriod === 3 || this.currentTimePeriod === 4 || this.currentTimePeriod === 5) {
541
+ return this.timeFormat(d, '%y-%m-%d');
542
+ }
543
+ return this.timeFormat(Number(d), '%X');
544
+ });
194
545
  if (this.model.displaySetting.axisSetting) {
195
546
  if (this.model.displaySetting.axisSetting.showAxisLabel && this.model.displaySetting.axisSetting.axisLabelFont) {
196
547
  chart.xAxis.fontSize(this.model.displaySetting.axisSetting.axisLabelFont.fontSize);
@@ -208,50 +559,165 @@ export class HistoricalCurveElement extends ConditionalDisplayElement {
208
559
  }
209
560
  chart.width(chartWidth);
210
561
  chart.height(chartHeight);
211
- chart.color(this.model.dataSetting.channels.map(c => c.connectorColor));
562
+ // 获取所有通道的颜色(支持多条目和单条目模式)
563
+ let channelColors = [];
564
+ if (this.model.dataSetting.dataItems && this.model.dataSetting.dataItems.length > 0) {
565
+ // 【新格式】多条目模式:收集所有条目的所有通道颜色
566
+ each(this.model.dataSetting.dataItems, dataItem => {
567
+ each(dataItem.channels, channel => {
568
+ channelColors.push(channel.connectorColor);
569
+ });
570
+ });
571
+ }
572
+ else {
573
+ // 【旧格式】单条目模式
574
+ channelColors = this.model.dataSetting.channels.map(c => c.connectorColor);
575
+ }
576
+ chart.color(channelColors);
212
577
  this.rootElement.append('g').datum(data).call(chart);
213
578
  this.rootElement.selectAll('.nv-noData').attr('x', chartWidth / 2).attr('y', chartHeight / 2 + this.displayOption.operationAreaHeight);
214
- nv.utils.windowResize(() => {
579
+ this.resizeEventListener = nv.utils.windowResize(() => {
580
+ if (!this.needResize)
581
+ return;
215
582
  chart.update();
216
583
  this.rootElement.selectAll('.nv-noData').attr('x', chartWidth / 2).attr('y', chartHeight / 2 + this.displayOption.operationAreaHeight);
217
584
  });
585
+ const fontSize = (_b = (_a = this.model.displaySetting.axisSetting) === null || _a === void 0 ? void 0 : _a.axisLabelFont) === null || _b === void 0 ? void 0 : _b.fontSize;
218
586
  this.rootElement.selectAll('.domain').style('stroke-opacity', 1);
219
587
  if (this.model.displaySetting.showAxis && this.model.displaySetting.axisSetting) {
220
588
  const axisColor = this.model.displaySetting.axisSetting.axisColor;
221
589
  this.rootElement.selectAll('.domain').style('stroke', axisColor);
222
- if (this.model.displaySetting.axisSetting.showAxisLabel) {
223
- const fontSize = this.model.displaySetting.axisSetting.axisLabelFont.fontSize;
590
+ if (fontSize && this.model.displaySetting.axisSetting.showAxisLabel) {
224
591
  this.rootElement.selectAll('.nv-axisMaxMin').select('text').style('font-size', fontSize);
225
592
  }
226
593
  }
594
+ let strokeWidth = 0;
595
+ if (this.model.displaySetting.axisSetting.showTick !== false) {
596
+ strokeWidth = 1;
597
+ }
598
+ this.rootElement
599
+ .selectAll('.nv-x')
600
+ .selectAll('.tick')
601
+ .selectAll('line')
602
+ .attr('style', `stroke:${this.model.displaySetting.axisSetting.xAxisTickColor || 'rgb(127, 147, 159)'};stroke-width:${strokeWidth};`);
603
+ this.rootElement
604
+ .selectAll('.nv-y')
605
+ .selectAll('.tick')
606
+ .selectAll('line')
607
+ .attr('style', `stroke:${this.model.displaySetting.axisSetting.yAxisTickColor || 'rgb(127, 147, 159)'};stroke-width:${strokeWidth};`);
608
+ if (fontSize && this.currentTimePeriod === 3 || this.currentTimePeriod === 4 || this.currentTimePeriod === 5) {
609
+ const self = this;
610
+ this.rootElement
611
+ .selectAll('.nv-x')
612
+ .selectAll('.tick')
613
+ .selectAll('text')
614
+ .data(function (d) {
615
+ return [self.timeFormat(Number(d), '%y-%m-%d'), self.timeFormat(Number(d), '%H:%M:%S')];
616
+ })
617
+ .enter()
618
+ .append('text')
619
+ .attr('class', 'full-date')
620
+ .attr('x', 0)
621
+ .attr('y', 0)
622
+ .attr('dy', '2.3em')
623
+ .style('text-anchor', 'middle')
624
+ .style('font-size', fontSize)
625
+ .text((d) => d);
626
+ this.rootElement
627
+ .selectAll('.nv-axisMaxMin-x')
628
+ .selectAll('text')
629
+ .data(function (d) {
630
+ return [self.timeFormat(Number(d), '%y-%m-%d'), self.timeFormat(Number(d), '%H:%M:%S')];
631
+ })
632
+ .enter()
633
+ .append('text')
634
+ .attr('class', 'full-date')
635
+ .attr('x', 0)
636
+ .attr('y', 0)
637
+ .attr('dy', '2.3em')
638
+ .style('text-anchor', 'middle')
639
+ .style('font-size', fontSize)
640
+ .text((d) => d);
641
+ const focusWrap = this.rootElement.selectAll('.nv-focusWrap');
642
+ if (focusWrap.size()) {
643
+ let h = focusWrap.attr('transform');
644
+ if (h && h.length && h.indexOf(',') !== -1) {
645
+ h = h.slice(0, -1).split(',')[1];
646
+ this.rootElement
647
+ .selectAll('.nv-focusWrap')
648
+ .attr('transform', `translate(0,${Number(h) + 15})`);
649
+ }
650
+ }
651
+ const resizeObserver = new window.MutationObserver(() => {
652
+ this.rootElement
653
+ .selectAll('.nv-x')
654
+ .selectAll('.tick')
655
+ .selectAll('.full-date')
656
+ .remove();
657
+ this.rootElement
658
+ .selectAll('.nv-x')
659
+ .selectAll('.tick')
660
+ .selectAll('text')
661
+ .data(function (d) {
662
+ return [self.timeFormat(Number(d), '%y-%m-%d'), self.timeFormat(Number(d), '%H:%M:%S')];
663
+ })
664
+ .enter()
665
+ .append('text')
666
+ .attr('class', 'full-date')
667
+ .attr('x', 0)
668
+ .attr('y', 0)
669
+ .attr('dy', '2.3em')
670
+ .style('text-anchor', 'middle')
671
+ .style('font-size', fontSize)
672
+ .text((d) => d);
673
+ });
674
+ const extent = document.getElementsByClassName('extent');
675
+ if (extent.length) {
676
+ resizeObserver.observe(extent[0], { attributes: true });
677
+ }
678
+ }
679
+ else {
680
+ this.rootElement
681
+ .selectAll('.full-date')
682
+ .remove();
683
+ }
227
684
  }
228
685
  renderOperationArea(chartWidth, chartHeight) {
686
+ const backgroundColor = this.model.displaySetting.axisSetting.filterBackgroudColor || 'inherit';
229
687
  const operationArea = this.rootElement.append('g').attr('transform', `translate(0,${chartHeight + this.displayOption.operationAreaMarginTop})`)
230
688
  .append('foreignObject').attr('width', chartWidth).attr('height', this.displayOption.operationAreaHeight).attr('fill', 'none')
231
689
  .append('xhtml:div').style('height', (this.displayOption.operationAreaHeight - 4) + 'px').style('overflow', 'hidden').style('margin-top', '4px');
232
690
  const selectElement = operationArea.append('select').style('margin-left', this.displayOption.marginLeft + 'px')
691
+ .style('background-color', backgroundColor)
233
692
  .style('font-size', this.displayOption.operationSelectFontSize).on('change', () => {
234
693
  const displayTimePeriod = this.rootElement.select('select').property('value');
235
694
  this.updateTimeRange(displayTimePeriod);
236
695
  this.reRenderElement(this.startTime, this.endTime, this.displayOption.dataLimit, HistoricalCurveTimeRange.BeginOpenEndOpen);
237
696
  });
697
+ const rect = this.$element.parent().parent().find('rect');
698
+ const fillColor = rect.attr('fill');
238
699
  const options = selectElement.selectAll('option').data(this.timePeriods).enter().append('option');
239
- options.text(d => d.name).attr('value', d => d.key).property('selected', d => d.key === Number(this.currentTimePeriod));
700
+ options.text(d => d.name).attr('value', d => d.key).property('selected', d => d.key === Number(this.currentTimePeriod))
701
+ .style('background-color', this.model.displaySetting.axisSetting.filterBackgroudColor || fillColor);
240
702
  const buttonWidth = this.displayOption.operationButtonWidth + 'px', buttonHeight = this.displayOption.operationButtonHeight + 'px';
241
703
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
242
- .style('float', 'right').style('background', 'white').style('background-image', 'url(assets/img/last_page.svg)')
704
+ .style('float', 'right').style('background-image', 'url(assets/img/black_last_page.png)')
705
+ .style('background-color', backgroundColor).style('background-size', 'cover')
243
706
  .on('click', () => { this.loadLastPage(); });
244
707
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
245
- .style('float', 'right').style('background', 'white').style('background-image', 'url(assets/img/next_page.svg)')
708
+ .style('float', 'right').style('background-image', 'url(assets/img/black_next_page.png)')
246
709
  .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
710
+ .style('background-color', backgroundColor).style('background-size', 'cover')
247
711
  .on('click', () => { this.loadNextPage(); });
248
712
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
249
- .style('float', 'right').style('background', 'white').style('background-image', 'url(assets/img/previous_page.svg)')
713
+ .style('float', 'right').style('background-image', 'url(assets/img/black_previous_page.png)')
250
714
  .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
715
+ .style('background-color', backgroundColor).style('background-size', 'cover')
251
716
  .on('click', () => { this.loadPreviousPage(); });
252
717
  operationArea.append('button').style('width', buttonWidth).style('height', buttonHeight).style('border', 'none')
253
- .style('float', 'right').style('background', 'white').style('background-image', 'url(assets/img/first_page.svg)')
718
+ .style('float', 'right').style('background-image', 'url(assets/img/black_first_page.png)')
254
719
  .style('margin', `0 ${this.displayOption.operationButtonMargin}px 0 0`)
720
+ .style('background-color', backgroundColor).style('background-size', 'cover')
255
721
  .on('click', () => { this.loadFirstPage(); });
256
722
  }
257
723
  timeFormat(datetime, specifier) {