@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 +11 -6
- package/package.json +1 -1
- package/src/index.ts +90 -21
- package/src/interface.ts +4 -0
- package/src/line.ts +13 -8
- package/src/tooltip.ts +9 -2
- package/src/utils.ts +4 -1
- package/src/xAxis.ts +11 -3
- package/src/yAxis.ts +1 -37
- package/src/yAxis2.ts +154 -0
- package/dist/BundleReport.html +0 -53
- package/dist/index.css +0 -104
- package/dist/index.css.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
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 =
|
|
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:
|
|
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 =
|
|
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) *
|
|
79
|
-
renderTo.style.height = `${(i + 1) *
|
|
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
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.
|
|
89
|
-
height: userOptions.chart.renderTo.
|
|
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 (
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
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 (
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
-
|
|
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
|
|
48
|
+
return yScalesFunc(val);
|
|
44
49
|
} else if (typeof fillNull === "number") {
|
|
45
|
-
return
|
|
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:
|
|
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([
|
|
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(
|
|
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(
|
|
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
|
+
}
|