hydro-graph 1.0.0

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.
@@ -0,0 +1,2586 @@
1
+ <template>
2
+ <!-- <el-card class="content-card" :style="{ background: backgroundColor }"> -->
3
+ <div class="box" ref="chartBox" @contextmenu="handleContextMenu($event)" v-resize="onResize">
4
+ <div class="title" v-show="chartOption.title" v-resize="onResize">{{ chartOption.title }}</div>
5
+ <div class="subTitle" v-show="chartOption.subTitle" v-resize="onResize">{{ chartOption.subTitle }}</div>
6
+ <!-- 图例 -->
7
+ <div class="legend-box" ref="myLegend" v-resize="onResize">
8
+ <el-checkbox v-model="isSelectedAll" label="全选" @change="onAllChange" :style="{ '--fill-color': '#409EFF' }"
9
+ v-if="legendArr.length > 1 ? true : false" />
10
+ <template v-for="(item, index) in legendArr" :key="index">
11
+ <el-checkbox v-model="item.isSelected" @change="(checked) => onChange(checked, item.name)"
12
+ :style="{ '--fill-color': item.color ? item.color : '#409EFF' }" v-if="!item.children">
13
+ <svg-icon :icon-class="item.icon" :style="{
14
+ width: item.iconWidth ? item.iconWidth + 'px' : '20px',
15
+ height: item.iconHeight ? item.iconHeight + 'px' : '20px',
16
+ }" :color="item.color" v-if="item.icon" />
17
+ <span :style="{ color: item.color, marginLeft: '3px' }">{{
18
+ item.key ? item.key : item.name
19
+ }}</span>
20
+ <el-icon class="el-icon--right" v-if="item.children && item.children.length > 0">
21
+ <ArrowDown />
22
+ </el-icon>
23
+ </el-checkbox>
24
+ <el-dropdown :hide-on-click="false" v-if="item.children && item.children.length > 0">
25
+ <el-checkbox v-model="item.isSelected" @change="(checked) => onChange(checked, item.name)"
26
+ :style="{ '--fill-color': item.color ? item.color : '#409EFF' }">
27
+ <svg-icon :icon-class="item.icon" :style="{
28
+ width: item.iconWidth ? item.iconWidth + 'px' : '20px',
29
+ height: item.iconHeight ? item.iconHeight + 'px' : '20px',
30
+ }" :color="item.color" v-if="item.icon" />
31
+ <span :style="{ color: item.color, marginLeft: '3px' }">
32
+ {{ item.key ? item.key : item.name }}
33
+ </span>
34
+ <el-icon class="el-icon--right" v-if="item.children && item.children.length > 0">
35
+ <ArrowDown />
36
+ </el-icon>
37
+ </el-checkbox>
38
+ <template #dropdown>
39
+ <el-dropdown-menu>
40
+ <el-dropdown-item v-for="(it, inx) in item.children" :key="inx">
41
+ <el-checkbox v-model="it.isSelected" @change="(checked) => onChange(checked, it.name)"
42
+ :style="{ '--fill-color': it.color ? it.color : '#409EFF' }">
43
+ <div style="width: 20px; display: flex; justify-content: center">
44
+ <svg-icon :icon-class="it.icon" :style="{
45
+ width: it.iconWidth ? it.iconWidth + 'px' : '20px',
46
+ height: it.iconHeight ? it.iconHeight + 'px' : '20px',
47
+ }" :color="it.color" v-if="it.icon" />
48
+ </div>
49
+ <span :style="{ color: it.color, marginLeft: '3px' }">{{ it.key ? it.key : it.name }}</span>
50
+ </el-checkbox>
51
+ </el-dropdown-item>
52
+ </el-dropdown-menu>
53
+ </template>
54
+ </el-dropdown>
55
+ </template>
56
+ </div>
57
+ <!-- 图表 -->
58
+ <div class="mychart">
59
+ <div :id="id" :style="{ width: width, height: height }"></div>
60
+ </div>
61
+ </div>
62
+ <!-- </el-card> -->
63
+ </template>
64
+
65
+ <script setup name="HydroGraph">
66
+ // 按需引入 echarts
67
+ import * as echarts from 'echarts/core';
68
+ import { LineChart, BarChart } from 'echarts/charts';
69
+ import {
70
+ TooltipComponent,
71
+ GridComponent,
72
+ LegendComponent,
73
+ DataZoomComponent
74
+ } from 'echarts/components';
75
+ import { LabelLayout } from 'echarts/features';
76
+ import { CanvasRenderer } from 'echarts/renderers';
77
+
78
+ // 注册必要的组件
79
+ echarts.use([
80
+ TooltipComponent,
81
+ GridComponent,
82
+ LegendComponent,
83
+ DataZoomComponent,
84
+ LineChart,
85
+ BarChart,
86
+ LabelLayout,
87
+ CanvasRenderer
88
+ ]);
89
+ import {
90
+ getTimeRange,
91
+ formatToFlowValue,
92
+ getInterval,
93
+ getMultipleTimeRange,
94
+ isTimeFormat,
95
+ getColors,
96
+ generateGUID
97
+ } from "./utils/ruoyi";
98
+ import { GetCotwlTransformation } from "./api/index";
99
+ import dayjs from "dayjs";
100
+ import { nextTick, onMounted, ref, watch } from "vue";
101
+ import html2canvas from "html2canvas";
102
+ import { ElMessage } from "element-plus";
103
+ import { ArrowDown } from "@element-plus/icons-vue";
104
+ import restorePng from "./assets/images/restore.png";
105
+ import copyPng from "./assets/images/copy.png";
106
+ import exportPng from "./assets/images/exportPng.png";
107
+ const chartBox = ref();
108
+ const props = defineProps({
109
+ id: {
110
+ type: String,
111
+ default() {
112
+ return generateGUID();
113
+ },
114
+ },
115
+ chartOption: {
116
+ type: Object,
117
+ default() {
118
+ return {};
119
+ },
120
+ },
121
+ legendList: {
122
+ type: Array,
123
+ default() {
124
+ return [];
125
+ },
126
+ },
127
+ width: {
128
+ type: String,
129
+ default() {
130
+ return "100%";
131
+ },
132
+ },
133
+ height: {
134
+ type: String,
135
+ default() {
136
+ return "100%";
137
+ },
138
+ },
139
+ backgroundColor: {
140
+ type: String,
141
+ default() {
142
+ return "#fff";
143
+ },
144
+ },
145
+ });
146
+
147
+ if (!props.chartOption.series) {
148
+ props.chartOption.series = [];
149
+ }
150
+ let legendAllColor = {};
151
+ const emit = defineEmits();
152
+ let dataZoom = {};
153
+ watch(
154
+ () => props.chartOption,
155
+ () => {
156
+ nextTick(() => {
157
+ let time = setInterval(() => {
158
+ if (
159
+ document.getElementById(props.id) &&
160
+ document.getElementById(props.id).offsetHeight > 100 &&
161
+ document.getElementById(props.id).offsetWidth > 100
162
+ ) {
163
+ if (
164
+ myChart &&
165
+ myChart.getOption() &&
166
+ !props.chartOption.restoreZoom
167
+ ) {
168
+ dataZoom = {
169
+ ...myChart.getOption().dataZoom[0],
170
+ moveOnMouseMove: props.chartOption.series.some(
171
+ (item) => item.openBarDrag && (item.type == "line" || item.type == "markLine")
172
+ )
173
+ ? "ctrl"
174
+ : true,
175
+ };
176
+ }
177
+ setChart();
178
+ clearInterval(time);
179
+ }
180
+ }, 100);
181
+ });
182
+ },
183
+ { deep: true, immediate: true }
184
+ );
185
+ let lastSelected = {} //每次图例改变,把图例的选中状态存起来
186
+ watch(
187
+ () => props.legendList,
188
+ () => {
189
+ if (myChart) {
190
+ lastSelected = myChart.getOption().legend[0].selected
191
+ }
192
+ let arr = props.legendList.map((item) => {
193
+ let obj = legendKeys.find((it) => it.code == item.name);
194
+ if (obj) {
195
+ return {
196
+ ...item,
197
+ ...obj,
198
+ };
199
+ } else {
200
+ return {
201
+ ...item,
202
+ };
203
+ }
204
+ });
205
+ let arr2 = JSON.parse(JSON.stringify(legendArr.value));
206
+ legendAllColor = {};
207
+ legendArr.value = arr.map((item) => {
208
+ const obj2 = arr2.find((it) => it.name == item.name);
209
+ legendAllColor[item.name] = item;
210
+ if (item.children) {
211
+ item.children = item.children.map((it) => {
212
+ legendAllColor[it.name] = it;
213
+ let isSelected2 = '';
214
+ if (props.chartOption.isDefaultElement === false) {
215
+ isSelected2 = lastSelected[it.name] != undefined ? lastSelected[it.name] : it.isSelected
216
+ } else {
217
+ if (obj2 && obj2.children && obj2.children.find((i) => i.name == it.name)) {
218
+ isSelected2 = obj2.children.find((i) => i.name == it.name).isSelected;
219
+ } else {
220
+ isSelected2 = it.isSelected
221
+ }
222
+ }
223
+ return {
224
+ ...it,
225
+ isSelected: isSelected2,
226
+ id: Math.random(),
227
+ };
228
+ });
229
+ }
230
+ let isSelected1 = '';
231
+ if (props.chartOption.isDefaultElement === false) {
232
+ isSelected1 = lastSelected[item.name] != undefined ? lastSelected[item.name] : item.isSelected
233
+ } else {
234
+ if (item.compel) {
235
+ isSelected1 = item.isSelected
236
+ } else if (obj2) {
237
+ isSelected1 = obj2.isSelected
238
+ } else {
239
+ isSelected1 = item.isSelected
240
+ }
241
+ }
242
+ return {
243
+ ...item,
244
+ isSelected: isSelected1,
245
+ id: Math.random(),
246
+ };
247
+ });
248
+ },
249
+ { deep: true }
250
+ );
251
+ //实测水位,库容,雨量图例属性配置
252
+ const keys = [
253
+ { name: "实况雨量", type: "bar", color: "#0000ff", unit: "mm" },
254
+ { name: "实测水位", type: "line", color: "#304755", unit: "m" },
255
+ { name: "库容", type: "line", color: "#197e2b", unit: "万m³" },
256
+ { name: "5分钟水位", type: "line", color: "#304755", unit: "m" },
257
+ { name: "5分钟库容", type: "line", color: "#197e2b", unit: "万m³" },
258
+ { name: "校核洪水位", type: "markLine", color: "#ffa500", unit: "m" },
259
+ { name: "设计洪水位", type: "markLine", color: "#a52a2a", unit: "m" },
260
+ { name: "正常高水位", type: "markLine", color: "#008000", unit: "m" },
261
+ { name: "死水位", type: "markLine", color: "#000000", unit: "m" },
262
+ { name: "坝顶高程", type: "markLine", color: "#cf0ce1", unit: "m" },
263
+ { name: "梅汛期", code: "MXQ", type: "markLine", color: "#ff0000", unit: "m" },
264
+ { name: "台汛期", code: "TXQ", type: "markLine", color: "#ff0000", unit: "m" },
265
+ { name: "累计降雨", type: "line", color: "red", unit: "mm" },
266
+ { name: "可纳雨量", type: "bar", color: "#0000ff", unit: "mm" },
267
+ { name: "作业预报时间", type: "markLine", color: "#ff0000" },
268
+ ];
269
+
270
+ //实测水位,库容,雨量图例属性配置
271
+ const legendKeys = [
272
+ { name: "实况雨量", code: "P", color: "#0000ff", icon: "histogram" },
273
+ { name: "实测水位", code: "RZ", color: "#304755", icon: "straightLine", iconWidth: "30", iconHeight: "30" },
274
+ { name: "库容", code: "W", color: "#197e2b", icon: "straightLine", iconWidth: "30", iconHeight: "30" },
275
+ ];
276
+
277
+ const floodControl = ["校核洪水位", "设计洪水位", "正常高水位", "坝顶高程", "死水位", "主汛期"];
278
+ //将传进来的图例数据与legendKeys匹配合并
279
+ const legendArr = ref(
280
+ props.legendList.map((item, index) => {
281
+ let obj = legendKeys.find((it) => it.code == item.name);
282
+ if (!item.color) {
283
+ item.color = getColors[index];
284
+ }
285
+ if (obj) {
286
+ return {
287
+ ...item,
288
+ ...obj,
289
+ };
290
+ } else {
291
+ return {
292
+ ...item,
293
+ };
294
+ }
295
+ })
296
+ );
297
+ legendArr.value.forEach((item) => {
298
+ legendAllColor[item.name] = item;
299
+ if (item.children) {
300
+ item.children.forEach((it) => {
301
+ legendAllColor[it.name] = it;
302
+ });
303
+ }
304
+ });
305
+ //是否全选
306
+ const isSelectedAll = ref(true);
307
+ let unselectedName = null;
308
+ //图例全选切换
309
+ const onAllChange = (e) => {
310
+ let names = [];
311
+ isSelectedAll.value = e;
312
+ legendArr.value.forEach((item) => {
313
+ item.isSelected = e;
314
+ names.push(item.name);
315
+ if (item.children) {
316
+ item.children.forEach((it) => {
317
+ it.isSelected = e;
318
+ names.push(it.name);
319
+ });
320
+ }
321
+ });
322
+ names.forEach((item) => {
323
+ selected[item] = e;
324
+ legendSelect(item, e);
325
+ });
326
+ dataZoom = { ...myChart.getOption()?.dataZoom[0] };
327
+ setChart();
328
+ };
329
+ //图例单个选中切换
330
+ const onChange = (e, name) => {
331
+ let names = [];
332
+ legendArr.value.forEach((item) => {
333
+ if (item.name == name) {
334
+ item.isSelected = e;
335
+ if (item.children) {
336
+ item.children.forEach((it) => {
337
+ it.isSelected = e;
338
+ names.push(it.name);
339
+ });
340
+ } else {
341
+ names.push(item.name);
342
+ }
343
+ } else {
344
+ item.children &&
345
+ item.children.forEach((it) => {
346
+ if (it.name == name) {
347
+ it.isSelected = e;
348
+ names.push(it.name);
349
+ if (
350
+ item.children.filter((i) => i.isSelected).length ==
351
+ item.children.length
352
+ ) {
353
+ item.isSelected = true;
354
+ } else {
355
+ item.isSelected = false;
356
+ }
357
+ }
358
+ });
359
+ }
360
+ });
361
+ names.forEach((item) => {
362
+ if (Array.isArray(item)) {
363
+ selected[item[0]] = e;
364
+ selected[item[1]] = e;
365
+ legendSelect(item[0], e);
366
+ legendSelect(item[1], e);
367
+ } else {
368
+ selected[item] = e;
369
+ legendSelect(item, e);
370
+ }
371
+ });
372
+ unselectedName = legendArr.value.some((item) => item.isSelected == false);
373
+ if (unselectedName) {
374
+ isSelectedAll.value = false;
375
+ } else {
376
+ isSelectedAll.value = true;
377
+ }
378
+ dataZoom = { ...myChart.getOption()?.dataZoom[0] };
379
+ setChart();
380
+ };
381
+
382
+ onMounted(() => {
383
+ window.addEventListener("keydown", handleKeyDown);
384
+ });
385
+ let markPointList = {};
386
+ const handleKeyDown = (event) => {
387
+ if (event.key === "i") {
388
+ let newOption = JSON.parse(JSON.stringify(myChart.getOption()));
389
+ newOption.series.forEach((item) => {
390
+ if (item.markPoint && item.markPoint.data.length != 0) {
391
+ item.markPoint.data = [];
392
+ } else if (item.markPoint && item.markPoint.data == 0) {
393
+ item.markPoint = markPointList[item.name];
394
+ }
395
+ });
396
+ myChart.setOption(newOption);
397
+ }
398
+ };
399
+ //初始化图表中每条线的显示隐藏需要的数据
400
+ let selected = {};
401
+ let myChart, chartDom;
402
+ const option = ref({});
403
+ const setChart = async () => {
404
+ //将传进来的series数据与keys匹配合并
405
+ let newSeries = props.chartOption.series.map((item) => {
406
+ let obj = "";
407
+ if (item.code) {
408
+ obj = keys.find((it) => it.code == item.code);
409
+ } else {
410
+ obj = keys.find((it) => it.name == item.name);
411
+ }
412
+ if (obj) {
413
+ return {
414
+ ...obj,
415
+ ...item,
416
+ };
417
+ } else {
418
+ return {
419
+ ...item,
420
+ };
421
+ }
422
+ });
423
+ //将图例中每个对象中的name与isSelected转为echarts识别的对象来初始化图表中每条线的显示隐藏
424
+ legendArr.value.forEach((item) => {
425
+ selected[item.name] = item.isSelected;
426
+ if (item.children) {
427
+ item.children.forEach((it) => {
428
+ selected[it.name] = it.isSelected;
429
+ });
430
+ }
431
+ });
432
+ chartDom = document.getElementById(props.id);
433
+ if (!myChart) {
434
+ myChart = echarts.init(chartDom);
435
+ }
436
+ //过滤series中不是数组的对象
437
+ let seriesDatas = newSeries.filter((item) => Array.isArray(item.data));
438
+ //判断数据是不是都是空的
439
+ const isAllEmptyArray = seriesDatas.every(
440
+ (item) => Array.isArray(item.data) && item.data.length === 0
441
+ );
442
+ //获取查询时间段的所有时间
443
+ const seriesEmptyArray = getTimeRange(
444
+ new Date(dayjs().subtract(5, "day").format("YYYY-MM-DD 08:00")),
445
+ new Date(dayjs().format("YYYY-MM-DD HH:00")),
446
+ 60
447
+ ).map((item) => [item, ""]);
448
+ //将数据中的时间放进一个数组进行排序
449
+ let timeArr = [];
450
+ seriesDatas.forEach((item) => {
451
+ timeArr = timeArr.concat(item.data);
452
+ });
453
+
454
+ timeArr = [...new Set(timeArr.map((item) => item[0]))];
455
+ timeArr.sort((a, b) => Date.parse(a) - Date.parse(b));
456
+ if (timeArr.some((item) => isTimeFormat(item))) {
457
+ timeArr = timeArr.filter((item) => isTimeFormat(item));
458
+ }
459
+ let sectionStartTime = timeArr[0]
460
+ props.chartOption.series.forEach(item => {
461
+ if (item.name == "开始" && item.sectionStartTime) {
462
+ sectionStartTime = item.sectionStartTime
463
+ }
464
+ })
465
+ let newGrid = JSON.parse(JSON.stringify(props.chartOption.grid));
466
+ let newXAxis = props.chartOption.xAxis.map((item, index) => {
467
+ let axisLabelShow = ''
468
+ if (item.show == false) {
469
+ axisLabelShow = false
470
+ } else if (newGrid.length > 1 && index == 0) {
471
+ axisLabelShow = false
472
+ } else {
473
+ axisLabelShow = true
474
+ }
475
+ let obj = {
476
+ type: item.type,
477
+ logBase: item.logBase || 10,
478
+ gridIndex: item.gridIndex,
479
+ name: axisLabelShow && item.type == 'time' ? '时间' : item.name,
480
+ nameLocation: axisLabelShow && item.type == 'time' ? 'end' : "middle", // x轴name处于x轴的什么位置
481
+ nameTextStyle: {
482
+ //x轴上方单位的颜色
483
+ color: "#333",
484
+ verticalAlign: axisLabelShow && item.type == 'time' ? 'top' : ''
485
+ },
486
+ position: item.position,
487
+ offset: item.offset ? item.offset : 0,
488
+ inverse: item.inverse ? item.inverse : false,
489
+ nameGap: axisLabelShow && item.type == 'time' ? 45 : item.nameGap ? item.nameGap : item.name ? 25 : 0, // x轴name与横纵坐标轴线的间距
490
+ axisLabel: {
491
+ show: axisLabelShow,
492
+ rotate: item.rotate,
493
+ formatter: function (value) {
494
+ if (item.type == "time") {
495
+ if (
496
+ isAnnualFirstDay(dayjs(dayjs(value).format("YYYY-MM-DD HH:mm")))
497
+ ) {
498
+ return props.chartOption.xTimeType
499
+ ? `{a|${props.chartOption.xTimeType}}`
500
+ : "{a|{yyyy}-{MM}-{dd} {HH}:{mm}}";
501
+ } else {
502
+ return props.chartOption.xTimeType
503
+ ? props.chartOption.xTimeType
504
+ : "{MM}-{dd} {HH}:{mm}";
505
+ }
506
+ } else {
507
+ if (item.name) {
508
+ if (item.name.includes("m³/s")) {
509
+ return formatToFlowValue(value);
510
+ } else if (item.name.includes("万m³")) {
511
+ return value.toFixed(2);
512
+ } else if (item.name.includes("mm")) {
513
+ return value.toFixed(1);
514
+ } else if (item.name.includes("m")) {
515
+ return value.toFixed(2);
516
+ } else {
517
+ return (value || value == 0) && item.toFixed ? Number(value).toFixed(item.toFixed) : value;
518
+ }
519
+ } else {
520
+ return value;
521
+ }
522
+ }
523
+ },
524
+ rich: {
525
+ a: {
526
+ fontWeight: "bold",
527
+ },
528
+ },
529
+ color: props.chartOption.yAxisColor
530
+ ? props.chartOption.yAxisColor
531
+ : "#333",
532
+ hideOverlap: true,
533
+ },
534
+ axisLine: {
535
+ show: true,
536
+ lineStyle: {
537
+ color: props.chartOption.yAxisColor
538
+ ? props.chartOption.yAxisColor
539
+ : "#8a949c",
540
+ },
541
+ },
542
+ splitLine: {
543
+ show: item.splitLineHide ? false : item.gridIndex != 2 ? true : false,
544
+ lineStyle: {
545
+ color: "#e0e6f1",
546
+ },
547
+ },
548
+ axisTick: {
549
+ show:
550
+ item.show == false
551
+ ? false
552
+ : newGrid.length > 1 && index == 0
553
+ ? false
554
+ : true, // 不显示坐标轴上的文字
555
+ alignWithLabel:
556
+ props.chartOption.alignWithLabel != undefined
557
+ ? props.chartOption.alignWithLabel
558
+ : true,
559
+ },
560
+ boundaryGap: item.boundaryGap ? item.boundaryGap : ["1%", "1%"],
561
+ };
562
+ if (item.data) {
563
+ obj.data = item.data;
564
+ }
565
+ if (item.type == "value" || item.type == "log") {
566
+
567
+ let min = 0;
568
+ let max = 100;
569
+ let interval = 10;
570
+
571
+ if (item.name.includes("m³/s")) {
572
+ max = 1000;
573
+ interval = 100;
574
+ } else if (item.name.includes("万m³")) {
575
+ max = 10000;
576
+ interval = 1000;
577
+ }
578
+ let filterNewData = props.chartOption.series.filter((it) => it.yAxisIndex == index);
579
+ //获取series中data为数组的并且合并在一起
580
+ let newData = [],
581
+ dataAll = [],
582
+ minValue = 0,
583
+ maxValue = 100;
584
+ filterNewData.forEach((it) => {
585
+ if (it.data instanceof Array) {
586
+ newData = newData.concat(it.data);
587
+ }
588
+ });
589
+ //获取所有的值
590
+ if (newData[0] instanceof Array) {
591
+ dataAll = newData
592
+ .filter(
593
+ (it) =>
594
+ it[0] != "" &&
595
+ it[0] != null &&
596
+ it[0] != undefined &&
597
+ !isNaN(it[0])
598
+ )
599
+ .map((it) => Number(it[0]));
600
+ }
601
+ if (dataAll.length > 0) {
602
+ minValue = Math.min(...dataAll);
603
+ maxValue = Math.max(...dataAll);
604
+ if (
605
+ filterNewData.some((it) => it.type == "bar") ||
606
+ item.name.includes("雨")
607
+ ) {
608
+ min = 0;
609
+ if (minValue !== 0 || maxValue !== 0) {
610
+ max =
611
+ Math.ceil(maxValue / getInterval(0, maxValue)) *
612
+ getInterval(0, maxValue);
613
+ interval = getInterval(0, maxValue);
614
+ }
615
+ } else {
616
+ if (item.min || item.min == 0) {
617
+ min = item.min;
618
+ if (minValue !== 0 || maxValue !== 0) {
619
+ max =
620
+ Math.ceil(maxValue / getInterval(item.min, maxValue)) *
621
+ getInterval(item.min, maxValue);
622
+ interval = getInterval(item.min, maxValue);
623
+ }
624
+ } else {
625
+ if (minValue !== 0 || maxValue !== 0) {
626
+ min =
627
+ Math.floor(minValue / getInterval(minValue, maxValue)) *
628
+ getInterval(minValue, maxValue);
629
+ max =
630
+ Math.ceil(maxValue / getInterval(minValue, maxValue)) *
631
+ getInterval(minValue, maxValue);
632
+ interval = getInterval(minValue, maxValue);
633
+ }
634
+ }
635
+ }
636
+ }
637
+
638
+ obj.min = item.min != "" && item.min != null ? item.min : min;
639
+ obj.max = item.max != "" && item.max != null ? item.max : max;
640
+ obj.interval = item.interval && item.max && (item.min || item.min == 0)
641
+ ? item.interval
642
+ : interval;
643
+ item.interval && item.max && (item.min || item.min == 0)
644
+ ? item.interval
645
+ : interval,
646
+ obj.minorTick = {
647
+ show: item.isMinorSplitLineShow ? true : false,
648
+ };
649
+ }
650
+ return obj;
651
+ });
652
+ let newYAxis = props.chartOption.yAxis.map((item, index) => {
653
+ let min = 0;
654
+ let max = 100;
655
+ let interval = 10;
656
+
657
+ if (item.name.includes("m³/s")) {
658
+ max = 1000;
659
+ interval = 100;
660
+ } else if (item.name.includes("万m³")) {
661
+ max = 10000;
662
+ interval = 1000;
663
+ }
664
+
665
+ if (item.name == "可纳雨量(mm)") {
666
+ return {
667
+ gridIndex: item.index,
668
+ name: item.name,
669
+ nameLocation: "middle", // y轴name处于y轴的什么位置
670
+ nameTextStyle: {
671
+ //y轴上方单位的颜色
672
+ color: "#333",
673
+ },
674
+ nameGap: item.nameGap, // y轴name与横纵坐标轴线的间距
675
+ type: "value",
676
+ position: item.position,
677
+ offset: item.offset,
678
+ min: item.min,
679
+ max: item.max,
680
+ interval: item.interval,
681
+ axisLabel: {
682
+ // 内容格式器
683
+ formatter: (value) => {
684
+ return value.toFixed(1);
685
+ },
686
+ color: "#333",
687
+ },
688
+ axisLine: {
689
+ show: true,
690
+ lineStyle: {
691
+ color: "#8a949c",
692
+ },
693
+ },
694
+ splitLine: {
695
+ show: false,
696
+ },
697
+ minorTick: {
698
+ show: true,
699
+ },
700
+ axisTick: {
701
+ show: true, // 是否显示坐标轴刻度
702
+ },
703
+ };
704
+ } else {
705
+ let filterNewData = props.chartOption.series.filter((it) => {
706
+ return (
707
+ it.yAxisIndex == index &&
708
+ (selected[it.name] || !Object.keys(selected).includes(it.name))
709
+ );
710
+ });
711
+ //获取series中data为数组的并且合并在一起
712
+ let newData = [],
713
+ dataAll = [],
714
+ jjData = [],
715
+ minValue = 0,
716
+ maxValue = 100,
717
+ firstYValue = null; // 保存第一个y轴值
718
+ filterNewData.forEach((it) => {
719
+ if (it.data instanceof Array) {
720
+ const seriesData = it.data2 ? it.data2 : it.data;
721
+ seriesData.forEach((item) => {
722
+ if (item instanceof Array && item.length >= 2) {
723
+ // 对于[[x1, y1], [x2, y2], ...]格式的数据
724
+ const yValue = item[1];
725
+ if (yValue != "" && yValue != null && yValue != undefined && !isNaN(yValue)) {
726
+ const numValue = Number(yValue);
727
+ // 保存第一个有效的y轴值
728
+ if (firstYValue === null) {
729
+ firstYValue = numValue;
730
+ }
731
+ }
732
+ }
733
+ });
734
+ newData = it.data2 ? newData.concat(it.data2) : newData.concat(it.data);
735
+ } else {
736
+ if (it.data.name == "yAxis" && it.data.value) {
737
+ jjData.push(Number(it.data.value));
738
+ }
739
+ }
740
+ });
741
+ //获取所有的值
742
+ if (newData[0] instanceof Array) {
743
+ dataAll = newData
744
+ .filter(
745
+ (it) =>
746
+ it[1] != "" &&
747
+ it[1] != null &&
748
+ it[1] != undefined &&
749
+ !isNaN(it[1])
750
+ )
751
+ .map((it) => Number(it[1]));
752
+ } else if (newData[0] instanceof Object && newData[0].value) {
753
+ let newDataAll = newData.map((it) => it.value);
754
+ dataAll = newDataAll
755
+ .filter(
756
+ (it) => it != "" && it != null && it != undefined && !isNaN(it)
757
+ )
758
+ .map((it) => Number(it));
759
+ } else {
760
+ dataAll = newData
761
+ .filter(
762
+ (it) => it != "" && it != null && it != undefined && !isNaN(it)
763
+ )
764
+ .map((it) => Number(it));
765
+ }
766
+ if (dataAll.length > 0 || jjData.length > 0) {
767
+ minValue = Math.min(...dataAll, ...jjData);
768
+ maxValue = Math.max(...dataAll, ...jjData);
769
+ if (
770
+ filterNewData.some((it) => it.type == "bar") ||
771
+ item.name.includes("雨")
772
+ ) {
773
+ min = 0;
774
+ if (props.chartOption.xAxis.length > 1 && item.inverse) {
775
+ if (minValue !== 0 || maxValue !== 0) {
776
+ max =
777
+ Math.ceil(maxValue / getInterval(0, maxValue, 1)) *
778
+ getInterval(0, maxValue, 1) +
779
+ getInterval(0, maxValue, 1) *
780
+ (item.upIntervalNumber != undefined
781
+ ? item.upIntervalNumber
782
+ : 1);
783
+ interval = getInterval(0, maxValue, 1);
784
+ }
785
+ } else {
786
+ if (minValue !== 0 || maxValue !== 0) {
787
+ max =
788
+ Math.ceil(maxValue / getInterval(0, maxValue)) *
789
+ getInterval(0, maxValue) +
790
+ getInterval(0, maxValue) *
791
+ (item.upIntervalNumber != undefined
792
+ ? item.upIntervalNumber
793
+ : 1);
794
+ interval = getInterval(0, maxValue);
795
+ }
796
+ }
797
+ } else {
798
+ if (item.min || item.min == 0) {
799
+ min = item.min;
800
+ if (minValue !== 0 || maxValue !== 0) {
801
+ max =
802
+ Math.ceil(maxValue / getInterval(item.min, maxValue)) *
803
+ getInterval(item.min, maxValue) +
804
+ getInterval(item.min, maxValue) *
805
+ (item.upIntervalNumber != undefined
806
+ ? item.upIntervalNumber
807
+ : 1);
808
+ interval = getInterval(item.min, maxValue);
809
+ }
810
+ } else {
811
+ if (minValue !== 0 || maxValue !== 0) {
812
+ // 检查是否至少有一个x轴是value类型
813
+ const xAxisIsValue = props.chartOption.xAxis.some(xAxis => xAxis.type === 'value');
814
+ if (xAxisIsValue && firstYValue !== null) {
815
+ // 当x轴是value类型时,使用第一个y轴值作为最小刻度值
816
+ min = firstYValue;
817
+ // 计算合适的间隔
818
+ const intervalValue = getInterval(min, maxValue);
819
+ // 计算最大值,确保包含所有数据
820
+ max =
821
+ Math.ceil((maxValue - min) / intervalValue) * intervalValue + min +
822
+ intervalValue *
823
+ (item.upIntervalNumber != undefined
824
+ ? item.upIntervalNumber
825
+ : 1);
826
+ interval = intervalValue;
827
+ } else {
828
+ // 其他情况,使用原来的逻辑
829
+ min =
830
+ Math.floor(minValue / getInterval(minValue, maxValue)) *
831
+ getInterval(minValue, maxValue) -
832
+ getInterval(minValue, maxValue) *
833
+ (item.downIntervalNumber != undefined
834
+ ? item.downIntervalNumber
835
+ : 1);
836
+ max =
837
+ Math.ceil(maxValue / getInterval(minValue, maxValue)) *
838
+ getInterval(minValue, maxValue) +
839
+ getInterval(minValue, maxValue) *
840
+ (item.upIntervalNumber != undefined
841
+ ? item.upIntervalNumber
842
+ : 1);
843
+ interval = getInterval(minValue, maxValue);
844
+ }
845
+ }
846
+ }
847
+ }
848
+ }
849
+ if (item.rangeType == 1) {
850
+ let yMax = "",
851
+ val = "";
852
+ if (Math.abs(maxValue) > Math.abs(minValue)) {
853
+ val = Math.abs(maxValue);
854
+ } else {
855
+ val = Math.abs(minValue);
856
+ }
857
+ yMax = Math.ceil(val / getInterval(0, val)) * getInterval(0, val);
858
+ max = yMax;
859
+ min = 0 - yMax;
860
+ interval = getInterval(0, Math.abs(yMax));
861
+ }
862
+ return {
863
+ gridIndex: item.index,
864
+ name: item.name,
865
+ nameLocation: "middle", // y轴name处于y轴的什么位置
866
+ nameTextStyle: {
867
+ //y轴上方单位的颜色
868
+ color: props.chartOption.yAxisColor
869
+ ? props.chartOption.yAxisColor
870
+ : "#333",
871
+ },
872
+ nameGap: item.nameGap, // y轴name与横纵坐标轴线的间距
873
+ type: item.type || "value",
874
+ logBase: item.logBase || 10,
875
+ position: item.position,
876
+ offset: item.offset ? item.offset : 0,
877
+ inverse: item.inverse ? item.inverse : false,
878
+ min: item.min != "" && item.min != null ? item.min : min,
879
+ max: item.max != "" && item.max != null ? item.max : max,
880
+ interval:
881
+ item.interval && item.max && (item.min || item.min == 0)
882
+ ? item.interval
883
+ : interval,
884
+ axisLabel: {
885
+ // 内容格式器
886
+ formatter: (value) => {
887
+ if (item.name.includes("m³/s")) {
888
+ return formatToFlowValue(value);
889
+ } else if (item.name.includes("万m³")) {
890
+ return value.toFixed(2);
891
+ } else if (item.name.includes("mm")) {
892
+ return value.toFixed(1);
893
+ } else if (item.name.includes("m")) {
894
+ return value.toFixed(2);
895
+ } else {
896
+ return value;
897
+ }
898
+ },
899
+ color: props.chartOption.yAxisColor
900
+ ? props.chartOption.yAxisColor
901
+ : "#333",
902
+ },
903
+ axisLine: {
904
+ show: true,
905
+ lineStyle: {
906
+ color: props.chartOption.yAxisColor
907
+ ? props.chartOption.yAxisColor
908
+ : "#8a949c",
909
+ },
910
+ },
911
+ axisTick: {
912
+ show: true, // 是否显示坐标轴刻度
913
+ },
914
+ splitLine: {
915
+ show:
916
+ (newGrid.length > 1 &&
917
+ item.index == 1 &&
918
+ item.position == "right") ||
919
+ (newGrid.length == 1 &&
920
+ item.index == 0 &&
921
+ item.position == "right") ||
922
+ item.splitLineHide
923
+ ? false
924
+ : true,
925
+ lineStyle: {
926
+ color: "#e0e6f1",
927
+ },
928
+ },
929
+ minorTick: {
930
+ show: true,
931
+ },
932
+ minorSplitLine: {
933
+ show:
934
+ (newGrid.length > 1 &&
935
+ item.index == 1 &&
936
+ item.position == "right") ||
937
+ (newGrid.length == 1 &&
938
+ item.index == 0 &&
939
+ item.position == "right") ||
940
+ item.splitLineHide ?
941
+ false : item.minorSplitLineHide
942
+ ? false
943
+ : true,
944
+ lineStyle: {
945
+ color: "#f4f7fd",
946
+ },
947
+ },
948
+ axisTick: {
949
+ show: true, // 是否显示坐标轴刻度
950
+ },
951
+ };
952
+ }
953
+ });
954
+ let openBarDrag = newSeries.some(item => item.openBarDrag) //图表是否打开了编辑模式
955
+ let seriesArr = newSeries.map((item, index) => {
956
+ let obj = {};
957
+ if (item.type == "bar") {
958
+ if (item.name == "可纳雨量") {
959
+ obj = {
960
+ name: item.name,
961
+ type: item.type,
962
+ xAxisIndex: item.xAxisIndex,
963
+ yAxisIndex: item.yAxisIndex,
964
+ barWidth: item.barWidth,
965
+ data: isAllEmptyArray ? seriesEmptyArray : item.data,
966
+ label: {
967
+ show: true, // 显示标签
968
+ position: "top", // 标签显示在柱子的顶部
969
+ color: "black", // 标签文字颜色
970
+ fontFamily: "Times New Roman",
971
+ },
972
+ itemStyle: {
973
+ color: function (params) {
974
+ // 根据条件设置柱子颜色
975
+ if (item.barColor == "1") {
976
+ if (params.dataIndex === 0) {
977
+ return "#ff0000";
978
+ } else if (params.dataIndex === 1) {
979
+ return "#a52a2a";
980
+ } else if (params.dataIndex === 2) {
981
+ return "#ffa500";
982
+ } else if (params.dataIndex === 3) {
983
+ return "#cf0ce1";
984
+ }
985
+ } else {
986
+ return "#00a651";
987
+ }
988
+ },
989
+ },
990
+ zlevel: 9,
991
+ z: 9,
992
+ };
993
+ } else {
994
+ obj = {
995
+ name: item.name,
996
+ type: item.type,
997
+ xAxisIndex: item.xAxisIndex,
998
+ yAxisIndex: item.yAxisIndex,
999
+ label: {
1000
+ show: item.isLabelShow ? item.isLabelShow : false,
1001
+ position: "top",
1002
+ fontFamily: "Times New Roman",
1003
+ formatter: function (data) {
1004
+ let val = Array.isArray(data.value) ? data.value[1] : data.value
1005
+ return "{a0|" + val + "}";
1006
+ },
1007
+ rich: {
1008
+ a0: {
1009
+ color: legendAllColor[item.name]
1010
+ ? legendAllColor[item.name].color
1011
+ : item.color,
1012
+ fontSize: 12,
1013
+ },
1014
+ },
1015
+ },
1016
+ stack: item.stack ? item.stack : "",
1017
+ tooltip: {
1018
+ show: item.isTooltipShow == false ? false : true,
1019
+ trigger: "axis",
1020
+ type: "none",
1021
+ },
1022
+ itemStyle: item.itemStyle
1023
+ ? item.itemStyle
1024
+ : {
1025
+ color: function (params) {
1026
+ let color = legendAllColor[item.name]
1027
+ ? legendAllColor[item.name].color
1028
+ : item.color
1029
+ ? item.color
1030
+ : getColors[index];
1031
+ if (item.color2) {
1032
+ if (params.value[1] < 0) {
1033
+ return item.color2;
1034
+ } else {
1035
+ return color;
1036
+ }
1037
+ } else {
1038
+ return color;
1039
+ }
1040
+ },
1041
+ decal: {
1042
+ symbol: item.pattern ? item.pattern : 'none'
1043
+ }
1044
+ },
1045
+ barCategoryGap: item.barCategoryGap ? item.barCategoryGap : newYAxis[item.yAxisIndex].inverse ? "0%" : "20%",
1046
+ barGap: item.barGap ? item.barGap : "0%",
1047
+ data: isAllEmptyArray ? seriesEmptyArray : item.data,
1048
+ zlevel: 9,
1049
+ z: 9,
1050
+ };
1051
+ }
1052
+ if (item.barWidth) {
1053
+ obj.barWidth = item.barWidth;
1054
+ if (item.barGap) {
1055
+ obj.barGap = item.barGap;
1056
+ } else {
1057
+ obj.barGap = "20%";
1058
+ }
1059
+ }
1060
+ if (item.barMaxWidth) {
1061
+ obj.barMaxWidth = item.barMaxWidth;
1062
+ if (item.barGap) {
1063
+ obj.barGap = item.barGap;
1064
+ } else {
1065
+ obj.barGap = "20%";
1066
+ }
1067
+ }
1068
+ } else if (item.type == "line") {
1069
+ let areaColor = "rgba(0, 0, 0, 0)";
1070
+ if (props.chartOption.isFace) {
1071
+ if (props.chartOption.faceNames) {
1072
+ if (props.chartOption.faceNames.includes(item.name)) {
1073
+ if (legendAllColor[item.name]) {
1074
+ areaColor = legendAllColor[item.name].color;
1075
+ } else {
1076
+ areaColor = item.color;
1077
+ }
1078
+ }
1079
+ } else {
1080
+ if (legendAllColor[item.name]) {
1081
+ areaColor = legendAllColor[item.name].color;
1082
+ } else {
1083
+ areaColor = item.color;
1084
+ }
1085
+ }
1086
+ }
1087
+ let symbolSize = '', triggerLineEvent = false;
1088
+ if (item.showSymbol || legendAllColor[item.name]?.icon == "dottedLine") {
1089
+ if (item.symbolSize) {
1090
+ symbolSize = item.symbolSize
1091
+ } else {
1092
+ symbolSize = 5
1093
+ }
1094
+ } else {
1095
+ if (props.chartOption.isTooltipItem) {
1096
+ symbolSize = 10
1097
+ triggerLineEvent = true
1098
+ } else {
1099
+ symbolSize = 0
1100
+ }
1101
+ }
1102
+ obj = {
1103
+ name: item.name,
1104
+ type: item.type,
1105
+ xAxisIndex: item.xAxisIndex,
1106
+ yAxisIndex: item.yAxisIndex,
1107
+ itemStyle: {
1108
+ color: legendAllColor[item.name]
1109
+ ? legendAllColor[item.name].color
1110
+ : item.color,
1111
+ opacity: item.showSymbol || legendAllColor[item.name]?.icon == "dottedLine" ? 1 : 0
1112
+ },
1113
+ lineStyle: item.lineStyle
1114
+ ? item.lineStyle
1115
+ : {
1116
+ type:
1117
+ legendAllColor[item.name]?.icon == "dotted"
1118
+ ? "dotted"
1119
+ : "solid",
1120
+ },
1121
+ areaStyle: {
1122
+ color: areaColor,
1123
+ opacity: 0.5,
1124
+ },
1125
+ smooth: item.smooth != undefined ? item.smooth : false,
1126
+ showSymbol: true,
1127
+ symbol: item.symbol ? item.symbol : "circle",
1128
+ connectNulls: true,
1129
+ symbolSize: symbolSize,
1130
+ data: isAllEmptyArray ? seriesEmptyArray : item.data,
1131
+ silent: openBarDrag ? item.openBarDrag === true ? false : true : false,
1132
+ triggerLineEvent: triggerLineEvent,
1133
+ zlevel: 9,
1134
+ z: 9,
1135
+ };
1136
+ if (item.isMaxMinShow && item.data.length > 0) {
1137
+ let newArr = item.data.filter(item => !item[2]).filter((it) => it[1]);
1138
+ let maxElement = newArr.reduce((max, current) => {
1139
+ return parseFloat(current[1]) > parseFloat(max[1]) ? current : max;
1140
+ }, newArr[0]);
1141
+
1142
+ let maxTime = maxElement ? maxElement[0] : '', maxValue = maxElement ? maxElement[1] : '',
1143
+ offset;
1144
+ timeArr.forEach((item, index) => {
1145
+ if (dayjs(item).isValid() && item == maxTime) {
1146
+ if (!item.markPointOffset) {
1147
+ if (index >= (timeArr.length / 5) * 4) {
1148
+ offset = [-200, 0];
1149
+ } else if (index >= (timeArr.length / 5) * 3) {
1150
+ offset = [-150, 0];
1151
+ } else if (index >= (timeArr.length / 5) * 2) {
1152
+ offset = [-100, 0];
1153
+ } else if (index >= (timeArr.length / 5) * 1) {
1154
+ offset = [-50, 0];
1155
+ } else if (index >= 0) {
1156
+ offset = [0, 0];
1157
+ }
1158
+ }
1159
+ }
1160
+ });
1161
+ obj.markPoint = {
1162
+ symbol: "pin",
1163
+ symbolSize: 20,
1164
+ label: {
1165
+ show: item.isMarkPointLabelShow === false ? false : true,
1166
+ position: "top",
1167
+ align: "left",
1168
+ fontSize: 16,
1169
+ backgroundColor: item.backgroundColor
1170
+ ? item.backgroundColor
1171
+ : legendAllColor[item.name]
1172
+ ? legendAllColor[item.name].color
1173
+ : item.color,
1174
+ borderRadius: 6,
1175
+ shadowColor: "#666666",
1176
+ shadowBlur: 5,
1177
+ shadowOffsetX: 3,
1178
+ shadowOffsetY: 3,
1179
+ fontWeight: "bold",
1180
+ padding: [4, 4, 4, 4],
1181
+ lineHeight: 30,
1182
+ color: item.markPointColor ? item.markPointColor : "#fff",
1183
+ formatter: (par) => {
1184
+ let maxTime = "";
1185
+ if (par.data && par.data.coord && par.data.coord[0]) {
1186
+ let tmType = item.tmType ? item.tmType : "YYYY-MM-DD HH:mm";
1187
+ maxTime = dayjs(par.data.coord[0]).format(tmType);
1188
+ }
1189
+ let text = "";
1190
+ let value = "";
1191
+ if (par.name == "Max") {
1192
+ text = item.maxText ? item.maxText : "最大值";
1193
+ if (item.unit.includes("m³")) {
1194
+ value = par.value ? formatToFlowValue(par.value) : "--";
1195
+ } else if (item.unit.includes("mm")) {
1196
+ value = par.value ? Number(par.value).toFixed(1) : "--";
1197
+ } else if (item.unit.includes("m")) {
1198
+ value = par.value ? Number(par.value).toFixed(2) : "--";
1199
+ } else {
1200
+ value = par.value;
1201
+ }
1202
+ if (item.tmText) {
1203
+ return `${text}: {a0|${value}} ${item.unit}\n${item.tmText}: {a1|${maxTime}}`;
1204
+ } else {
1205
+ return `${item.tmText2 ? item.tmText2 : "相应时间"
1206
+ }: {a1|${maxTime}}\n${text}: {a0|${value}} ${item.unit}`;
1207
+ }
1208
+ }
1209
+ },
1210
+ rich: {
1211
+ a0: {
1212
+ fontSize: 25,
1213
+ fontFamily: "Times New Roman",
1214
+ },
1215
+ a1: {
1216
+ fontSize: 20,
1217
+ fontFamily: "Times New Roman",
1218
+ },
1219
+ },
1220
+ },
1221
+ data: [
1222
+ {
1223
+ name: "Max",
1224
+ label: {
1225
+ offset: item.markPointOffset
1226
+ ? item.markPointOffset
1227
+ : offset
1228
+ ? offset
1229
+ : [-120, 0],
1230
+ },
1231
+ xAxis: maxTime,
1232
+ yAxis: maxValue,
1233
+ value: maxValue
1234
+ },
1235
+ ],
1236
+ };
1237
+ }
1238
+ } else if (item.type == "markLine") {
1239
+ let markLineLabel = {}, padding = [];
1240
+ if (item.labelType == 2) {
1241
+ if (item.name == '开始') {
1242
+ padding = [0, 0, -80, 180]
1243
+ } else if (item.name == '结束') {
1244
+ padding = [0, 180, -120, 0]
1245
+ }
1246
+ markLineLabel = {
1247
+ show: item.labelHide ? false : true,
1248
+ position: "end",
1249
+ fontWeight: "bold",
1250
+ padding: padding,
1251
+ fontFamily: "Times New Roman",
1252
+ lineHeight: 20,
1253
+ fontSize: 15,
1254
+ };
1255
+ } else {
1256
+ markLineLabel = {
1257
+ show: item.labelHide ? false : true,
1258
+ position: "insideStartTop",
1259
+ fontFamily: "Times New Roman",
1260
+ lineHeight: 20,
1261
+ fontSize: 15,
1262
+ };
1263
+ }
1264
+ obj = {
1265
+ name: item.name,
1266
+ type: "line",
1267
+ xAxisIndex: item.xAxisIndex,
1268
+ yAxisIndex: item.yAxisIndex,
1269
+ markLine: {
1270
+ symbol: "none",
1271
+ label: markLineLabel,
1272
+ data: [
1273
+ {
1274
+ lineStyle: {
1275
+ type: item.markLineStyle ? item.markLineStyle : item.name == '开始' || item.name == '结束' ? 'dashed' : [5, 2],
1276
+ dashOffset: 0,
1277
+ color: legendAllColor[item.name]
1278
+ ? legendAllColor[item.name].color
1279
+ : item.color,
1280
+ width: item.name == '开始' || item.name == '结束' ? 5 : 1,
1281
+ },
1282
+ [item.data.name]: String(item.data.value),
1283
+ label: {
1284
+ color: legendAllColor[item.name]
1285
+ ? legendAllColor[item.name].color
1286
+ : item.color,
1287
+ fontFamily: "Times New Roman, serif",
1288
+ distance: -2,
1289
+ position: item.position ? item.position : "insideStartTop",
1290
+ formatter: function (params) {
1291
+ if (item.labelType == 2) {
1292
+ let text = '';
1293
+ if (item.name == '开始') {
1294
+ text = `${item.name}: ${params.value}`
1295
+ } else if (item.name == '结束') {
1296
+ text = `${item.name}: ${formatSecondTime(params.value)}`
1297
+ }
1298
+ if (item.labelArr) {
1299
+ item.labelArr.forEach((it) => {
1300
+ text += `{a1|\n${it.name}: ${it.value} ${it.unit}}`;
1301
+ });
1302
+ }
1303
+ return text;
1304
+ } else {
1305
+ let icon = "";
1306
+ if (floodControl.includes(item.name) || item.name.includes("梅汛期") || item.name.includes("台汛期")) {
1307
+ icon = "{a0|▽}";
1308
+ }
1309
+ return item.data.name == "xAxis"
1310
+ ? item.name
1311
+ : ` ${icon}${item.name}: ${item.data.value} ${item.unit} `;
1312
+ }
1313
+ },
1314
+ rich: {
1315
+ a0: {
1316
+ fontSize: 15,
1317
+ },
1318
+ a1: {
1319
+ color: 'red',
1320
+ fontSize: 16,
1321
+ fontFamily: '黑体'
1322
+ },
1323
+ },
1324
+ },
1325
+ emphasis: {
1326
+ lineStyle: {
1327
+ width: item.name == '开始' || item.name == '结束' ? 6 : 3,
1328
+ }
1329
+ }
1330
+ },
1331
+ ],
1332
+ }
1333
+ };
1334
+ } else if (item.type == "scatter") {
1335
+ obj = {
1336
+ name: item.name,
1337
+ type: item.type,
1338
+ xAxisIndex: item.xAxisIndex,
1339
+ yAxisIndex: item.yAxisIndex,
1340
+ symbolSize: item.symbolSize,
1341
+ itemStyle: {
1342
+ color: legendAllColor[item.name]
1343
+ ? legendAllColor[item.name].color
1344
+ : item.color,
1345
+ },
1346
+ data: isAllEmptyArray ? seriesEmptyArray : item.data,
1347
+ zlevel: 9,
1348
+ z: 9,
1349
+ };
1350
+ } else if (item.type == "boxplot") {
1351
+ obj = {
1352
+ name: item.name,
1353
+ type: item.type,
1354
+ xAxisIndex: item.xAxisIndex,
1355
+ yAxisIndex: item.yAxisIndex,
1356
+ itemStyle: {
1357
+ color: legendAllColor[item.name]
1358
+ ? legendAllColor[item.name].color
1359
+ : item.color,
1360
+ borderWidth: 2,
1361
+ borderColor: "black",
1362
+ },
1363
+ boxWidth: item.boxWidth ? item.boxWidth : 30, // 设置箱子宽度
1364
+ emphasis: {
1365
+ // 鼠标移入时的样式
1366
+ itemStyle: {
1367
+ borderWidth: 2,
1368
+ },
1369
+ },
1370
+ data: isAllEmptyArray ? seriesEmptyArray : item.data,
1371
+ zlevel: 9,
1372
+ z: 9,
1373
+ };
1374
+ }
1375
+ if (item.markArea) {
1376
+ if (item.markArea.data) {
1377
+ obj.markArea = {
1378
+ silent: item.markArea.silent ? item.markArea.silent : false,
1379
+ label: item.markArea.label ? item.markArea.label : {},
1380
+ itemStyle: item.markArea.itemStyle ? item.markArea.itemStyle : {},
1381
+ data: item.markArea.data,
1382
+ };
1383
+ } else {
1384
+ obj.markArea = {
1385
+ silent: true,
1386
+ itemStyle: {
1387
+ opacity: item.markArea.opacity ? item.markArea.opacity : 0.3,
1388
+ color: item.markArea.color ? item.markArea.color : "#BEE6E6",
1389
+ borderColor: item.markArea.borderColor
1390
+ ? item.markArea.borderColor
1391
+ : "red",
1392
+ borderWidth: item.markArea.borderWidth
1393
+ ? item.markArea.borderWidth
1394
+ : 2,
1395
+ },
1396
+ data: [
1397
+ [
1398
+ {
1399
+ xAxis: item.markArea.start,
1400
+ },
1401
+ {
1402
+ xAxis: item.markArea.end,
1403
+ },
1404
+ ],
1405
+ ],
1406
+ };
1407
+ }
1408
+ }
1409
+ return obj;
1410
+ });
1411
+
1412
+ let yNames = newYAxis.map((item) => item.name),
1413
+ krData = {},
1414
+ krData2 = {};
1415
+ if (
1416
+ yNames.includes("水位(m)") &&
1417
+ yNames.includes("库容(万m³)") &&
1418
+ props.chartOption.stationCode
1419
+ ) {
1420
+ let obj = newYAxis.find((it) => it.name == "水位(m)");
1421
+ let nums = [];
1422
+ for (let i = obj.min; i <= obj.max; i += obj.interval) {
1423
+ nums.push(i);
1424
+ }
1425
+ let krArr = [];
1426
+ for (let i = 0; i < nums.length; i++) {
1427
+ if (obj.max == 100) {
1428
+ krArr.push(i * 1000);
1429
+ } else {
1430
+ if (nums[i] == 0) {
1431
+ krArr.push(0);
1432
+ } else {
1433
+ let val = await cotwlTransformation(nums[i], i);
1434
+ krArr.push(val);
1435
+ }
1436
+ }
1437
+ }
1438
+ newYAxis.forEach((item) => {
1439
+ if (item.name == "水位(m)") {
1440
+ item.offset = 80;
1441
+ } else if (item.name == "库容(万m³)") {
1442
+ item.offset = 80;
1443
+ item.nameGap = -70;
1444
+ item.splitLine.show = false;
1445
+ item.minorSplitLine.show = false;
1446
+ item.axisLabel.inside = true;
1447
+ item.axisTick.inside = true;
1448
+ if (newGrid.length > 1) {
1449
+ if (item.gridIndex == 0) {
1450
+ newGrid[item.gridIndex].left = 150;
1451
+ newGrid[item.gridIndex].right = 20;
1452
+ newGrid[1].left = 150;
1453
+ newGrid[1].right = 20;
1454
+ } else if (item.gridIndex == 1) {
1455
+ newGrid[0].left = 150;
1456
+ newGrid[0].right = 70;
1457
+ newGrid[item.gridIndex].left = 150;
1458
+ newGrid[item.gridIndex].right = 70;
1459
+ }
1460
+ } else if (newGrid.length == 1) {
1461
+ newGrid[item.gridIndex].left = 150;
1462
+ newGrid[item.gridIndex].right = 20;
1463
+ }
1464
+ item.position = "left";
1465
+ item.max = obj.max;
1466
+ item.min = obj.min;
1467
+ item.interval = obj.interval;
1468
+ item.axisLabel.formatter = (value, index) => {
1469
+ if (krArr[index] || krArr[index] == 0) {
1470
+ return Number(krArr[index]).toFixed(2);
1471
+ } else {
1472
+ return "";
1473
+ }
1474
+ };
1475
+ }
1476
+ });
1477
+ let krObj = seriesArr.find((item) => item.name == "库容");
1478
+ let krObj2 = seriesArr.find((item) => item.name == "5分钟库容");
1479
+ let swObj = seriesArr.find(
1480
+ (item) => item.name == "实测水位" || item.name == "水位"
1481
+ );
1482
+ let swObj2 = seriesArr.find((item) => item.name == "5分钟水位");
1483
+ if (krObj && krObj.data) {
1484
+ krObj.data.forEach((item) => {
1485
+ krData[item[0]] = item[1];
1486
+ });
1487
+ }
1488
+ if (krObj2 && krObj2.data) {
1489
+ krObj2.data.forEach((item) => {
1490
+ krData2[item[0]] = item[1];
1491
+ });
1492
+ }
1493
+ seriesArr.forEach((item) => {
1494
+ if (item.name == "库容") {
1495
+ item.data = swObj.data;
1496
+ } else if (item.name == "5分钟库容") {
1497
+ item.data = swObj2.data;
1498
+ }
1499
+ });
1500
+ }
1501
+ //过滤掉非整时时间,这样取消图例选中后,图表上没有非整时数据
1502
+ let newTimeArr = [...timeArr];
1503
+ if (timeArr.some((item) => isTimeFormat(item))) {
1504
+ newTimeArr = newTimeArr.filter((item) => {
1505
+ let dateTime = dayjs(item);
1506
+ if (
1507
+ isTimeFormat(item) &&
1508
+ dateTime.minute() === 0 &&
1509
+ dateTime.second() === 0
1510
+ ) {
1511
+ return item;
1512
+ }
1513
+ });
1514
+ }
1515
+ if (newGrid.length == 1) {
1516
+ seriesArr.push({
1517
+ name: "a",
1518
+ xAxisIndex: 0,
1519
+ yAxisIndex: 0,
1520
+ data:
1521
+ props.chartOption.series.length == 0
1522
+ ? seriesEmptyArray
1523
+ : newTimeArr.map((item) => [item, undefined]),
1524
+ type: "line",
1525
+ z: 9,
1526
+ zlevel: 9,
1527
+ });
1528
+ } else {
1529
+ seriesArr.push(
1530
+ {
1531
+ name: "a",
1532
+ xAxisIndex: 0,
1533
+ yAxisIndex: 0,
1534
+ data:
1535
+ props.chartOption.series.length == 0
1536
+ ? seriesEmptyArray
1537
+ : newTimeArr.map((item) => [item, undefined]),
1538
+ type: "line",
1539
+ z: 9,
1540
+ zlevel: 9,
1541
+ },
1542
+ {
1543
+ name: "b",
1544
+ xAxisIndex: 1,
1545
+ yAxisIndex: newYAxis.findIndex((it) => it.gridIndex == 1),
1546
+ data:
1547
+ props.chartOption.series.length == 0
1548
+ ? seriesEmptyArray
1549
+ : newTimeArr.map((item) => [item, undefined]),
1550
+ type: "line",
1551
+ z: 9,
1552
+ zlevel: 9,
1553
+ }
1554
+ );
1555
+ }
1556
+ //根据图例高度来改变图表距离上边距的高度(图表的上边距与下边距定死只能通过图例高度来改变)
1557
+
1558
+ if (newGrid.length == 1) {
1559
+ newGrid.forEach((item, index) => {
1560
+ item.top = item.newTop ? item.newTop : 10;
1561
+ item.bottom = item.newBottom ? item.newBottom : props.chartOption.xAxis[index].name ? 40 : 20;
1562
+ });
1563
+ } else if (newGrid.length == 2) {
1564
+ newGrid.forEach((item, index) => {
1565
+ if (index == 0) {
1566
+ item.top = 10;
1567
+ item.height = props.chartOption.isTwoXAxis ? "48%" : "26%";
1568
+ } else if (index == 1) {
1569
+ item.top = props.chartOption.isTwoXAxis ? "52%" : "30%";
1570
+ item.bottom = props.chartOption.xAxis[index].name ? 40 : 20;
1571
+ }
1572
+ });
1573
+ } else if (newGrid.length == 3) {
1574
+ newGrid.forEach((item, index) => {
1575
+ if (index == 0) {
1576
+ item.top = 10;
1577
+ item.height = "26%";
1578
+ } else if (index == 1) {
1579
+ item.top = "30%";
1580
+ item.bottom = 40;
1581
+ } else if (index == 2) {
1582
+ item.top = "30%";
1583
+ item.bottom = 40;
1584
+ }
1585
+ });
1586
+ }
1587
+ option.value = {
1588
+ animation: true, // 将 animation 设置为 false 关闭动画效果
1589
+ tooltip: {
1590
+ show: props.chartOption.isTooltipItem || props.chartOption.tooltipShow == false ? false : true,
1591
+ hideDelay: 0,
1592
+ triggerOn: 'mousemove',
1593
+ trigger: props.chartOption.tooltipType == "1" ? "item" : "axis",
1594
+ axisPointer: {
1595
+ animation: false,
1596
+ animationDuration: 1000, // 初始动画时长
1597
+ animationDurationUpdate: 200, // 数据更新动画的时长
1598
+ },
1599
+ formatter: function (params) {
1600
+ if (props.chartOption.tooltipType == "1") {
1601
+ if (params.componentSubType == "boxplot") {
1602
+ let unit = seriesDatas[0] ? seriesDatas[0].unit : "";
1603
+ let str = params.name + "<br/>";
1604
+ str += `<div style='padding-right:8px'>
1605
+ <div style='display:flex;flex-direction: column;'>
1606
+ <div>${params.marker}\t${params.seriesName}</div>
1607
+ <div style='display:flex;align-items: center;margin-left: 18px'>
1608
+ <div style='margin-right:5px;'>最大:${params.value[4] ? params.value[4] : "--"
1609
+ }</div>
1610
+ <div style='width:30px'>${unit}</div>
1611
+ </div>
1612
+ <div style='display:flex;align-items: center;margin-left: 18px'>
1613
+ <div style='margin-right:5px;'>平均:${params.value[3] ? params.value[3] : "--"
1614
+ }</div>
1615
+ <div style='width:30px'>${unit}</div>
1616
+ </div>
1617
+ <div style='display:flex;align-items: center;margin-left: 18px'>
1618
+ <div style='margin-right:5px;'>最小:${params.value[2] ? params.value[2] : "--"
1619
+ }</div>
1620
+ <div style='width:30px'>${unit}</div>
1621
+ </div>
1622
+ </div>
1623
+ </div>`;
1624
+ return str;
1625
+ }
1626
+ } else if (props.chartOption.tooltipType == "2" || props.chartOption.tooltipType == "4") {
1627
+ let str = "";
1628
+ seriesDatas.forEach((item) => {
1629
+ let obj = params.find((it) => it.seriesName == item.name);
1630
+ if (obj) {
1631
+ let t = obj.axisId;
1632
+ let regExp = /[\u4e00-\u9fa5]+|\([^)]+\)/g;
1633
+ let xMatches = t.match(regExp);
1634
+ let xName = xMatches[0];
1635
+ let xUnit = xMatches[1] ? xMatches[1].replace(/[\(\)]/g, "") : xMatches[0];
1636
+
1637
+ let yMatches = props.chartOption.yAxis[0].name.match(regExp);
1638
+ let yName = yMatches[0]
1639
+ let yUnit = yMatches[1] ? yMatches[1].replace(/[\(\)]/g, "") : yMatches[0];
1640
+ if (props.chartOption.tooltipType == "4") {
1641
+ str += `<div style='font-weight: bold;color: ${item.color};'>${obj.seriesName}</div>`
1642
+ }
1643
+ str += `<div style='padding-right:8px'>
1644
+ <div style='display:flex;align-items: center;justify-content: space-between'>
1645
+ <div style='margin-right:8px;'>${yName}</div>
1646
+ <div style='display:flex;align-items: center;'>
1647
+ <div style='margin-right:5px;'>${obj.value[1] || obj.value[1] === 0 ? obj.value[1] : "--"
1648
+ }</div>
1649
+ <div style='width:30px'>${yUnit ? yUnit : ""}</div>
1650
+ </div>
1651
+ </div>
1652
+ <div style='display:flex;align-items: center;justify-content: space-between'>
1653
+ <div style='margin-right:8px;'>${xName}</div>
1654
+ <div style='display:flex;align-items: center;'>
1655
+ <div style='margin-right:5px;'>${obj.value[0] || obj.value[0] === 0 ? obj.value[0] : "--"
1656
+ }</div>
1657
+ <div style='width:30px'>${xUnit ? xUnit : ""
1658
+ }</div>
1659
+ </div>
1660
+ </div>
1661
+ </div>`;
1662
+ }
1663
+ });
1664
+ return str;
1665
+ } else if (props.chartOption.tooltipType == "3") {
1666
+ // 使用正则表达式和 replace() 方法移除数字
1667
+ let arr = [];
1668
+ params.forEach((item) => {
1669
+ arr.push(item.seriesName.replace(/\d+/g, ""));
1670
+ });
1671
+ // 使用 reduce() 方法和对象进行字符计数
1672
+ let char = "预报潮位";
1673
+ let str = params[0].value[0] + "<br/>";
1674
+ let num = 0;
1675
+ let html = "";
1676
+ seriesDatas.forEach((item, index) => {
1677
+ let obj = params.find((it) => it.seriesName == item.name);
1678
+ let text = "";
1679
+ if (item.name.includes(char)) {
1680
+ text = props.chartOption.plan[num];
1681
+ num++;
1682
+ if (seriesDatas.find((item) => item.name == "预报潮位1")) {
1683
+ html = `<div>${text}</div>`;
1684
+ }
1685
+ } else {
1686
+ html = "";
1687
+ }
1688
+ if (obj) {
1689
+ let htmlStr = "";
1690
+ if (obj.value[1]) {
1691
+ htmlStr = `<div style='padding-right:8px'>
1692
+ ${html}
1693
+ <div style='display:flex;align-items: center;justify-content: space-between'>
1694
+ <div style='margin-right:8px;'>${obj.marker
1695
+ }\t${obj.seriesName.replace(/\d+/g, "")}</div>
1696
+ <div style='display:flex;align-items: center;'>
1697
+ <div style='margin-right:5px;'>${obj.value[1] ? obj.value[1] : "--"
1698
+ }</div>
1699
+ <div style='width:30px'>${item.unit ? item.unit : ""}</div>
1700
+ </div>
1701
+ </div>
1702
+ </div>`;
1703
+ }
1704
+ str += htmlStr;
1705
+ }
1706
+ });
1707
+ return str;
1708
+ } else {
1709
+ let str = "";
1710
+ if (props.chartOption.tooltipNameTimeType) {
1711
+ if (Array.isArray(params[0].value)) {
1712
+ str =
1713
+ dayjs(params[0].value[0]).format(
1714
+ props.chartOption.tooltipNameTimeType
1715
+ ) + "<br/>";
1716
+ } else {
1717
+ str =
1718
+ dayjs(params[0].name).format(
1719
+ props.chartOption.tooltipNameTimeType
1720
+ ) + "<br/>";
1721
+ }
1722
+ } else {
1723
+ if (Array.isArray(params[0].value)) {
1724
+ // 对特殊字符进行 HTML 转义,防止被解析为 HTML 标签
1725
+ const xAxisValue = String(params[0].value[0])
1726
+ .replace(/&/g, '&amp;')
1727
+ .replace(/</g, '&lt;')
1728
+ .replace(/>/g, '&gt;');
1729
+ str = xAxisValue + "<br/>";
1730
+ } else {
1731
+ str = params[0].name + "<br/>";
1732
+ }
1733
+ }
1734
+ seriesDatas.forEach((item) => {
1735
+ let obj = params.find((it) => it.seriesName == item.name);
1736
+ if (obj) {
1737
+ if (Array.isArray(obj.value) && obj.value[2] === true) {
1738
+
1739
+ } else {
1740
+ let seriesName = '';
1741
+ if (item.key) {
1742
+ seriesName = item.key;
1743
+ } else {
1744
+ legendArr.value.forEach((it) => {
1745
+ if (it.name == obj.seriesName) {
1746
+ seriesName = it.key ? it.key : item.name;
1747
+ } else if (it.children) {
1748
+ it.children.forEach((i) => {
1749
+ if (i.name == obj.seriesName) {
1750
+ seriesName = i.key;
1751
+ }
1752
+ });
1753
+ }
1754
+ });
1755
+ }
1756
+ let htmlStr = "";
1757
+ let marker = "";
1758
+ if (
1759
+ obj.marker ==
1760
+ '<span style="display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:transparent;"></span>'
1761
+ ) {
1762
+ marker = `<span style=\"display:inline-block;margin-right:4px;border-radius:10px;width:10px;height:10px;background-color:${legendAllColor[item.name]?.color
1763
+ };\"></span>`;
1764
+ } else {
1765
+ marker = obj.marker;
1766
+ }
1767
+ if (obj.value) {
1768
+ let val = '';
1769
+ if (item.data2) {
1770
+ let newDataObj = item.data2.find(item => item[0] == obj.value[0])
1771
+ val = newDataObj[1]
1772
+ } else {
1773
+ if (Array.isArray(obj.value)) {
1774
+ val = obj.value[1]
1775
+ } else {
1776
+ val = obj.value
1777
+ }
1778
+ }
1779
+ if (JSON.stringify(krData) != "{}" && obj.seriesName == "库容") {
1780
+ val = krData[params[0].value[0]];
1781
+ } else if (JSON.stringify(krData2) != "{}" && obj.seriesName == "5分钟库容") {
1782
+ val = krData2[params[0].value[0]];
1783
+ }
1784
+ htmlStr = `<div style='padding-right:8px'>
1785
+ <div style='display:flex;align-items: center;justify-content: space-between'>
1786
+ <div style='margin-right:8px;'>${marker}\t${seriesName ? seriesName : obj.seriesName
1787
+ }</div>
1788
+ <div style='display:flex;align-items: center;'>
1789
+ <div style='margin-right:5px;'>${val || val === 0 ? val : '--'}</div>
1790
+ <div style='width:30px'>${item.unit ? item.unit : ""}</div>
1791
+ </div>
1792
+ </div>
1793
+ </div>`;
1794
+ }
1795
+ str += htmlStr;
1796
+ }
1797
+ }
1798
+ });
1799
+ return str;
1800
+ }
1801
+ },
1802
+ },
1803
+ legend: {
1804
+ show: false,
1805
+ selected: selected,
1806
+ },
1807
+ grid: newGrid,
1808
+ axisPointer: {
1809
+ link: {
1810
+ xAxisIndex: "all",
1811
+ },
1812
+ },
1813
+ xAxis: newXAxis,
1814
+ yAxis: newYAxis,
1815
+ dataZoom: [
1816
+ {
1817
+ type: "inside", //内置滑动,随鼠标滚轮展示
1818
+ xAxisIndex: [0, 1],
1819
+ zoomLock: props.chartOption.zoomLock ? true : false,
1820
+ start: props.chartOption.viewDataRange
1821
+ ? props.chartOption.viewDataRange[0]
1822
+ : 0,
1823
+ end: props.chartOption.viewDataRange
1824
+ ? props.chartOption.viewDataRange[1]
1825
+ : 100,
1826
+ moveOnMouseMove: props.chartOption.series.some(
1827
+ (item) => item.openBarDrag && (item.type == "line" || item.type == "markLine")
1828
+ )
1829
+ ? "ctrl"
1830
+ : true,
1831
+ },
1832
+ ],
1833
+ series: seriesArr,
1834
+ };
1835
+ if (props.chartOption.visualMap) {
1836
+ option.value.visualMap = props.chartOption.visualMap.map((item) => {
1837
+ let seriesObj = seriesArr[item.seriesIndex];
1838
+ let pieces = [],
1839
+ newPieces = [];
1840
+ if (item.step) {
1841
+ newPieces = getMultipleTimeRange(item.pieces, item.step);
1842
+ } else {
1843
+ newPieces = item.pieces;
1844
+ }
1845
+ newPieces.forEach((it, inx) => {
1846
+ let startIndex = new Date(it.startTm).getTime();
1847
+ let endIndex = new Date(it.endTm).getTime();
1848
+ if (inx == 0) {
1849
+ pieces.push(
1850
+ {
1851
+ lt: startIndex,
1852
+ color: seriesObj.itemStyle.color,
1853
+ },
1854
+ {
1855
+ gte: startIndex,
1856
+ lte: endIndex,
1857
+ color: item.color ? item.color : "red",
1858
+ }
1859
+ );
1860
+ } else {
1861
+ pieces.push(
1862
+ {
1863
+ gt: pieces[pieces.length - 1].lte,
1864
+ lt: startIndex,
1865
+ color: seriesObj.itemStyle.color,
1866
+ },
1867
+ {
1868
+ gte: startIndex,
1869
+ lte: endIndex,
1870
+ color: item.color ? item.color : "red",
1871
+ }
1872
+ );
1873
+ }
1874
+ });
1875
+ pieces.push({
1876
+ gt: pieces[pieces.length - 1].lte,
1877
+ color: seriesObj.itemStyle.color,
1878
+ });
1879
+ return {
1880
+ show: false,
1881
+ dimension: item.dimension ? item.dimension : 0,
1882
+ seriesIndex: item.seriesIndex,
1883
+ pieces: pieces,
1884
+ };
1885
+ });
1886
+ }
1887
+ if (JSON.stringify(dataZoom) != "{}") {
1888
+ option.value.dataZoom[0] = dataZoom;
1889
+ }
1890
+ console.log(option.value);
1891
+ myChart.setOption(option.value, true);
1892
+ myChart.getOption().series.map((item) => {
1893
+ if (item.markPoint) {
1894
+ markPointList[item.name] = item.markPoint;
1895
+ }
1896
+ });
1897
+ if (props.chartOption.isTooltipItem) {
1898
+ let customTooltipDom = document.createElement("div");
1899
+ customTooltipDom.className = "line-name-tooltip-style";
1900
+ chartDom.appendChild(customTooltipDom);
1901
+ myChart.on("mouseover", function (params) {
1902
+ // 1. 仅在需要显示的场景下创建 DOM(如 hover 到系列数据时,可根据需求调整条件)
1903
+ if (params.componentType === "series" && params.seriesType === "line") {
1904
+ customTooltipDom.innerText = `${params.seriesName}`;
1905
+ // 设置 DOM 位置
1906
+ customTooltipDom.style.left = `${params.event.offsetX}px`;
1907
+ customTooltipDom.style.top = `${params.event.offsetY}px`;
1908
+ // 显示 DOM(修改 opacity 触发过渡动画)
1909
+ customTooltipDom.style.opacity = "1";
1910
+ } else {
1911
+ if (customTooltipDom) {
1912
+ customTooltipDom.style.opacity = "0";
1913
+ }
1914
+ }
1915
+ })
1916
+ myChart.on("mouseout", function (params) {
1917
+ if (customTooltipDom) {
1918
+ customTooltipDom.style.opacity = "0";
1919
+ }
1920
+ })
1921
+ } else {
1922
+ const tooltips = chartDom.querySelectorAll('.line-name-tooltip-style');
1923
+ if (tooltips.length > 0) {
1924
+ tooltips.forEach(item => {
1925
+ item.remove();
1926
+ });
1927
+ }
1928
+ }
1929
+ //点击做标记
1930
+ myChart.off("click");
1931
+ myChart.on("click", (params) => {
1932
+ if (seriesDatas.find((item) => item.name == params.seriesName)) {
1933
+ let seriesObj = seriesDatas.find(
1934
+ (item) => item.name == params.seriesName
1935
+ );
1936
+ if (params.seriesType === "line") {
1937
+ const pointData = params.data;
1938
+ const seriesIndex = params.seriesIndex;
1939
+ let markData = myChart.getOption().series[seriesIndex].markPoint
1940
+ ? myChart.getOption().series[seriesIndex].markPoint.data
1941
+ : [];
1942
+ let names = markData
1943
+ .filter((it) => it.name != "Max" && it.name != "Min")
1944
+ .map((it) => it.coord[0]);
1945
+ let data = [];
1946
+
1947
+ let offset;
1948
+ timeArr.forEach((item, index) => {
1949
+ if (dayjs(item).isValid() && item == pointData[0]) {
1950
+ if (index >= (timeArr.length / 5) * 4) {
1951
+ offset = [-200, 0];
1952
+ } else if (index >= (timeArr.length / 5) * 3) {
1953
+ offset = [-150, 0];
1954
+ } else if (index >= (timeArr.length / 5) * 2) {
1955
+ offset = [-100, 0];
1956
+ } else if (index >= (timeArr.length / 5) * 1) {
1957
+ offset = [-50, 0];
1958
+ } else if (index >= 0) {
1959
+ offset = [0, 0];
1960
+ }
1961
+ }
1962
+ });
1963
+ if (!names.includes(params.value[0])) {
1964
+ data = [
1965
+ ...markData,
1966
+ {
1967
+ coord: pointData,
1968
+ name: `${pointData[0]}\n${params.seriesName}: ${pointData[1]} ${seriesObj.unit}`,
1969
+ label: {
1970
+ offset: offset ? offset : [-120, 0],
1971
+ },
1972
+ },
1973
+ ];
1974
+ } else {
1975
+ data = markData.filter(
1976
+ (it) =>
1977
+ it.name == "Max" ||
1978
+ it.name == "Min" ||
1979
+ it.coord[0] != params.value[0]
1980
+ );
1981
+ }
1982
+ option.value.series[seriesIndex].markPoint = {
1983
+ symbol: "pin",
1984
+ symbolSize: 20,
1985
+ label: {
1986
+ show: true,
1987
+ position: "top",
1988
+ align: "left",
1989
+ fontSize: 16,
1990
+ backgroundColor: seriesObj.backgroundColor
1991
+ ? seriesObj.backgroundColor
1992
+ : legendAllColor[seriesObj.name]
1993
+ ? legendAllColor[seriesObj.name].color
1994
+ : seriesObj.color,
1995
+ borderRadius: 6,
1996
+ shadowColor: "#666666",
1997
+ shadowBlur: 5,
1998
+ shadowOffsetX: 3,
1999
+ shadowOffsetY: 3,
2000
+ fontWeight: "bold",
2001
+ padding: [4, 4, 4, 4],
2002
+ lineHeight: 30,
2003
+ color: seriesObj.markPointColor ? seriesObj.markPointColor : "#fff",
2004
+ formatter: (par) => {
2005
+ let maxTime = "",
2006
+ tmType = seriesObj.tmType
2007
+ ? seriesObj.tmType
2008
+ : "YYYY-MM-DD HH:mm";
2009
+ if (par.data && par.data.coord && par.data.coord[0]) {
2010
+ maxTime = dayjs(par.data.coord[0]).format(tmType);
2011
+ }
2012
+ let text = "";
2013
+ let value = "";
2014
+ if (par.name == "Max" || par.name == "Min") {
2015
+ if (par.name == "Max") {
2016
+ text = seriesObj.maxText ? seriesObj.maxText : "最大值";
2017
+ if (seriesObj.unit.includes("m³")) {
2018
+ value = par.value ? formatToFlowValue(par.value) : "--";
2019
+ } else if (seriesObj.unit.includes("mm")) {
2020
+ value = par.value ? Number(par.value).toFixed(1) : "--";
2021
+ } else if (seriesObj.unit.includes("m")) {
2022
+ value = par.value ? Number(par.value).toFixed(2) : "--";
2023
+ } else {
2024
+ value = par.value;
2025
+ }
2026
+ if (seriesObj.tmText) {
2027
+ return `${text}: {a0|${value}} ${seriesObj.unit}\n${seriesObj.tmText}: {a1|${maxTime}}`;
2028
+ } else {
2029
+ return `${seriesObj.tmText2 ? seriesObj.tmText2 : "相应时间"
2030
+ }: {a1|${maxTime}}\n${text}: {a0|${value}} ${seriesObj.unit
2031
+ }`;
2032
+ }
2033
+ }
2034
+ } else {
2035
+ return `相应时间: {a1|${dayjs(par.data.coord[0]).format(
2036
+ tmType
2037
+ )}}\n${seriesObj.name}: {a0|${par.data.coord[1]}} ${seriesObj.unit
2038
+ }`;
2039
+ }
2040
+ },
2041
+ rich: {
2042
+ a0: {
2043
+ fontSize: 25,
2044
+ fontFamily: "Times New Roman",
2045
+ },
2046
+ a1: {
2047
+ fontSize: 20,
2048
+ fontFamily: "Times New Roman",
2049
+ },
2050
+ },
2051
+ },
2052
+ data: data,
2053
+ };
2054
+ option.value.dataZoom[0] = { ...myChart.getOption()?.dataZoom[0] };
2055
+ myChart.setOption(option.value, true);
2056
+ myChart.getOption().series.map((item) => {
2057
+ if (item.markPoint) {
2058
+ markPointList[item.name] = item.markPoint;
2059
+ }
2060
+ });
2061
+ }
2062
+ }
2063
+ });
2064
+ // 监听鼠标按下事件
2065
+ myChart.on("mousedown", function (params) {
2066
+ // 手动触发 tooltip 关闭
2067
+ myChart.setOption({
2068
+ tooltip: {
2069
+ show: false
2070
+ }
2071
+ })
2072
+ myChart.dispatchAction({
2073
+ type: "hideTip"
2074
+ });
2075
+ let seriesIndex = params.seriesIndex;
2076
+ let seriesObj = props.chartOption.series[seriesIndex];
2077
+ let stepTM = seriesObj.stepTM ? seriesObj.stepTM : 60;
2078
+ let ksTime = '', jsTime = '', diffHour = '';
2079
+ if (seriesObj.openBarDrag) {
2080
+ let newSeriesData = {}, trackTimes = {}, yObj = props.chartOption.yAxis[seriesObj.yAxisIndex], newSeriesArr = [];
2081
+ if (params.componentType == "markLine" && seriesObj.data.name == "xAxis") {
2082
+ newSeriesArr = option.value.series.map((item, index) => {
2083
+ if (item.name == '开始' || item.name == '结束') {
2084
+ return JSON.parse(JSON.stringify(item))
2085
+ } else {
2086
+ return {}
2087
+ }
2088
+ })
2089
+ } else {
2090
+ newSeriesArr = option.value.series.map((item, index) => {
2091
+ if (index == seriesIndex) {
2092
+ return {
2093
+ data: JSON.parse(JSON.stringify(item.data))
2094
+ }
2095
+ } else {
2096
+ return {}
2097
+ }
2098
+ })
2099
+ }
2100
+ let lastXValue, lastYValue, lastXValue2;
2101
+ if (props.chartOption.fixedTimePeriod) {
2102
+ ksTime = props.chartOption.series.find(item => item.name == '开始').data.value
2103
+ jsTime = props.chartOption.series.find(item => item.name == '结束').data.value
2104
+ diffHour = dayjs(jsTime).diff(dayjs(ksTime), 'hour')
2105
+ }
2106
+ myChart.getZr().off("mousemove");
2107
+ myChart.getZr().off("mouseup");
2108
+ myChart.getZr().on("mousemove", function (event) {
2109
+ if (params.componentType == "markLine" && seriesObj.data.name == "xAxis") {
2110
+ let valueDelta = myChart.convertFromPixel(
2111
+ { xAxisIndex: seriesObj.xAxisIndex },
2112
+ event.offsetX
2113
+ );
2114
+ let newTime = dayjs(valueDelta).format("YYYY-MM-DD HH:00")
2115
+ if (newTime !== lastXValue) {
2116
+ const time1 = dayjs(newTime);
2117
+ const time2 = dayjs(timeArr[timeArr.length - 1]);
2118
+ const time3 = sectionStartTime ? dayjs(sectionStartTime) : '';
2119
+ if (time1.isAfter(time2) || time1.isBefore(time3)) {
2120
+ return;
2121
+ }
2122
+ if (props.chartOption.fixedTimePeriod) {
2123
+ if (seriesObj.name == '开始') {
2124
+ lastXValue2 = dayjs(newTime).add(diffHour, 'hours').format("YYYY-MM-DD HH:00")
2125
+ } else if (seriesObj.name == '结束') {
2126
+ lastXValue2 = dayjs(newTime).add(-diffHour, 'hours').format("YYYY-MM-DD HH:00")
2127
+ }
2128
+ if (seriesObj.name == '开始' && dayjs(lastXValue2).isAfter(time2)) {
2129
+ return;
2130
+ } else if (seriesObj.name == '结束' && dayjs(lastXValue2).isBefore(time3)) {
2131
+ return;
2132
+ }
2133
+ newSeriesArr.forEach(item => {
2134
+ if (seriesObj.name == '开始') {
2135
+ if (item.name == '开始') {
2136
+ item.markLine.data[0].xAxis = newTime
2137
+
2138
+ item.markArea.data[0][0].xAxis = newTime
2139
+ item.markArea.data[0][1].xAxis = lastXValue2
2140
+ } else if (item.name == '结束') {
2141
+ item.markLine.data[0].xAxis = lastXValue2
2142
+ }
2143
+ } else if (seriesObj.name == '结束') {
2144
+ if (item.name == '开始') {
2145
+ item.markLine.data[0].xAxis = lastXValue2
2146
+
2147
+ item.markArea.data[0][0].xAxis = lastXValue2
2148
+ item.markArea.data[0][1].xAxis = newTime
2149
+ } else if (item.name == '结束') {
2150
+ item.markLine.data[0].xAxis = newTime
2151
+ }
2152
+ }
2153
+ })
2154
+ } else {
2155
+ newSeriesArr.forEach(item => {
2156
+ if (seriesObj.name == '开始') {
2157
+ if (item.name == '开始') {
2158
+ item.markLine.data[0].xAxis = newTime
2159
+
2160
+ item.markArea.data[0][0].xAxis = newTime
2161
+ }
2162
+ } else if (seriesObj.name == '结束') {
2163
+ if (item.name == '开始') {
2164
+ item.markArea.data[0][1].xAxis = newTime
2165
+ } else if (item.name == '结束') {
2166
+ item.markLine.data[0].xAxis = newTime
2167
+ }
2168
+ }
2169
+ })
2170
+ }
2171
+ myChart.setOption({
2172
+ series: newSeriesArr
2173
+ }, {
2174
+ notMerge: false,
2175
+ lazyUpdate: true
2176
+ });
2177
+ // 更新记录值
2178
+ lastXValue = newTime;
2179
+ }
2180
+ } else {
2181
+ let [x, y] = myChart.convertFromPixel({ seriesIndex: seriesIndex }, [
2182
+ event.offsetX,
2183
+ event.offsetY,
2184
+ ])
2185
+ if ((dayjs(x).format("YYYY-MM-DD HH:00") !== lastXValue) || (!lastYValue || Math.abs(y - lastYValue) >= 0.5)) {
2186
+ const currentX = dayjs(x).format("YYYY-MM-DD HH:00");
2187
+ trackTimes[currentX] = y;
2188
+
2189
+ // 优化数据处理,使用 Map 或 Set 提高查找效率
2190
+ let trackTimesKeys = Object.keys(trackTimes);
2191
+ let trackTimesSet = new Set(trackTimesKeys);
2192
+
2193
+ newSeriesArr[seriesIndex].data.forEach((item) => {
2194
+ if (trackTimesSet.has(item[0])) {
2195
+ item[1] = trackTimes[item[0]];
2196
+ }
2197
+ });
2198
+
2199
+ let times = getTimeRange(
2200
+ new Date(trackTimesKeys[0]),
2201
+ new Date(trackTimesKeys[trackTimesKeys.length - 1]),
2202
+ stepTM
2203
+ );
2204
+
2205
+ let trackData = Object.entries(trackTimes);
2206
+ let timesSet = new Set(trackTimesKeys);
2207
+ times.forEach((item) => {
2208
+ if (!timesSet.has(item)) {
2209
+ trackData.push(AddDataForAppointTime(trackData, item));
2210
+ }
2211
+ });
2212
+
2213
+ let newTrackTimes = {};
2214
+ trackData.forEach((item) => {
2215
+ newTrackTimes[item[0]] = item[1];
2216
+ });
2217
+ let newTrackTimesKeys = Object.keys(newTrackTimes);
2218
+ let newTrackTimesSet = new Set(newTrackTimesKeys);
2219
+
2220
+ newSeriesArr[seriesIndex].data.forEach((item) => {
2221
+ if (newTrackTimesSet.has(item[0])) {
2222
+ let val = "";
2223
+ if (yObj.name.includes("m³")) {
2224
+ val = formatToFlowValue(newTrackTimes[item[0]]);
2225
+ } else if (yObj.name.includes("mm")) {
2226
+ val = newTrackTimes[item[0]].toFixed(1);
2227
+ } else if (yObj.name.includes("m")) {
2228
+ val = newTrackTimes[item[0]].toFixed(2);
2229
+ }
2230
+ item[1] = val;
2231
+ }
2232
+ });
2233
+
2234
+ myChart.setOption({
2235
+ series: newSeriesArr
2236
+ }, {
2237
+ notMerge: false,
2238
+ lazyUpdate: true
2239
+ });
2240
+
2241
+ // 更新记录值
2242
+ lastXValue = currentX;
2243
+ lastYValue = y
2244
+ }
2245
+ }
2246
+ });
2247
+ // 监听鼠标松开事件
2248
+ myChart.getZr().on("mouseup", function () {
2249
+ myChart.getZr().off("mousemove");
2250
+ myChart.getZr().off("mouseup");
2251
+ if (params.componentType == "markLine" && seriesObj.data.name == "xAxis") {
2252
+ if (lastXValue) {
2253
+ if (lastXValue2) {
2254
+ const time1 = dayjs(timeArr[timeArr.length - 1]);
2255
+ const time2 = sectionStartTime ? dayjs(sectionStartTime) : '';
2256
+ if (seriesObj.name == '开始' && dayjs(lastXValue2).isAfter(time1)) {
2257
+ lastXValue2 = dayjs(lastXValue).add(diffHour, 'hours').format("YYYY-MM-DD HH:00")
2258
+ } else if (seriesObj.name == '结束' && dayjs(lastXValue2).isBefore(time2)) {
2259
+ lastXValue2 = dayjs(lastXValue).add(-diffHour, 'hours').format("YYYY-MM-DD HH:00")
2260
+ }
2261
+ newSeriesData = {
2262
+ name: '开始/结束',
2263
+ value: seriesObj.name == '开始' ? `${lastXValue}/${lastXValue2}` : `${lastXValue2}/${lastXValue}`
2264
+ };
2265
+ } else {
2266
+ newSeriesData = {
2267
+ name: seriesObj.name,
2268
+ value: lastXValue
2269
+ };
2270
+ }
2271
+ }
2272
+ } else {
2273
+ newSeriesData = {
2274
+ name: params.seriesName,
2275
+ data: newSeriesArr[seriesIndex].data
2276
+ };
2277
+ }
2278
+ if (newSeriesData.name) {
2279
+ emit("getNewSeriesData", newSeriesData);
2280
+ }
2281
+ //开启鼠标悬浮时的 tooltip 显示
2282
+ myChart.getZr().on("mousemove", function (par) {
2283
+ // 获取鼠标坐标
2284
+ let x = par.offsetX;
2285
+ let y = par.offsetY;
2286
+ // 手动触发 tooltip 显示
2287
+ myChart.dispatchAction({
2288
+ type: "showTip",
2289
+ x: x,
2290
+ y: y,
2291
+ });
2292
+ });
2293
+ });
2294
+ }
2295
+ });
2296
+ window.onresize = function () {
2297
+ myChart.resize();
2298
+ };
2299
+ };
2300
+ // 当元素宽高发生变化时,触发下面的方法
2301
+ const onResize = (dom) => {
2302
+ nextTick(() => {
2303
+ if (myChart) {
2304
+ myChart.resize();
2305
+ }
2306
+ });
2307
+ };
2308
+ const legendSelect = (name, e) => {
2309
+ myChart.dispatchAction({
2310
+ type: e ? "legendSelect" : "legendUnSelect",
2311
+ // 图例名称
2312
+ name: name,
2313
+ });
2314
+ };
2315
+
2316
+ function isAnnualFirstDay(dateToCheck) {
2317
+ return (
2318
+ dateToCheck.month() === 0 &&
2319
+ dateToCheck.date() === 1 &&
2320
+ dateToCheck.hour() === 0 &&
2321
+ dateToCheck.minute() === 0
2322
+ );
2323
+ }
2324
+
2325
+ function handleContextMenu(event) {
2326
+ event.preventDefault(); // 阻止默认的右键菜单弹出
2327
+
2328
+ // 判断是否存在类名为 chartMenu 的元素
2329
+ let chartMenu = document.querySelector("body .chartMenu");
2330
+
2331
+ // 如果存在,则删除该元素
2332
+ if (chartMenu) {
2333
+ chartMenu.remove();
2334
+ }
2335
+
2336
+ let x = event.pageX; // 获取鼠标点击位置的横坐标
2337
+ let y = event.pageY; // 获取鼠标点击位置的纵坐标
2338
+
2339
+ // 创建并显示自定义菜单
2340
+ let menu = document.createElement("ul");
2341
+ menu.style.position = "absolute";
2342
+ menu.style.left = x + "px";
2343
+ menu.style.top = y + "px";
2344
+ menu.className = "chartMenu";
2345
+
2346
+ // 添加菜单项
2347
+ let item1 = document.createElement("li");
2348
+ item1.style.cursor = "pointer";
2349
+ item1.innerHTML = `<div><img src='${restorePng}'><span>还原缩放</span></div>`;
2350
+ menu.appendChild(item1);
2351
+
2352
+ let item2 = document.createElement("li");
2353
+ item2.style.cursor = "pointer";
2354
+ item2.innerHTML = `<div><img src='${copyPng}'><span>复制图片</span></div>`;
2355
+ menu.appendChild(item2);
2356
+
2357
+ let item3 = document.createElement("li");
2358
+ item3.style.cursor = "pointer";
2359
+ item3.innerHTML = `<div><img src='${exportPng}'><span>导出图片</span></div>`;
2360
+ menu.appendChild(item3);
2361
+
2362
+ // 添加点击菜单项的事件处理
2363
+ item1.addEventListener("click", () => {
2364
+ myChart.dispatchAction({
2365
+ type: "dataZoom",
2366
+ dataZoomIndex: 0,
2367
+ start: 0,
2368
+ end: 100,
2369
+ });
2370
+ });
2371
+
2372
+ item2.addEventListener("click", () => {
2373
+ html2canvas(chartBox.value, {
2374
+ // dpi: 300, // 精度,处理模糊问题
2375
+ useCORS: true, // 允许跨域
2376
+ scale: 2, // 当前显示设备的物理像素分辨率与CSS像素分辨率之比
2377
+ width: chartBox.value.offsetWidth, //图片宽度可自行设置
2378
+ height: chartBox.value.offsetHeight + 50, //图片高度可自行设置
2379
+ backgroundColor: "#fff", //图片背景色
2380
+ allowTaint: true, //若是 useCORS:true,且同时设置allowTaint为true,仍然会认为画布已被污染而不可用。
2381
+ removeContainer: true, // 清除临时创建的克隆dom元素
2382
+ // eslint-disable-next-line space-before-function-paren
2383
+ }).then((canvas) => {
2384
+ // 获取图像数据URL
2385
+ const imageDataURL = canvas.toDataURL("image/png");
2386
+ const file = base64toFile(imageDataURL, "图片"); // 转file
2387
+ copyFile(file);
2388
+ ElMessage.success("复制成功");
2389
+ });
2390
+ });
2391
+
2392
+ item3.addEventListener("click", () => {
2393
+ exportChartPng();
2394
+ });
2395
+
2396
+ // 将菜单添加到页面中
2397
+ document.body.appendChild(menu);
2398
+ // 点击页面其他地方时,隐藏菜单
2399
+ document.addEventListener("click", () => {
2400
+ if (menu.parentNode) {
2401
+ document.body.removeChild(menu);
2402
+ }
2403
+ });
2404
+ }
2405
+ const base64toFile = (dataBase64, filename = "file") => {
2406
+ const arr = dataBase64.split(",");
2407
+ const mime = arr[0].match(/:(.*?);/)[1]; // 获取file文件流的type名称
2408
+ const suffix = mime.split("/")[1]; // 获取文件类型
2409
+ const bstr = window.atob(arr[1]);
2410
+ let n = bstr.length;
2411
+ const u8arr = new Uint8Array(n);
2412
+ while (n--) {
2413
+ u8arr[n] = bstr.charCodeAt(n);
2414
+ }
2415
+ return new File([u8arr], `${filename}.${suffix}`, {
2416
+ type: mime,
2417
+ });
2418
+ };
2419
+ const copyFile = (file) => {
2420
+ const reader = new FileReader();
2421
+ reader.onload = (e) => {
2422
+ const newFile = e.target.result.toString();
2423
+ const img = new Image();
2424
+ img.src = newFile;
2425
+ img.onload = () => {
2426
+ //blob对象在写入时可能会出现格式出题,所以先将图片解析成base64,在转换成blob对象写入,减少后面不必要的麻烦
2427
+ let base64 = imageBase64(img);
2428
+ let blob = base64ToBlob(
2429
+ base64.replace("data:image/png;base64,", ""),
2430
+ "image/png",
2431
+ 512
2432
+ );
2433
+ navigator.clipboard.write([
2434
+ new ClipboardItem({
2435
+ "image/png": blob,
2436
+ }),
2437
+ ]);
2438
+ };
2439
+ };
2440
+ reader.readAsDataURL(file);
2441
+ };
2442
+ //先将图片解析成base64
2443
+ const imageBase64 = (img) => {
2444
+ let canvas = document.createElement("canvas");
2445
+ canvas.width = img.width;
2446
+ canvas.height = img.height;
2447
+ let ctx = canvas.getContext("2d");
2448
+ ctx.drawImage(img, 0, 0, img.width, img.height);
2449
+ let dataURL = canvas.toDataURL("image/png");
2450
+ return dataURL;
2451
+ };
2452
+ // 再转成blod // 注意base64里面的特殊符号 在atob的时候不能识别“,”
2453
+ const base64ToBlob = (b64Data, contentType, sliceSize) => {
2454
+ contentType = contentType || "";
2455
+ sliceSize = sliceSize || 512;
2456
+ let byteCharacters = window.atob(b64Data);
2457
+ // var byteCharacters = b64Data;
2458
+ // 该atob函数将base64编码的字符串解码为一个新字符串,其中包含二进制数据每个字节的字符。
2459
+ let byteArrays = [];
2460
+ for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
2461
+ let slice = byteCharacters.slice(offset, offset + sliceSize);
2462
+ let byteNumbers = new Array(slice.length);
2463
+ // 通过使用.charCodeAt字符串中每个字符的方法应用它来创建一个新的数组。
2464
+ for (let i = 0; i < slice.length; i++) {
2465
+ byteNumbers[i] = slice.charCodeAt(i);
2466
+ }
2467
+ // 将这个数组转换为实际类型的数组,方法是将其传递给Uint8Array构造函数。
2468
+ let byteArray = new Uint8Array(byteNumbers);
2469
+ byteArrays.push(byteArray);
2470
+ }
2471
+ // 创建一个blob:包含这条数据的URL,返回去。
2472
+ let blob = new Blob(byteArrays, { type: contentType });
2473
+ return blob;
2474
+ };
2475
+
2476
+ const exportChartPng = () => {
2477
+ html2canvas(chartBox.value, {
2478
+ // dpi: 300, // 精度,处理模糊问题
2479
+ useCORS: true, // 允许跨域
2480
+ scale: 1, // 当前显示设备的物理像素分辨率与CSS像素分辨率之比
2481
+ width: chartBox.value.offsetWidth, //图片宽度可自行设置
2482
+ height: chartBox.value.offsetHeight + 50, //图片高度可自行设置
2483
+ backgroundColor: "#fff", //图片背景色
2484
+ allowTaint: true, //若是 useCORS:true,且同时设置allowTaint为true,仍然会认为画布已被污染而不可用。
2485
+ removeContainer: true, // 清除临时创建的克隆dom元素
2486
+ // eslint-disable-next-line space-before-function-paren
2487
+ }).then((canvas) => {
2488
+ // 获取图像数据URL
2489
+ const imageDataURL = canvas.toDataURL("image/png");
2490
+
2491
+ // 创建下载链接
2492
+ const link = document.createElement("a");
2493
+ link.href = imageDataURL;
2494
+ link.download = props.chartOption.title;
2495
+
2496
+ // 模拟点击链接进行下载
2497
+ link.click();
2498
+ });
2499
+ };
2500
+ const myLegend = ref();
2501
+ function getLegendBoxHeight() {
2502
+ if (myLegend.value) {
2503
+ return myLegend.value.offsetHeight;
2504
+ } else {
2505
+ return 0;
2506
+ }
2507
+ }
2508
+ function cotwlTransformation(val, i) {
2509
+ return new Promise((resolve) => {
2510
+ GetCotwlTransformation({
2511
+ STCD: props.chartOption.stationCode,
2512
+ rzw: val,
2513
+ rzwType: "rz",
2514
+ }).then((res) => {
2515
+ if (res.statusCode == 200 && res.data) {
2516
+ resolve(res.data);
2517
+ } else {
2518
+ resolve(i * 1000);
2519
+ }
2520
+ });
2521
+ });
2522
+ }
2523
+
2524
+ //曲线插值
2525
+ function AddDataForAppointTime(data, appointTime) {
2526
+ if (data.length > 0) {
2527
+ let beforeData = data.filter((item) =>
2528
+ dayjs(item[0]).isBefore(dayjs(appointTime))
2529
+ );
2530
+ let afterData = data.filter((item) =>
2531
+ dayjs(item[0]).isAfter(dayjs(appointTime))
2532
+ );
2533
+ if (beforeData.length == 0) {
2534
+ return [appointTime, afterData[0][1]];
2535
+ } else if (afterData.length == 0) {
2536
+ return [appointTime, beforeData[beforeData.length - 1][1]];
2537
+ } else {
2538
+ let secondsDifference = dayjs(appointTime).diff(
2539
+ dayjs(beforeData[beforeData.length - 1][0]),
2540
+ "seconds"
2541
+ );
2542
+ let diffValue = afterData[0][1] - beforeData[beforeData.length - 1][1];
2543
+ let diffTmValue = dayjs(afterData[0][0]).diff(
2544
+ dayjs(beforeData[beforeData.length - 1][0]),
2545
+ "seconds"
2546
+ );
2547
+ let val =
2548
+ (secondsDifference * diffValue) / diffTmValue +
2549
+ beforeData[beforeData.length - 1][1];
2550
+ return [appointTime, Number(val)];
2551
+ }
2552
+ }
2553
+ }
2554
+
2555
+ function formatSecondTime(time2) {
2556
+ let time1 = props.chartOption.series.find(item => item.name == '开始')?.data.value
2557
+ // 解析时间
2558
+ const d1 = dayjs(time1);
2559
+ const d2 = dayjs(time2);
2560
+
2561
+ // 检查年是否相同
2562
+ const isSameYear = d1.year() === d2.year();
2563
+ // 检查月是否相同(考虑年份相同的前提)
2564
+ const isSameMonth = isSameYear && d1.month() === d2.month();
2565
+
2566
+ if (isSameMonth) {
2567
+ // 年月都相同 - 返回 日 时间
2568
+ return d2.format('DD HH:mm');
2569
+ } else if (isSameYear) {
2570
+ // 年相同月不同 - 返回 月-日 时间
2571
+ return d2.format('MM-DD HH:mm');
2572
+ } else {
2573
+ // 年月都不同 - 返回 年-月-日 时间
2574
+ return d2.format('YYYY-MM-DD HH:mm');
2575
+ }
2576
+ }
2577
+
2578
+ defineExpose({
2579
+ getLegendBoxHeight,
2580
+ onChange,
2581
+ });
2582
+ </script>
2583
+
2584
+ <style scoped lang="scss">
2585
+ @import "./index.scss";
2586
+ </style>