1 | var { DataSet } = require('vis-data');
|
2 | var { DataView } = require('vis-data');
|
3 | var Range = require('./Range');
|
4 | var Filter = require('./Filter');
|
5 | var Settings = require('./Settings');
|
6 | var Point3d = require('./Point3d');
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 | function DataGroup() {
|
22 | this.dataTable = null;
|
23 | }
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 |
|
41 | DataGroup.prototype.initializeData = function(graph3d, rawData, style) {
|
42 | if (rawData === undefined) return;
|
43 |
|
44 | if (Array.isArray(rawData)) {
|
45 | rawData = new DataSet(rawData);
|
46 | }
|
47 |
|
48 | var data;
|
49 | if (rawData instanceof DataSet || rawData instanceof DataView) {
|
50 | data = rawData.get();
|
51 | }
|
52 | else {
|
53 | throw new Error('Array, DataSet, or DataView expected');
|
54 | }
|
55 |
|
56 | if (data.length == 0) return;
|
57 |
|
58 | this.style = style;
|
59 |
|
60 |
|
61 | if (this.dataSet) {
|
62 | this.dataSet.off('*', this._onChange);
|
63 | }
|
64 |
|
65 | this.dataSet = rawData;
|
66 | this.dataTable = data;
|
67 |
|
68 |
|
69 | var me = this;
|
70 | this._onChange = function () {
|
71 | graph3d.setData(me.dataSet);
|
72 | };
|
73 | this.dataSet.on('*', this._onChange);
|
74 |
|
75 |
|
76 | this.colX = 'x';
|
77 | this.colY = 'y';
|
78 | this.colZ = 'z';
|
79 |
|
80 |
|
81 | var withBars = graph3d.hasBars(style);
|
82 |
|
83 |
|
84 | if (withBars) {
|
85 | if (graph3d.defaultXBarWidth !== undefined) {
|
86 | this.xBarWidth = graph3d.defaultXBarWidth;
|
87 | }
|
88 | else {
|
89 | this.xBarWidth = this.getSmallestDifference(data, this.colX) || 1;
|
90 | }
|
91 |
|
92 | if (graph3d.defaultYBarWidth !== undefined) {
|
93 | this.yBarWidth = graph3d.defaultYBarWidth;
|
94 | }
|
95 | else {
|
96 | this.yBarWidth = this.getSmallestDifference(data, this.colY) || 1;
|
97 | }
|
98 | }
|
99 |
|
100 |
|
101 | this._initializeRange(data, this.colX, graph3d, withBars);
|
102 | this._initializeRange(data, this.colY, graph3d, withBars);
|
103 | this._initializeRange(data, this.colZ, graph3d, false);
|
104 |
|
105 | if (data[0].hasOwnProperty('style')) {
|
106 | this.colValue = 'style';
|
107 | var valueRange = this.getColumnRange(data, this.colValue);
|
108 | this._setRangeDefaults(valueRange, graph3d.defaultValueMin, graph3d.defaultValueMax);
|
109 | this.valueRange = valueRange;
|
110 | }
|
111 |
|
112 |
|
113 | var table = this.getDataTable();
|
114 | if (table[0].hasOwnProperty('filter')) {
|
115 | if (this.dataFilter === undefined) {
|
116 | this.dataFilter = new Filter(this, 'filter', graph3d);
|
117 | this.dataFilter.setOnLoadCallback(function() { graph3d.redraw(); });
|
118 | }
|
119 | }
|
120 |
|
121 |
|
122 | var dataPoints;
|
123 | if (this.dataFilter) {
|
124 |
|
125 | dataPoints = this.dataFilter._getDataPoints();
|
126 | }
|
127 | else {
|
128 |
|
129 | dataPoints = this._getDataPoints(this.getDataTable());
|
130 | }
|
131 | return dataPoints;
|
132 | };
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 |
|
141 |
|
142 |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 |
|
148 |
|
149 |
|
150 | DataGroup.prototype._collectRangeSettings = function(column, graph3d) {
|
151 | var index = ['x', 'y', 'z'].indexOf(column);
|
152 |
|
153 | if (index == -1) {
|
154 | throw new Error('Column \'' + column + '\' invalid');
|
155 | }
|
156 |
|
157 | var upper = column.toUpperCase();
|
158 |
|
159 | return {
|
160 | barWidth : this[column + 'BarWidth'],
|
161 | min : graph3d['default' + upper + 'Min'],
|
162 | max : graph3d['default' + upper + 'Max'],
|
163 | step : graph3d['default' + upper + 'Step'],
|
164 | range_label: column + 'Range',
|
165 | step_label : column + 'Step'
|
166 | };
|
167 | };
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | DataGroup.prototype._initializeRange = function(data, column, graph3d, withBars) {
|
184 | var NUMSTEPS = 5;
|
185 | var settings = this._collectRangeSettings(column, graph3d);
|
186 |
|
187 | var range = this.getColumnRange(data, column);
|
188 | if (withBars && column != 'z') {
|
189 | range.expand(settings.barWidth / 2);
|
190 | }
|
191 |
|
192 | this._setRangeDefaults(range, settings.min, settings.max);
|
193 | this[settings.range_label] = range;
|
194 | this[settings.step_label ] = (settings.step !== undefined) ? settings.step : range.range()/NUMSTEPS;
|
195 | }
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 | DataGroup.prototype.getDistinctValues = function(column, data) {
|
209 | if (data === undefined) {
|
210 | data = this.dataTable;
|
211 | }
|
212 |
|
213 | var values = [];
|
214 |
|
215 | for (var i = 0; i < data.length; i++) {
|
216 | var value = data[i][column] || 0;
|
217 | if (values.indexOf(value) === -1) {
|
218 | values.push(value);
|
219 | }
|
220 | }
|
221 |
|
222 | return values.sort(function(a,b) { return a - b; });
|
223 | };
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 | DataGroup.prototype.getSmallestDifference = function(data, column) {
|
237 | var values = this.getDistinctValues(data, column);
|
238 |
|
239 |
|
240 |
|
241 | var smallest_diff = null;
|
242 |
|
243 | for (var i = 1; i < values.length; i++) {
|
244 | var diff = values[i] - values[i - 1];
|
245 |
|
246 | if (smallest_diff == null || smallest_diff > diff ) {
|
247 | smallest_diff = diff;
|
248 | }
|
249 | }
|
250 |
|
251 | return smallest_diff;
|
252 | }
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | DataGroup.prototype.getColumnRange = function(data, column) {
|
264 | var range = new Range();
|
265 |
|
266 |
|
267 | for (var i = 0; i < data.length; i++) {
|
268 | var item = data[i][column];
|
269 | range.adjust(item);
|
270 | }
|
271 |
|
272 | return range;
|
273 | };
|
274 |
|
275 |
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 | DataGroup.prototype.getNumberOfRows = function() {
|
282 | return this.dataTable.length;
|
283 | };
|
284 |
|
285 |
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 | DataGroup.prototype._setRangeDefaults = function (range, defaultMin, defaultMax) {
|
301 | if (defaultMin !== undefined) {
|
302 | range.min = defaultMin;
|
303 | }
|
304 |
|
305 | if (defaultMax !== undefined) {
|
306 | range.max = defaultMax;
|
307 | }
|
308 |
|
309 |
|
310 |
|
311 |
|
312 | if (range.max <= range.min) range.max = range.min + 1;
|
313 | };
|
314 |
|
315 |
|
316 | DataGroup.prototype.getDataTable = function() {
|
317 | return this.dataTable;
|
318 | };
|
319 |
|
320 |
|
321 | DataGroup.prototype.getDataSet = function() {
|
322 | return this.dataSet;
|
323 | };
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 | DataGroup.prototype.getDataPoints = function(data) {
|
332 | var dataPoints = [];
|
333 |
|
334 | for (var i = 0; i < data.length; i++) {
|
335 | var point = new Point3d();
|
336 | point.x = data[i][this.colX] || 0;
|
337 | point.y = data[i][this.colY] || 0;
|
338 | point.z = data[i][this.colZ] || 0;
|
339 | point.data = data[i];
|
340 |
|
341 | if (this.colValue !== undefined) {
|
342 | point.value = data[i][this.colValue] || 0;
|
343 | }
|
344 |
|
345 | var obj = {};
|
346 | obj.point = point;
|
347 | obj.bottom = new Point3d(point.x, point.y, this.zRange.min);
|
348 | obj.trans = undefined;
|
349 | obj.screen = undefined;
|
350 |
|
351 | dataPoints.push(obj);
|
352 | }
|
353 |
|
354 | return dataPoints;
|
355 | };
|
356 |
|
357 |
|
358 |
|
359 |
|
360 |
|
361 |
|
362 |
|
363 |
|
364 |
|
365 |
|
366 | DataGroup.prototype.initDataAsMatrix = function(data) {
|
367 |
|
368 |
|
369 | var x, y, i, obj;
|
370 |
|
371 |
|
372 | var dataX = this.getDistinctValues(this.colX, data);
|
373 | var dataY = this.getDistinctValues(this.colY, data);
|
374 |
|
375 | var dataPoints = this.getDataPoints(data);
|
376 |
|
377 |
|
378 | var dataMatrix = [];
|
379 | for (i = 0; i < dataPoints.length; i++) {
|
380 | obj = dataPoints[i];
|
381 |
|
382 |
|
383 | var xIndex = dataX.indexOf(obj.point.x);
|
384 | var yIndex = dataY.indexOf(obj.point.y);
|
385 |
|
386 | if (dataMatrix[xIndex] === undefined) {
|
387 | dataMatrix[xIndex] = [];
|
388 | }
|
389 |
|
390 | dataMatrix[xIndex][yIndex] = obj;
|
391 | }
|
392 |
|
393 |
|
394 | for (x = 0; x < dataMatrix.length; x++) {
|
395 | for (y = 0; y < dataMatrix[x].length; y++) {
|
396 | if (dataMatrix[x][y]) {
|
397 | dataMatrix[x][y].pointRight = (x < dataMatrix.length-1) ? dataMatrix[x+1][y] : undefined;
|
398 | dataMatrix[x][y].pointTop = (y < dataMatrix[x].length-1) ? dataMatrix[x][y+1] : undefined;
|
399 | dataMatrix[x][y].pointCross =
|
400 | (x < dataMatrix.length-1 && y < dataMatrix[x].length-1) ?
|
401 | dataMatrix[x+1][y+1] :
|
402 | undefined;
|
403 | }
|
404 | }
|
405 | }
|
406 |
|
407 | return dataPoints;
|
408 | };
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 |
|
416 | DataGroup.prototype.getInfo = function() {
|
417 | var dataFilter = this.dataFilter;
|
418 | if (!dataFilter) return undefined;
|
419 |
|
420 | return dataFilter.getLabel() + ': ' + dataFilter.getSelectedValue();
|
421 | };
|
422 |
|
423 |
|
424 |
|
425 |
|
426 |
|
427 | DataGroup.prototype.reload = function() {
|
428 | if (this.dataTable) {
|
429 | this.setData(this.dataTable);
|
430 | }
|
431 | };
|
432 |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 |
|
441 | DataGroup.prototype._getDataPoints = function (data) {
|
442 | var dataPoints = [];
|
443 |
|
444 | if (this.style === Settings.STYLE.GRID || this.style === Settings.STYLE.SURFACE) {
|
445 | dataPoints = this.initDataAsMatrix(data);
|
446 | }
|
447 | else {
|
448 | this._checkValueField(data);
|
449 | dataPoints = this.getDataPoints(data);
|
450 |
|
451 | if (this.style === Settings.STYLE.LINE) {
|
452 |
|
453 | for (var i = 0; i < dataPoints.length; i++) {
|
454 | if (i > 0) {
|
455 | dataPoints[i - 1].pointNext = dataPoints[i];
|
456 | }
|
457 | }
|
458 | }
|
459 | }
|
460 |
|
461 | return dataPoints;
|
462 | };
|
463 |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 | DataGroup.prototype._checkValueField = function (data) {
|
474 |
|
475 | var hasValueField = this.style === Settings.STYLE.BARCOLOR
|
476 | || this.style === Settings.STYLE.BARSIZE
|
477 | || this.style === Settings.STYLE.DOTCOLOR
|
478 | || this.style === Settings.STYLE.DOTSIZE;
|
479 |
|
480 | if (!hasValueField) {
|
481 | return;
|
482 | }
|
483 |
|
484 |
|
485 |
|
486 | if (this.colValue === undefined) {
|
487 | throw new Error('Expected data to have '
|
488 | + ' field \'style\' '
|
489 | + ' for graph style \'' + this.style + '\''
|
490 | );
|
491 | }
|
492 |
|
493 |
|
494 |
|
495 | if (data[0][this.colValue] === undefined) {
|
496 | throw new Error('Expected data to have '
|
497 | + ' field \'' + this.colValue + '\' '
|
498 | + ' for graph style \'' + this.style + '\''
|
499 | );
|
500 | }
|
501 | };
|
502 |
|
503 |
|
504 | module.exports = DataGroup;
|