@fc-plot/ts-graph 0.16.3 → 0.17.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.
package/src/index.ts CHANGED
@@ -1,18 +1,36 @@
1
- import * as d3 from 'd3';
2
- import { assign, merge, debounce, throttle, uniqueId, isEmpty, find, sortBy } from 'lodash';
3
- import { addListener, removeListener } from 'resize-detector';
4
- import EventEmitter from 'events';
5
- import XAxis from './xAxis';
6
- import YAxis from './yAxis';
7
- import Tooltip from './tooltip';
8
- import Line from './line';
9
- import Bar from './bar';
10
- import Zoom from './zoom';
11
- import Legend from './legend';
12
- import Shapes from './shapes';
13
- import { TsGraphType, Options, EventPosition, Transform, Serie, SerieDataItem, XScales, YScales } from './interface';
14
- import { getTouchPosition, getYkeyValue } from './utils';
15
- import '../assets/style.less';
1
+ import * as d3 from "d3";
2
+ import {
3
+ assign,
4
+ merge,
5
+ debounce,
6
+ throttle,
7
+ uniqueId,
8
+ isEmpty,
9
+ find,
10
+ sortBy,
11
+ } from "lodash";
12
+ import { addListener, removeListener } from "resize-detector";
13
+ import EventEmitter from "events";
14
+ import XAxis from "./xAxis";
15
+ import YAxis from "./yAxis";
16
+ import Tooltip from "./tooltip";
17
+ import Line from "./line";
18
+ import Bar from "./bar";
19
+ import Zoom from "./zoom";
20
+ import Legend from "./legend";
21
+ import Shapes from "./shapes";
22
+ import {
23
+ TsGraphType,
24
+ Options,
25
+ EventPosition,
26
+ Transform,
27
+ Serie,
28
+ SerieDataItem,
29
+ XScales,
30
+ YScales,
31
+ } from "./interface";
32
+ import { getTouchPosition, getYkeyValue } from "./utils";
33
+ import "../assets/style.less";
16
34
 
17
35
  const eventEmitter = new EventEmitter();
