-
Notifications
You must be signed in to change notification settings - Fork 346
/
flow.ts
219 lines (190 loc) 路 6.21 KB
/
flow.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/**
* Copyright (c) 2017 ~ present NAVER Corp.
* billboard.js project is licensed under the MIT license
*/
import {isDefined, isTabVisible, isValue, parseDate} from "../../module/util";
export default {
/**
* Flow data to the chart.<br><br>
* By this API, you can append new data points to the chart.
* @function flow
* @instance
* @memberof Chart
* @param {object} args The object can consist with following members:<br>
*
* | Key | Type | Description |
* | --- | --- | --- |
* | json | Object | Data as JSON format (@see [data鈥son](Options.html#.data%25E2%2580%25A4json)) |
* | rows | Array | Data in array as row format (@see [data鈥ows](Options.html#.data%25E2%2580%25A4json)) |
* | columns | Array | Data in array as column format (@see [data鈥olumns](Options.html#.data%25E2%2580%25A4columns)) |
* | to | String | The lower x edge will move to that point. If not given, the lower x edge will move by the number of given data points |
* | length | Number | The lower x edge will move by the number of this argument |
* | duration | Number | The duration of the transition will be specified value. If not given, transition.duration will be used as default |
* | done | Function | The specified function will be called when flow ends |
*
* - **NOTE:**
* - If json, rows and columns given, the data will be loaded.
* - If data that has the same target id is given, the chart will be appended.
* - Otherwise, new target will be added. One of these is required when calling.
* - If json specified, keys is required as well as data.json.
* - If tab isn't visible(by evaluating `document.hidden`), will not be executed to prevent unnecessary work.
* @example
* // 2 data points will be apprended to the tail and popped from the head.
* // After that, 4 data points will be appended and no data points will be poppoed.
* chart.flow({
* columns: [
* ["x", "2018-01-11", "2018-01-21"],
* ["data1", 500, 200],
* ["data2", 100, 300],
* ["data3", 200, 120]
* ],
* to: "2013-01-11",
* done: function () {
* chart.flow({
* columns: [
* ["x", "2018-02-11", "2018-02-12", "2018-02-13", "2018-02-14"],
* ["data1", 200, 300, 100, 250],
* ["data2", 100, 90, 40, 120],
* ["data3", 100, 100, 300, 500]
* ],
* length: 2,
* duration: 1500
* });
* }
* });
*/
flow(args): void {
const $$ = this.internal;
let data;
if (args.json || args.rows || args.columns) {
$$.convertData(args, res => {
data = res;
_();
});
}
/**
* Process flows
* @private
*/
function _(): void {
let domain;
let length: number = 0;
let tail = 0;
let diff;
let to;
if ($$.state.redrawing || !data || !isTabVisible()) {
return;
}
const notfoundIds: string[] = [];
const orgDataCount = $$.getMaxDataCount();
const targets = $$.convertDataToTargets(data, true);
const isTimeSeries = $$.axis.isTimeSeries();
// Update/Add data
$$.data.targets.forEach(t => {
let found = false;
for (let i = 0; i < targets.length; i++) {
if (t.id === targets[i].id) {
found = true;
if (t.values[t.values.length - 1]) {
tail = t.values[t.values.length - 1].index + 1;
}
length = targets[i].values.length;
for (let j = 0; j < length; j++) {
targets[i].values[j].index = tail + j;
if (!isTimeSeries) {
targets[i].values[j].x = tail + j;
}
}
t.values = t.values.concat(targets[i].values);
targets.splice(i, 1);
break;
}
}
!found && notfoundIds.push(t.id);
});
// Append null for not found targets
$$.data.targets.forEach(t => {
for (let i = 0; i < notfoundIds.length; i++) {
if (t.id === notfoundIds[i]) {
tail = t.values[t.values.length - 1].index + 1;
for (let j = 0; j < length; j++) {
t.values.push({
id: t.id,
index: tail + j,
x: isTimeSeries ? $$.getOtherTargetX(tail + j) : tail + j,
value: null
});
}
}
}
});
// Generate null values for new target
if ($$.data.targets.length) {
targets.forEach(t => {
const missing: any[] = [];
for (let i = $$.data.targets[0].values[0].index; i < tail; i++) {
missing.push({
id: t.id,
index: i,
x: isTimeSeries ? $$.getOtherTargetX(i) : i,
value: null
});
}
t.values.forEach(v => {
v.index += tail;
if (!isTimeSeries) {
v.x += tail;
}
});
t.values = missing.concat(t.values);
});
}
$$.data.targets = $$.data.targets.concat(targets); // add remained
// check data count because behavior needs to change when it"s only one
// const dataCount = $$.getMaxDataCount();
const baseTarget = $$.data.targets[0];
const baseValue = baseTarget.values[0];
// Update length to flow if needed
if (isDefined(args.to)) {
length = 0;
to = isTimeSeries ? parseDate.call($$, args.to) : args.to;
baseTarget.values.forEach(v => {
v.x < to && length++;
});
} else if (isDefined(args.length)) {
length = args.length;
}
// If only one data, update the domain to flow from left edge of the chart
if (!orgDataCount) {
if (isTimeSeries) {
diff = baseTarget.values.length > 1 ?
baseTarget.values[baseTarget.values.length - 1].x - baseValue.x :
baseValue.x - $$.getXDomain($$.data.targets)[0];
} else {
diff = 1;
}
domain = [baseValue.x - diff, baseValue.x];
} else if (orgDataCount === 1 && isTimeSeries) {
diff = (baseTarget.values[baseTarget.values.length - 1].x - baseValue.x) / 2;
domain = [new Date(+baseValue.x - diff), new Date(+baseValue.x + diff)];
}
domain && $$.updateXDomain(null, true, true, false, domain);
// Set targets
$$.updateTargets($$.data.targets);
// Redraw with new targets
$$.redraw({
flow: {
index: baseValue.index,
length: length,
duration: isValue(args.duration) ? args.duration : $$.config.transition_duration,
done: args.done,
orgDataCount: orgDataCount,
},
withLegend: true,
withTransition: orgDataCount > 1,
withTrimXDomain: false,
withUpdateXAxis: true
});
}
}
};