@fc-plot/ts-graph 0.16.4 → 0.17.1

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/tooltip.ts CHANGED
@@ -1,9 +1,14 @@
1
- import * as d3 from 'd3';
2
- import { groupBy, keys, orderBy, isNumber } from 'lodash';
3
- import { distanceBetweenPointsX, distanceBetweenPoints, getColor, formatTrim } from './utils';
4
- import { Options, EventPosition, Point, XScales, YScales } from './interface';
5
- import TsGraph from './index';
6
- import getNearestPoints from './getNearestPoints';
1
+ import * as d3 from "d3";
2
+ import { groupBy, keys, orderBy, isNumber } from "lodash";
3
+ import {
4
+ distanceBetweenPointsX,
5
+ distanceBetweenPoints,
6
+ getColor,
7
+ formatTrim,
8
+ } from "./utils";
9
+ import { Options, EventPosition, Point, XScales, YScales } from "./interface";
10
+ import TsGraph from "./index";
11
+ import getNearestPoints from "./getNearestPoints";
7
12
 
8
13
  export default class Tooltip {
9
14
  options: Options;
@@ -11,7 +16,12 @@ export default class Tooltip {
11
16
  flag: boolean;
12
17
  container: any;
13
18
  isMouserover: boolean;
14
- constructor(userOptions: Options, ctx: CanvasRenderingContext2D, container: HTMLElement, canvas: HTMLCanvasElement) {
19
+ constructor(
20
+ userOptions: Options,
21
+ ctx: CanvasRenderingContext2D,
22
+ container: HTMLElement,
23
+ canvas: HTMLCanvasElement
24
+ ) {
15
25
  this.options = userOptions;
16
26
  this.ctx = ctx;
17
27
  this.flag = false;
@@ -21,11 +31,13 @@ export default class Tooltip {
21
31
  }
22
32
 
23
33
  init(container: HTMLElement, canvas: HTMLCanvasElement) {
24
- const { chart: { id } } = this.options;
25
- const tooltipNode = document.createElement('div');
34
+ const {
35
+ chart: { id },
36
+ } = this.options;
37
+ const tooltipNode = document.createElement("div");
26
38
 
27
39
  tooltipNode.id = `${id}-tooltip`;
28
- tooltipNode.className = 'ts-graph-tooltip';
40
+ tooltipNode.className = "ts-graph-tooltip";
29
41
  // 插到 eventCanvas 前,事件是绑定在 eventCanvas 层,防止 tooltip 遮挡
30
42
  if (!document.getElementById(tooltipNode.id)) {
31
43
  // container.insertBefore(tooltipNode, canvas);
@@ -34,7 +46,10 @@ export default class Tooltip {
34
46
  }
35
47
 
36
48
  clear() {
37
- const { ratio, chart: { id, containerWidth, containerHeight } } = this.options;
49
+ const {
50
+ ratio,
51
+ chart: { id, containerWidth, containerHeight },
52
+ } = this.options;
38
53
  const tooltipNode = document.getElementById(`${id}-tooltip`) as HTMLElement;
39
54
 
40
55
  this.isMouserover = false;
@@ -42,25 +57,42 @@ export default class Tooltip {
42
57
  this.ctx.setTransform(1 * ratio, 0, 0, 1 * ratio, 0, 0);
43
58
  this.ctx.clearRect(0, 0, containerWidth, containerHeight);
44
59
  this.ctx.restore();
45
- tooltipNode.style.top = '-99999px';
60
+ tooltipNode.style.top = "-99999px";
46
61
  if (tooltipNode.lastChild) {
47
62
  tooltipNode.removeChild(tooltipNode.lastChild);
48
63
  }
49
64
  }
50
65
 
51
- getNearestPoints(eventPosition: EventPosition, xScales: XScales, yScales: YScales, cbk: (nearestPoints: Point[]) => void) {
52
- const { series = [], chart: { colors }, tooltip: { shared }, xkey, ykey, oykey, timestamp, fillNull } = this.options;
66
+ getNearestPoints(
67
+ eventPosition: EventPosition,
68
+ xScales: XScales,
69
+ yScales: YScales,
70
+ cbk: (nearestPoints: Point[]) => void
71
+ ) {
72
+ const {
73
+ series = [],
74
+ chart: { colors },
75
+ tooltip: { shared },
76
+ xkey,
77
+ ykey,
78
+ ykey2,
79
+ oykey,
80
+ timestamp,
81
+ fillNull,
82
+ } = this.options;
53
83
  const containerRect = this.container.getBoundingClientRect();
54
- const offsetX = eventPosition.offsetX || eventPosition.clientX - containerRect.left;
84
+ const offsetX =
85
+ eventPosition.offsetX || eventPosition.clientX - containerRect.left;
55
86
  const x = xScales.invert(offsetX);
56
87
  let nearestPoints: Point[] = [];
57
-
88
+
58
89
  if (this.isMouserover === false) return;
59
90
 
60
91
  nearestPoints = getNearestPoints({
61
92
  x,
62
93
  xkey,
63
94
  ykey,
95
+ ykey2,
64
96
  oykey,
65
97
  timestamp,
66
98
  series,
@@ -75,7 +107,7 @@ export default class Tooltip {
75
107
  });
76
108
 
77
109
  // 不同时间点数据,还需要再处理一遍
78
- const nearestPointsGroup = groupBy(nearestPoints, 'x');
110
+ const nearestPointsGroup = groupBy(nearestPoints, "x");
79
111
 
80
112
  if (keys(nearestPointsGroup).length > 1) {
81
113
  let minDistance = Number.POSITIVE_INFINITY;
@@ -97,10 +129,13 @@ export default class Tooltip {
97
129
  let minDistance = Number.POSITIVE_INFINITY;
98
130
 
99
131
  nearestPoints.forEach((point) => {
100
- const d = distanceBetweenPoints({
101
- x: eventPosition.offsetX,
102
- y: eventPosition.offsetY,
103
- }, point);
132
+ const d = distanceBetweenPoints(
133
+ {
134
+ x: eventPosition.offsetX,
135
+ y: eventPosition.offsetY,
136
+ },
137
+ point
138
+ );
104
139
 
105
140
  if (d < minDistance) {
106
141
  minDistance = d;
@@ -112,29 +147,38 @@ export default class Tooltip {
112
147
  cbk(nearestPoints);
113
148
  }
114
149
 
115
- draw(eventPosition: EventPosition, instance: TsGraph, cbk?: (nearestPoints: Point[]) => void) {
150
+ draw(
151
+ eventPosition: EventPosition,
152
+ instance: TsGraph,
153
+ cbk?: (nearestPoints: Point[]) => void
154
+ ) {
116
155
  const { xScales, yScales, yAxis } = instance;
117
156
  this.isMouserover = true;
118
157
  this.getNearestPoints(eventPosition, xScales, yScales, (nearestPoints) => {
119
158
  this.clear();
120
159
  if (nearestPoints.length) {
121
- if (nearestPoints[0].x < yAxis.tickMaxWidth) return; // 判断是否在 y 轴上
160
+ if (nearestPoints[0].x < yAxis.tickMaxWidth) return; // 判断是否在 y 轴上
122
161
  this.drawCrosshair(nearestPoints[0].x);
123
162
  this.drawSymbol(nearestPoints);
124
163
  this.drawModal(nearestPoints, eventPosition);
125
164
  }
126
- if (cbk && Object.prototype.toString.call(cbk) === '[object Function]') {
165
+ if (cbk && Object.prototype.toString.call(cbk) === "[object Function]") {
127
166
  cbk(nearestPoints);
128
167
  }
129
168
  });
130
169
  }
131
170
 
132
171
  drawModal(nearestPoints: Point[], eventPosition: EventPosition) {
133
- const { chart: { id, renderTo }, tooltip, time, notDisplayedSeries } = this.options;
172
+ const {
173
+ chart: { id, renderTo },
174
+ tooltip,
175
+ time,
176
+ notDisplayedSeries,
177
+ } = this.options;
134
178
  const renderToWidth = renderTo.offsetWidth;
135
179
  let renderToHeight = renderTo.offsetHeight;
136
180
  const tooltipNode = document.getElementById(`${id}-tooltip`) as HTMLElement;
137
- const wrapEle = document.createElement('div');
181
+ const wrapEle = document.createElement("div");
138
182
  const originalNearestPoints = nearestPoints;
139
183
 
140
184
  renderToHeight = window.innerHeight / 1.5;
@@ -148,9 +192,13 @@ export default class Tooltip {
148
192
  let overflow = false;
149
193
 
150
194
  if (tooltip.sharedSortDirection) {
151
- nearestPoints = orderBy(nearestPoints, (point: Point) => {
152
- return point.value;
153
- }, tooltip.sharedSortDirection);
195
+ nearestPoints = orderBy(
196
+ nearestPoints,
197
+ (point: Point) => {
198
+ return point.value;
199
+ },
200
+ tooltip.sharedSortDirection
201
+ );
154
202
  }
155
203
 
156
204
  if (nearestPoints.length > maxLength) {
@@ -158,40 +206,48 @@ export default class Tooltip {
158
206
  overflow = true;
159
207
  }
160
208
 
161
- wrapEle.className = 'ts-graph-tooltip-content';
209
+ wrapEle.className = "ts-graph-tooltip-content";
162
210
  tooltipNode.appendChild(wrapEle);
163
211
 
164
- if (Object.prototype.toString.call(tooltip.formatter) === '[object Function]') {
165
- wrapEle.innerHTML = tooltip.formatter([...nearestPoints], [...originalNearestPoints]);
212
+ if (
213
+ Object.prototype.toString.call(tooltip.formatter) === "[object Function]"
214
+ ) {
215
+ wrapEle.innerHTML = tooltip.formatter(
216
+ [...nearestPoints],
217
+ [...originalNearestPoints]
218
+ );
166
219
  } else {
167
220
  const firstNearestPoint = nearestPoints[0];
168
221
  const frag = document.createDocumentFragment();
169
- const ulNode = document.createElement('ul');
170
- const headerNode = document.createElement('li');
222
+ const ulNode = document.createElement("ul");
223
+ const headerNode = document.createElement("li");
171
224
 
172
225
  let tzD = new Date(firstNearestPoint.timestamp);
173
226
 
174
227
  if (time && time.timezoneOffset) {
175
228
  const timezoneOffset = tzD.getTimezoneOffset();
176
229
  const ts = tzD.getTime();
177
- const destTs = ts + (timezoneOffset * 60 * 1000) + (time.timezoneOffset * 60 * 1000);
230
+ const destTs =
231
+ ts + timezoneOffset * 60 * 1000 + time.timezoneOffset * 60 * 1000;
178
232
  tzD = new Date(destTs);
179
233
  }
180
- const headerTextNode = document.createTextNode(d3.timeFormat(tooltip.timeFormat)(tzD));
234
+ const headerTextNode = document.createTextNode(
235
+ d3.timeFormat(tooltip.timeFormat)(tzD)
236
+ );
181
237
 
182
238
  headerNode.appendChild(headerTextNode);
183
- headerNode.style.color = '#666';
239
+ headerNode.style.color = "#666";
184
240
  ulNode.style.maxWidth = `${window.innerWidth / 1.5}px`; // 宽度最大值
185
241
  ulNode.appendChild(headerNode);
186
242
  frag.appendChild(ulNode);
187
243
 
188
244
  nearestPoints.forEach(({ color, name, origin, filledNull }) => {
189
245
  if (notDisplayedSeries.indexOf(name) > -1) return;
190
- const liNode = document.createElement('li');
246
+ const liNode = document.createElement("li");
191
247
 
192
248
  if (color) {
193
- const symbolNode = document.createElement('span');
194
- const symbolTextNode = document.createTextNode('');
249
+ const symbolNode = document.createElement("span");
250
+ const symbolTextNode = document.createTextNode("");
195
251
 
196
252
  symbolNode.style.color = color;
197
253
  symbolNode.appendChild(symbolTextNode);
@@ -207,26 +263,26 @@ export default class Tooltip {
207
263
  const value = origin;
208
264
 
209
265
  if (isNumber(value)) {
210
- const valueNode = document.createElement('strong');
211
- let formatValue
266
+ const valueNode = document.createElement("strong");
267
+ let formatValue;
212
268
 
213
- if (typeof tooltip.pointValueformatter === 'function') {
269
+ if (typeof tooltip.pointValueformatter === "function") {
214
270
  formatValue = tooltip.pointValueformatter(value);
215
271
  } else {
216
- if (tooltip.precision === 'origin') {
217
- formatValue = value
218
- } else if (tooltip.precision === 'short') {
219
- let text = d3.format('.5s')(value);
272
+ if (tooltip.precision === "origin") {
273
+ formatValue = value;
274
+ } else if (tooltip.precision === "short") {
275
+ let text = d3.format(".5s")(value);
220
276
  formatValue = formatTrim(text);
221
277
  } else if (tooltip.precision > 0) {
222
- formatValue = d3.format(',.'+tooltip.precision+'f')(value)
278
+ formatValue = d3.format(",." + tooltip.precision + "f")(value);
223
279
  } else {
224
- formatValue = d3.format(',.3f')(value)
280
+ formatValue = d3.format(",.3f")(value);
225
281
  }
226
- }
282
+ }
283
+
284
+ formatValue += filledNull ? "(空值填补,仅限看图使用)" : "";
227
285
 
228
- formatValue += filledNull ? '(空值填补,仅限看图使用)' : ''
229
-
230
286
  const valueTextNode = document.createTextNode(formatValue);
231
287
 
232
288
  valueNode.appendChild(valueTextNode);
@@ -236,8 +292,8 @@ export default class Tooltip {
236
292
  });
237
293
 
238
294
  if (overflow) {
239
- const overflowLiNode = document.createElement('li');
240
- const overflowLiTextNode = document.createTextNode('......');
295
+ const overflowLiNode = document.createElement("li");
296
+ const overflowLiTextNode = document.createTextNode("......");
241
297
 
242
298
  overflowLiNode.appendChild(overflowLiTextNode);
243
299
  ulNode.appendChild(overflowLiNode);
@@ -257,21 +313,21 @@ export default class Tooltip {
257
313
 
258
314
  if (clientX - tooltipWidth - 20 < 0) {
259
315
  tooltipNode.style.left = `${clientX + 20}px`;
260
- if ((clientX + 20 + tooltipWidth) > renderToWidth) {
261
- tooltipNode.style.left = '0px';
316
+ if (clientX + 20 + tooltipWidth > renderToWidth) {
317
+ tooltipNode.style.left = "0px";
262
318
  }
263
319
  }
264
320
 
265
- if ((clientY + 20 + tooltipHeight) > renderToHeight) {
321
+ if (clientY + 20 + tooltipHeight > renderToHeight) {
266
322
  if (clientY - tooltipHeight - 20 < 0) {
267
- tooltipNode.style.top = '0px';
323
+ tooltipNode.style.top = "0px";
268
324
  } else {
269
325
  tooltipNode.style.top = `${clientY - tooltipHeight - 20}px`;
270
326
  }
271
327
  }
272
328
 
273
- tooltipNode.style.zIndex = '9999';
274
- tooltipNode.style.visibility = 'visible';
329
+ tooltipNode.style.zIndex = "9999";
330
+ tooltipNode.style.visibility = "visible";
275
331
  }
276
332
 
277
333
  drawSymbol(points: Point[] = []) {
@@ -288,7 +344,7 @@ export default class Tooltip {
288
344
  ctx.beginPath();
289
345
  ctx.arc(x, y, 3, 0, 360, false);
290
346
  ctx.lineWidth = 1;
291
- ctx.fillStyle = 'white';
347
+ ctx.fillStyle = "white";
292
348
  ctx.fill();
293
349
  });
294
350
  }
@@ -296,7 +352,11 @@ export default class Tooltip {
296
352
  drawCrosshair(x: number) {
297
353
  const { ctx, options } = this;
298
354
  const { chart, xAxis } = options;
299
- const tickBottom = chart.height - xAxis.tickpadding - xAxis.labels.fontSize - xAxis.tickLength;
355
+ const tickBottom =
356
+ chart.height -
357
+ xAxis.tickpadding -
358
+ xAxis.labels.fontSize -
359
+ xAxis.tickLength;
300
360
 
301
361
  ctx.beginPath();
302
362
  ctx.moveTo(x, 0);
@@ -307,7 +367,9 @@ export default class Tooltip {
307
367
  }
308
368
 
309
369
  destroy() {
310
- const { chart: { id } } = this.options;
370
+ const {
371
+ chart: { id },
372
+ } = this.options;
311
373
  const tooltipNode = document.getElementById(`${id}-tooltip`) as HTMLElement;
312
374
  if (tooltipNode && tooltipNode.parentNode) {
313
375
  tooltipNode.parentNode.removeChild(tooltipNode);
package/src/yAxis.ts CHANGED
@@ -1,7 +1,6 @@
1
- import * as d3 from 'd3';
2
- import { map } from 'lodash';
3
- import { Options, YScales } from './interface';
4
- import { shortUint, getMaxWidthByYAxisTicks } from './utils';
1
+ import * as d3 from "d3";
2
+ import { Options, YScales } from "./interface";
3
+ import { shortUint, getMaxWidthByYAxisTicks } from "./utils";
5
4
 
6
5
  interface RealData {
7
6
  [index: string]: any;
@@ -26,7 +25,13 @@ export default class YAxis {
26
25
 
27
26
  init() {
28
27
  const { chart, xAxis } = this.options;
29
- const yScales = d3.scaleLinear().range([chart.height - (xAxis.labels.fontSize + xAxis.tickpadding + xAxis.tickLength), 20]);
28
+ const yScales = d3
29
+ .scaleLinear()
30
+ .range([
31
+ chart.height -
32
+ (xAxis.labels.fontSize + xAxis.tickpadding + xAxis.tickLength),
33
+ 20,
34
+ ]);
30
35
 
31
36
  this.setDomain(yScales, this.options);
32
37
  return yScales;
@@ -38,19 +43,23 @@ export default class YAxis {
38
43
  * @return {Array} [description]
39
44
  */
40
45
  getRealData(data: RealData) {
41
- const { yAxis: { plotLines }, ykey, fillNull } = this.options;
46
+ const {
47
+ yAxis: { plotLines },
48
+ ykey,
49
+ fillNull,
50
+ } = this.options;
42
51
 
43
52
  if (Array.isArray(data)) {
44
53
  if (Array.isArray(plotLines)) {
45
54
  plotLines.forEach((plotLine) => {
46
- if (typeof plotLine.value === 'number') {
55
+ if (typeof plotLine.value === "number") {
47
56
  data.push({
48
57
  [ykey]: plotLine.value,
49
58
  });
50
59
  }
51
60
  });
52
61
  }
53
- if (typeof fillNull === 'number') {
62
+ if (typeof fillNull === "number") {
54
63
  data.push({
55
64
  [ykey]: fillNull,
56
65
  });
@@ -61,7 +70,9 @@ export default class YAxis {
61
70
  }
62
71
 
63
72
  getPlotLinesMaxAbs() {
64
- const { yAxis: { plotLines } } = this.options;
73
+ const {
74
+ yAxis: { plotLines },
75
+ } = this.options;
65
76
  let maxAbs: undefined | number;
66
77
  if (Array.isArray(plotLines)) {
67
78
  plotLines.forEach((plotLine) => {
@@ -73,7 +84,7 @@ export default class YAxis {
73
84
  return maxAbs;
74
85
  }
75
86
 
76
- setDomain(yScales: YScales, { ymin, ymax }: { ymin: number, ymax: number}) {
87
+ setDomain(yScales: YScales, { ymin, ymax }: { ymin: number; ymax: number }) {
77
88
  const { options } = this;
78
89
  const { yAxis } = options;
79
90
  const plotLinesMaxAbs = this.getPlotLinesMaxAbs();
@@ -108,7 +119,8 @@ export default class YAxis {
108
119
  yScales.domain([ymin, ymax]);
109
120
  yScales.nice(realTickLength);
110
121
  const ticks = yScales.ticks(realTickLength);
111
- const yAxisTickMaxWidth = getMaxWidthByYAxisTicks(ticks, this.ctx, yAxis.tickValueFormatter) + 5;
122
+ const yAxisTickMaxWidth =
123
+ getMaxWidthByYAxisTicks(ticks, this.ctx, yAxis.tickValueFormatter) + 5;
112
124
  this.ticks = ticks;
113
125
  this.tickMaxWidth = yAxisTickMaxWidth;
114
126
  }
@@ -119,21 +131,21 @@ export default class YAxis {
119
131
 
120
132
  // draw background
121
133
  ctx.beginPath();
122
- ctx.fillStyle = '#fff';
134
+ ctx.fillStyle = "#fff";
123
135
  ctx.fillRect(0, 0, this.tickMaxWidth, chart.height);
124
136
  ctx.stroke();
125
137
  ctx.closePath();
126
138
 
127
139
  // draw labels
128
- ctx.textAlign = 'right';
129
- ctx.textBaseline = 'middle';
140
+ ctx.textAlign = "right";
141
+ ctx.textBaseline = "middle";
130
142
  ctx.strokeStyle = yAxis.labels.color;
131
143
  ctx.lineWidth = 1;
132
144
  ctx.fillStyle = yAxis.labels.color;
133
145
  // ctx.font = `${yAxis.labels.fontSize}px Palantino`;
134
146
  this.ticks.forEach((d) => {
135
147
  let text;
136
- if (typeof yAxis.tickValueFormatter === 'function') {
148
+ if (typeof yAxis.tickValueFormatter === "function") {
137
149
  text = yAxis.tickValueFormatter(d);
138
150
  } else {
139
151
  text = shortUint(d);
@@ -160,7 +172,11 @@ export default class YAxis {
160
172
 
161
173
  drawPlotLines(yScales: YScales) {
162
174
  const { ctx, options } = this;
163
- const { chart, yAxis, yAxis: { plotLines } } = options;
175
+ const {
176
+ chart,
177
+ yAxis,
178
+ yAxis: { plotLines },
179
+ } = options;
164
180
 
165
181
  if (Array.isArray(plotLines)) {
166
182
  plotLines.forEach((plotLine) => {
@@ -173,9 +189,9 @@ export default class YAxis {
173
189
  ctx.stroke();
174
190
  ctx.setLineDash([]);
175
191
 
176
- ctx.textAlign = 'right';
177
- ctx.textBaseline = 'top';
178
- ctx.shadowColor = '#fff';
192
+ ctx.textAlign = "right";
193
+ ctx.textBaseline = "top";
194
+ ctx.shadowColor = "#fff";
179
195
  ctx.shadowBlur = 1;
180
196
  ctx.lineWidth = 1;
181
197
  ctx.fillStyle = plotLine.color;