@fc-plot/ts-graph 0.23.2 → 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/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
+ }