@fc-plot/ts-graph 0.23.3 → 0.24.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/examples/index.js CHANGED
@@ -39,13 +39,12 @@ newSeries.push({
39
39
  });
40
40
 
41
41
  newSeries.push(origin);
42
- console.log(newSeries);
43
42
 
44
43
  function random(m, n) {
45
44
  return Math.floor(Math.random() * (n - m + 1));
46
45
  }
47
46
 
48
- function generateSeries(idx, seriesCount = 3) {
47
+ function generateSeries(idx, seriesCount = 2) {
49
48
  const series = [];
50
49
 
51
50
  for (let n = 1; n <= seriesCount; n++) {
@@ -56,7 +55,8 @@ function generateSeries(idx, seriesCount = 3) {
56
55
  seriesData.push({
57
56
  timestamp:
58
57
  1609430399 + m * (m < 100 ? (idx === 0 ? 1000 : 1001) : 1000),
59
- value: m < 100 ? random(0, 100000000) : random(0, 1000000000),
58
+ value: random(0, n === 1 ? 100 : 1000000),
59
+ // value: m < 100 ? random(0, 100000000) : random(0, 1000000000),
60
60
  });
61
61
  }
62
62
 
@@ -65,18 +65,19 @@ function generateSeries(idx, seriesCount = 3) {
65
65
  data: seriesData,
66
66
  });
67
67
  }
68
+ console.log("series", series);
68
69
  return series;
69
70
  }
70
71
 
71
- const graphsCount = 3;
72
+ const graphsCount = 1;
72
73
  const charts = [];
73
74
 