18
36
  export default class TsGraph {
@@ -39,11 +57,28 @@ export default class TsGraph {
39
57
  ratio: window.devicePixelRatio || 1,
40
58
  xkey: 0,
41
59
  ykey: 1,
42
- oykey: '__originValue', // stack area 用于缓存原始值
43
- timestamp: 'x',
60
+ ykey2: 2,
61
+ oykey: "__originValue", // stack area 用于缓存原始值
62
+ timestamp: "x",
44
63
  chart: {
45
- id: uniqueId('ts-graph-'),
46
- colors: ['#3399CC', '#CC9933', '#9966CC', '#66CC66', '#CC3333', '#99CCCC', '#CCCC66', '#CC99CC', '#99CC99', '#CC6666', '#336699', '#996633', '#993399', '#339966', '#993333'],
64
+ id: uniqueId("ts-graph-"),
65
+ colors: [
66
+ "#3399CC",
67
+ "#CC9933",
68
+ "#9966CC",
69
+ "#66CC66",
70
+ "#CC3333",
71
+ "#99CCCC",
72
+ "#CCCC66",
73
+ "#CC99CC",
74
+ "#99CC99",
75
+ "#CC6666",
76
+ "#336699",
77
+ "#996633",
78
+ "#993399",
79
+ "#339966",
80
+ "#993333",
81
+ ],
47
82
  width: userOptions.chart.renderTo.offsetWidth,
48
83
  height: userOptions.chart.renderTo.offsetHeight || 350,
49
84
  marginTop: 10,
@@ -53,13 +88,13 @@ export default class TsGraph {
53
88
  },
54
89
  xAxis: {
55
90
  visible: true,
56
- lineColor: '#ccc',
91
+ lineColor: "#ccc",
57
92
  lineWidth: 1,
58
93
  tickLength: 5,
59
94
  tickpadding: 5,
60
- tickColor: '#ccc',
95
+ tickColor: "#ccc",
61
96
  labels: {
62
- color: '#999',
97
+ color: "#999",
63
98
  fontSize: 11,
64
99
  },
65
100
  },
@@ -67,18 +102,18 @@ export default class TsGraph {
67
102
  // min: -Infinity,
68
103
  // max: Infinity,
69
104
  visible: true,
70
- lineColor: '#ccc',
105
+ lineColor: "#ccc",
71
106
  lineWidth: 1,
72
107
  tickLength: 5,
73
108
  tickpadding: 5,
74
- tickColor: '#ccc',
75
- gridLineColor: '#efefef',
109
+ tickColor: "#ccc",
110
+ gridLineColor: "#efefef",
76
111
  labels: {
77
- color: '#999',
112
+ color: "#999",
78
113
  fontSize: 11,
79
114
  },
80
115
  },
81
- type: 'line',
116
+ type: "line",
82
117
  line: {
83
118
  enable: true,
84
119
  width: 2,
@@ -99,12 +134,12 @@ export default class TsGraph {
99
134
  shared: true,
100
135
  cascade: false, // tooltip 联动
101
136
  cascadeScope: undefined, // tooltip 联动的范围
102
- timeFormat: '%Y-%m-%d %H:%M:%S',
137
+ timeFormat: "%Y-%m-%d %H:%M:%S",
103
138
  },
104
139
  series: [],
105
140
  legend: {
106
- align: 'center',
107
- verticalAlign: 'top',
141
+ align: "center",
142
+ verticalAlign: "top",
108
143
  enabled: false,
109
144
  },
110
145
  fillNull: undefined,
@@ -130,17 +165,19 @@ export default class TsGraph {
130
165
  this.options.notDisplayedSeries = [];
131
166
  this.options.chart.containerWidth = chart.width;
132
167
  this.options.chart.containerHeight = chart.height;
133
- this.options.chart.width = chart.width - chart.marginLeft - chart.marginRight;
134
- this.options.chart.height = chart.height - chart.marginTop - chart.marginBottom;
168
+ this.options.chart.width =
169
+ chart.width - chart.marginLeft - chart.marginRight;
170
+ this.options.chart.height =
171
+ chart.height - chart.marginTop - chart.marginBottom;
135
172
  this.createContainer();
136
173
  this.createCanvas();
137
174
  this.initSeries();
138
175
  this.initScales();
139
176
  this.initEvent();
140
- if (this.options.type === 'line') {
177
+ if (this.options.type === "line") {
141
178
  this.initLine();
142
179
  }
143
- if (this.options.type === 'bar') {
180
+ if (this.options.type === "bar") {
144
181
  this.initBar();
145
182
  }
146
183
  this.initLegend();
@@ -151,7 +188,9 @@ export default class TsGraph {
151
188
  }
152
189
 
153
190
  clearRect(ctx: CanvasRenderingContext2D) {
154
- const { chart: { containerWidth, containerHeight } } = this.options;
191
+ const {
192
+ chart: { containerWidth, containerHeight },
193
+ } = this.options;
155
194
 
156
195
  ctx.clearRect(0, 0, containerWidth, containerHeight);
157
196
  }
@@ -161,10 +200,10 @@ export default class TsGraph {
161
200
  if (this.options.xAxis.visible) {
162
201
  this.yAxis.drawGridLine(this.yScales);
163
202
  }
164
- if (this.options.type === 'line') {
203
+ if (this.options.type === "line") {
165
204
  this.line.draw(this.xScales, this.yScales);
166
205
  }
167
- if (this.options.type === 'bar') {
206
+ if (this.options.type === "bar") {
168
207
  this.bar.draw(this.xScales, this.yScales, transform);
169
208
  }
170
209
  if (this.options.xAxis.visible) {
@@ -195,13 +234,14 @@ export default class TsGraph {
195
234
  this.initSeries();
196
235
  this.initScales();
197
236
  this.initEvent();
198
- if (this.options.type === 'line') {
237
+ if (this.options.type === "line") {
199
238
  this.initLine();
200
239
  }
201
- if (this.options.type === 'bar') {
240
+ if (this.options.type === "bar") {
202
241
  this.initBar();
203
242
  }
204
243
  this.initTooltip();
244
+ this.initShapes();
205
245
  this.legend.updateOptions(options);
206
246
  this.draw();
207
247
  }
@@ -212,16 +252,18 @@ export default class TsGraph {
212
252
 
213
253
  showTooltip = (eventPosition: EventPosition) => {
214
254
  this.tooltip.draw(eventPosition, this);
215
- }
255
+ };
216
256
 
217
257
  hideTooltip = () => {
218
258
  this.tooltip.clear();
219
- }
259
+ };
220
260
 
221
261
  initEvent() {
222
262
  const { cascade, cascadeScope } = this.options.tooltip;
223
- const plotmoveType = cascadeScope ? `plotmove:${cascadeScope}` : 'plotmove';
224
- const plotleaveType = cascadeScope ? `plotleave:${cascadeScope}` : 'plotleave';
263
+ const plotmoveType = cascadeScope ? `plotmove:${cascadeScope}` : "plotmove";
264
+ const plotleaveType = cascadeScope
265
+ ? `plotleave:${cascadeScope}`
266
+ : "plotleave";
225
267
  let mousedownStatus = false;
226
268
  let mousedownPos: EventPosition = {} as EventPosition;
227
269
  let mouseupPos: EventPosition = {} as EventPosition;
@@ -240,72 +282,107 @@ export default class TsGraph {
240
282
  const handleMouseLeave = throttle(() => {
241
283
  _this.tooltip.clear();
242
284
  }, 5);
243
- d3.select(this.eventCanvas).on('mousemove', function mousemove(this: HTMLCanvasElement) {
244
- isMouserover = true;
245
- handleMouseover(d3.event);
246
- if (cascade) eventEmitter.emit(plotmoveType, d3.event);
247
- }).on('mouseleave', function mouseleave(this: HTMLCanvasElement) {
248
- mouseleavePos = d3.event;
249
- isMouserover = false;
250
- handleMouseLeave();
251
- if (cascade) eventEmitter.emit(plotleaveType);
252
- }).on('mousedown', function mousedown(this: HTMLCanvasElement) {
253
- if (d3.event.which === 1) {
254
- mousedownStatus = true;
255
- mousedownPos = d3.event;
256
- }
257
- }).on('mouseup', function mouseup(this: HTMLCanvasElement) {
258
- d3.event.stopPropagation();
259
- const eventPosition = d3.event as EventPosition;
260
- if (mousedownPos && (mousedownPos.offsetX !== eventPosition.offsetX)) {
261
- _this.zoom.clearMarker();
262
- _this.zoom.onZoom(mousedownPos, eventPosition, (transform: Transform) => {
263
- _this.handleZoom(transform, [mousedownPos, eventPosition]);
264
- });
265
- } else {
266
- _this.options.onClick(d3.event, _this.xScales.invert(d3.event.offsetX), _this.yScales.invert(d3.event.offsetY));
267
- }
268
- mousedownStatus = false;
269
- mousedownPos = {} as EventPosition;
270
- }).on('contextmenu', function contextmenu() {
271
- _this.options.onRightClick(d3.event, _this.xScales.invert(d3.event.offsetX), _this.yScales.invert(d3.event.offsetY));
272
- d3.event.preventDefault();
273
- }).on('touchstart', function touchmove(this: HTMLCanvasElement) {
274
- // 模拟 mousedown
275
- if (d3.event.touches.length > 1) {
276
- mousedownStatus = true;
277
- // mousedownPos = getTouchPosition(_this.eventCanvas, d3.event);
278
- }
279
- }).on('touchmove', function touchmove(this: HTMLCanvasElement) {
280
- const eventPosition = getTouchPosition(_this.eventCanvas, d3.event) as EventPosition;
281
-
282
- if (d3.event.touches.length === 1) {
283
- _this.tooltip.draw(eventPosition, _this);
284
- }
285
-
286
- // 触发 zoom marker
287
- if (mousedownStatus) {
288
- mousedownPos = eventPosition;
289
- mouseupPos = getTouchPosition(_this.eventCanvas, d3.event, 1) as EventPosition;
290
- _this.zoom.drawMarker(mousedownPos, mouseupPos);
291
- }
292
- }).on('touchend', function mouseleave(this: HTMLCanvasElement) {
293
- isMouserover = false;
294
- handleMouseLeave();
285
+ d3.select(this.eventCanvas)
286
+ .on("mousemove", function mousemove(this: HTMLCanvasElement) {
287
+ isMouserover = true;
288
+ handleMouseover(d3.event);
289
+ if (cascade) eventEmitter.emit(plotmoveType, d3.event);
290
+ })
291
+ .on("mouseleave", function mouseleave(this: HTMLCanvasElement) {
292
+ mouseleavePos = d3.event;
293
+ isMouserover = false;
294
+ handleMouseLeave();
295
+ if (cascade) eventEmitter.emit(plotleaveType);
296
+ })
297
+ .on("mousedown", function mousedown(this: HTMLCanvasElement) {
298
+ if (d3.event.which === 1) {
299
+ mousedownStatus = true;
300
+ mousedownPos = d3.event;
301
+ }
302
+ })
303
+ .on("mouseup", function mouseup(this: HTMLCanvasElement) {
304
+ d3.event.stopPropagation();
305
+ const eventPosition = d3.event as EventPosition;
306
+ if (mousedownPos && mousedownPos.offsetX !== eventPosition.offsetX) {
307
+ _this.zoom.clearMarker();
308
+ _this.zoom.onZoom(
309
+ mousedownPos,
310
+ eventPosition,
311
+ (transform: Transform) => {
312
+ _this.handleZoom(transform, [mousedownPos, eventPosition]);
313
+ }
314
+ );
315
+ } else {
316
+ _this.options.onClick(
317
+ d3.event,
318
+ _this.xScales.invert(d3.event.offsetX),
319
+ _this.yScales.invert(d3.event.offsetY)
320
+ );
321
+ }
322
+ mousedownStatus = false;
323
+ mousedownPos = {} as EventPosition;
324
+ })
325
+ .on("contextmenu", function contextmenu() {
326
+ _this.options.onRightClick(
327
+ d3.event,
328
+ _this.xScales.invert(d3.event.offsetX),
329
+ _this.yScales.invert(d3.event.offsetY)
330
+ );
331
+ d3.event.preventDefault();
332
+ })
333
+ .on("touchstart", function touchmove(this: HTMLCanvasElement) {
334
+ // 模拟 mousedown
335
+ if (d3.event.touches.length > 1) {
336
+ mousedownStatus = true;
337
+ // mousedownPos = getTouchPosition(_this.eventCanvas, d3.event);
338
+ }
339
+ })
340
+ .on("touchmove", function touchmove(this: HTMLCanvasElement) {
341
+ const eventPosition = getTouchPosition(
342
+ _this.eventCanvas,
343
+ d3.event
344
+ ) as EventPosition;
345
+
346
+ if (d3.event.touches.length === 1) {
347
+ _this.tooltip.draw(eventPosition, _this);
348
+ }
295
349
 
296
- // 触发 zoom
297
- if (mousedownPos && (mousedownPos.offsetX !== mouseupPos.offsetX)) {
298
- _this.zoom.clearMarker();
299
- _this.zoom.onZoom(mousedownPos, mouseupPos, (transform: Transform) => {
300
- _this.handleZoom(transform, [mousedownPos, mouseupPos]);
301
- });
302
- } else {
303
- _this.options.onClick(d3.event, _this.xScales.invert(d3.event.offsetX), _this.yScales.invert(d3.event.offsetY));
304
- }
305
- mousedownStatus = false;
306
- mousedownPos = {} as EventPosition;
307
- mouseupPos = {} as EventPosition;
308
- });
350
+ // 触发 zoom marker
351
+ if (mousedownStatus) {
352
+ mousedownPos = eventPosition;
353
+ mouseupPos = getTouchPosition(
354
+ _this.eventCanvas,
355
+ d3.event,
356
+ 1
357
+ ) as EventPosition;
358
+ _this.zoom.drawMarker(mousedownPos, mouseupPos);
359
+ }
360
+ })
361
+ .on("touchend", function mouseleave(this: HTMLCanvasElement) {
362
+ isMouserover = false;
363
+ handleMouseLeave();
364
+
365
+ // 触发 zoom
366
+ if (mousedownPos && mousedownPos.offsetX !== mouseupPos.offsetX) {
367
+ _this.zoom.clearMarker();
368
+ _this.zoom.onZoom(
369
+ mousedownPos,
370
+ mouseupPos,
371
+ (transform: Transform) => {
372
+ _this.handleZoom(transform, [mousedownPos, mouseupPos]);
373
+ }
374
+ );
375
+ } else {
376
+ _this.options.onClick(
377
+ d3.event,
378
+ _this.xScales.invert(d3.event.offsetX),
379
+ _this.yScales.invert(d3.event.offsetY)
380
+ );
381
+ }
382
+ mousedownStatus = false;
383
+ mousedownPos = {} as EventPosition;
384
+ mouseupPos = {} as EventPosition;
385
+ });
309
386
 
310
387
  if (cascade) {
311
388
  eventEmitter.on(plotmoveType, this.showTooltip);
@@ -313,14 +390,18 @@ export default class TsGraph {
313
390
  }
314
391
 
315
392
  // TODO: removeListener
316
- window.addEventListener('mouseup', () => {
393
+ window.addEventListener("mouseup", () => {
317
394
  if (!isEmpty(mousedownPos)) {
318
395
  const eventPosition = mouseleavePos;
319
396
  mousedownStatus = false;
320
397
  _this.zoom.clearMarker();
321
- _this.zoom.onZoom(mousedownPos, eventPosition, (transform: Transform) => {
322
- _this.handleZoom(transform, [mousedownPos, eventPosition]);
323
- });
398
+ _this.zoom.onZoom(
399
+ mousedownPos,
400
+ eventPosition,
401
+ (transform: Transform) => {
402
+ _this.handleZoom(transform, [mousedownPos, eventPosition]);
403
+ }
404
+ );
324
405
  mousedownPos = {} as EventPosition;
325
406
  }
326
407
  });
@@ -329,12 +410,17 @@ export default class TsGraph {
329
410
  }
330
411
 
331
412
  getZoomedSeries = () => {
332
- const { chart: { renderTo }, series, timestamp, xkey } = this.options;
413
+ const {
414
+ chart: { renderTo },
415
+ series,
416
+ timestamp,
417
+ xkey,
418
+ } = this.options;
333
419
  const renderToWidth = renderTo.offsetWidth;
334
420
  return series.map((serie) => {
335
- if (Object.prototype.toString.call(serie.data) === '[object Array]') {
421
+ if (Object.prototype.toString.call(serie.data) === "[object Array]") {
336
422
  const data = serie.data.filter((point) => {
337
- const xVal = timestamp === 'X' ? point[xkey] * 1000 : point[xkey];
423
+ const xVal = timestamp === "X" ? point[xkey] * 1000 : point[xkey];
338
424
  const x = this.xScales(new Date(xVal));
339
425
  return x >= 0 && x <= renderToWidth;
340
426
  });
@@ -345,7 +431,7 @@ export default class TsGraph {
345
431
  }
346
432
  return serie;
347
433
  });
348
- }
434
+ };
349
435
 
350
436
  handleResize = () => {
351
437
  const { chart } = this.options;
@@ -358,23 +444,25 @@ export default class TsGraph {
358
444
  this.options.chart.containerHeight = height;
359
445
  this.container.style.width = `${width}px`;
360
446
  this.container.style.height = `${height}px`;
361
- this.retinaScaled(this.backCanvas, 'back');
362
- this.retinaScaled(this.frontCanvas, 'front');
363
- this.retinaScaled(this.eventCanvas, 'event');
447
+ this.retinaScaled(this.backCanvas, "back");
448
+ this.retinaScaled(this.frontCanvas, "front");
449
+ this.retinaScaled(this.eventCanvas, "event");
364
450
  this.initScales();
365
451
  this.initZoom();
366
452
  this.draw(false);
367
- }
453
+ };
368
454
 
369
455
  handleZoom = (transform?: Transform, eventPositions?: EventPosition[]) => {
370
456
  if (this.options.onZoomWithoutDefult) {
371
457
  let times;
372
458
  if (eventPositions) {
373
- times = sortBy(eventPositions, 'offsetX').map((pos: EventPosition) => this.xScales.invert(pos.offsetX));
459
+ times = sortBy(eventPositions, "offsetX").map((pos: EventPosition) =>
460
+ this.xScales.invert(pos.offsetX)
461
+ );
374
462
  }
375
463
  this.options.onZoomWithoutDefult(times);
376
464
  } else {
377
- const { ykey, yAxis, ykeyFormatter } = this.options
465
+ const { ykey, yAxis, ykeyFormatter } = this.options;
378
466
  let { series } = this.options;
379
467
  if (transform) {
380
468
  this.transform = transform;
@@ -409,7 +497,7 @@ export default class TsGraph {
409
497
  this.options.onZoom(this.getZoomedSeries);
410
498
  }
411
499
  this.draw(false);
412
- }
500
+ };
413
501
 
414
502
  handleLegendItemClick = (serieName: string) => {
415
503
  const { notDisplayedSeries } = this.options;
@@ -422,24 +510,24 @@ export default class TsGraph {
422
510
  });
423
511
  }
424
512
  this.draw(false);
425
- }
513
+ };
426
514
 
427
515
  retinaScaled(canvas: HTMLCanvasElement, name: string) {
428
516
  const { chart, ratio } = this.options;
429
- const ctx = canvas.getContext('2d')!;
430
- const width = name === 'front' ? chart.containerWidth : chart.width;
431
- const height = name === 'front' ? chart.containerHeight : chart.height;
432
- const left = name === 'front' ? '0px' : `${chart.marginLeft}px`;
433
- const top = name === 'front' ? '0px' : `${chart.marginTop}px`;
517
+ const ctx = canvas.getContext("2d")!;
518
+ const width = name === "front" ? chart.containerWidth : chart.width;
519
+ const height = name === "front" ? chart.containerHeight : chart.height;
520
+ const left = name === "front" ? "0px" : `${chart.marginLeft}px`;
521
+ const top = name === "front" ? "0px" : `${chart.marginTop}px`;
434
522
 
435
523
  canvas.width = width * ratio;
436
524
  canvas.height = height * ratio;
437
525
  canvas.style.width = `${width}px`;
438
526
  canvas.style.height = `${height}px`;
439
- canvas.style.position = 'absolute';
527
+ canvas.style.position = "absolute";
440
528
  canvas.style.left = left;
441
529
  canvas.style.top = top;
442
- if (name === 'front') {
530
+ if (name === "front") {
443
531
  ctx.translate(chart.marginLeft * ratio, chart.marginTop * ratio);
444
532
  }
445
533
  ctx.scale(ratio, ratio);
@@ -447,44 +535,54 @@ export default class TsGraph {
447
535
 
448
536
  createContainer() {
449
537
  const { chart } = this.options;
450
- const container = document.createElement('div');
538
+ const container = document.createElement("div");
451
539
 
452
- container.style.position = 'relative';
540
+ container.style.position = "relative";
453
541
  container.style.width = `${chart.containerWidth}px`;
454
542
  container.style.height = `${chart.containerHeight}px`;
455
- container.style.overflow = 'hidden';
456
- container.className = 'd3-graph-container';
543
+ container.style.overflow = "hidden";
544
+ container.className = "d3-graph-container";
457
545
  chart.renderTo.appendChild(container);
458
546
  this.container = container;
459
547
  }
460
548
 
461
549
  createCanvas() {
462
- const { chart: { id } } = this.options;
550
+ const {
551
+ chart: { id },
552
+ } = this.options;
463
553
 
464
554
  function create(this: TsGraphType, name: string) {
465
- const canvas = document.createElement('canvas');
466
- const context = canvas.getContext('2d');
555
+ const canvas = document.createElement("canvas");
556
+ const context = canvas.getContext("2d");
467
557
 
468
- canvas.setAttribute('id', `${id}-${name}Canvas`);
558
+ canvas.setAttribute("id", `${id}-${name}Canvas`);
469
559
  this.container.appendChild(canvas);
470
560
  this[`${name}Canvas`] = canvas;
471
561
  this[`${name}Context`] = context;
472
562
  this.retinaScaled(canvas, name);
473
563
  }
474
- create.call(this, 'back');
475
- create.call(this, 'front');
476
- create.call(this, 'event');
564
+ create.call(this, "back");
565
+ create.call(this, "front");
566
+ create.call(this, "event");
477
567
  }
478
568
 
479
569
  initSeries() {
480
- const { fillNull, series, xkey, ykey, ykeyFormatter, oykey, yAxis, stack } = this.options;
570
+ const {
571
+ fillNull,
572
+ series,
573
+ xkey,
574
+ ykey,
575
+ ykey2,
576
+ ykeyFormatter,
577
+ oykey,
578
+ yAxis,
579
+ stack,
580
+ } = this.options;
481
581
  let xmin = -Infinity;
482
582
  let xmax = Infinity;
483
583
  let ymin = yAxis.min;
484
584
  let ymax = yAxis.max;
485
585
 
486
-
487
-
488
586
  if (Array.isArray(series)) {
489
587
  const newSeries: Serie[] = [];
490
588
  series.forEach((serie, idx) => {
@@ -493,13 +591,19 @@ export default class TsGraph {
493
591
  let flag = false; // 起始标记,后面有连续空值即丢掉
494
592
  let dataIdx;
495
593
  for (dataIdx = 0; dataIdx < data.length; dataIdx++) {
496
- const ykeyVal = data[dataIdx][oykey] ? data[dataIdx][oykey]: getYkeyValue(data[dataIdx][ykey], ykeyFormatter);
594
+ const ykeyVal = data[dataIdx][oykey]
595
+ ? data[dataIdx][oykey]
596
+ : getYkeyValue(data[dataIdx][ykey], ykeyFormatter);
497
597
  const item = {
498
598
  [xkey]: data[dataIdx][xkey],
499
599
  [ykey]: ykeyVal,
500
600
  [oykey]: ykeyVal,
501
601
  };
502
602
 
603
+ if (ykey2 && ykey2 in data[dataIdx]) {
604
+ item[ykey2] = data[dataIdx][ykey2];
605
+ }
606
+
503
607
  if (stack.enabled) {
504
608
  if (item[oykey] === undefined) {
505
609
  item[oykey] = getYkeyValue(item[ykey], ykeyFormatter);
@@ -507,7 +611,9 @@ export default class TsGraph {
507
611
  let preIdx = idx;
508
612
  if (preIdx > 0) {
509
613
  while (preIdx > 0) {
510
- const preData = Array.isArray(series[preIdx - 1].data) ? series[preIdx - 1].data : [];
614
+ const preData = Array.isArray(series[preIdx - 1].data)
615
+ ? series[preIdx - 1].data
616
+ : [];
511
617
  const preItem = find(preData, (pItem: SerieDataItem) => {
512
618
  return pItem[xkey] === item[xkey];
513
619
  });
@@ -529,17 +635,19 @@ export default class TsGraph {
529
635
  }
530
636
 
531
637
  data[dataIdx] = item;
532
-
638
+
533
639
  const x = item[xkey];
534
640
  const y = item[ykey];
535
-
536
641
 
537
642
  // filter is invalid points
538
643
  if (fillNull === undefined) {
539
644
  if (
540
- dataIdx === 0
541
- || dataIdx === data.length - 1
542
- || (dataIdx > 0 && dataIdx < data.length -1 && typeof y === 'number' && !isNaN(y))
645
+ !isNaN(y) &&
646
+ (dataIdx === 0 ||
647
+ dataIdx === data.length - 1 ||
648
+ (dataIdx > 0 &&
649
+ dataIdx < data.length - 1 &&
650
+ typeof y === "number"))
543
651
  ) {
544
652
  newData.push(item);
545
653
  flag = true;
@@ -558,14 +666,14 @@ export default class TsGraph {
558
666
  if (xmax > x) {
559
667
  xmax = x;
560
668
  }
561
- if (typeof y === 'number' && !isNaN(y)) {
562
- if (typeof ymin !== 'number' || y < ymin) {
669
+ if (typeof y === "number" && !isNaN(y)) {
670
+ if (typeof ymin !== "number" || y < ymin) {
563
671
  ymin = y;
564
672
  }
565
- if (typeof ymax !== 'number' || y > ymax) {
673
+ if (typeof ymax !== "number" || y > ymax) {
566
674
  ymax = y;
567
675
  }
568
- } else if (typeof fillNull === 'number') {
676
+ } else if (typeof fillNull === "number") {
569
677
  if (fillNull < ymin) {
570
678
  ymin = fillNull;
571
679
  }
@@ -574,7 +682,7 @@ export default class TsGraph {
574
682
  }
575
683
  }
576
684
  }
577
-
685
+
578
686
  newSeries.push({
579
687
  ...serie,
580
688
  data: newData,
@@ -599,15 +707,30 @@ export default class TsGraph {
599
707
  }
600
708
 
601
709
  initTooltip() {
602
- this.tooltip = new Tooltip(this.options, this.frontContext, this.container, this.eventCanvas);
710
+ this.tooltip = new Tooltip(
711
+ this.options,
712
+ this.frontContext,
713
+ this.container,
714
+ this.eventCanvas
715
+ );
603
716
  }
604
717
 
605
718
  initZoom() {
606
- this.zoom = new Zoom(this.options, this.handleZoom, this.container, this.eventCanvas);
719
+ this.zoom = new Zoom(
720
+ this.options,
721
+ this.handleZoom,
722
+ this.container,
723
+ this.eventCanvas
724
+ );
607
725
  }
608
726
 
609
727
  initLegend() {
610
- this.legend = new Legend(this.options, this.handleLegendItemClick, this.container, this.eventCanvas);
728
+ this.legend = new Legend(
729
+ this.options,
730
+ this.handleLegendItemClick,
731
+ this.container,
732
+ this.eventCanvas
733
+ );
611
734
  }
612
735
 
613
736
  initScales() {
@@ -631,14 +754,17 @@ export default class TsGraph {
631
754
 
632
755
  offEvents() {
633
756
  const { cascade, cascadeScope } = this.options.tooltip;
634
- const plotmoveType = cascadeScope ? `plotmove:${cascadeScope}` : 'plotmove';
635
- const plotleaveType = cascadeScope ? `plotleave:${cascadeScope}` : 'plotleave';
636
-
637
- d3.select(this.eventCanvas).on('mousemove', null)
638
- .on('mouseleave', null)
639
- .on('mousedown', null)
640
- .on('mouseup', null)
641
- .on('touchmove', null);
757
+ const plotmoveType = cascadeScope ? `plotmove:${cascadeScope}` : "plotmove";
758
+ const plotleaveType = cascadeScope
759
+ ? `plotleave:${cascadeScope}`
760
+ : "plotleave";
761
+
762
+ d3.select(this.eventCanvas)
763
+ .on("mousemove", null)
764
+ .on("mouseleave", null)
765
+ .on("mousedown", null)
766
+ .on("mouseup", null)
767
+ .on("touchmove", null);
642
768
  removeListener(this.options.chart.renderTo, this.handleResize);
643
769
 
644
770
  if (cascade) {