74
75
  for (let i = 0; i < graphsCount; i++) {
75
76
  const id = `c${i}`;
76
77
  const renderTo = document.createElement("div");
77
78
  renderTo.id = id;
78
- renderTo.style.width = `${(i + 1) * 200}px`;
79
- renderTo.style.height = `${(i + 1) * 100}px`;
79
+ renderTo.style.width = `${(i + 1) * 1000}px`;
80
+ renderTo.style.height = `${(i + 1) * 400}px`;
80
81
  renderTo.style.margin = "20px";
81
82
  renderTo.style.border = "1px solid #ccc";
82
83
  document.body.appendChild(renderTo);
@@ -98,6 +99,10 @@ for (let i = 0; i < graphsCount; i++) {
98
99
  line: {
99
100
  width: 1,
100
101
  },
102
+ yAxis2: {
103
+ visible: true,
104
+ matchName: "series_2",
105
+ },
101
106
  // xAxis: {
102
107
  // visible: false,
103
108
  // },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fc-plot/ts-graph",
3
- "version": "0.23.3",
3
+ "version": "0.24.0",
4
4
  "scripts": {
5
5
  "commit": "npx git-cz",
6
6
  "compile": "fetk run compile",
package/src/index.ts CHANGED
@@ -14,6 +14,7 @@ import { addListener, removeListener } from "resize-detector";
14
14
  import EventEmitter from "events";
15
15
  import XAxis from "./xAxis";
16
16
  import YAxis from "./yAxis";
17
+ import YAxis2 from "./yAxis2";
17
18
  import Tooltip from "./tooltip";
18
19
  import Line from "./line";
19
20
  import Bar from "./bar";
@@ -49,7 +50,9 @@ export default class TsGraph {
49
50
  xAxis!: XAxis;
50
51
  xScales!: XScales;
51
52
  yAxis!: YAxis;
53
+ yAxis2!: YAxis2;
52
54
  yScales!: YScales;
55
+ y2Scales!: YScales;
53
56
  line!: Line;
54
57
  bar!: Bar;
55
58
  legend!: Legend;
@@ -85,8 +88,8 @@ export default class TsGraph {
85
88
  "#339966",
86
89
  "#993333",
87
90
  ],
88
- width: userOptions.chart.renderTo.offsetWidth,
89
- height: userOptions.chart.renderTo.offsetHeight || 350,
91
+ width: userOptions.chart.renderTo.clientWidth,
92
+ height: userOptions.chart.renderTo.clientHeight || 350,
90
93
  marginTop: 10,
91
94
  marginRight: 10,
92
95
  marginBottom: 10,
@@ -123,6 +126,22 @@ export default class TsGraph {
123
126
  fontSize: 11,
124
127
  },
125
128
  },
129
+ yAxis2: {
130
+ scale: {
131
+ type: "linear",
132
+ log: 10,
133
+ },
134
+ visible: false,
135
+ lineColor: "#ccc",
136
+ lineWidth: 1,
137
+ tickLength: 5,
138
+ tickpadding: 5,
139
+ tickColor: "#ccc",
140
+ labels: {
141
+ color: "#999",
142
+ fontSize: 11,
143
+ },
144
+ },
126
145
  type: "line",
127
146
  line: {
128
147
  enable: true,
@@ -218,7 +237,7 @@ export default class TsGraph {
218
237
  this.xAxis.draw(this.xScales);
219
238
  }
220
239
  if (this.options.type === "line") {
221
- this.line.draw(this.xScales, this.yScales);
240
+ this.line.draw(this.xScales, this.yScales, this.y2Scales);
222
241
  }
223
242
  if (this.options.type === "bar") {
224
243
  this.bar.draw(this.xScales, this.yScales, transform);
@@ -228,6 +247,9 @@ export default class TsGraph {
228
247
  if (this.options.yAxis.visible) {
229
248
  this.yAxis.draw(this.yScales);
230
249
  }
250
+ if (this.options.yAxis2.visible && this.options.yAxis2.matchName) {
251
+ this.yAxis2.draw(this.y2Scales);
252
+ }
231
253
  if (redrawLegend) {
232
254
  this.legend.draw();
233
255
  }
@@ -520,7 +542,7 @@ export default class TsGraph {
520
542
  }
521
543
  this.options.onZoomWithoutDefult(times);
522
544
  } else {
523
- const { ykey, ykey2, yAxis, ykeyFormatter } = this.options;
545
+ const { ykey, ykey2, yAxis, yAxis2, ykeyFormatter } = this.options;
524
546
  let { series } = this.options;
525
547
  if (transform) {
526
548
  this.transform = transform;
@@ -534,6 +556,8 @@ export default class TsGraph {
534
556
  if (Array.isArray(series)) {
535
557
  let ymin = yAxis.min || -Infinity;
536
558
  let ymax = yAxis.max || Infinity;
559
+ let y2min = yAxis2.min || -Infinity;
560
+ let y2max = yAxis2.max || Infinity;
537
561
  for (const serie of series) {
538
562
  const data = Array.isArray(serie.data) ? serie.data : [];
539
563
  let dataIdx;
@@ -543,11 +567,24 @@ export default class TsGraph {
543
567
 
544
568
  if (y === null) continue;
545
569
  // get axis domain
546
- if (ymin < y) {
547
- ymin = y;
548
- }
549
- if (ymax > y) {
550
- ymax = y;
570
+ if (
571
+ yAxis2.visible &&
572
+ yAxis2.matchName &&
573
+ yAxis2.matchName === serie.name
574
+ ) {
575
+ if (y2min < y) {
576
+ y2min = y;
577
+ }
578
+ if (y2max > y) {
579
+ y2max = y;
580
+ }
581
+ } else {
582
+ if (ymin < y) {
583
+ ymin = y;
584
+ }
585
+ if (ymax > y) {
586
+ ymax = y;
587
+ }
551
588
  }
552
589
  if (ykey2) {
553
590
  const y2 = getYkeyValue(item[ykey2], ykeyFormatter);
@@ -564,6 +601,9 @@ export default class TsGraph {
564
601
  // 如果缩放至没有数据点(无法计算出 ymin 和 ymax),则不更新 domain
565
602
  if (ymin !== -Infinity && ymax !== Infinity) {
566
603
  this.yAxis.setDomain(this.yScales, { ymin, ymax });
604
+ if (yAxis2.visible && yAxis2.matchName) {
605
+ this.yAxis2.setDomain(this.y2Scales, { y2min, y2max });
606
+ }
567
607
  }
568
608
  }
569
609
  this.options.onZoom(this.getZoomedSeries);
@@ -649,6 +689,7 @@ export default class TsGraph {
649
689
  oykey,
650
690
  xAxis,
651
691
  yAxis,
692
+ yAxis2,
652
693
  stack,
653
694
  notDisplayedSeries,
654
695
  } = this.options;
@@ -656,6 +697,8 @@ export default class TsGraph {
656
697
  let xmax = xAxis.max || Infinity;
657
698
  let ymin = yAxis.min;
658
699
  let ymax = yAxis.max;
700
+ let y2min = yAxis2.min;
701
+ let y2max = yAxis2.max;
659
702
 
660
703
  if (Array.isArray(series)) {
661
704
  const newSeries: Serie[] = [];
@@ -745,17 +788,30 @@ export default class TsGraph {
745
788
  xmax = x;
746
789
  }
747
790
  if (typeof y === "number" && !isNaN(y)) {
748
- if (typeof ymin !== "number" || y < ymin) {
749
- ymin = y;
750
- }
751
- if (typeof y2 === "number" && y2 < ymin) {
752
- ymin = y2;
753
- }
754
- if (typeof ymax !== "number" || y > ymax) {
755
- ymax = y;
756
- }
757
- if (typeof y2 === "number" && y2 > ymax) {
758
- ymax = y2;
791
+ if (
792
+ yAxis2.visible &&
793
+ yAxis2.matchName &&
794
+ yAxis2.matchName === serie.name
795
+ ) {
796
+ if (typeof y2min !== "number" || y < y2min) {
797
+ y2min = y;
798
+ }
799
+ if (typeof y2max !== "number" || y > y2max) {
800
+ y2max = y;
801
+ }
802
+ } else {
803
+ if (typeof ymin !== "number" || y < ymin) {
804
+ ymin = y;
805
+ }
806
+ if (typeof y2 === "number" && y2 < ymin) {
807
+ ymin = y2;
808
+ }
809
+ if (typeof ymax !== "number" || y > ymax) {
810
+ ymax = y;
811
+ }
812
+ if (typeof y2 === "number" && y2 > ymax) {
813
+ ymax = y2;
814
+ }
759
815
  }
760
816
  } else if (typeof fillNull === "number") {
761
817
  if (fillNull < ymin) {
@@ -795,6 +851,8 @@ export default class TsGraph {
795
851
  this.options.xmax = xmax;
796
852
  this.options.ymin = ymin;
797
853
  this.options.ymax = ymax;
854
+ this.options.y2min = y2min;
855
+ this.options.y2max = y2max;
798
856
  }
799
857
  }
800
858
 
@@ -838,7 +896,18 @@ export default class TsGraph {
838
896
  this.yAxis = yAxis;
839
897
  this.yScales = yAxis.init();
840
898
 
841
- const xAxis = new XAxis(this.options, this.backContext, this.yAxis);
899
+ if (this.options.yAxis2.visible && this.options.yAxis2.matchName) {
900
+ const yAxis2 = new YAxis2(this.options, this.backContext);
901
+ this.yAxis2 = yAxis2;
902
+ this.y2Scales = yAxis2.init();
903
+ }
904
+
905
+ const xAxis = new XAxis(
906
+ this.options,
907
+ this.backContext,
908
+ this.yAxis,
909
+ this.yAxis2
910
+ );
842
911
  this.xAxis = xAxis;
843
912
  let xScales = xAxis.init();
844
913
  if (this.transform) {
package/src/interface.ts CHANGED
@@ -82,6 +82,7 @@ export type YAxis = {
82
82
  plotLines: PlotLine[];
83
83
  plotLinesFixed?: boolean;
84
84
  tickValueFormatter?: (value: number) => string;
85
+ matchName?: string; // 用于匹配 y 轴,如果不填则默认匹配第一个 y 轴
85
86
  };
86
87
 
87
88
  export type SerieDataItemMarker = {
@@ -178,6 +179,7 @@ export interface Options extends BaseOptions {
178
179
  chart: Chart;
179
180
  xAxis: XAxis;
180
181
  yAxis: YAxis;
182
+ yAxis2: YAxis;
181
183
  tooltip: Tooltip;
182
184
  type: "line" | "bar";
183
185
  line: {
@@ -204,6 +206,8 @@ export interface Options extends BaseOptions {
204
206
  xmax: number;
205
207
  ymin: number;
206
208
  ymax: number;
209
+ y2min: number;
210
+ y2max: number;
207
211
  shapes: any[];
208
212
  onClick: (
209
213
  d3Event: any,
package/src/line.ts CHANGED
@@ -11,11 +11,12 @@ export default class Line {
11
11
  this.ctx = ctx;
12
12
  }
13
13
 
14
- draw(xScales: XScales, yScales: YScales) {
14
+ draw(xScales: XScales, yScales: YScales, y2Scales: YScales) {
15
15
  const {
16
16
  series,
17
17
  chart: { colors, height },
18
18
  xAxis,
19
+ yAxis2,
19
20
  xkey,
20
21
  ykey,
21
22
  ykey2,
@@ -37,12 +38,16 @@ export default class Line {
37
38
  const x = xScales(new Date(xVal));
38
39
  return x;
39
40
  };
40
- const yAccessor = (d: SerieDataItem, ykey: any) => {
41
+ const yAccessor = (d: SerieDataItem, ykey: any, serieName: string) => {
41
42
  const val = d[ykey];
43
+ const yScalesFunc =
44
+ yAxis2.visible && yAxis2.matchName && serieName === yAxis2.matchName
45
+ ? y2Scales
46
+ : yScales;
42
47
  if (typeof val === "number" && !isNaN(val)) {
43
- return yScales(val);
48
+ return yScalesFunc(val);
44
49
  } else if (typeof fillNull === "number") {
45
- return yScales(fillNull);
50
+ return yScalesFunc(fillNull);
46
51
  }
47
52
  return undefined;
48
53
  };
@@ -73,7 +78,7 @@ export default class Line {
73
78
  .x(xAccessor)
74
79
  .y0((d: SerieDataItem) => {
75
80
  if (ykey2 && ykey2 in d) {
76
- return yAccessor(d, ykey);
81
+ return yAccessor(d, ykey, serie.name);
77
82
  }
78
83
  if (xAxis.visible) {
79
84
  return height - xAxis.tickpadding - xAxis.labels.fontSize - 5;
@@ -82,9 +87,9 @@ export default class Line {
82
87
  })
83
88
  .y1((d: SerieDataItem) => {
84
89
  if (ykey2 && ykey2 in d) {
85
- return yAccessor(d, ykey2);
90
+ return yAccessor(d, ykey2, serie.name);
86
91
  }
87
- return yAccessor(d, ykey);
92
+ return yAccessor(d, ykey, serie.name);
88
93
  })
89
94
  .defined(definedAccessor)
90
95
  .context(ctx);
@@ -110,7 +115,7 @@ export default class Line {
110
115
  .line()
111
116
  .x(xAccessor)
112
117
  .y((d: SerieDataItem) => {
113
- return yAccessor(d, ykey);
118
+ return yAccessor(d, ykey, serie.name);
114
119
  })
115
120
  .defined(definedAccessor)
116
121
  .context(ctx);
package/src/tooltip.ts CHANGED
@@ -68,6 +68,7 @@ export default class Tooltip {
68
68
  eventPosition: EventPosition,
69
69
  xScales: XScales,
70
70
  yScales: YScales,
71
+ y2Scales: YScales,
71
72
  cbk: (nearestPoints: Point[], nearestPoint: Point) => void,
72
73
  forceTimestamp?: number
73
74
  ) {
@@ -81,6 +82,7 @@ export default class Tooltip {
81
82
  oykey,
82
83
  timestamp,
83
84
  fillNull,
85
+ yAxis2,
84
86
  } = this.options;
85
87
  const offsetX = eventPosition.offsetX || eventPosition.layerX;
86
88
  const offsetY = eventPosition.offsetY || eventPosition.layerY;
@@ -106,10 +108,14 @@ export default class Tooltip {
106
108
  }
107
109
 
108
110
  nearestPoints = tempNearestPoints.map((item: any) => {
111
+ const yScalesFunc =
112
+ yAxis2.visible && yAxis2.matchName && item.name === yAxis2.matchName
113
+ ? y2Scales
114
+ : yScales;
109
115
  return {
110
116
  ...item,
111
117
  x: xScales(item.timestamp),
112
- y: yScales(item.value),
118
+ y: yScalesFunc(item.value),
113
119
  color: item.color || getColor(colors, item.serieIndex),
114
120
  };
115
121
  });
@@ -163,13 +169,14 @@ export default class Tooltip {
163
169
  crosshairX?: number,
164
170
  crosshairY?: number
165
171
  ) {
166
- const { xScales, yScales, yAxis, options } = instance;
172
+ const { xScales, yScales, y2Scales, yAxis, options } = instance;
167
173
  const cascadeMode = options?.tooltip?.cascadeMode;
168
174
  this.isMouserover = true;
169
175
  this.getNearestPoints(
170
176
  eventPosition,
171
177
  xScales,
172
178
  yScales,
179
+ y2Scales,
173
180
  (nearestPoints, nearestPoint) => {
174
181
  this.clear();
175
182
  this.drawCrosshair(eventPosition, crosshairX, crosshairY);
package/src/utils.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  import * as d3 from "d3";
2
- import { max, pickBy } from "lodash";
2
+ import { max, pickBy, map, find } from "lodash";
3
3
  import {
4
4
  Timestamp,
5
5
  Options,
6
6
  XScales,
7
7
  YScales,
8
8
  NearestPoint,
9
+ Serie,
10
+ SerieDataItem,
9
11
  } from "./interface";
12
+
10
13
  import getNearestPoints from "./getNearestPoints";
11
14
 
12
15
  type Point = {
package/src/xAxis.ts CHANGED
@@ -2,19 +2,23 @@ import * as d3 from "d3";
2
2
  import { getMsTs } from "./utils";
3
3
  import { Options, XScales } from "./interface";
4
4
  import YAxis from "./yAxis";
5
+ import Y2Axis from "./yAxis2";
5
6
 
6
7
  export default class XAxis {
7
8
  options: Options;
8
9
  ctx: CanvasRenderingContext2D;
9
10
  yAxis: YAxis;
11
+ y2Axis: Y2Axis;
10
12
  constructor(
11
13
  userOptions: Options,
12
14
  ctx: CanvasRenderingContext2D,
13
- yAxis: YAxis
15
+ yAxis: YAxis,
16
+ y2Axis: Y2Axis
14
17
  ) {
15
18
  this.options = userOptions;
16
19
  this.ctx = ctx;
17
20
  this.yAxis = yAxis;
21
+ this.y2Axis = y2Axis;
18
22
  }
19
23
 
20
24
  init() {
@@ -25,9 +29,13 @@ export default class XAxis {
25
29
  xmax,
26
30
  xAxis,
27
31
  } = this.options;
32
+ const y2AxisTickMaxWidth = this.y2Axis?.tickMaxWidth || 0;
28
33
  const xScales = d3
29
34
  .scaleTime()
30
- .range([xAxis.visible ? this.yAxis.tickMaxWidth : 0, width]);
35
+ .range([
36
+ xAxis.visible ? this.yAxis.tickMaxWidth : 0,
37
+ width - y2AxisTickMaxWidth,
38
+ ]);
31
39
 
32
40
  xScales.domain([
33
41
  getMsTs(xmin, timestamp) - (xmin === xmax ? 1000 : 0),
@@ -62,7 +70,7 @@ export default class XAxis {
62
70
 
63
71
  // draw line
64
72
  ctx.beginPath();
65
- ctx.moveTo(0, tickBottom - xAxis.tickLength);
73
+ ctx.moveTo(this.yAxis.tickMaxWidth, tickBottom - xAxis.tickLength);
66
74
  ctx.lineTo(chart.width, tickBottom - xAxis.tickLength);
67
75
  ctx.lineWidth = 1;
68
76
  ctx.strokeStyle = xAxis.lineColor;
package/src/yAxis.ts CHANGED
@@ -3,10 +3,6 @@ import { map, floor } from "lodash";
3
3
  import { Options, YScales } from "./interface";
4
4
  import { shortUint, getMaxWidthByYAxisTicks } from "./utils";
5
5
 
6
- interface RealData {
7
- [index: string]: any;
8
- }
9
-
10
6
  export default class YAxis {
11
7
  options: Options;
12
8
  ctx: CanvasRenderingContext2D;
@@ -40,38 +36,6 @@ export default class YAxis {
40
36
  return yScales;
41
37
  }
42
38
 
43
- /**
44
- * 返回真实的数据,其中包含 plotLines
45
- * @param {Array} data [description]
46
- * @return {Array} [description]
47
- */
48
- getRealData(data: RealData) {
49
- const {
50
- yAxis: { plotLines },
51
- ykey,
52
- fillNull,
53
- } = this.options;
54
-
55
- if (Array.isArray(data)) {
56
- if (Array.isArray(plotLines)) {
57
- plotLines.forEach((plotLine) => {
58
- if (typeof plotLine.value === "number") {
59
- data.push({
60
- [ykey]: plotLine.value,
61
- });
62
- }
63
- });
64
- }
65
- if (typeof fillNull === "number") {
66
- data.push({
67
- [ykey]: fillNull,
68
- });
69
- }
70
- return data;
71
- }
72
- return [];
73
- }
74
-
75
39
  getPlotLinesMaxAbs() {
76
40
  const {
77
41
  yAxis: { plotLines },
@@ -187,7 +151,7 @@ export default class YAxis {
187
151
  ctx.beginPath();
188
152
  this.ticks.forEach((d) => {
189
153
  const yValue = yScales(d);
190
- ctx.moveTo(0, yValue);
154
+ ctx.moveTo(this.tickMaxWidth, yValue);
191
155
  ctx.lineTo(chart.width, yValue);
192
156
  });
193
157
  ctx.lineWidth = 1;
package/src/yAxis2.ts ADDED
@@ -0,0 +1,154 @@
1
+ import * as d3 from "d3";
2
+ import { map, floor } from "lodash";
3
+ import { Options, YScales } from "./interface";
4
+ import { shortUint, getMaxWidthByYAxisTicks } from "./utils";
5
+
6
+ export default class YAxis {
7
+ options: Options;
8
+ ctx: CanvasRenderingContext2D;
9
+ tickLength: number;
10
+ ticks: number[];
11
+ tickMaxWidth: number; // 刻度文字最大宽度
12
+
13
+ constructor(userOptions: Options, ctx: CanvasRenderingContext2D) {
14
+ this.options = userOptions;
15
+ const { yAxis } = userOptions;
16
+ ctx.font = `${yAxis.labels.fontSize}px Palantino`;
17
+ this.ctx = ctx;
18
+ this.tickLength = Math.floor(userOptions.chart.height / 50);
19
+ this.ticks = [];
20
+ this.tickMaxWidth = 0;
21
+ }
22
+
23
+ init() {
24
+ const { chart, xAxis, yAxis } = this.options;
25
+ let scale = d3.scaleLinear();
26
+ if (yAxis.scale && yAxis.scale.type === "log") {
27
+ scale = d3.scaleLog().base(yAxis.scale.log || 10);
28
+ }
29
+ const yScales = scale.range([
30
+ chart.height -
31
+ (xAxis.labels.fontSize + xAxis.tickpadding + xAxis.tickLength),
32
+ 10,
33
+ ]);
34
+
35
+ this.setDomain(yScales, this.options);
36
+ return yScales;
37
+ }
38
+
39
+ getPlotLinesMaxAbs() {
40
+ const {
41
+ yAxis: { plotLines },
42
+ } = this.options;
43
+ let maxAbs: undefined | number;
44
+ if (Array.isArray(plotLines)) {
45
+ plotLines.forEach((plotLine) => {
46
+ if (!maxAbs || Math.abs(maxAbs) < Math.abs(plotLine.value)) {
47
+ maxAbs = plotLine.value;
48
+ }
49
+ });
50
+ }
51
+ return maxAbs;
52
+ }
53
+
54
+ setDomain(
55
+ yScales: YScales,
56
+ { y2min, y2max }: { y2min: number; y2max: number }
57
+ ) {
58
+ const { options } = this;
59
+ const { yAxis, yAxis2 } = options;
60
+ let realTickLength = this.tickLength;
61
+
62
+ // TODO: 只有在唯一值不为 0 的时候才做居中处理
63
+ if (y2min === y2max && y2min !== 0) {
64
+ const increment = (y2max - y2min) / (this.tickLength - 1);
65
+ const halfIncrement = increment / 2 || y2max || 1;
66
+ realTickLength = increment === 0 ? 1 : this.tickLength;
67
+
68
+ y2min -= halfIncrement;
69
+ y2max += halfIncrement;
70
+ }
71
+
72
+ if (y2min > y2max) {
73
+ const cachemin = y2min;
74
+ y2min = y2max;
75
+ y2max = cachemin;
76
+ }
77
+
78
+ // 开了固定显示 plotLines 或是单一值的时候,需要计算出最大的 plotLines 的绝对值
79
+ if (yAxis.plotLinesFixed || y2min === y2max) {
80
+ const plotLinesMaxAbs = this.getPlotLinesMaxAbs();
81
+ if (plotLinesMaxAbs) {
82
+ if (plotLinesMaxAbs < y2min) {
83
+ y2min = plotLinesMaxAbs;
84
+ }
85
+
86
+ if (plotLinesMaxAbs > y2max) {
87
+ y2max = plotLinesMaxAbs;
88
+ }
89
+ }
90
+ }
91
+
92
+ let ticks = [];
93
+
94
+ // 如果用户设置了 min 或者 max,则不用默认的 tick 计算
95
+ if (typeof yAxis.min === "number" || typeof yAxis.max === "number") {
96
+ const realMin = typeof yAxis.min === "number" ? yAxis.min : y2min;
97
+ const realMax = typeof yAxis.max === "number" ? yAxis.max : y2max;
98
+
99
+ yScales.domain([realMin, realMax]);
100
+ if (typeof yAxis.min === "number" && yAxis.min > realMax) {
101
+ ticks = [yAxis.min];
102
+ } else if (typeof yAxis.max === "number" && yAxis.max < realMin) {
103
+ ticks = [yAxis.max];
104
+ } else {
105
+ const step = d3.tickStep(realMin, realMax, realTickLength);
106
+ ticks = map(d3.range(realMin, realMax, step), (d: number) => {
107
+ return floor(d, 2);
108
+ });
109
+ }
110
+ } else {
111
+ yScales.domain([y2min, y2max]);
112
+ yScales.nice(realTickLength);
113
+ ticks = yScales.ticks(realTickLength);
114
+ }
115
+ const yAxisTickMaxWidth =
116
+ getMaxWidthByYAxisTicks(ticks, this.ctx, yAxis2.tickValueFormatter) + 10;
117
+ this.ticks = ticks;
118
+ this.tickMaxWidth = yAxisTickMaxWidth;
119
+ }
120
+
121
+ draw(yScales: YScales) {
122
+ const { ctx, options } = this;
123
+ const { yAxis, chart } = options;
124
+
125
+ // draw background 用于遮挡 gridline
126
+ ctx.beginPath();
127
+ ctx.fillStyle = yAxis.backgroundColor || "#fff";
128
+ ctx.fillRect(
129
+ chart.width - this.tickMaxWidth,
130
+ 0,
131
+ this.tickMaxWidth,
132
+ chart.height - 12
133
+ );
134
+ ctx.stroke();
135
+ ctx.closePath();
136
+
137
+ // draw labels
138
+ ctx.textAlign = "right";
139
+ ctx.textBaseline = "middle";
140
+ ctx.strokeStyle = yAxis.labels.color;
141
+ ctx.lineWidth = 1;
142
+ ctx.fillStyle = yAxis.labels.color;
143
+ this.ticks.forEach((d) => {
144
+ let text;
145
+ if (typeof yAxis.tickValueFormatter === "function") {
146
+ text = yAxis.tickValueFormatter(d);
147
+ } else {
148
+ text = shortUint(d);
149
+ }
150
+ const y = yScales(d);
151
+ ctx.fillText(text, chart.width - 5, y);
152
+ });
153
+ }
154
+ }