@hpcc-js/marshaller 2.28.5 → 2.28.7
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/LICENSE +43 -43
- package/dist/index.es6.js +22 -22
- package/dist/index.es6.js.map +1 -1
- package/dist/index.js +20 -20
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/package.json +16 -16
- package/src/__package__.ts +3 -3
- package/src/dashy.css +239 -239
- package/src/dashy.ts +521 -521
- package/src/ddl1/DDLApi.ts +229 -229
- package/src/ddl1/FlyoutButton.ts +120 -120
- package/src/ddl1/Graph.ts +93 -93
- package/src/ddl1/HTML.ts +77 -77
- package/src/ddl1/HipieDDL.ts +2437 -2437
- package/src/ddl1/HipieDDLMixin.ts +380 -380
- package/src/ddl1/Tabbed.ts +91 -91
- package/src/ddl1/TargetMarshaller.ts +57 -57
- package/src/ddl2/PopupManager.ts +89 -89
- package/src/ddl2/activities/activity.ts +431 -431
- package/src/ddl2/activities/databomb.ts +237 -237
- package/src/ddl2/activities/datasource.ts +52 -52
- package/src/ddl2/activities/dspicker.ts +106 -106
- package/src/ddl2/activities/filter.ts +542 -542
- package/src/ddl2/activities/form.ts +153 -153
- package/src/ddl2/activities/groupby.ts +439 -439
- package/src/ddl2/activities/hipiepipeline.ts +114 -114
- package/src/ddl2/activities/limit.ts +49 -49
- package/src/ddl2/activities/logicalfile.ts +62 -62
- package/src/ddl2/activities/nullview.ts +12 -12
- package/src/ddl2/activities/project.ts +764 -764
- package/src/ddl2/activities/rest.ts +568 -568
- package/src/ddl2/activities/roxie.ts +490 -490
- package/src/ddl2/activities/sampledata.json +16264 -16264
- package/src/ddl2/activities/sort.ts +176 -176
- package/src/ddl2/activities/wuresult.ts +395 -395
- package/src/ddl2/dashboard.css +13 -13
- package/src/ddl2/dashboard.ts +330 -330
- package/src/ddl2/dashboardDockPanel.ts +123 -123
- package/src/ddl2/dashboardGrid.ts +202 -202
- package/src/ddl2/ddl.ts +410 -410
- package/src/ddl2/ddleditor.ts +60 -60
- package/src/ddl2/dsTable.ts +238 -238
- package/src/ddl2/dvTable.ts +31 -31
- package/src/ddl2/graphadapter.ts +297 -297
- package/src/ddl2/javascriptadapter.ts +354 -354
- package/src/ddl2/model/element.ts +398 -398
- package/src/ddl2/model/visualization.ts +351 -351
- package/src/ddl2/model/vizChartPanel.ts +149 -149
- package/src/ddl2/pipelinePanel.css +4 -4
- package/src/ddl2/pipelinePanel.ts +465 -465
- package/src/index.ts +26 -26
- package/types/__package__.d.ts +2 -2
- package/types-3.4/__package__.d.ts +2 -2
package/src/ddl1/HipieDDL.ts
CHANGED
|
@@ -1,2437 +1,2437 @@
|
|
|
1
|
-
import { Class, Database, Utility, Widget } from "@hpcc-js/common";
|
|
2
|
-
import { MultiChart } from "@hpcc-js/composite";
|
|
3
|
-
import { DDL1 } from "@hpcc-js/ddl-shim";
|
|
4
|
-
import { Comms, Table } from "@hpcc-js/other";
|
|
5
|
-
import { map as d3Map } from "d3-collection";
|
|
6
|
-
|
|
7
|
-
declare const require: any;
|
|
8
|
-
|
|
9
|
-
const LOADING = "...loading...";
|
|
10
|
-
const _CHANGED = "_changed";
|
|
11
|
-
|
|
12
|
-
function faCharFix(faChar) {
|
|
13
|
-
if (faChar) {
|
|
14
|
-
return String.fromCharCode(parseInt(faChar));
|
|
15
|
-
}
|
|
16
|
-
return faChar;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function hipieType2DBType(hipieType) {
|
|
20
|
-
switch (hipieType) {
|
|
21
|
-
case "bool":
|
|
22
|
-
case "boolean":
|
|
23
|
-
return "boolean";
|
|
24
|
-
case "integer":
|
|
25
|
-
case "float":
|
|
26
|
-
case "double":
|
|
27
|
-
return "number";
|
|
28
|
-
case "date":
|
|
29
|
-
case "time":
|
|
30
|
-
return "time";
|
|
31
|
-
case "geohash":
|
|
32
|
-
return "geohash";
|
|
33
|
-
case "dataset":
|
|
34
|
-
return "dataset";
|
|
35
|
-
case "visualization":
|
|
36
|
-
return "widget";
|
|
37
|
-
default:
|
|
38
|
-
if (hipieType) {
|
|
39
|
-
if (hipieType.indexOf("unsigned") === 0) {
|
|
40
|
-
return "number";
|
|
41
|
-
} else if (hipieType.indexOf("integer") === 0) {
|
|
42
|
-
return "number";
|
|
43
|
-
} else if (hipieType.indexOf("real") === 0) {
|
|
44
|
-
return "number";
|
|
45
|
-
} else if (hipieType.indexOf("string") === 0) {
|
|
46
|
-
return "string";
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if ((window as any).__hpcc_debug) {
|
|
51
|
-
console.warn("unknown hipieType: " + hipieType);
|
|
52
|
-
}
|
|
53
|
-
return "string";
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Mappings ---
|
|
57
|
-
function SourceMappings(this: any, visualization, mappings) {
|
|
58
|
-
this.visualization = visualization;
|
|
59
|
-
const newMappings = {};
|
|
60
|
-
for (const key in mappings) {
|
|
61
|
-
if (mappings[key] instanceof Array) {
|
|
62
|
-
mappings[key].forEach(function (mapingItem, idx) {
|
|
63
|
-
newMappings[idx === 0 ? key : key + "_" + idx] = mapingItem;
|
|
64
|
-
});
|
|
65
|
-
} else {
|
|
66
|
-
newMappings[key] = mappings[key];
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
this.mappings = newMappings;
|
|
70
|
-
this.hasMappings = false;
|
|
71
|
-
this.reverseMappings = {};
|
|
72
|
-
this.columns = [];
|
|
73
|
-
this.columnsIdx = {};
|
|
74
|
-
this.columnsRHS = [];
|
|
75
|
-
this.columnsRHSIdx = {};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
SourceMappings.prototype.init = function () {
|
|
79
|
-
for (const key in this.mappings) {
|
|
80
|
-
this.reverseMappings[this.mappings[key]] = key;
|
|
81
|
-
if (this.columnsIdx[key] === undefined) {
|
|
82
|
-
this.columns.push(key);
|
|
83
|
-
this.columnsIdx[key] = this.columns.length - 1;
|
|
84
|
-
}
|
|
85
|
-
this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
|
|
86
|
-
this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
|
|
87
|
-
this.hasMappings = true;
|
|
88
|
-
}
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
SourceMappings.prototype.init = function () {
|
|
92
|
-
for (const key in this.mappings) {
|
|
93
|
-
this.reverseMappings[this.mappings[key]] = key;
|
|
94
|
-
if (this.columnsIdx[key] === undefined) {
|
|
95
|
-
this.columns.push(key);
|
|
96
|
-
this.columnsIdx[key] = this.columns.length - 1;
|
|
97
|
-
}
|
|
98
|
-
this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
|
|
99
|
-
this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
|
|
100
|
-
this.hasMappings = true;
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
SourceMappings.prototype.getFields = function () {
|
|
105
|
-
if (this.visualization.fields()) {
|
|
106
|
-
return Object.keys(this.mappings).map(key => {
|
|
107
|
-
const field = this.visualization.field(key);
|
|
108
|
-
if (!field) {
|
|
109
|
-
console.warn("Unknown mapping field: " + key);
|
|
110
|
-
}
|
|
111
|
-
return new Database.Field(field.id())
|
|
112
|
-
.type(field.jsType())
|
|
113
|
-
.label(this.reverseMappings[field.id()])
|
|
114
|
-
;
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
return null;
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
SourceMappings.prototype.contains = function (key) {
|
|
121
|
-
return this.mappings[key] !== undefined;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
SourceMappings.prototype.doMap = function (item) {
|
|
125
|
-
const retVal = [];
|
|
126
|
-
for (const key in this.mappings) {
|
|
127
|
-
const rhsKey = this.mappings[key];
|
|
128
|
-
try {
|
|
129
|
-
let val = item[rhsKey];
|
|
130
|
-
if (val === undefined) {
|
|
131
|
-
val = item[rhsKey.toLowerCase()];
|
|
132
|
-
}
|
|
133
|
-
retVal[this.columnsIdx[key]] = val;
|
|
134
|
-
} catch (e) {
|
|
135
|
-
console.warn("Invalid Mapping: " + this.visualization.id + " [" + rhsKey + "->" + item + "]");
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
return retVal;
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
SourceMappings.prototype.doReverseMap = function (item) {
|
|
142
|
-
const retVal = {};
|
|
143
|
-
for (const key in this.mappings) {
|
|
144
|
-
const rhsKey = this.mappings[key];
|
|
145
|
-
try {
|
|
146
|
-
let val = item[key];
|
|
147
|
-
if (val === undefined) {
|
|
148
|
-
val = item[key.toLowerCase()];
|
|
149
|
-
}
|
|
150
|
-
retVal[rhsKey] = val;
|
|
151
|
-
} catch (e) {
|
|
152
|
-
console.warn("Invalid Mapping: " + this.visualization.id + " [" + key + "->" + item + "]");
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
return retVal;
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
SourceMappings.prototype.doMapAll = function (data) {
|
|
159
|
-
return data.hipieMappings(this.columnsRHS.map(col => {
|
|
160
|
-
return this.visualization.field(col);
|
|
161
|
-
}), this.visualization.dashboard.marshaller.missingDataString());
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
SourceMappings.prototype.getMap = function (key) {
|
|
165
|
-
return this.mappings[key];
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
SourceMappings.prototype.getReverseMap = function (key) {
|
|
169
|
-
return this.reverseMappings[key];
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
SourceMappings.prototype.hipieMapSortArray = function (sort) {
|
|
173
|
-
return sort.map(sortField => {
|
|
174
|
-
let reverse = false;
|
|
175
|
-
if (sortField.indexOf("-") === 0) {
|
|
176
|
-
sortField = sortField.substring(1);
|
|
177
|
-
reverse = true;
|
|
178
|
-
}
|
|
179
|
-
const fieldIdx = this.columnsRHS.indexOf(sortField);
|
|
180
|
-
if (fieldIdx < 0) {
|
|
181
|
-
console.warn("SourceMappings.prototype.hipieMapSortArray: Invalid sort array - " + sortField);
|
|
182
|
-
}
|
|
183
|
-
return {
|
|
184
|
-
idx: fieldIdx,
|
|
185
|
-
reverse
|
|
186
|
-
};
|
|
187
|
-
}).filter(function (d) { return d.idx >= 0; });
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
function ChartMappings(this: any, visualization, mappings) {
|
|
191
|
-
SourceMappings.call(this, visualization, mappings);
|
|
192
|
-
this.columns = ["label", "weight"];
|
|
193
|
-
this.columnsIdx = { label: 0, weight: 1 };
|
|
194
|
-
this.init();
|
|
195
|
-
}
|
|
196
|
-
ChartMappings.prototype = Object.create(SourceMappings.prototype);
|
|
197
|
-
|
|
198
|
-
function ChoroMappings(this: any, visualization, mappings) {
|
|
199
|
-
SourceMappings.call(this, visualization, mappings);
|
|
200
|
-
if (mappings.state) {
|
|
201
|
-
this.columns = ["state", "weight"];
|
|
202
|
-
this.columnsIdx = { state: 0, weight: 1 };
|
|
203
|
-
} else if (mappings.county) {
|
|
204
|
-
this.columns = ["county", "weight"];
|
|
205
|
-
this.columnsIdx = { county: 0, weight: 1 };
|
|
206
|
-
} else if (mappings.geohash) {
|
|
207
|
-
this.columns = ["geohash", "weight"];
|
|
208
|
-
this.columnsIdx = { geohash: 0, weight: 1 };
|
|
209
|
-
}
|
|
210
|
-
this.init();
|
|
211
|
-
}
|
|
212
|
-
ChoroMappings.prototype = Object.create(SourceMappings.prototype);
|
|
213
|
-
|
|
214
|
-
function ChoroMappings2(this: any, visualization, mappings) {
|
|
215
|
-
SourceMappings.call(this, visualization, mappings);
|
|
216
|
-
if (mappings.state) {
|
|
217
|
-
this.columns = ["state"];
|
|
218
|
-
this.columnsIdx = { state: 0 };
|
|
219
|
-
} else if (mappings.county) {
|
|
220
|
-
this.columns = ["county"];
|
|
221
|
-
this.columnsIdx = { county: 0 };
|
|
222
|
-
} else if (mappings.geohash) {
|
|
223
|
-
this.columns = ["geohash", "label"];
|
|
224
|
-
this.columnsIdx = { geohash: 0, label: 1 };
|
|
225
|
-
}
|
|
226
|
-
const weightOffset = this.columns.length;
|
|
227
|
-
if (mappings.weight instanceof Array) {
|
|
228
|
-
mappings.weight.forEach((w, i) => {
|
|
229
|
-
this.columns.push(w);
|
|
230
|
-
this.columnsIdx[i === 0 ? "weight" : "weight_" + i] = i + weightOffset;
|
|
231
|
-
});
|
|
232
|
-
}
|
|
233
|
-
this.init();
|
|
234
|
-
}
|
|
235
|
-
ChoroMappings2.prototype = Object.create(SourceMappings.prototype);
|
|
236
|
-
|
|
237
|
-
function HeatMapMappings(this: any, visualization, mappings) {
|
|
238
|
-
SourceMappings.call(this, visualization, mappings);
|
|
239
|
-
this.columns = ["x", "y", "weight"];
|
|
240
|
-
this.columnsIdx = { x: 0, y: 1, weight: 2 };
|
|
241
|
-
this.init();
|
|
242
|
-
}
|
|
243
|
-
HeatMapMappings.prototype = Object.create(SourceMappings.prototype);
|
|
244
|
-
|
|
245
|
-
function LineMappings(this: any, visualization, mappings) {
|
|
246
|
-
const newMappings = {
|
|
247
|
-
label: mappings.x[0]
|
|
248
|
-
};
|
|
249
|
-
mappings.y.forEach(function (item, idx) {
|
|
250
|
-
newMappings[item] = item;
|
|
251
|
-
});
|
|
252
|
-
SourceMappings.call(this, visualization, newMappings);
|
|
253
|
-
this.init();
|
|
254
|
-
}
|
|
255
|
-
LineMappings.prototype = Object.create(SourceMappings.prototype);
|
|
256
|
-
|
|
257
|
-
function TableMappings(this: any, visualization, mappings) {
|
|
258
|
-
const newMappings = {};
|
|
259
|
-
for (const key in mappings) {
|
|
260
|
-
mappings[key].forEach(function (mapingItem, idx) {
|
|
261
|
-
newMappings[visualization.label[idx]] = mapingItem;
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
SourceMappings.call(this, visualization, newMappings);
|
|
265
|
-
this.init();
|
|
266
|
-
}
|
|
267
|
-
TableMappings.prototype = Object.create(SourceMappings.prototype);
|
|
268
|
-
|
|
269
|
-
TableMappings.prototype.init = function () {
|
|
270
|
-
this.visualization.label.forEach((label, idx) => {
|
|
271
|
-
this.reverseMappings[this.mappings[label]] = label;
|
|
272
|
-
this.columns.push(label);
|
|
273
|
-
this.columnsIdx[label] = idx;
|
|
274
|
-
this.columnsRHS[idx] = this.mappings[label];
|
|
275
|
-
this.columnsRHSIdx[this.mappings[label]] = idx;
|
|
276
|
-
this.hasMappings = true;
|
|
277
|
-
});
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
TableMappings.prototype.doMapAll = function (data) {
|
|
281
|
-
let retVal = SourceMappings.prototype.doMapAll.apply(this, arguments);
|
|
282
|
-
if (retVal instanceof Array) {
|
|
283
|
-
const columnsRHSIdx = this.visualization.source.getColumnsRHSIdx();
|
|
284
|
-
this.visualization.fields().forEach(field => {
|
|
285
|
-
const fieldType = field.jsType();
|
|
286
|
-
const colIdx = columnsRHSIdx[field.id()];
|
|
287
|
-
if (colIdx === undefined) {
|
|
288
|
-
console.warn("Invalid Mapping: " + field.id());
|
|
289
|
-
} else {
|
|
290
|
-
retVal = retVal.map((row) => {
|
|
291
|
-
let cell = row[colIdx];
|
|
292
|
-
if (cell && cell.Row) {
|
|
293
|
-
cell = cell.Row;
|
|
294
|
-
}
|
|
295
|
-
if (cell instanceof Array) {
|
|
296
|
-
switch (fieldType) {
|
|
297
|
-
case "dataset":
|
|
298
|
-
const columns = [];
|
|
299
|
-
const columnsIdx = {};
|
|
300
|
-
const data2 = cell.map(function (row2, idx) {
|
|
301
|
-
const retVal2 = [];
|
|
302
|
-
retVal2.length = columns.length;
|
|
303
|
-
for (const key in row2) {
|
|
304
|
-
if (idx === 0) {
|
|
305
|
-
columnsIdx[key] = columns.length;
|
|
306
|
-
columns.push(key);
|
|
307
|
-
}
|
|
308
|
-
retVal2[columnsIdx[key]] = row2[key];
|
|
309
|
-
}
|
|
310
|
-
return retVal2;
|
|
311
|
-
});
|
|
312
|
-
const table = new Table()
|
|
313
|
-
.columns(columns)
|
|
314
|
-
.data(data2)
|
|
315
|
-
;
|
|
316
|
-
row[colIdx] = table;
|
|
317
|
-
break;
|
|
318
|
-
case "widget":
|
|
319
|
-
const viz = this.visualization.vizDeclarations[field.localVisualizationID()];
|
|
320
|
-
const output = viz.source.getOutput();
|
|
321
|
-
const db = output.db;
|
|
322
|
-
output.setData(cell, []);
|
|
323
|
-
const widget = viz.widget;
|
|
324
|
-
const newWidget = new widget.constructor()
|
|
325
|
-
.showToolbar(false)
|
|
326
|
-
.chartType(widget.chartType())
|
|
327
|
-
.chartTypeDefaults(widget.chartTypeDefaults())
|
|
328
|
-
.columns(viz.source.getColumns())
|
|
329
|
-
.data(viz.source.getData())
|
|
330
|
-
;
|
|
331
|
-
output.db = db;
|
|
332
|
-
row[colIdx] = newWidget;
|
|
333
|
-
break;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
return row;
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
return retVal;
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
function GraphMappings(this: any, visualization, mappings, link) {
|
|
345
|
-
SourceMappings.call(this, visualization, mappings);
|
|
346
|
-
this.icon = visualization.icon || {};
|
|
347
|
-
this.fields = visualization.fields();
|
|
348
|
-
this.columns = ["uid", "label", "weight", "flags"];
|
|
349
|
-
this.columnsIdx = { uid: 0, label: 1, weight: 2, flags: 3 };
|
|
350
|
-
this.init();
|
|
351
|
-
this.link = link;
|
|
352
|
-
this.linkMappings = new SourceMappings(visualization, this.link.mappings);
|
|
353
|
-
this.linkMappings.columns = ["uid"];
|
|
354
|
-
this.linkMappings.columnsIdx = { uid: 0, label: 1 };
|
|
355
|
-
this.visualization = visualization;
|
|
356
|
-
}
|
|
357
|
-
GraphMappings.prototype = Object.create(SourceMappings.prototype);
|
|
358
|
-
|
|
359
|
-
GraphMappings.prototype.calcIconInfo = function (flag, origItem, forAnnotation) {
|
|
360
|
-
const retVal = {};
|
|
361
|
-
function mapStruct(struct, retVal2) {
|
|
362
|
-
if (struct) {
|
|
363
|
-
for (const key in struct) {
|
|
364
|
-
switch (key) {
|
|
365
|
-
case "faChar":
|
|
366
|
-
retVal2.faChar = faCharFix(struct.faChar);
|
|
367
|
-
break;
|
|
368
|
-
default:
|
|
369
|
-
if (forAnnotation && key.indexOf("icon_") === 0) { // Backward compatability
|
|
370
|
-
console.warn("Deprecated flag property: " + key);
|
|
371
|
-
retVal2[key.split("icon_")[1]] = struct[key];
|
|
372
|
-
} else {
|
|
373
|
-
retVal2[key] = struct[key];
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
if (origItem && origItem[flag.fieldid] && flag.valuemappings) {
|
|
380
|
-
const annotationInfo = flag.valuemappings[origItem[flag.fieldid]];
|
|
381
|
-
mapStruct(annotationInfo, retVal);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
for (const _key in retVal) { // jshint ignore:line
|
|
385
|
-
return retVal;
|
|
386
|
-
}
|
|
387
|
-
return null;
|
|
388
|
-
};
|
|
389
|
-
|
|
390
|
-
GraphMappings.prototype.doMapAll = function (db) {
|
|
391
|
-
const data = db.jsonObj();
|
|
392
|
-
const context = this;
|
|
393
|
-
const vertexMap = {};
|
|
394
|
-
const vertices = [];
|
|
395
|
-
const megaChart = this.visualization.widget;
|
|
396
|
-
const graph = megaChart.chart();
|
|
397
|
-
function getVertex(item, origItem?) {
|
|
398
|
-
const id = "uid_" + item[0];
|
|
399
|
-
let retVal = vertexMap[id];
|
|
400
|
-
if (!retVal && origItem) {
|
|
401
|
-
retVal = new graph.Vertex()
|
|
402
|
-
.faChar((context.icon && context.icon.faChar ? faCharFix(context.icon.faChar) : "\uf128"))
|
|
403
|
-
.text(item[1] ? item[1] : "")
|
|
404
|
-
.data(item)
|
|
405
|
-
;
|
|
406
|
-
retVal.__hpcc_uid = item[0];
|
|
407
|
-
vertexMap[id] = retVal;
|
|
408
|
-
vertices.push(retVal);
|
|
409
|
-
|
|
410
|
-
// Icon ---
|
|
411
|
-
const iconInfo = context.calcIconInfo(context.visualization.icon, origItem, false);
|
|
412
|
-
if (iconInfo) {
|
|
413
|
-
for (const key in iconInfo) {
|
|
414
|
-
if (retVal[key]) {
|
|
415
|
-
retVal[key](iconInfo[key]);
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Annotations ---
|
|
421
|
-
const annotations = [];
|
|
422
|
-
context.visualization.flags.forEach(function (flag) {
|
|
423
|
-
const iconInfo2 = context.calcIconInfo(flag, origItem, true);
|
|
424
|
-
if (iconInfo2) {
|
|
425
|
-
annotations.push(iconInfo2);
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
retVal.annotationIcons(annotations);
|
|
429
|
-
}
|
|
430
|
-
return retVal;
|
|
431
|
-
}
|
|
432
|
-
const edges = [];
|
|
433
|
-
data.forEach(function (item) {
|
|
434
|
-
const mappedItem = context.doMap(item);
|
|
435
|
-
getVertex(mappedItem, item);
|
|
436
|
-
});
|
|
437
|
-
data.forEach(function (item) {
|
|
438
|
-
const mappedItem = context.doMap(item);
|
|
439
|
-
const vertex = getVertex(mappedItem, item);
|
|
440
|
-
if (item[context.link.childfile] && item[context.link.childfile] instanceof Array) {
|
|
441
|
-
const childItems = item[context.link.childfile];
|
|
442
|
-
childItems.forEach(function (childItem, i) {
|
|
443
|
-
const childMappedItem = context.linkMappings.doMap(childItem);
|
|
444
|
-
const childVertex = getVertex(childMappedItem);
|
|
445
|
-
if (childVertex && vertex.id() !== childVertex.id()) {
|
|
446
|
-
const edge = new graph.Edge()
|
|
447
|
-
.sourceVertex(vertex)
|
|
448
|
-
.targetVertex(childVertex)
|
|
449
|
-
.sourceMarker("circle")
|
|
450
|
-
.targetMarker("arrow")
|
|
451
|
-
.text(childMappedItem[1] ? childMappedItem[1] : "")
|
|
452
|
-
.data(childMappedItem)
|
|
453
|
-
;
|
|
454
|
-
const linkcolor = graph.linkcolor_default();
|
|
455
|
-
if (linkcolor && linkcolor.fieldid) {
|
|
456
|
-
edge.strokeColor(childItem[linkcolor.fieldid]);
|
|
457
|
-
}
|
|
458
|
-
const linktooltip = graph.linkcolor_default();
|
|
459
|
-
if (linktooltip && linktooltip.fieldid) {
|
|
460
|
-
edge.tooltip(childItem[linktooltip.fieldid]);
|
|
461
|
-
}
|
|
462
|
-
edges.push(edge);
|
|
463
|
-
}
|
|
464
|
-
});
|
|
465
|
-
}
|
|
466
|
-
});
|
|
467
|
-
return { vertices, edges, merge: false };
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
// Viz Source ---
|
|
471
|
-
function Source(this: any, visualization, source) {
|
|
472
|
-
this.visualization = visualization;
|
|
473
|
-
if (source) {
|
|
474
|
-
this._id = source.id;
|
|
475
|
-
this._output = source.output;
|
|
476
|
-
this.mappings = null;
|
|
477
|
-
if (!source.mappings) {
|
|
478
|
-
console.warn("no mappings for:" + visualization.id + "->" + source.id);
|
|
479
|
-
}
|
|
480
|
-
switch (this.visualization.type) {
|
|
481
|
-
case "LINE":
|
|
482
|
-
this.mappings = new LineMappings(this.visualization, source.mappings);
|
|
483
|
-
break;
|
|
484
|
-
case "TABLE":
|
|
485
|
-
this.mappings = new TableMappings(this.visualization, source.mappings);
|
|
486
|
-
break;
|
|
487
|
-
case "GRAPH":
|
|
488
|
-
this.mappings = new GraphMappings(this.visualization, source.mappings, source.link);
|
|
489
|
-
break;
|
|
490
|
-
case "CHORO":
|
|
491
|
-
if (source.mappings.weight instanceof Array && source.mappings.weight.length) {
|
|
492
|
-
this.mappings = new ChoroMappings2(this.visualization, source.mappings);
|
|
493
|
-
if (source.mappings.weight.length > 1) {
|
|
494
|
-
this.visualization.type = "LINE";
|
|
495
|
-
}
|
|
496
|
-
} else {
|
|
497
|
-
this.mappings = new ChoroMappings(this.visualization, source.mappings);
|
|
498
|
-
}
|
|
499
|
-
break;
|
|
500
|
-
case "HEAT_MAP":
|
|
501
|
-
this.mappings = new HeatMapMappings(this.visualization, source.mappings);
|
|
502
|
-
break;
|
|
503
|
-
default:
|
|
504
|
-
this.mappings = new ChartMappings(this.visualization, source.mappings);
|
|
505
|
-
break;
|
|
506
|
-
}
|
|
507
|
-
this.first = source.first;
|
|
508
|
-
this.reverse = source.reverse;
|
|
509
|
-
this.sort = source.sort;
|
|
510
|
-
this.properties = source.properties;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
Source.prototype.getQualifiedID = function () {
|
|
515
|
-
return this.visualization.getQualifiedID() + "." + this._id;
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
Source.prototype.exists = function () {
|
|
519
|
-
return this._id;
|
|
520
|
-
};
|
|
521
|
-
|
|
522
|
-
Source.prototype.getDatasource = function () {
|
|
523
|
-
return this.visualization.dashboard.getDatasource(this._id);
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
Source.prototype.getOutput = function () {
|
|
527
|
-
const datasource = this.getDatasource();
|
|
528
|
-
if (datasource && datasource._outputs) {
|
|
529
|
-
return datasource._outputs[this._output];
|
|
530
|
-
}
|
|
531
|
-
return null;
|
|
532
|
-
};
|
|
533
|
-
|
|
534
|
-
Source.prototype.hasData = function () {
|
|
535
|
-
return this.getOutput().db ? true : false;
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
Source.prototype.getFields = function () {
|
|
539
|
-
return this.mappings.getFields();
|
|
540
|
-
};
|
|
541
|
-
|
|
542
|
-
Source.prototype.getColumnsRHS = function () {
|
|
543
|
-
return this.mappings.columnsRHS;
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
Source.prototype.getColumnsRHSIdx = function () {
|
|
547
|
-
return this.mappings.columnsRHSIdx;
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
Source.prototype.getColumns = function () {
|
|
551
|
-
return this.mappings && this.mappings.columns ? this.mappings.columns : [];
|
|
552
|
-
};
|
|
553
|
-
|
|
554
|
-
Source.prototype.getData = function () {
|
|
555
|
-
const db = this.getOutput().db;
|
|
556
|
-
const retVal = this.mappings.doMapAll(db);
|
|
557
|
-
if (retVal.length && this.sort) {
|
|
558
|
-
Utility.multiSort(retVal, this.mappings.hipieMapSortArray(this.sort));
|
|
559
|
-
}
|
|
560
|
-
if (this.reverse) {
|
|
561
|
-
retVal.reverse();
|
|
562
|
-
}
|
|
563
|
-
if (this.first && retVal.length > this.first) {
|
|
564
|
-
retVal.length = this.first;
|
|
565
|
-
}
|
|
566
|
-
return retVal;
|
|
567
|
-
};
|
|
568
|
-
|
|
569
|
-
Source.prototype.getXTitle = function () {
|
|
570
|
-
return this.mappings.columns[0];
|
|
571
|
-
};
|
|
572
|
-
|
|
573
|
-
Source.prototype.getYTitle = function () {
|
|
574
|
-
return this.mappings.columns.filter(function (d, i) { return i > 0; }).join(" / ");
|
|
575
|
-
};
|
|
576
|
-
|
|
577
|
-
Source.prototype.getMap = function (col) {
|
|
578
|
-
return (this.mappings && this.mappings.hasMappings) ? this.mappings.getMap(col) : col;
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
Source.prototype.getReverseMap = function (col) {
|
|
582
|
-
return (this.mappings && this.mappings.hasMappings) ? this.mappings.getReverseMap(col) : col;
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
// Viz Events ---
|
|
586
|
-
function EventUpdate(this: any, event, update, defMappings) {
|
|
587
|
-
this.event = event;
|
|
588
|
-
this.dashboard = event.visualization.dashboard;
|
|
589
|
-
this._col = update.col;
|
|
590
|
-
this._visualization = update.visualization;
|
|
591
|
-
this._instance = update.instance;
|
|
592
|
-
this._datasource = update.datasource;
|
|
593
|
-
this._merge = update.merge;
|
|
594
|
-
this._mappings = update.mappings || defMappings;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
EventUpdate.prototype.getDatasource = function () {
|
|
598
|
-
return this.dashboard.getDatasource(this._datasource);
|
|
599
|
-
};
|
|
600
|
-
|
|
601
|
-
EventUpdate.prototype.getVisualization = function () {
|
|
602
|
-
return this.dashboard.getVisualization(this._visualization);
|
|
603
|
-
};
|
|
604
|
-
|
|
605
|
-
EventUpdate.prototype.mapData = function (row) {
|
|
606
|
-
const retVal = {};
|
|
607
|
-
if (row) {
|
|
608
|
-
for (const key in this._mappings) {
|
|
609
|
-
const origKey = this.getReverseMap(key);
|
|
610
|
-
retVal[this._mappings[key]] = row[origKey];
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
return retVal;
|
|
614
|
-
};
|
|
615
|
-
|
|
616
|
-
EventUpdate.prototype.getMap = function (col) {
|
|
617
|
-
return this.event.visualization.source.getMap(col);
|
|
618
|
-
};
|
|
619
|
-
|
|
620
|
-
EventUpdate.prototype.getReverseMap = function (col) {
|
|
621
|
-
return this.event.visualization.source.getReverseMap(col);
|
|
622
|
-
};
|
|
623
|
-
|
|
624
|
-
EventUpdate.prototype.selectedRow = function () {
|
|
625
|
-
if (this.event.visualization.hasSelection()) {
|
|
626
|
-
return this.event.visualization._widgetState.row;
|
|
627
|
-
}
|
|
628
|
-
return {};
|
|
629
|
-
};
|
|
630
|
-
|
|
631
|
-
EventUpdate.prototype.mapSelected = function () {
|
|
632
|
-
return this.mapData(this.selectedRow());
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
EventUpdate.prototype.calcRequestFor = function (visualization) {
|
|
636
|
-
const retVal = {};
|
|
637
|
-
const updateVisualization = this.getVisualization();
|
|
638
|
-
updateVisualization.getInputVisualizations().forEach(function (inViz, idx) {
|
|
639
|
-
// Calc request for each visualization to be updated ---
|
|
640
|
-
const changed = inViz === visualization;
|
|
641
|
-
inViz.getUpdatesForVisualization(updateVisualization).forEach(function (inVizUpdateObj) {
|
|
642
|
-
// Gather all contributing "input visualization events" for the visualization that is to be updated ---
|
|
643
|
-
const inVizRequest = inVizUpdateObj.mapSelected();
|
|
644
|
-
for (const key in inVizRequest) {
|
|
645
|
-
if (retVal[key] && retVal[key] !== inVizRequest[key]) {
|
|
646
|
-
console.warn("Duplicate Filter with mismatched value (defaulting to 'first' or 'first changed' instance): " + key);
|
|
647
|
-
if (changed) {
|
|
648
|
-
retVal[key] = inVizRequest[key];
|
|
649
|
-
retVal[key + _CHANGED] = changed;
|
|
650
|
-
}
|
|
651
|
-
} else {
|
|
652
|
-
retVal[key] = inVizRequest[key];
|
|
653
|
-
retVal[key + _CHANGED] = changed;
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
});
|
|
657
|
-
});
|
|
658
|
-
return retVal;
|
|
659
|
-
};
|
|
660
|
-
|
|
661
|
-
function Event(this: any, visualization, eventID, event) {
|
|
662
|
-
this.visualization = visualization;
|
|
663
|
-
this.eventID = eventID;
|
|
664
|
-
this._updates = [];
|
|
665
|
-
this._mappings = event.mappings;
|
|
666
|
-
if (event) {
|
|
667
|
-
this._updates = event.updates.map(updateInfo => {
|
|
668
|
-
return new EventUpdate(this, updateInfo, event.mappings);
|
|
669
|
-
});
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
Event.prototype.exists = function () {
|
|
674
|
-
return this._updates.length;
|
|
675
|
-
};
|
|
676
|
-
|
|
677
|
-
Event.prototype.getUpdates = function () {
|
|
678
|
-
return this._updates.filter(updateInfo => {
|
|
679
|
-
if (!updateInfo._col) return true;
|
|
680
|
-
return updateInfo._col === updateInfo.getMap(this.visualization._widgetState.col);
|
|
681
|
-
});
|
|
682
|
-
};
|
|
683
|
-
|
|
684
|
-
Event.prototype.getUpdatesDatasources = function () {
|
|
685
|
-
const dedup = {};
|
|
686
|
-
const retVal = [];
|
|
687
|
-
this.getUpdatesVisualizations().forEach(function (item, idx) {
|
|
688
|
-
const datasource = item.source.getDatasource();
|
|
689
|
-
if (datasource && !dedup[datasource.id]) {
|
|
690
|
-
dedup[datasource.id] = true;
|
|
691
|
-
retVal.push(datasource);
|
|
692
|
-
}
|
|
693
|
-
}, this);
|
|
694
|
-
return retVal;
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
Event.prototype.getUpdatesVisualizations = function () {
|
|
698
|
-
const dedup = {};
|
|
699
|
-
const retVal = [];
|
|
700
|
-
this._updates.forEach(function (updateObj, idx) {
|
|
701
|
-
const visualization = updateObj.getVisualization();
|
|
702
|
-
if (!dedup[visualization.id]) {
|
|
703
|
-
dedup[visualization.id] = true;
|
|
704
|
-
retVal.push(visualization);
|
|
705
|
-
}
|
|
706
|
-
}, this);
|
|
707
|
-
return retVal;
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
Event.prototype.fetchData = function () {
|
|
711
|
-
const fetchDataOptimizer = new VisualizationRequestOptimizer();
|
|
712
|
-
this.getUpdates().forEach(updateObj => {
|
|
713
|
-
fetchDataOptimizer.appendRequest(updateObj.getDatasource(), updateObj.calcRequestFor(this.visualization), updateObj.getVisualization());
|
|
714
|
-
});
|
|
715
|
-
return fetchDataOptimizer.fetchData();
|
|
716
|
-
};
|
|
717
|
-
|
|
718
|
-
function Events(this: any, visualization, events) {
|
|
719
|
-
this.visualization = visualization;
|
|
720
|
-
this.events = {};
|
|
721
|
-
for (const key in events) {
|
|
722
|
-
this.events[key] = new Event(visualization, key, events[key]);
|
|
723
|
-
}
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
Events.prototype.setWidget = function (widget) {
|
|
727
|
-
const context = this;
|
|
728
|
-
for (const key in this.events) {
|
|
729
|
-
if (widget["vertex_" + key]) {
|
|
730
|
-
widget["vertex_" + key] = function (row, col, selected) {
|
|
731
|
-
context.visualization.processEvent(key, context.events[key], row, col, selected);
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
if (widget[key]) {
|
|
735
|
-
widget[key] = function (row, col, selected) {
|
|
736
|
-
context.visualization.processEvent(key, context.events[key], row, col, selected);
|
|
737
|
-
};
|
|
738
|
-
}
|
|
739
|
-
}
|
|
740
|
-
};
|
|
741
|
-
|
|
742
|
-
Events.prototype.exists = function () {
|
|
743
|
-
return this._updates !== undefined;
|
|
744
|
-
};
|
|
745
|
-
|
|
746
|
-
Events.prototype.getUpdates = function () {
|
|
747
|
-
let retVal = [];
|
|
748
|
-
for (const key in this.events) {
|
|
749
|
-
retVal = retVal.concat(this.events[key].getUpdates());
|
|
750
|
-
}
|
|
751
|
-
return retVal;
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
Events.prototype.getUpdatesDatasources = function () {
|
|
755
|
-
let retVal = [];
|
|
756
|
-
for (const key in this.events) {
|
|
757
|
-
retVal = retVal.concat(this.events[key].getUpdatesDatasources());
|
|
758
|
-
}
|
|
759
|
-
return retVal;
|
|
760
|
-
};
|
|
761
|
-
|
|
762
|
-
Events.prototype.getUpdatesVisualizations = function () {
|
|
763
|
-
let retVal = [];
|
|
764
|
-
for (const key in this.events) {
|
|
765
|
-
retVal = retVal.concat(this.events[key].getUpdatesVisualizations());
|
|
766
|
-
}
|
|
767
|
-
return retVal;
|
|
768
|
-
};
|
|
769
|
-
|
|
770
|
-
// Visualization Field---
|
|
771
|
-
function Field(this: any, ddlField) {
|
|
772
|
-
this._id = ddlField.id;
|
|
773
|
-
this._label = ddlField.label;
|
|
774
|
-
this._properties = ddlField.properties || {};
|
|
775
|
-
}
|
|
776
|
-
Field.prototype = Object.create(Class.prototype);
|
|
777
|
-
Field.prototype.constructor = Field;
|
|
778
|
-
|
|
779
|
-
Field.prototype.id = function () {
|
|
780
|
-
return this._id;
|
|
781
|
-
};
|
|
782
|
-
|
|
783
|
-
Field.prototype.label = function () {
|
|
784
|
-
return this._properties.label || this._label;
|
|
785
|
-
};
|
|
786
|
-
|
|
787
|
-
Field.prototype.type = function () {
|
|
788
|
-
return this._properties.type || "";
|
|
789
|
-
};
|
|
790
|
-
|
|
791
|
-
Field.prototype.jsType = function () {
|
|
792
|
-
return hipieType2DBType(this.type());
|
|
793
|
-
};
|
|
794
|
-
|
|
795
|
-
Field.prototype.charttype = function (_) {
|
|
796
|
-
if (!arguments.length) return this._properties.charttype || "";
|
|
797
|
-
this._properties.charttype = _;
|
|
798
|
-
return this;
|
|
799
|
-
};
|
|
800
|
-
|
|
801
|
-
Field.prototype.localVisualizationID = function () {
|
|
802
|
-
return this._properties.localVisualizationID || "";
|
|
803
|
-
};
|
|
804
|
-
|
|
805
|
-
Field.prototype.enumvals = function () {
|
|
806
|
-
return this._properties.enumvals; // Return undefined if non existent
|
|
807
|
-
};
|
|
808
|
-
|
|
809
|
-
Field.prototype.hasDefault = function () {
|
|
810
|
-
return this.default() !== undefined;
|
|
811
|
-
};
|
|
812
|
-
|
|
813
|
-
Field.prototype.default = function () {
|
|
814
|
-
if (this.type() === "range") {
|
|
815
|
-
return this._properties.default || ["", ""];
|
|
816
|
-
}
|
|
817
|
-
if (this._properties.default instanceof Array && this._properties.default.length) {
|
|
818
|
-
return this._properties.default[0];
|
|
819
|
-
}
|
|
820
|
-
return this._properties.default || "";
|
|
821
|
-
};
|
|
822
|
-
|
|
823
|
-
Field.prototype.hasFunction = function () {
|
|
824
|
-
return this.function() !== undefined;
|
|
825
|
-
};
|
|
826
|
-
|
|
827
|
-
Field.prototype.function = function () {
|
|
828
|
-
return this._properties.function;
|
|
829
|
-
};
|
|
830
|
-
|
|
831
|
-
Field.prototype.params = function () {
|
|
832
|
-
const retVal = [];
|
|
833
|
-
const params = this._properties.params || {};
|
|
834
|
-
for (const key in params) {
|
|
835
|
-
retVal.push(params[key]);
|
|
836
|
-
}
|
|
837
|
-
return retVal;
|
|
838
|
-
};
|
|
839
|
-
|
|
840
|
-
Field.prototype.properties = function () {
|
|
841
|
-
return this._properties;
|
|
842
|
-
};
|
|
843
|
-
|
|
844
|
-
// Visualization ---
|
|
845
|
-
function requirePromise(this: any, packageID) {
|
|
846
|
-
return new Promise((resolve, reject) => {
|
|
847
|
-
if (require) {
|
|
848
|
-
require([packageID], Package => {
|
|
849
|
-
resolve.call(this, Package);
|
|
850
|
-
});
|
|
851
|
-
} else {
|
|
852
|
-
reject("No require.");
|
|
853
|
-
}
|
|
854
|
-
});
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
function legacyRequire(this: any, packageArr, callback) {
|
|
858
|
-
const promises = packageArr.map(function (packageID) {
|
|
859
|
-
if (packageID.indexOf("../") === 0) {
|
|
860
|
-
const parts = packageID.split("/");
|
|
861
|
-
return requirePromise("@hpcc-js/" + parts[1]).then(function (Package) {
|
|
862
|
-
return Package[parts[2]];
|
|
863
|
-
});
|
|
864
|
-
}
|
|
865
|
-
return requirePromise(packageID);
|
|
866
|
-
});
|
|
867
|
-
Promise.all(promises).then(packages => {
|
|
868
|
-
callback.apply(this, packages);
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
export class Visualization extends Class {
|
|
873
|
-
protected dashboard;
|
|
874
|
-
parentVisualization;
|
|
875
|
-
protected type;
|
|
876
|
-
protected id;
|
|
877
|
-
protected label;
|
|
878
|
-
protected icon;
|
|
879
|
-
protected flags;
|
|
880
|
-
protected title;
|
|
881
|
-
protected _fields;
|
|
882
|
-
protected _fieldsMap;
|
|
883
|
-
properties;
|
|
884
|
-
protected source;
|
|
885
|
-
protected events;
|
|
886
|
-
protected layers;
|
|
887
|
-
protected hasVizDeclarations;
|
|
888
|
-
protected vizDeclarations;
|
|
889
|
-
widget;
|
|
890
|
-
protected _widgetState;
|
|
891
|
-
|
|
892
|
-
constructor(dashboard, visualization, parentVisualization) {
|
|
893
|
-
super();
|
|
894
|
-
|
|
895
|
-
this.dashboard = dashboard;
|
|
896
|
-
this.parentVisualization = parentVisualization;
|
|
897
|
-
this.type = visualization.type;
|
|
898
|
-
this.id = visualization.id;
|
|
899
|
-
|
|
900
|
-
switch (this.type) {
|
|
901
|
-
case "TABLE":
|
|
902
|
-
this.label = (visualization).label;
|
|
903
|
-
break;
|
|
904
|
-
case "GRAPH":
|
|
905
|
-
this.label = (visualization).label;
|
|
906
|
-
this.icon = (visualization).icon || { faChar: "\uf128" };
|
|
907
|
-
this.flags = (visualization).flag || [];
|
|
908
|
-
break;
|
|
909
|
-
}
|
|
910
|
-
this.title = visualization.title || visualization.id;
|
|
911
|
-
this._fields = (visualization.fields || []).map(function (field) {
|
|
912
|
-
return new Field(field);
|
|
913
|
-
});
|
|
914
|
-
this._fieldsMap = {};
|
|
915
|
-
this._fields.forEach(field => {
|
|
916
|
-
this._fieldsMap[field.id()] = field;
|
|
917
|
-
});
|
|
918
|
-
|
|
919
|
-
this.properties = visualization.properties || (visualization.source ? visualization.source.properties : null) || {};
|
|
920
|
-
this.source = new Source(this, visualization.source);
|
|
921
|
-
this.events = new Events(this, visualization.events);
|
|
922
|
-
this.layers = [];
|
|
923
|
-
this.hasVizDeclarations = false;
|
|
924
|
-
this.vizDeclarations = {};
|
|
925
|
-
if (this.type === "CHORO") {
|
|
926
|
-
this.layers = (visualization.visualizations || []).map(innerViz => {
|
|
927
|
-
return dashboard.createVisualization(innerViz, this);
|
|
928
|
-
});
|
|
929
|
-
} else {
|
|
930
|
-
(visualization.visualizations || []).forEach(innerViz => {
|
|
931
|
-
this.vizDeclarations[innerViz.id] = dashboard.createVisualization(innerViz, this);
|
|
932
|
-
this.hasVizDeclarations = true;
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
const context = this;
|
|
936
|
-
switch (this.type) {
|
|
937
|
-
case "CHORO":
|
|
938
|
-
let chartType = visualization.properties && visualization.properties.charttype ? visualization.properties.charttype : "";
|
|
939
|
-
if (parentVisualization) {
|
|
940
|
-
switch (chartType) {
|
|
941
|
-
case "MAP_PINS":
|
|
942
|
-
this.loadWidget("../map/Pins", function (widget) {
|
|
943
|
-
try {
|
|
944
|
-
widget
|
|
945
|
-
.id(visualization.id)
|
|
946
|
-
.columns(context.source.getColumns())
|
|
947
|
-
.geohashColumn("geohash")
|
|
948
|
-
.tooltipColumn("label")
|
|
949
|
-
.fillColor(visualization.color ? visualization.color : null)
|
|
950
|
-
.projection("albersUsaPr")
|
|
951
|
-
;
|
|
952
|
-
} catch (e) {
|
|
953
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
954
|
-
}
|
|
955
|
-
});
|
|
956
|
-
break;
|
|
957
|
-
}
|
|
958
|
-
} else {
|
|
959
|
-
chartType = chartType || "CHORO";
|
|
960
|
-
if (chartType === "CHORO") {
|
|
961
|
-
if (this.source.mappings.contains("state")) {
|
|
962
|
-
chartType = "CHORO_USSTATES";
|
|
963
|
-
} else if (this.source.mappings.contains("county")) {
|
|
964
|
-
chartType = "CHORO_USCOUNTIES";
|
|
965
|
-
} else if (this.source.mappings.contains("country")) {
|
|
966
|
-
chartType = "CHORO_COUNTRIES";
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
Promise.all(context.layers.map(function (layer) { return layer.loadedPromise(); })).then(function () {
|
|
970
|
-
context.loadWidget("../composite/MegaChart", function (widget) {
|
|
971
|
-
const layers = context.layers.map(function (layer) { return layer.widget; });
|
|
972
|
-
try {
|
|
973
|
-
switch (widget.classID()) {
|
|
974
|
-
case "composite_MegaChart":
|
|
975
|
-
widget
|
|
976
|
-
.id(visualization.id)
|
|
977
|
-
.showChartSelect_default(false)
|
|
978
|
-
.chartType_default(chartType)
|
|
979
|
-
.chartTypeDefaults({
|
|
980
|
-
autoScaleMode: layers.length ? "data" : "mesh"
|
|
981
|
-
})
|
|
982
|
-
.chartTypeProperties({
|
|
983
|
-
layers
|
|
984
|
-
})
|
|
985
|
-
;
|
|
986
|
-
break;
|
|
987
|
-
default:
|
|
988
|
-
widget
|
|
989
|
-
.id(visualization.id)
|
|
990
|
-
.autoScaleMode(layers.length ? "data" : "mesh")
|
|
991
|
-
.layers(layers)
|
|
992
|
-
;
|
|
993
|
-
break;
|
|
994
|
-
}
|
|
995
|
-
} catch (e) {
|
|
996
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
997
|
-
}
|
|
998
|
-
});
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
break;
|
|
1002
|
-
case "2DCHART":
|
|
1003
|
-
case "PIE":
|
|
1004
|
-
case "BUBBLE":
|
|
1005
|
-
case "BAR":
|
|
1006
|
-
case "WORD_CLOUD":
|
|
1007
|
-
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1008
|
-
try {
|
|
1009
|
-
widget
|
|
1010
|
-
.id(visualization.id)
|
|
1011
|
-
.chartType_default(context.properties.chartType || context.properties.charttype || context.type)
|
|
1012
|
-
;
|
|
1013
|
-
} catch (e) {
|
|
1014
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1015
|
-
}
|
|
1016
|
-
});
|
|
1017
|
-
break;
|
|
1018
|
-
case "LINE":
|
|
1019
|
-
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1020
|
-
try {
|
|
1021
|
-
widget
|
|
1022
|
-
.id(visualization.id)
|
|
1023
|
-
.chartType_default(context.properties.chartType || context.properties.charttype || context.type)
|
|
1024
|
-
;
|
|
1025
|
-
} catch (e) {
|
|
1026
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1027
|
-
}
|
|
1028
|
-
});
|
|
1029
|
-
break;
|
|
1030
|
-
case "TABLE":
|
|
1031
|
-
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1032
|
-
try {
|
|
1033
|
-
widget
|
|
1034
|
-
.id(visualization.id)
|
|
1035
|
-
.showChartSelect_default(false)
|
|
1036
|
-
.chartType_default("TABLE")
|
|
1037
|
-
;
|
|
1038
|
-
} catch (e) {
|
|
1039
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1040
|
-
}
|
|
1041
|
-
});
|
|
1042
|
-
break;
|
|
1043
|
-
case "SLIDER":
|
|
1044
|
-
this.loadWidget("../form/Slider", function (widget) {
|
|
1045
|
-
try {
|
|
1046
|
-
widget
|
|
1047
|
-
.id(visualization.id)
|
|
1048
|
-
;
|
|
1049
|
-
if (visualization.range) {
|
|
1050
|
-
let selectionLabel = "";
|
|
1051
|
-
if (Utility.exists("events.click.updates", visualization) && visualization.events.click.updates.length) {
|
|
1052
|
-
for (const key in visualization.events.click.updates[0].mappings) {
|
|
1053
|
-
selectionLabel = key;
|
|
1054
|
-
break;
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
widget
|
|
1058
|
-
.low_default(+visualization.range[0])
|
|
1059
|
-
.high_default(+visualization.range[1])
|
|
1060
|
-
.step_default(+visualization.range[2])
|
|
1061
|
-
.selectionLabel_default(selectionLabel)
|
|
1062
|
-
.selectionLabel(selectionLabel)
|
|
1063
|
-
;
|
|
1064
|
-
}
|
|
1065
|
-
} catch (e) {
|
|
1066
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1067
|
-
}
|
|
1068
|
-
});
|
|
1069
|
-
break;
|
|
1070
|
-
case "GRAPH":
|
|
1071
|
-
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1072
|
-
try {
|
|
1073
|
-
widget
|
|
1074
|
-
.id(visualization.id)
|
|
1075
|
-
.showChartSelect_default(false)
|
|
1076
|
-
.chartType_default("GRAPH")
|
|
1077
|
-
.chartTypeDefaults({
|
|
1078
|
-
layout: "ForceDirected2",
|
|
1079
|
-
applyScaleOnLayout: true
|
|
1080
|
-
})
|
|
1081
|
-
;
|
|
1082
|
-
} catch (e) {
|
|
1083
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1084
|
-
}
|
|
1085
|
-
});
|
|
1086
|
-
break;
|
|
1087
|
-
case "FORM":
|
|
1088
|
-
this.loadWidgets(["../form/Form", "../form/Input", "../form/Button", "../form/CheckBox", "../form/ColorInput", "../form/Radio", "../form/Range", "../form/Select", "../form/Slider", "../form/TextArea", "../form/InputRange"], function (widget, widgetClasses) {
|
|
1089
|
-
const Input = widgetClasses[1];
|
|
1090
|
-
const CheckBox = widgetClasses[3];
|
|
1091
|
-
const Radio = widgetClasses[5];
|
|
1092
|
-
const Select = widgetClasses[7];
|
|
1093
|
-
const TextArea = widgetClasses[9];
|
|
1094
|
-
const InputRange = widgetClasses[10];
|
|
1095
|
-
|
|
1096
|
-
try {
|
|
1097
|
-
widget
|
|
1098
|
-
.id(visualization.id)
|
|
1099
|
-
.inputs(context.fields().map(function (field) {
|
|
1100
|
-
|
|
1101
|
-
const selectOptions = [];
|
|
1102
|
-
let options = [];
|
|
1103
|
-
let inp;
|
|
1104
|
-
if (!field.charttype() && field.type() === "range") {
|
|
1105
|
-
// TODO - Verify with @DL
|
|
1106
|
-
field.charttype("RANGE");
|
|
1107
|
-
}
|
|
1108
|
-
switch (field.charttype()) {
|
|
1109
|
-
case "TEXT":
|
|
1110
|
-
inp = new Input()
|
|
1111
|
-
.type_default("text")
|
|
1112
|
-
;
|
|
1113
|
-
break;
|
|
1114
|
-
case "TEXTAREA":
|
|
1115
|
-
inp = new TextArea();
|
|
1116
|
-
break;
|
|
1117
|
-
case "CHECKBOX":
|
|
1118
|
-
inp = new CheckBox();
|
|
1119
|
-
break;
|
|
1120
|
-
case "RADIO":
|
|
1121
|
-
inp = new Radio();
|
|
1122
|
-
break;
|
|
1123
|
-
case "HIDDEN":
|
|
1124
|
-
inp = new Input()
|
|
1125
|
-
.type_default("hidden")
|
|
1126
|
-
;
|
|
1127
|
-
break;
|
|
1128
|
-
case "RANGE":
|
|
1129
|
-
inp = new InputRange();
|
|
1130
|
-
break;
|
|
1131
|
-
default:
|
|
1132
|
-
if (field.enumvals()) {
|
|
1133
|
-
inp = new Select();
|
|
1134
|
-
options = field.enumvals();
|
|
1135
|
-
for (const val in options) {
|
|
1136
|
-
selectOptions.push([val, options[val]]);
|
|
1137
|
-
}
|
|
1138
|
-
} else {
|
|
1139
|
-
inp = new Input()
|
|
1140
|
-
.type_default("text")
|
|
1141
|
-
;
|
|
1142
|
-
}
|
|
1143
|
-
break;
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
inp
|
|
1147
|
-
.name_default(field.id())
|
|
1148
|
-
.label_default(field.label())
|
|
1149
|
-
.value_default(field.default()) // TODO Hippie support for multiple default values (checkbox only)
|
|
1150
|
-
;
|
|
1151
|
-
|
|
1152
|
-
if (inp instanceof CheckBox || inp instanceof Radio) { // change this to instanceof?
|
|
1153
|
-
const vals = Object.keys(field.enumvals());
|
|
1154
|
-
inp.selectOptions_default(vals);
|
|
1155
|
-
} else if (selectOptions.length) {
|
|
1156
|
-
inp.selectOptions_default(selectOptions);
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
return inp;
|
|
1160
|
-
}))
|
|
1161
|
-
;
|
|
1162
|
-
} catch (e) {
|
|
1163
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1164
|
-
}
|
|
1165
|
-
});
|
|
1166
|
-
break;
|
|
1167
|
-
case "HEAT_MAP":
|
|
1168
|
-
this.loadWidgets(["../other/HeatMap"], function (widget) {
|
|
1169
|
-
try {
|
|
1170
|
-
widget
|
|
1171
|
-
.id(visualization.id)
|
|
1172
|
-
.image_default(context.properties.imageUrl)
|
|
1173
|
-
;
|
|
1174
|
-
} catch (e) {
|
|
1175
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1176
|
-
}
|
|
1177
|
-
});
|
|
1178
|
-
break;
|
|
1179
|
-
default:
|
|
1180
|
-
this.loadWidget("../common/TextBox", function (widget) {
|
|
1181
|
-
try {
|
|
1182
|
-
widget
|
|
1183
|
-
.id(visualization.id)
|
|
1184
|
-
.text_default(context.id + "\n" + "TODO: " + context.type)
|
|
1185
|
-
;
|
|
1186
|
-
} catch (e) {
|
|
1187
|
-
console.warn("Unexpected widget type: " + widget.classID());
|
|
1188
|
-
}
|
|
1189
|
-
});
|
|
1190
|
-
break;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
getQualifiedID() {
|
|
1195
|
-
return this.id;
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
fields() {
|
|
1199
|
-
return this._fields;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
hasField(id) {
|
|
1203
|
-
return this.field[id] !== undefined;
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
field(id) {
|
|
1207
|
-
return this._fieldsMap[id];
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
loadedPromise() {
|
|
1211
|
-
const context = this;
|
|
1212
|
-
return new Promise<void>(function (resolve, reject) {
|
|
1213
|
-
const intervalHandle = setInterval(function () {
|
|
1214
|
-
if (context.isLoaded()) {
|
|
1215
|
-
clearInterval(intervalHandle);
|
|
1216
|
-
resolve();
|
|
1217
|
-
}
|
|
1218
|
-
}, 100);
|
|
1219
|
-
});
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
isLoading() {
|
|
1223
|
-
return this.widget === null;
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
isLoaded() {
|
|
1227
|
-
return this.widget instanceof Widget;
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
loadMegaChartWidget(widgetPath, callback) {
|
|
1231
|
-
this.loadWidgets(["../composite/MegaChart", widgetPath], function (megaChart, widgets) {
|
|
1232
|
-
const chart = new widgets[1]();
|
|
1233
|
-
megaChart
|
|
1234
|
-
.chartType_default(MultiChart.prototype._allChartTypesByClass[chart.classID()].id)
|
|
1235
|
-
.chart(chart)
|
|
1236
|
-
;
|
|
1237
|
-
if (callback) {
|
|
1238
|
-
callback(megaChart, chart, widgets);
|
|
1239
|
-
}
|
|
1240
|
-
});
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
loadWidget(widgetPath, callback) {
|
|
1244
|
-
this.loadWidgets([widgetPath], callback);
|
|
1245
|
-
}
|
|
1246
|
-
|
|
1247
|
-
loadWidgets(widgetPaths, callback) {
|
|
1248
|
-
this.widget = null;
|
|
1249
|
-
|
|
1250
|
-
const context = this;
|
|
1251
|
-
legacyRequire(widgetPaths, function (WidgetClass) {
|
|
1252
|
-
const existingWidget = context.dashboard.marshaller.getWidget(context.id);
|
|
1253
|
-
if (existingWidget) {
|
|
1254
|
-
if (WidgetClass.prototype._class !== existingWidget.classID()) {
|
|
1255
|
-
console.warn("Unexpected persisted widget type (old persist string?)");
|
|
1256
|
-
}
|
|
1257
|
-
context.setWidget(existingWidget);
|
|
1258
|
-
} else {
|
|
1259
|
-
context.setWidget(new WidgetClass());
|
|
1260
|
-
}
|
|
1261
|
-
if (callback) {
|
|
1262
|
-
callback(context.widget, arguments);
|
|
1263
|
-
}
|
|
1264
|
-
});
|
|
1265
|
-
}
|
|
1266
|
-
|
|
1267
|
-
setWidget(widget) {
|
|
1268
|
-
this.widget = widget;
|
|
1269
|
-
this.events.setWidget(widget);
|
|
1270
|
-
if (this.widget.columns) {
|
|
1271
|
-
const columns = this.source.getColumns();
|
|
1272
|
-
this.widget.columns(columns, true);
|
|
1273
|
-
}
|
|
1274
|
-
for (const key in this.properties) {
|
|
1275
|
-
switch (widget.classID()) {
|
|
1276
|
-
case "chart_MultiChart":
|
|
1277
|
-
case "composite_MegaChart":
|
|
1278
|
-
if (widget[key + "_default"]) {
|
|
1279
|
-
widget[key + "_default"](this.properties[key]);
|
|
1280
|
-
}
|
|
1281
|
-
widget.chartTypeDefaults()[key] = this.properties[key];
|
|
1282
|
-
break;
|
|
1283
|
-
default:
|
|
1284
|
-
if (this.widget[key + "_default"]) {
|
|
1285
|
-
try {
|
|
1286
|
-
this.widget[key + "_default"](this.properties[key]);
|
|
1287
|
-
} catch (e) {
|
|
1288
|
-
console.warn("Invalid Property:" + this.id + ".properties." + key);
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
return this.widget;
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
accept(visitor) {
|
|
1297
|
-
visitor.visit(this);
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
getUpdates() {
|
|
1301
|
-
return this.events.getUpdates();
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
getUpdatesForDatasource(otherDatasource) {
|
|
1305
|
-
return this.events.getUpdates().filter(function (updateObj) {
|
|
1306
|
-
return updateObj.getDatasource() === otherDatasource;
|
|
1307
|
-
});
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
getUpdatesForVisualization(otherViz) {
|
|
1311
|
-
return this.events.getUpdates().filter(function (updateObj) {
|
|
1312
|
-
return updateObj.getVisualization() === otherViz;
|
|
1313
|
-
});
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
getInputFields(mapped?): any {
|
|
1317
|
-
const retVal = {};
|
|
1318
|
-
const updatedBy = this.getInputVisualizations();
|
|
1319
|
-
updatedBy.forEach(viz => {
|
|
1320
|
-
if (viz.hasSelection()) {
|
|
1321
|
-
viz.getUpdatesForVisualization(this).forEach(function (updateObj) {
|
|
1322
|
-
const sel = mapped ? updateObj.mapSelected() : updateObj.selectedRow();
|
|
1323
|
-
for (const key in sel) {
|
|
1324
|
-
retVal[key] = sel[key];
|
|
1325
|
-
}
|
|
1326
|
-
});
|
|
1327
|
-
}
|
|
1328
|
-
});
|
|
1329
|
-
return retVal;
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
|
-
update(params?) {
|
|
1333
|
-
let titleWidget = null;
|
|
1334
|
-
if (!this.parentVisualization) {
|
|
1335
|
-
titleWidget = this.widget;
|
|
1336
|
-
while (titleWidget && !titleWidget.title) {
|
|
1337
|
-
titleWidget = titleWidget.locateParentWidget();
|
|
1338
|
-
}
|
|
1339
|
-
}
|
|
1340
|
-
|
|
1341
|
-
if (!params) {
|
|
1342
|
-
params = "";
|
|
1343
|
-
let titleFormatStr = "";
|
|
1344
|
-
if (titleWidget && titleWidget.ddlParamsFormat) {
|
|
1345
|
-
titleFormatStr = titleWidget.ddlParamsFormat();
|
|
1346
|
-
}
|
|
1347
|
-
|
|
1348
|
-
const dedupParams = {};
|
|
1349
|
-
if (titleFormatStr) {
|
|
1350
|
-
params = Utility.template(titleFormatStr, this.getInputFields());
|
|
1351
|
-
} else {
|
|
1352
|
-
const paramsArr = [];
|
|
1353
|
-
const mappedData = this.getInputFields(true);
|
|
1354
|
-
for (const key in mappedData) {
|
|
1355
|
-
if (mappedData[key]) {
|
|
1356
|
-
if (!dedupParams[key]) {
|
|
1357
|
-
dedupParams[key] = true;
|
|
1358
|
-
paramsArr.push(mappedData[key]);
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
params = paramsArr.join(", ");
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
|
|
1366
|
-
const context = this;
|
|
1367
|
-
return new Promise<void>(function (resolve, reject) {
|
|
1368
|
-
if (titleWidget) {
|
|
1369
|
-
const title = titleWidget.title();
|
|
1370
|
-
const titleParts = title.split(" (");
|
|
1371
|
-
titleWidget
|
|
1372
|
-
.title(titleParts[0] + (params.trim() ? " (" + params + ")" : ""))
|
|
1373
|
-
.render(function () {
|
|
1374
|
-
resolve();
|
|
1375
|
-
})
|
|
1376
|
-
;
|
|
1377
|
-
} else {
|
|
1378
|
-
let ddlViz = context;
|
|
1379
|
-
while (ddlViz.parentVisualization) {
|
|
1380
|
-
ddlViz = ddlViz.parentVisualization;
|
|
1381
|
-
}
|
|
1382
|
-
ddlViz.widget.render(function () {
|
|
1383
|
-
resolve();
|
|
1384
|
-
});
|
|
1385
|
-
}
|
|
1386
|
-
if (context.dashboard.marshaller.propogateClear()) {
|
|
1387
|
-
context.events.getUpdatesVisualizations().forEach(function (updatedViz) {
|
|
1388
|
-
updatedViz.update();
|
|
1389
|
-
});
|
|
1390
|
-
}
|
|
1391
|
-
});
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
notify() {
|
|
1395
|
-
if (this.widget) {
|
|
1396
|
-
const data = this.source.hasData() ? this.source.getData() : [];
|
|
1397
|
-
this.widget.data(data);
|
|
1398
|
-
if (this.type === "GRAPH" && data.vertices) {
|
|
1399
|
-
const ipFields = this.getInputFields(true);
|
|
1400
|
-
data.vertices.filter(function (v) {
|
|
1401
|
-
return v.__hpcc_uid === ipFields.treeuid;
|
|
1402
|
-
}).forEach(function (v) {
|
|
1403
|
-
v.centroid(true);
|
|
1404
|
-
});
|
|
1405
|
-
}
|
|
1406
|
-
return this.update();
|
|
1407
|
-
}
|
|
1408
|
-
return Promise.resolve();
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
clear() {
|
|
1412
|
-
this._widgetState = {
|
|
1413
|
-
row: {},
|
|
1414
|
-
selected: false
|
|
1415
|
-
};
|
|
1416
|
-
this.fields().forEach(field => {
|
|
1417
|
-
if (field.hasDefault()) {
|
|
1418
|
-
this._widgetState.row[field.id()] = field.default();
|
|
1419
|
-
this._widgetState.selected = true;
|
|
1420
|
-
}
|
|
1421
|
-
});
|
|
1422
|
-
if (this.widget && this.dashboard.marshaller.clearDataOnUpdate()) {
|
|
1423
|
-
this.widget.data([]);
|
|
1424
|
-
}
|
|
1425
|
-
if (this.dashboard.marshaller.propogateClear()) {
|
|
1426
|
-
this.events.getUpdatesVisualizations().forEach(function (updatedViz) {
|
|
1427
|
-
updatedViz.clear();
|
|
1428
|
-
});
|
|
1429
|
-
}
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
on(eventID, func) {
|
|
1433
|
-
const context = this;
|
|
1434
|
-
this.overrideMethod(eventID, function (origFunc, args) {
|
|
1435
|
-
origFunc.apply(context, args);
|
|
1436
|
-
setTimeout(function () {
|
|
1437
|
-
func.apply(context, args);
|
|
1438
|
-
}, 0);
|
|
1439
|
-
});
|
|
1440
|
-
return this;
|
|
1441
|
-
}
|
|
1442
|
-
|
|
1443
|
-
calcRequestFor(visualization) {
|
|
1444
|
-
let retVal = {};
|
|
1445
|
-
this.getUpdatesForVisualization(visualization).forEach(function (updatesObj) {
|
|
1446
|
-
// TODO: When we support more than "click" this will need enhancment...
|
|
1447
|
-
retVal = updatesObj.calcRequestFor(visualization);
|
|
1448
|
-
});
|
|
1449
|
-
return retVal;
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
processEvent(eventID, event, row, col, selected) {
|
|
1453
|
-
this._widgetState = {
|
|
1454
|
-
row,
|
|
1455
|
-
col,
|
|
1456
|
-
selected: selected === undefined ? true : selected
|
|
1457
|
-
};
|
|
1458
|
-
const context = this;
|
|
1459
|
-
setTimeout(function () {
|
|
1460
|
-
event.fetchData().then(function (promises) {
|
|
1461
|
-
context.dashboard.marshaller.vizEvent(context.widget, "post_" + eventID, row, col, selected);
|
|
1462
|
-
});
|
|
1463
|
-
}, 0);
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
hasSelection() {
|
|
1467
|
-
return this._widgetState && this._widgetState.selected;
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
selection() {
|
|
1471
|
-
if (this.hasSelection()) {
|
|
1472
|
-
return this._widgetState.row;
|
|
1473
|
-
}
|
|
1474
|
-
return null;
|
|
1475
|
-
}
|
|
1476
|
-
|
|
1477
|
-
reverseMappedSelection() {
|
|
1478
|
-
if (this.hasSelection()) {
|
|
1479
|
-
return this.source.mappings ? this.source.mappings.doReverseMap(this._widgetState.row) : this._widgetState.row;
|
|
1480
|
-
}
|
|
1481
|
-
return null;
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
getInputVisualizations() {
|
|
1485
|
-
return this.dashboard.marshaller.getVisualizationArray().filter(viz => {
|
|
1486
|
-
const updates = viz.events.getUpdatesVisualizations();
|
|
1487
|
-
if (updates.indexOf(this) >= 0) {
|
|
1488
|
-
return true;
|
|
1489
|
-
}
|
|
1490
|
-
return false;
|
|
1491
|
-
});
|
|
1492
|
-
}
|
|
1493
|
-
|
|
1494
|
-
serializeState() {
|
|
1495
|
-
const state: any = {
|
|
1496
|
-
widgetState: this._widgetState
|
|
1497
|
-
};
|
|
1498
|
-
if (this.widget) {
|
|
1499
|
-
if (this.widget.serializeState) {
|
|
1500
|
-
state.widget = this.widget.serializeState();
|
|
1501
|
-
} else if (this.widget.data) {
|
|
1502
|
-
state.widget = {
|
|
1503
|
-
data: this.widget.data()
|
|
1504
|
-
};
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
|
-
return state;
|
|
1508
|
-
}
|
|
1509
|
-
|
|
1510
|
-
deserializeState(state) {
|
|
1511
|
-
if (state) {
|
|
1512
|
-
this._widgetState = state.widgetState;
|
|
1513
|
-
if (this.widget && state.widget) {
|
|
1514
|
-
if (this.widget.deserializeState) {
|
|
1515
|
-
this.widget.deserializeState(state.widget);
|
|
1516
|
-
} else if (this.widget.data && state.widget.data) {
|
|
1517
|
-
this.widget.data(state.widget.data);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
}
|
|
1521
|
-
return this;
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
// Output ---
|
|
1526
|
-
function Filter(this: any, datasource, ddlFilter: string | DDL1.IFilter) {
|
|
1527
|
-
this.datasource = datasource;
|
|
1528
|
-
if (typeof ddlFilter === "string") {
|
|
1529
|
-
ddlFilter = {
|
|
1530
|
-
fieldid: ddlFilter,
|
|
1531
|
-
nullable: true,
|
|
1532
|
-
rule: "=="
|
|
1533
|
-
};
|
|
1534
|
-
}
|
|
1535
|
-
this.fieldid = ddlFilter.fieldid;
|
|
1536
|
-
this.nullable = ddlFilter.nullable;
|
|
1537
|
-
this.rule = ddlFilter.rule || "==";
|
|
1538
|
-
this.minid = ddlFilter.minid;
|
|
1539
|
-
this.maxid = ddlFilter.maxid;
|
|
1540
|
-
this.calcRequestFieldID();
|
|
1541
|
-
}
|
|
1542
|
-
|
|
1543
|
-
Filter.prototype.calcRequestFieldID = function () {
|
|
1544
|
-
this._requestFieldID = this.fieldid;
|
|
1545
|
-
this._requestMinID = this.minid;
|
|
1546
|
-
this._requestMaxID = this.maxid;
|
|
1547
|
-
switch (this.rule) {
|
|
1548
|
-
case "<":
|
|
1549
|
-
case "<=":
|
|
1550
|
-
if (Utility.endsWith(this.fieldid, "-max")) {
|
|
1551
|
-
this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
|
|
1552
|
-
}
|
|
1553
|
-
break;
|
|
1554
|
-
case ">":
|
|
1555
|
-
case ">=":
|
|
1556
|
-
if (Utility.endsWith(this.fieldid, "-min")) {
|
|
1557
|
-
this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
|
|
1558
|
-
}
|
|
1559
|
-
break;
|
|
1560
|
-
case "set":
|
|
1561
|
-
if (Utility.endsWith(this.fieldid, "-set")) {
|
|
1562
|
-
this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_set" : "");
|
|
1563
|
-
}
|
|
1564
|
-
break;
|
|
1565
|
-
case "range":
|
|
1566
|
-
if (Utility.endsWith(this.minid, "-min")) {
|
|
1567
|
-
this._requestMinID = this.minid.substring(0, this.minid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
|
|
1568
|
-
}
|
|
1569
|
-
if (Utility.endsWith(this.maxid, "-max")) {
|
|
1570
|
-
this._requestMaxID = this.maxid.substring(0, this.maxid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
|
|
1571
|
-
}
|
|
1572
|
-
break;
|
|
1573
|
-
}
|
|
1574
|
-
};
|
|
1575
|
-
|
|
1576
|
-
Filter.prototype.isRange = function () {
|
|
1577
|
-
return this.rule === "range";
|
|
1578
|
-
};
|
|
1579
|
-
|
|
1580
|
-
Filter.prototype.isSet = function () {
|
|
1581
|
-
return this.rule === "set";
|
|
1582
|
-
};
|
|
1583
|
-
|
|
1584
|
-
Filter.prototype._calcRequest = function (filteredRequest, request, fieldid, requestFieldID, value) {
|
|
1585
|
-
if (!this.datasource.isRoxie()) {
|
|
1586
|
-
// Ignore requestFieldID, until filtering WU results
|
|
1587
|
-
// Otherwise there are many fieldID collisions
|
|
1588
|
-
requestFieldID = fieldid;
|
|
1589
|
-
}
|
|
1590
|
-
filteredRequest[requestFieldID + _CHANGED] = request[fieldid + _CHANGED] || false;
|
|
1591
|
-
if (filteredRequest[requestFieldID] !== value) {
|
|
1592
|
-
filteredRequest[requestFieldID] = value;
|
|
1593
|
-
}
|
|
1594
|
-
};
|
|
1595
|
-
|
|
1596
|
-
Filter.prototype.calcRequest = function (filteredRequest, request, fillInMissing) {
|
|
1597
|
-
if (!fillInMissing && request[this.fieldid] === undefined) {
|
|
1598
|
-
return;
|
|
1599
|
-
}
|
|
1600
|
-
const value = request[this.fieldid] === undefined ? null : request[this.fieldid];
|
|
1601
|
-
if (this.isRange()) {
|
|
1602
|
-
if (value instanceof Array && value.length === 2) {
|
|
1603
|
-
this._calcRequest(filteredRequest, request, this.minid, this._requestMinID, value[0]);
|
|
1604
|
-
this._calcRequest(filteredRequest, request, this.maxid, this._requestMaxID, value[1]);
|
|
1605
|
-
}
|
|
1606
|
-
} else {
|
|
1607
|
-
this._calcRequest(filteredRequest, request, this.fieldid, this._requestFieldID, value);
|
|
1608
|
-
if (this.isSet() && this.datasource.isRoxie()) {
|
|
1609
|
-
// TODO in the future the value should be an array ---
|
|
1610
|
-
filteredRequest[this._requestFieldID + ".Item$"] = filteredRequest[this._requestFieldID];
|
|
1611
|
-
delete filteredRequest[this._requestFieldID];
|
|
1612
|
-
}
|
|
1613
|
-
}
|
|
1614
|
-
};
|
|
1615
|
-
|
|
1616
|
-
Filter.prototype.matches = function (row, value): boolean {
|
|
1617
|
-
if (value === undefined || value === null || value === "") {
|
|
1618
|
-
return this.nullable;
|
|
1619
|
-
}
|
|
1620
|
-
let rowValue = row[this._requestFieldID];
|
|
1621
|
-
if (rowValue === undefined) {
|
|
1622
|
-
rowValue = row[this._requestFieldID.toLowerCase()];
|
|
1623
|
-
}
|
|
1624
|
-
if (rowValue === undefined) {
|
|
1625
|
-
console.warn("Empty cell value: '" + this._requestFieldID + "'");
|
|
1626
|
-
return false;
|
|
1627
|
-
}
|
|
1628
|
-
switch (this.rule) {
|
|
1629
|
-
case "<":
|
|
1630
|
-
if (rowValue.localeCompare) {
|
|
1631
|
-
return rowValue.localeCompare(value) < 0;
|
|
1632
|
-
}
|
|
1633
|
-
return rowValue < value;
|
|
1634
|
-
case ">":
|
|
1635
|
-
if (rowValue.localeCompare) {
|
|
1636
|
-
return rowValue.localeCompare(value) > 0;
|
|
1637
|
-
}
|
|
1638
|
-
return rowValue > value;
|
|
1639
|
-
case "<=":
|
|
1640
|
-
if (rowValue.localeCompare) {
|
|
1641
|
-
return rowValue.localeCompare(value) <= 0;
|
|
1642
|
-
}
|
|
1643
|
-
return rowValue <= value;
|
|
1644
|
-
case ">=":
|
|
1645
|
-
if (rowValue.localeCompare) {
|
|
1646
|
-
return rowValue.localeCompare(value) >= 0;
|
|
1647
|
-
}
|
|
1648
|
-
return rowValue >= value;
|
|
1649
|
-
case "!=":
|
|
1650
|
-
case "notequals":
|
|
1651
|
-
return rowValue != value; // jshint ignore:line
|
|
1652
|
-
case "set":
|
|
1653
|
-
if (value instanceof Array) {
|
|
1654
|
-
return value.indexOf(rowValue) >= 0;
|
|
1655
|
-
}
|
|
1656
|
-
return value == rowValue; // jshint ignore:line
|
|
1657
|
-
case "==":
|
|
1658
|
-
return value == rowValue; // jshint ignore:line
|
|
1659
|
-
default:
|
|
1660
|
-
console.warn("Unknown filter rule: '" + this.rule + "'");
|
|
1661
|
-
return value == rowValue; // jshint ignore:line
|
|
1662
|
-
}
|
|
1663
|
-
};
|
|
1664
|
-
|
|
1665
|
-
export class Output {
|
|
1666
|
-
|
|
1667
|
-
datasource;
|
|
1668
|
-
id;
|
|
1669
|
-
from;
|
|
1670
|
-
protected notify;
|
|
1671
|
-
filters;
|
|
1672
|
-
protected db;
|
|
1673
|
-
|
|
1674
|
-
constructor(datasource, output) {
|
|
1675
|
-
this.datasource = datasource;
|
|
1676
|
-
this.id = output.id;
|
|
1677
|
-
this.from = output.from;
|
|
1678
|
-
this.notify = output.notify || [];
|
|
1679
|
-
this.filters = (output.filter || []).map(filter => {
|
|
1680
|
-
return new Filter(this.datasource, filter);
|
|
1681
|
-
});
|
|
1682
|
-
}
|
|
1683
|
-
|
|
1684
|
-
getQualifiedID() {
|
|
1685
|
-
return this.datasource.getQualifiedID() + "." + this.id;
|
|
1686
|
-
}
|
|
1687
|
-
|
|
1688
|
-
getUpdatesVisualizations() {
|
|
1689
|
-
const retVal = [];
|
|
1690
|
-
this.notify.forEach(item => {
|
|
1691
|
-
retVal.push(this.datasource.marshaller.getVisualization(item));
|
|
1692
|
-
});
|
|
1693
|
-
return retVal;
|
|
1694
|
-
}
|
|
1695
|
-
|
|
1696
|
-
accept(visitor) {
|
|
1697
|
-
visitor.visit(this);
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
vizNotify(updates) {
|
|
1701
|
-
const promises = [];
|
|
1702
|
-
this.notify.filter(function (item) {
|
|
1703
|
-
return !updates || updates.indexOf(item) >= 0;
|
|
1704
|
-
}).forEach(item => {
|
|
1705
|
-
const viz = this.datasource.marshaller.getVisualization(item);
|
|
1706
|
-
promises.push(viz.notify());
|
|
1707
|
-
});
|
|
1708
|
-
return Promise.all(promises);
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
setData(data, updates) {
|
|
1712
|
-
this.db = new Database.Grid().jsonObj(data);
|
|
1713
|
-
return this.vizNotify(updates);
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1716
|
-
|
|
1717
|
-
// FetchData Optimizers ---
|
|
1718
|
-
function DatasourceRequestOptimizer(this: any) {
|
|
1719
|
-
this.datasourceRequests = {
|
|
1720
|
-
};
|
|
1721
|
-
}
|
|
1722
|
-
|
|
1723
|
-
DatasourceRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
|
|
1724
|
-
const datasourceRequestID = updateDatasource.id + "(" + JSON.stringify(request) + ")";
|
|
1725
|
-
if (!this.datasourceRequests[datasourceRequestID]) {
|
|
1726
|
-
this.datasourceRequests[datasourceRequestID] = {
|
|
1727
|
-
updateDatasource,
|
|
1728
|
-
request,
|
|
1729
|
-
updates: []
|
|
1730
|
-
};
|
|
1731
|
-
} else if ((window as any).__hpcc_debug) {
|
|
1732
|
-
console.warn("Optimized duplicate fetch: " + datasourceRequestID);
|
|
1733
|
-
}
|
|
1734
|
-
const datasourceOptimizedItem = this.datasourceRequests[datasourceRequestID];
|
|
1735
|
-
if (datasourceOptimizedItem.updates.indexOf(updateVisualization.id) < 0) {
|
|
1736
|
-
datasourceOptimizedItem.updates.push(updateVisualization.id);
|
|
1737
|
-
}
|
|
1738
|
-
};
|
|
1739
|
-
|
|
1740
|
-
DatasourceRequestOptimizer.prototype.fetchData = function () {
|
|
1741
|
-
const promises = [];
|
|
1742
|
-
for (const key in this.datasourceRequests) {
|
|
1743
|
-
const item = this.datasourceRequests[key];
|
|
1744
|
-
promises.push(item.updateDatasource.fetchData(item.request, item.updates));
|
|
1745
|
-
}
|
|
1746
|
-
return Promise.all(promises);
|
|
1747
|
-
};
|
|
1748
|
-
|
|
1749
|
-
function VisualizationRequestOptimizer(this: any, skipClear?) {
|
|
1750
|
-
this.skipClear = skipClear;
|
|
1751
|
-
this.visualizationRequests = {
|
|
1752
|
-
};
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
VisualizationRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
|
|
1756
|
-
if (updateDatasource && updateVisualization) {
|
|
1757
|
-
const visualizationRequestID = updateVisualization.id + "(" + updateDatasource.id + ")";
|
|
1758
|
-
if (!this.visualizationRequests[visualizationRequestID]) {
|
|
1759
|
-
this.visualizationRequests[visualizationRequestID] = {
|
|
1760
|
-
updateVisualization,
|
|
1761
|
-
updateDatasource,
|
|
1762
|
-
request: {}
|
|
1763
|
-
};
|
|
1764
|
-
} else if ((window as any).__hpcc_debug) {
|
|
1765
|
-
console.warn("Optimized duplicate fetch: " + visualizationRequestID);
|
|
1766
|
-
}
|
|
1767
|
-
const visualizationOptimizedItem = this.visualizationRequests[visualizationRequestID];
|
|
1768
|
-
Utility.mixin(visualizationOptimizedItem.request, request);
|
|
1769
|
-
}
|
|
1770
|
-
};
|
|
1771
|
-
|
|
1772
|
-
VisualizationRequestOptimizer.prototype.fetchData = function () {
|
|
1773
|
-
const datasourceRequestOptimizer = new DatasourceRequestOptimizer();
|
|
1774
|
-
for (const key in this.visualizationRequests) {
|
|
1775
|
-
const item = this.visualizationRequests[key];
|
|
1776
|
-
if (!this.skipClear && item.updateVisualization.type !== "GRAPH") {
|
|
1777
|
-
item.updateVisualization.clear();
|
|
1778
|
-
}
|
|
1779
|
-
item.updateVisualization.update(LOADING);
|
|
1780
|
-
datasourceRequestOptimizer.appendRequest(item.updateDatasource, item.request, item.updateVisualization);
|
|
1781
|
-
}
|
|
1782
|
-
return datasourceRequestOptimizer.fetchData();
|
|
1783
|
-
};
|
|
1784
|
-
|
|
1785
|
-
// Datasource ---
|
|
1786
|
-
let transactionID = 0;
|
|
1787
|
-
const transactionQueue = [];
|
|
1788
|
-
export class Datasource {
|
|
1789
|
-
|
|
1790
|
-
protected marshaller;
|
|
1791
|
-
id;
|
|
1792
|
-
protected WUID;
|
|
1793
|
-
protected URL;
|
|
1794
|
-
databomb;
|
|
1795
|
-
protected filters;
|
|
1796
|
-
protected _loadedCount;
|
|
1797
|
-
protected _outputs;
|
|
1798
|
-
protected _outputArray;
|
|
1799
|
-
comms;
|
|
1800
|
-
protected _loadedCount2;
|
|
1801
|
-
protected _loadedCount3;
|
|
1802
|
-
protected _loadedCount4;
|
|
1803
|
-
|
|
1804
|
-
constructor(marshaller, datasource: DDL1.IAnyDatasource, proxyMappings, timeout) {
|
|
1805
|
-
this.marshaller = marshaller;
|
|
1806
|
-
this.id = datasource.id;
|
|
1807
|
-
if (DDL1.isWorkunitDatasource(datasource)) {
|
|
1808
|
-
this.WUID = datasource.WUID;
|
|
1809
|
-
} else if (DDL1.isHipieDatasource(datasource)) {
|
|
1810
|
-
this.URL = (marshaller.espUrl && marshaller.espUrl.url()) ? marshaller.espUrl.url() : datasource.URL;
|
|
1811
|
-
} else if (DDL1.isDatabombDatasource(datasource)) {
|
|
1812
|
-
this.databomb = datasource.databomb;
|
|
1813
|
-
}
|
|
1814
|
-
this.filters = (datasource.filter || []).map(filter => {
|
|
1815
|
-
return new Filter(this, filter);
|
|
1816
|
-
});
|
|
1817
|
-
this._loadedCount = 0;
|
|
1818
|
-
|
|
1819
|
-
const context = this;
|
|
1820
|
-
this._outputs = {};
|
|
1821
|
-
this._outputArray = [];
|
|
1822
|
-
const hipieResults = [];
|
|
1823
|
-
datasource.outputs.forEach(item => {
|
|
1824
|
-
const output = new Output(context, item);
|
|
1825
|
-
context._outputs[item.id] = output;
|
|
1826
|
-
context._outputArray.push(output);
|
|
1827
|
-
hipieResults.push({
|
|
1828
|
-
id: item.id,
|
|
1829
|
-
from: item.from,
|
|
1830
|
-
filters: output.filters || this.filters
|
|
1831
|
-
});
|
|
1832
|
-
});
|
|
1833
|
-
|
|
1834
|
-
if (this.WUID) {
|
|
1835
|
-
this.comms = new Comms.HIPIEWorkunit()
|
|
1836
|
-
.url(this.URL)
|
|
1837
|
-
.proxyMappings(proxyMappings)
|
|
1838
|
-
.timeout(timeout)
|
|
1839
|
-
.hipieResults(hipieResults)
|
|
1840
|
-
;
|
|
1841
|
-
} else if (this.databomb) {
|
|
1842
|
-
this.comms = new Comms.HIPIEDatabomb()
|
|
1843
|
-
.hipieResults(hipieResults)
|
|
1844
|
-
;
|
|
1845
|
-
} else if (DDL1.isHipieDatasource(datasource)) {
|
|
1846
|
-
this.comms = new Comms.HIPIERoxie()
|
|
1847
|
-
.url(datasource.URL)
|
|
1848
|
-
.proxyMappings(proxyMappings)
|
|
1849
|
-
.timeout(timeout)
|
|
1850
|
-
.hipieResults(hipieResults)
|
|
1851
|
-
;
|
|
1852
|
-
}
|
|
1853
|
-
}
|
|
1854
|
-
|
|
1855
|
-
isRoxie() {
|
|
1856
|
-
return !this.WUID && !this.databomb;
|
|
1857
|
-
}
|
|
1858
|
-
|
|
1859
|
-
isWU() {
|
|
1860
|
-
return !!this.WUID;
|
|
1861
|
-
}
|
|
1862
|
-
|
|
1863
|
-
isDatabomb() {
|
|
1864
|
-
return !!this.databomb;
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
getQualifiedID() {
|
|
1868
|
-
return this.id;
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
getOutputs() {
|
|
1872
|
-
return this._outputs;
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
getUpdatesVisualizations() {
|
|
1876
|
-
const retVal = [];
|
|
1877
|
-
for (const key in this._outputs) {
|
|
1878
|
-
this._outputs[key].getUpdatesVisualizations().forEach(function (visualization) {
|
|
1879
|
-
retVal.push(visualization);
|
|
1880
|
-
});
|
|
1881
|
-
}
|
|
1882
|
-
return retVal;
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
|
-
accept(visitor) {
|
|
1886
|
-
visitor.visit(this);
|
|
1887
|
-
for (const key in this._outputs) {
|
|
1888
|
-
this._outputs[key].accept(visitor);
|
|
1889
|
-
}
|
|
1890
|
-
}
|
|
1891
|
-
|
|
1892
|
-
calcRequest(request, fillInMissing) {
|
|
1893
|
-
const retVal = {};
|
|
1894
|
-
this.filters.forEach(function (item) {
|
|
1895
|
-
item.calcRequest(retVal, request, fillInMissing);
|
|
1896
|
-
});
|
|
1897
|
-
// TODO - Workaround HIPIE issue where it omits filters at datasource level ---
|
|
1898
|
-
this._outputArray.forEach(function (output) {
|
|
1899
|
-
output.filters.forEach(function (item) {
|
|
1900
|
-
item.calcRequest(retVal, request, fillInMissing);
|
|
1901
|
-
});
|
|
1902
|
-
});
|
|
1903
|
-
return retVal;
|
|
1904
|
-
}
|
|
1905
|
-
|
|
1906
|
-
fetchData(request, updates) {
|
|
1907
|
-
const myTransactionID = ++transactionID;
|
|
1908
|
-
transactionQueue.push(myTransactionID);
|
|
1909
|
-
|
|
1910
|
-
let dsRequest = request;
|
|
1911
|
-
dsRequest = this.calcRequest(request, this.isRoxie());
|
|
1912
|
-
dsRequest.refresh = request.refresh || false;
|
|
1913
|
-
if ((window as any).__hpcc_debug) {
|
|
1914
|
-
console.warn("fetchData: " + JSON.stringify(updates) + "(" + JSON.stringify(request) + ")");
|
|
1915
|
-
}
|
|
1916
|
-
for (const key in dsRequest) {
|
|
1917
|
-
if (dsRequest[key] === undefined) {
|
|
1918
|
-
delete dsRequest[key];
|
|
1919
|
-
}
|
|
1920
|
-
}
|
|
1921
|
-
const now = Date.now();
|
|
1922
|
-
this.marshaller.commsEvent(this, "request", dsRequest);
|
|
1923
|
-
const context = this;
|
|
1924
|
-
return new Promise(function (resolve, reject) {
|
|
1925
|
-
context.comms.call(dsRequest).then(function (_response) {
|
|
1926
|
-
const response = JSON.parse(JSON.stringify(_response));
|
|
1927
|
-
const intervalHandle = setInterval(function () {
|
|
1928
|
-
if (transactionQueue[0] === myTransactionID && Date.now() - now >= 500) { // 500 is to allow for all "clear" transitions to complete...
|
|
1929
|
-
clearTimeout(intervalHandle);
|
|
1930
|
-
context.processResponse(response, dsRequest, updates).then(function () {
|
|
1931
|
-
transactionQueue.shift();
|
|
1932
|
-
resolve(response);
|
|
1933
|
-
context.marshaller.commsEvent(context, "response", dsRequest, response);
|
|
1934
|
-
++context._loadedCount;
|
|
1935
|
-
});
|
|
1936
|
-
}
|
|
1937
|
-
}, 100);
|
|
1938
|
-
}).catch(function (e) {
|
|
1939
|
-
context.marshaller.commsEvent(context, "error", dsRequest, e);
|
|
1940
|
-
reject(e);
|
|
1941
|
-
});
|
|
1942
|
-
});
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
|
-
processResponse(response, request, updates) {
|
|
1946
|
-
const lowerResponse = {};
|
|
1947
|
-
for (const responseKey in response) {
|
|
1948
|
-
lowerResponse[responseKey.toLowerCase()] = response[responseKey];
|
|
1949
|
-
}
|
|
1950
|
-
const promises = [];
|
|
1951
|
-
for (const key in this._outputs) {
|
|
1952
|
-
const from = this._outputs[key].id;
|
|
1953
|
-
if (Utility.exists(from, response)) {
|
|
1954
|
-
if (!Utility.exists(from + _CHANGED, response) || (Utility.exists(from + _CHANGED, response) && response[from + _CHANGED].length && response[from + _CHANGED][0][from + _CHANGED])) {
|
|
1955
|
-
promises.push(this._outputs[key].setData(response[from], updates));
|
|
1956
|
-
} else {
|
|
1957
|
-
// TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
|
|
1958
|
-
promises.push(this._outputs[key].vizNotify(updates));
|
|
1959
|
-
}
|
|
1960
|
-
} else if (Utility.exists(from, lowerResponse)) {
|
|
1961
|
-
console.warn("DDL 'Datasource.From' case is Incorrect");
|
|
1962
|
-
if (!Utility.exists(from + _CHANGED, lowerResponse) || (Utility.exists(from + _CHANGED, lowerResponse) && response[from + _CHANGED].length && lowerResponse[from + _CHANGED][0][from + _CHANGED])) {
|
|
1963
|
-
promises.push(this._outputs[key].setData(lowerResponse[from], updates));
|
|
1964
|
-
} else {
|
|
1965
|
-
// TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
|
|
1966
|
-
promises.push(this._outputs[key].vizNotify(updates));
|
|
1967
|
-
}
|
|
1968
|
-
} else {
|
|
1969
|
-
const responseItems = [];
|
|
1970
|
-
for (const responseKey2 in response) {
|
|
1971
|
-
responseItems.push(responseKey2);
|
|
1972
|
-
}
|
|
1973
|
-
console.warn("Unable to locate '" + from + "' in response {" + responseItems.join(", ") + "}");
|
|
1974
|
-
}
|
|
1975
|
-
}
|
|
1976
|
-
return Promise.all(promises);
|
|
1977
|
-
}
|
|
1978
|
-
|
|
1979
|
-
isLoaded() {
|
|
1980
|
-
return this._loadedCount > 0;
|
|
1981
|
-
}
|
|
1982
|
-
|
|
1983
|
-
serializeState() {
|
|
1984
|
-
return {
|
|
1985
|
-
};
|
|
1986
|
-
}
|
|
1987
|
-
|
|
1988
|
-
deserializeState(state) {
|
|
1989
|
-
if (!state) return;
|
|
1990
|
-
}
|
|
1991
|
-
}
|
|
1992
|
-
|
|
1993
|
-
// Dashboard ---
|
|
1994
|
-
export function Dashboard(this: any, marshaller, dashboard, proxyMappings, timeout?) {
|
|
1995
|
-
this.marshaller = marshaller;
|
|
1996
|
-
this.id = dashboard.id;
|
|
1997
|
-
this.title = dashboard.title;
|
|
1998
|
-
|
|
1999
|
-
this._datasources = {};
|
|
2000
|
-
this._datasourceArray = [];
|
|
2001
|
-
this._datasourceTotal = 0;
|
|
2002
|
-
if (dashboard.datasources) {
|
|
2003
|
-
dashboard.datasources.forEach(item => {
|
|
2004
|
-
this.createDatasource(item, proxyMappings, timeout);
|
|
2005
|
-
});
|
|
2006
|
-
}
|
|
2007
|
-
this._datasourceTotal = this._datasourceArray.length;
|
|
2008
|
-
|
|
2009
|
-
this._visualizations = {};
|
|
2010
|
-
this._visualizationArray = [];
|
|
2011
|
-
dashboard.visualizations.forEach(item => {
|
|
2012
|
-
this.createVisualization(item);
|
|
2013
|
-
});
|
|
2014
|
-
this._visualizationTotal = this._visualizationArray.length;
|
|
2015
|
-
}
|
|
2016
|
-
|
|
2017
|
-
Dashboard.prototype.createDatasource = function (ddlDatasouce) {
|
|
2018
|
-
let retVal = this._datasources[ddlDatasouce.id];
|
|
2019
|
-
if (!retVal) {
|
|
2020
|
-
retVal = this.marshaller.createDatasource(ddlDatasouce);
|
|
2021
|
-
this._datasources[ddlDatasouce.id] = retVal;
|
|
2022
|
-
this._datasourceArray.push(retVal);
|
|
2023
|
-
}
|
|
2024
|
-
this._datasourceTotal = this._datasourceArray.length;
|
|
2025
|
-
return retVal;
|
|
2026
|
-
};
|
|
2027
|
-
|
|
2028
|
-
Dashboard.prototype.createVisualization = function (ddlVisualization, parentVisualization) {
|
|
2029
|
-
const retVal = new Visualization(this, ddlVisualization, parentVisualization);
|
|
2030
|
-
this._visualizations[ddlVisualization.id] = retVal;
|
|
2031
|
-
this._visualizationArray.push(retVal);
|
|
2032
|
-
this.marshaller.appendVisualization(retVal);
|
|
2033
|
-
return retVal;
|
|
2034
|
-
};
|
|
2035
|
-
|
|
2036
|
-
Dashboard.prototype.loadedPromise = function () {
|
|
2037
|
-
return Promise.all(this._visualizationArray.map(function (visualization) { return visualization.loadedPromise(); }));
|
|
2038
|
-
};
|
|
2039
|
-
|
|
2040
|
-
Dashboard.prototype.getQualifiedID = function () {
|
|
2041
|
-
return this.id;
|
|
2042
|
-
};
|
|
2043
|
-
|
|
2044
|
-
Dashboard.prototype.getDatasources = function () {
|
|
2045
|
-
return this._datasources;
|
|
2046
|
-
};
|
|
2047
|
-
|
|
2048
|
-
Dashboard.prototype.getDatasourceArray = function () {
|
|
2049
|
-
return this._datasourceArray;
|
|
2050
|
-
};
|
|
2051
|
-
|
|
2052
|
-
Dashboard.prototype.getDatasource = function (id) {
|
|
2053
|
-
return this._datasources[id] || this.marshaller.getDatasource(id);
|
|
2054
|
-
};
|
|
2055
|
-
|
|
2056
|
-
Dashboard.prototype.getDataSourceArray = function () {
|
|
2057
|
-
return this._datasourceArray;
|
|
2058
|
-
};
|
|
2059
|
-
|
|
2060
|
-
Dashboard.prototype.getVisualization = function (id) {
|
|
2061
|
-
return this._visualizations[id] || this.marshaller.getVisualization(id);
|
|
2062
|
-
};
|
|
2063
|
-
|
|
2064
|
-
Dashboard.prototype.getVisualizations = function () {
|
|
2065
|
-
return this._visualizations;
|
|
2066
|
-
};
|
|
2067
|
-
|
|
2068
|
-
Dashboard.prototype.getVisualizationArray = function () {
|
|
2069
|
-
return this._visualizationArray;
|
|
2070
|
-
};
|
|
2071
|
-
|
|
2072
|
-
Dashboard.prototype.getVisualizationTotal = function () {
|
|
2073
|
-
return this._visualizationTotal;
|
|
2074
|
-
};
|
|
2075
|
-
|
|
2076
|
-
Dashboard.prototype.accept = function (visitor) {
|
|
2077
|
-
visitor.visit(this);
|
|
2078
|
-
for (const key in this._datasources) {
|
|
2079
|
-
this._datasources[key].accept(visitor);
|
|
2080
|
-
}
|
|
2081
|
-
this._visualizationArray.forEach(function (item) {
|
|
2082
|
-
item.accept(visitor);
|
|
2083
|
-
}, this);
|
|
2084
|
-
};
|
|
2085
|
-
|
|
2086
|
-
Dashboard.prototype.primeData = function (state) {
|
|
2087
|
-
const fetchDataOptimizer = new VisualizationRequestOptimizer(true);
|
|
2088
|
-
this.getVisualizationArray().forEach(function (visualization) {
|
|
2089
|
-
// Clear all charts back to their default values ---
|
|
2090
|
-
visualization.clear();
|
|
2091
|
-
visualization.update();
|
|
2092
|
-
if (state && state[visualization.id]) {
|
|
2093
|
-
if (Utility.exists("source.mappings.mappings", visualization)) {
|
|
2094
|
-
for (const key in visualization.source.mappings.mappings) {
|
|
2095
|
-
if (state[visualization.id][visualization.source.mappings.mappings[key]]) {
|
|
2096
|
-
visualization._widgetState.row[key] = state[visualization.id][visualization.source.mappings.mappings[key]];
|
|
2097
|
-
visualization._widgetState.selected = true;
|
|
2098
|
-
}
|
|
2099
|
-
}
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
});
|
|
2103
|
-
this.getVisualizationArray().forEach(function (visualization) {
|
|
2104
|
-
const inputVisualizations = visualization.getInputVisualizations();
|
|
2105
|
-
const datasource = visualization.source.getDatasource();
|
|
2106
|
-
let hasInputSelection = false;
|
|
2107
|
-
inputVisualizations.forEach(function (inViz) {
|
|
2108
|
-
if (inViz.hasSelection()) {
|
|
2109
|
-
const request = inViz.calcRequestFor(visualization);
|
|
2110
|
-
request.refresh = true;
|
|
2111
|
-
fetchDataOptimizer.appendRequest(datasource, request, visualization);
|
|
2112
|
-
hasInputSelection = true;
|
|
2113
|
-
}
|
|
2114
|
-
});
|
|
2115
|
-
if (!hasInputSelection && ((datasource && datasource.isRoxie()) || inputVisualizations.length === 0)) {
|
|
2116
|
-
fetchDataOptimizer.appendRequest(datasource, { refresh: true }, visualization);
|
|
2117
|
-
}
|
|
2118
|
-
});
|
|
2119
|
-
return fetchDataOptimizer.fetchData();
|
|
2120
|
-
};
|
|
2121
|
-
|
|
2122
|
-
Dashboard.prototype.serializeState = function () {
|
|
2123
|
-
const retVal = {
|
|
2124
|
-
datasources: {},
|
|
2125
|
-
visualizations: {}
|
|
2126
|
-
};
|
|
2127
|
-
for (const key in this._datasources) {
|
|
2128
|
-
retVal.datasources[key] = this._datasources[key].serializeState();
|
|
2129
|
-
}
|
|
2130
|
-
for (const vizKey in this._visualizations) {
|
|
2131
|
-
retVal.visualizations[vizKey] = this._visualizations[vizKey].serializeState();
|
|
2132
|
-
}
|
|
2133
|
-
return retVal;
|
|
2134
|
-
};
|
|
2135
|
-
|
|
2136
|
-
Dashboard.prototype.deserializeState = function (state) {
|
|
2137
|
-
if (!state) return;
|
|
2138
|
-
for (const key in this._datasources) {
|
|
2139
|
-
if (state.datasources[key]) {
|
|
2140
|
-
this._datasources[key].deserializeState(state.datasources[key]);
|
|
2141
|
-
}
|
|
2142
|
-
}
|
|
2143
|
-
for (const vizKey in this._visualizations) {
|
|
2144
|
-
if (state.visualizations[vizKey]) {
|
|
2145
|
-
this._visualizations[vizKey].deserializeState(state.visualizations[vizKey]);
|
|
2146
|
-
}
|
|
2147
|
-
}
|
|
2148
|
-
};
|
|
2149
|
-
|
|
2150
|
-
// Marshaller ---
|
|
2151
|
-
export function Marshaller(this: any) {
|
|
2152
|
-
Class.call(this);
|
|
2153
|
-
|
|
2154
|
-
this._proxyMappings = {};
|
|
2155
|
-
this._widgetMappings = d3Map();
|
|
2156
|
-
this._clearDataOnUpdate = true;
|
|
2157
|
-
this._propogateClear = false;
|
|
2158
|
-
this.id = "Marshaller";
|
|
2159
|
-
this._missingDataString = "";
|
|
2160
|
-
this.dashboards = {};
|
|
2161
|
-
this.dashboardArray = [];
|
|
2162
|
-
|
|
2163
|
-
this._datasources = {};
|
|
2164
|
-
this._datasourceArray = [];
|
|
2165
|
-
this._visualizations = {};
|
|
2166
|
-
this._visualizationArray = [];
|
|
2167
|
-
}
|
|
2168
|
-
Marshaller.prototype = Object.create(Class.prototype);
|
|
2169
|
-
Marshaller.prototype.constructor = Marshaller;
|
|
2170
|
-
|
|
2171
|
-
Marshaller.prototype.commsDataLoaded = function () {
|
|
2172
|
-
for (let i = 0; i < this.dashboardArray.length; i++) {
|
|
2173
|
-
for (const ds in this.dashboardArray[i].getDatasources()) {
|
|
2174
|
-
if (!this.dashboardArray[i].getDatasource(ds).isLoaded()) {
|
|
2175
|
-
return false;
|
|
2176
|
-
}
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
return true;
|
|
2180
|
-
};
|
|
2181
|
-
|
|
2182
|
-
Marshaller.prototype.accept = function (visitor) {
|
|
2183
|
-
visitor.visit(this);
|
|
2184
|
-
for (const key2 in this._datasources) {
|
|
2185
|
-
this._datasources[key2].accept(visitor);
|
|
2186
|
-
}
|
|
2187
|
-
this.dashboardTotal = 0;
|
|
2188
|
-
for (const key in this.dashboards) {
|
|
2189
|
-
this.dashboards[key].accept(visitor);
|
|
2190
|
-
++this.dashboardTotal;
|
|
2191
|
-
}
|
|
2192
|
-
};
|
|
2193
|
-
|
|
2194
|
-
Marshaller.prototype.url = function (url, callback) {
|
|
2195
|
-
this.espUrl = new Comms.ESPUrl()
|
|
2196
|
-
.url(url)
|
|
2197
|
-
;
|
|
2198
|
-
let transport = null;
|
|
2199
|
-
let hipieResultName = "HIPIE_DDL";
|
|
2200
|
-
if (this.espUrl.isWorkunitResult()) {
|
|
2201
|
-
hipieResultName = this.espUrl.param("ResultName");
|
|
2202
|
-
transport = new Comms.HIPIEWorkunit()
|
|
2203
|
-
.url(url)
|
|
2204
|
-
.proxyMappings(this._proxyMappings)
|
|
2205
|
-
.timeout(this._timeout)
|
|
2206
|
-
;
|
|
2207
|
-
} else {
|
|
2208
|
-
transport = new Comms.HIPIERoxie()
|
|
2209
|
-
.url(url)
|
|
2210
|
-
.proxyMappings(this._proxyMappings)
|
|
2211
|
-
.timeout(this._timeout)
|
|
2212
|
-
;
|
|
2213
|
-
}
|
|
2214
|
-
|
|
2215
|
-
const context = this;
|
|
2216
|
-
transport.fetchResults().then(function (response) {
|
|
2217
|
-
if (Utility.exists(hipieResultName, response)) {
|
|
2218
|
-
return transport.fetchResult(hipieResultName).then(function (ddlResponse) {
|
|
2219
|
-
const json = ddlResponse[0][hipieResultName];
|
|
2220
|
-
context.parse(json, function () {
|
|
2221
|
-
callback(response);
|
|
2222
|
-
});
|
|
2223
|
-
}).catch(function (e) {
|
|
2224
|
-
context.commsEvent(context, "error", hipieResultName, e);
|
|
2225
|
-
});
|
|
2226
|
-
}
|
|
2227
|
-
}).catch(function (e) {
|
|
2228
|
-
context.commsEvent(context, "error", "fetchResults", e);
|
|
2229
|
-
});
|
|
2230
|
-
};
|
|
2231
|
-
|
|
2232
|
-
Marshaller.prototype.proxyMappings = function (_) {
|
|
2233
|
-
if (!arguments.length) return this._proxyMappings;
|
|
2234
|
-
this._proxyMappings = _;
|
|
2235
|
-
return this;
|
|
2236
|
-
};
|
|
2237
|
-
|
|
2238
|
-
Marshaller.prototype.timeout = function (_) {
|
|
2239
|
-
if (!arguments.length) return this._timeout;
|
|
2240
|
-
this._timeout = _;
|
|
2241
|
-
return this;
|
|
2242
|
-
};
|
|
2243
|
-
|
|
2244
|
-
Marshaller.prototype.widgetMappings = function (_) {
|
|
2245
|
-
if (!arguments.length) return this._widgetMappings;
|
|
2246
|
-
this._widgetMappings = _;
|
|
2247
|
-
return this;
|
|
2248
|
-
};
|
|
2249
|
-
|
|
2250
|
-
Marshaller.prototype.clearDataOnUpdate = function (_) {
|
|
2251
|
-
if (!arguments.length) return this._clearDataOnUpdate;
|
|
2252
|
-
this._clearDataOnUpdate = _;
|
|
2253
|
-
return this;
|
|
2254
|
-
};
|
|
2255
|
-
|
|
2256
|
-
Marshaller.prototype.propogateClear = function (_) {
|
|
2257
|
-
if (!arguments.length) return this._propogateClear;
|
|
2258
|
-
this._propogateClear = _;
|
|
2259
|
-
return this;
|
|
2260
|
-
};
|
|
2261
|
-
|
|
2262
|
-
Marshaller.prototype.missingDataString = function (_) {
|
|
2263
|
-
if (!arguments.length) return this._missingDataString;
|
|
2264
|
-
this._missingDataString = _;
|
|
2265
|
-
return this;
|
|
2266
|
-
};
|
|
2267
|
-
|
|
2268
|
-
Marshaller.prototype.parse = function (json, callback) {
|
|
2269
|
-
const context = this;
|
|
2270
|
-
this._json = json;
|
|
2271
|
-
this._jsonParsed = JSON.parse(this._json);
|
|
2272
|
-
|
|
2273
|
-
// Global Datasources ---
|
|
2274
|
-
this._datasources = {};
|
|
2275
|
-
this._datasourceArray = [];
|
|
2276
|
-
if (this._jsonParsed.datasources) {
|
|
2277
|
-
this._jsonParsed.datasources.forEach(function (item) {
|
|
2278
|
-
context.createDatasource(item);
|
|
2279
|
-
});
|
|
2280
|
-
}
|
|
2281
|
-
|
|
2282
|
-
this.dashboards = {};
|
|
2283
|
-
this.dashboardArray = [];
|
|
2284
|
-
this._visualizations = {};
|
|
2285
|
-
this._visualizationArray = [];
|
|
2286
|
-
const dashboards = this._jsonParsed.dashboards || this._jsonParsed;
|
|
2287
|
-
dashboards.forEach(function (item) {
|
|
2288
|
-
const newDashboard = new Dashboard(context, item, context._proxyMappings, context._timeout);
|
|
2289
|
-
context.dashboards[item.id] = newDashboard;
|
|
2290
|
-
context.dashboardArray.push(newDashboard);
|
|
2291
|
-
});
|
|
2292
|
-
this.dashboardTotal = this.dashboardArray.length;
|
|
2293
|
-
this._visualizationArray.forEach(function (ddlViz) {
|
|
2294
|
-
ddlViz.on("processEvent", function (eventID, event, row, col, selected) {
|
|
2295
|
-
context.vizEvent(ddlViz.widget, eventID, row, col, selected);
|
|
2296
|
-
});
|
|
2297
|
-
});
|
|
2298
|
-
this._datasourceTotal = this._datasourceArray.length;
|
|
2299
|
-
|
|
2300
|
-
this.ready(callback);
|
|
2301
|
-
return this;
|
|
2302
|
-
};
|
|
2303
|
-
|
|
2304
|
-
Marshaller.prototype.dashboardsLoaded = function () {
|
|
2305
|
-
return Promise.all(this.dashboardArray.map(function (dashboard) { return dashboard.loadedPromise(); }));
|
|
2306
|
-
};
|
|
2307
|
-
|
|
2308
|
-
Marshaller.prototype.createDatasource = function (ddlDatasouce: DDL1.IAnyDatasource) {
|
|
2309
|
-
let retVal = this._datasources[ddlDatasouce.id];
|
|
2310
|
-
if (!retVal) {
|
|
2311
|
-
retVal = new Datasource(this, ddlDatasouce, this._proxyMappings, this._timeout);
|
|
2312
|
-
this._datasources[ddlDatasouce.id] = retVal;
|
|
2313
|
-
this._datasourceArray.push(retVal);
|
|
2314
|
-
}
|
|
2315
|
-
this._datasourceTotal = this._datasourceArray.length;
|
|
2316
|
-
return retVal;
|
|
2317
|
-
};
|
|
2318
|
-
|
|
2319
|
-
Marshaller.prototype.getDatasource = function (id) {
|
|
2320
|
-
return this._datasources[id];
|
|
2321
|
-
};
|
|
2322
|
-
|
|
2323
|
-
Marshaller.prototype.getDatasources = function () {
|
|
2324
|
-
return this._datasources;
|
|
2325
|
-
};
|
|
2326
|
-
|
|
2327
|
-
Marshaller.prototype.getDatasourceArray = function () {
|
|
2328
|
-
return this._datasourceArray;
|
|
2329
|
-
};
|
|
2330
|
-
|
|
2331
|
-
Marshaller.prototype.appendVisualization = function (visualization) {
|
|
2332
|
-
this._visualizations[visualization.id] = visualization;
|
|
2333
|
-
this._visualizationArray.push(visualization);
|
|
2334
|
-
};
|
|
2335
|
-
|
|
2336
|
-
Marshaller.prototype.getVisualization = function (id) {
|
|
2337
|
-
return this._visualizations[id];
|
|
2338
|
-
};
|
|
2339
|
-
|
|
2340
|
-
Marshaller.prototype.appendDataSource = function (datasource) {
|
|
2341
|
-
this._datasources[datasource.id] = datasource;
|
|
2342
|
-
this._datasourceArray.push(datasource);
|
|
2343
|
-
};
|
|
2344
|
-
|
|
2345
|
-
Marshaller.prototype.getVisualizations = function () {
|
|
2346
|
-
return this._visualizations;
|
|
2347
|
-
};
|
|
2348
|
-
|
|
2349
|
-
Marshaller.prototype.getVisualizationArray = function () {
|
|
2350
|
-
return this._visualizationArray;
|
|
2351
|
-
};
|
|
2352
|
-
|
|
2353
|
-
Marshaller.prototype.getWidget = function (id) {
|
|
2354
|
-
return this._widgetMappings.get(id);
|
|
2355
|
-
};
|
|
2356
|
-
|
|
2357
|
-
Marshaller.prototype.on = function (eventID, func) {
|
|
2358
|
-
const context = this;
|
|
2359
|
-
this.overrideMethod(eventID, function (origFunc, args) {
|
|
2360
|
-
const retVal = origFunc.apply(context, args);
|
|
2361
|
-
return func.apply(context, args) || retVal;
|
|
2362
|
-
});
|
|
2363
|
-
return this;
|
|
2364
|
-
};
|
|
2365
|
-
|
|
2366
|
-
Marshaller.prototype.ready = function (callback) {
|
|
2367
|
-
if (!callback) {
|
|
2368
|
-
return;
|
|
2369
|
-
}
|
|
2370
|
-
this.dashboardsLoaded().then(function () {
|
|
2371
|
-
callback();
|
|
2372
|
-
});
|
|
2373
|
-
};
|
|
2374
|
-
|
|
2375
|
-
Marshaller.prototype.vizEvent = function (sourceWidget, eventID, row, col, selected) {
|
|
2376
|
-
console.warn("Marshaller.vizEvent: " + sourceWidget.id() + "-" + eventID);
|
|
2377
|
-
};
|
|
2378
|
-
|
|
2379
|
-
Marshaller.prototype.commsEvent = function (ddlSource, eventID, request, response) {
|
|
2380
|
-
switch (eventID) {
|
|
2381
|
-
case "request":
|
|
2382
|
-
if ((window as any).__hpcc_debug) {
|
|
2383
|
-
console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(request));
|
|
2384
|
-
}
|
|
2385
|
-
break;
|
|
2386
|
-
case "response":
|
|
2387
|
-
case "error":
|
|
2388
|
-
if ((window as any).__hpcc_debug) {
|
|
2389
|
-
console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(response));
|
|
2390
|
-
}
|
|
2391
|
-
break;
|
|
2392
|
-
default:
|
|
2393
|
-
if ((window as any).__hpcc_debug) {
|
|
2394
|
-
console.warn("Marshaller.commsEvent: " + JSON.stringify(arguments));
|
|
2395
|
-
}
|
|
2396
|
-
break;
|
|
2397
|
-
|
|
2398
|
-
}
|
|
2399
|
-
};
|
|
2400
|
-
|
|
2401
|
-
Marshaller.prototype.createDatabomb = function () {
|
|
2402
|
-
const retVal = {};
|
|
2403
|
-
this.dashboardArray.forEach(function (dashboard) {
|
|
2404
|
-
for (const key in dashboard.getDatasources()) {
|
|
2405
|
-
const comms = dashboard.getDatasource(key).comms;
|
|
2406
|
-
retVal[key] = {};
|
|
2407
|
-
for (const key2 in comms._hipieResults) {
|
|
2408
|
-
const hipieResult = comms._hipieResults[key2];
|
|
2409
|
-
retVal[key][key2] = comms._resultNameCache[hipieResult.from];
|
|
2410
|
-
}
|
|
2411
|
-
}
|
|
2412
|
-
});
|
|
2413
|
-
return retVal;
|
|
2414
|
-
};
|
|
2415
|
-
|
|
2416
|
-
Marshaller.prototype.primeData = function (state) {
|
|
2417
|
-
const promises = this.dashboardArray.map(function (dashboard) {
|
|
2418
|
-
return dashboard.primeData(state);
|
|
2419
|
-
});
|
|
2420
|
-
return Promise.all(promises);
|
|
2421
|
-
};
|
|
2422
|
-
|
|
2423
|
-
Marshaller.prototype.serializeState = function () {
|
|
2424
|
-
const retVal = {};
|
|
2425
|
-
this.dashboardArray.forEach(function (dashboard, idx) {
|
|
2426
|
-
retVal[dashboard.id] = dashboard.serializeState();
|
|
2427
|
-
});
|
|
2428
|
-
return retVal;
|
|
2429
|
-
};
|
|
2430
|
-
|
|
2431
|
-
Marshaller.prototype.deserializeState = function (state) {
|
|
2432
|
-
if (!state) return;
|
|
2433
|
-
this.dashboardArray.forEach(function (dashboard, idx) {
|
|
2434
|
-
dashboard.deserializeState(state[dashboard.id]);
|
|
2435
|
-
});
|
|
2436
|
-
return this;
|
|
2437
|
-
};
|
|
1
|
+
import { Class, Database, Utility, Widget } from "@hpcc-js/common";
|
|
2
|
+
import { MultiChart } from "@hpcc-js/composite";
|
|
3
|
+
import { DDL1 } from "@hpcc-js/ddl-shim";
|
|
4
|
+
import { Comms, Table } from "@hpcc-js/other";
|
|
5
|
+
import { map as d3Map } from "d3-collection";
|
|
6
|
+
|
|
7
|
+
declare const require: any;
|
|
8
|
+
|
|
9
|
+
const LOADING = "...loading...";
|
|
10
|
+
const _CHANGED = "_changed";
|
|
11
|
+
|
|
12
|
+
function faCharFix(faChar) {
|
|
13
|
+
if (faChar) {
|
|
14
|
+
return String.fromCharCode(parseInt(faChar));
|
|
15
|
+
}
|
|
16
|
+
return faChar;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function hipieType2DBType(hipieType) {
|
|
20
|
+
switch (hipieType) {
|
|
21
|
+
case "bool":
|
|
22
|
+
case "boolean":
|
|
23
|
+
return "boolean";
|
|
24
|
+
case "integer":
|
|
25
|
+
case "float":
|
|
26
|
+
case "double":
|
|
27
|
+
return "number";
|
|
28
|
+
case "date":
|
|
29
|
+
case "time":
|
|
30
|
+
return "time";
|
|
31
|
+
case "geohash":
|
|
32
|
+
return "geohash";
|
|
33
|
+
case "dataset":
|
|
34
|
+
return "dataset";
|
|
35
|
+
case "visualization":
|
|
36
|
+
return "widget";
|
|
37
|
+
default:
|
|
38
|
+
if (hipieType) {
|
|
39
|
+
if (hipieType.indexOf("unsigned") === 0) {
|
|
40
|
+
return "number";
|
|
41
|
+
} else if (hipieType.indexOf("integer") === 0) {
|
|
42
|
+
return "number";
|
|
43
|
+
} else if (hipieType.indexOf("real") === 0) {
|
|
44
|
+
return "number";
|
|
45
|
+
} else if (hipieType.indexOf("string") === 0) {
|
|
46
|
+
return "string";
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if ((window as any).__hpcc_debug) {
|
|
51
|
+
console.warn("unknown hipieType: " + hipieType);
|
|
52
|
+
}
|
|
53
|
+
return "string";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Mappings ---
|
|
57
|
+
function SourceMappings(this: any, visualization, mappings) {
|
|
58
|
+
this.visualization = visualization;
|
|
59
|
+
const newMappings = {};
|
|
60
|
+
for (const key in mappings) {
|
|
61
|
+
if (mappings[key] instanceof Array) {
|
|
62
|
+
mappings[key].forEach(function (mapingItem, idx) {
|
|
63
|
+
newMappings[idx === 0 ? key : key + "_" + idx] = mapingItem;
|
|
64
|
+
});
|
|
65
|
+
} else {
|
|
66
|
+
newMappings[key] = mappings[key];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
this.mappings = newMappings;
|
|
70
|
+
this.hasMappings = false;
|
|
71
|
+
this.reverseMappings = {};
|
|
72
|
+
this.columns = [];
|
|
73
|
+
this.columnsIdx = {};
|
|
74
|
+
this.columnsRHS = [];
|
|
75
|
+
this.columnsRHSIdx = {};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
SourceMappings.prototype.init = function () {
|
|
79
|
+
for (const key in this.mappings) {
|
|
80
|
+
this.reverseMappings[this.mappings[key]] = key;
|
|
81
|
+
if (this.columnsIdx[key] === undefined) {
|
|
82
|
+
this.columns.push(key);
|
|
83
|
+
this.columnsIdx[key] = this.columns.length - 1;
|
|
84
|
+
}
|
|
85
|
+
this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
|
|
86
|
+
this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
|
|
87
|
+
this.hasMappings = true;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
SourceMappings.prototype.init = function () {
|
|
92
|
+
for (const key in this.mappings) {
|
|
93
|
+
this.reverseMappings[this.mappings[key]] = key;
|
|
94
|
+
if (this.columnsIdx[key] === undefined) {
|
|
95
|
+
this.columns.push(key);
|
|
96
|
+
this.columnsIdx[key] = this.columns.length - 1;
|
|
97
|
+
}
|
|
98
|
+
this.columnsRHS[this.columnsIdx[key]] = this.mappings[key];
|
|
99
|
+
this.columnsRHSIdx[this.mappings[key]] = this.columnsIdx[key];
|
|
100
|
+
this.hasMappings = true;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
SourceMappings.prototype.getFields = function () {
|
|
105
|
+
if (this.visualization.fields()) {
|
|
106
|
+
return Object.keys(this.mappings).map(key => {
|
|
107
|
+
const field = this.visualization.field(key);
|
|
108
|
+
if (!field) {
|
|
109
|
+
console.warn("Unknown mapping field: " + key);
|
|
110
|
+
}
|
|
111
|
+
return new Database.Field(field.id())
|
|
112
|
+
.type(field.jsType())
|
|
113
|
+
.label(this.reverseMappings[field.id()])
|
|
114
|
+
;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return null;
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
SourceMappings.prototype.contains = function (key) {
|
|
121
|
+
return this.mappings[key] !== undefined;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
SourceMappings.prototype.doMap = function (item) {
|
|
125
|
+
const retVal = [];
|
|
126
|
+
for (const key in this.mappings) {
|
|
127
|
+
const rhsKey = this.mappings[key];
|
|
128
|
+
try {
|
|
129
|
+
let val = item[rhsKey];
|
|
130
|
+
if (val === undefined) {
|
|
131
|
+
val = item[rhsKey.toLowerCase()];
|
|
132
|
+
}
|
|
133
|
+
retVal[this.columnsIdx[key]] = val;
|
|
134
|
+
} catch (e) {
|
|
135
|
+
console.warn("Invalid Mapping: " + this.visualization.id + " [" + rhsKey + "->" + item + "]");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return retVal;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
SourceMappings.prototype.doReverseMap = function (item) {
|
|
142
|
+
const retVal = {};
|
|
143
|
+
for (const key in this.mappings) {
|
|
144
|
+
const rhsKey = this.mappings[key];
|
|
145
|
+
try {
|
|
146
|
+
let val = item[key];
|
|
147
|
+
if (val === undefined) {
|
|
148
|
+
val = item[key.toLowerCase()];
|
|
149
|
+
}
|
|
150
|
+
retVal[rhsKey] = val;
|
|
151
|
+
} catch (e) {
|
|
152
|
+
console.warn("Invalid Mapping: " + this.visualization.id + " [" + key + "->" + item + "]");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return retVal;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
SourceMappings.prototype.doMapAll = function (data) {
|
|
159
|
+
return data.hipieMappings(this.columnsRHS.map(col => {
|
|
160
|
+
return this.visualization.field(col);
|
|
161
|
+
}), this.visualization.dashboard.marshaller.missingDataString());
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
SourceMappings.prototype.getMap = function (key) {
|
|
165
|
+
return this.mappings[key];
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
SourceMappings.prototype.getReverseMap = function (key) {
|
|
169
|
+
return this.reverseMappings[key];
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
SourceMappings.prototype.hipieMapSortArray = function (sort) {
|
|
173
|
+
return sort.map(sortField => {
|
|
174
|
+
let reverse = false;
|
|
175
|
+
if (sortField.indexOf("-") === 0) {
|
|
176
|
+
sortField = sortField.substring(1);
|
|
177
|
+
reverse = true;
|
|
178
|
+
}
|
|
179
|
+
const fieldIdx = this.columnsRHS.indexOf(sortField);
|
|
180
|
+
if (fieldIdx < 0) {
|
|
181
|
+
console.warn("SourceMappings.prototype.hipieMapSortArray: Invalid sort array - " + sortField);
|
|
182
|
+
}
|
|
183
|
+
return {
|
|
184
|
+
idx: fieldIdx,
|
|
185
|
+
reverse
|
|
186
|
+
};
|
|
187
|
+
}).filter(function (d) { return d.idx >= 0; });
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
function ChartMappings(this: any, visualization, mappings) {
|
|
191
|
+
SourceMappings.call(this, visualization, mappings);
|
|
192
|
+
this.columns = ["label", "weight"];
|
|
193
|
+
this.columnsIdx = { label: 0, weight: 1 };
|
|
194
|
+
this.init();
|
|
195
|
+
}
|
|
196
|
+
ChartMappings.prototype = Object.create(SourceMappings.prototype);
|
|
197
|
+
|
|
198
|
+
function ChoroMappings(this: any, visualization, mappings) {
|
|
199
|
+
SourceMappings.call(this, visualization, mappings);
|
|
200
|
+
if (mappings.state) {
|
|
201
|
+
this.columns = ["state", "weight"];
|
|
202
|
+
this.columnsIdx = { state: 0, weight: 1 };
|
|
203
|
+
} else if (mappings.county) {
|
|
204
|
+
this.columns = ["county", "weight"];
|
|
205
|
+
this.columnsIdx = { county: 0, weight: 1 };
|
|
206
|
+
} else if (mappings.geohash) {
|
|
207
|
+
this.columns = ["geohash", "weight"];
|
|
208
|
+
this.columnsIdx = { geohash: 0, weight: 1 };
|
|
209
|
+
}
|
|
210
|
+
this.init();
|
|
211
|
+
}
|
|
212
|
+
ChoroMappings.prototype = Object.create(SourceMappings.prototype);
|
|
213
|
+
|
|
214
|
+
function ChoroMappings2(this: any, visualization, mappings) {
|
|
215
|
+
SourceMappings.call(this, visualization, mappings);
|
|
216
|
+
if (mappings.state) {
|
|
217
|
+
this.columns = ["state"];
|
|
218
|
+
this.columnsIdx = { state: 0 };
|
|
219
|
+
} else if (mappings.county) {
|
|
220
|
+
this.columns = ["county"];
|
|
221
|
+
this.columnsIdx = { county: 0 };
|
|
222
|
+
} else if (mappings.geohash) {
|
|
223
|
+
this.columns = ["geohash", "label"];
|
|
224
|
+
this.columnsIdx = { geohash: 0, label: 1 };
|
|
225
|
+
}
|
|
226
|
+
const weightOffset = this.columns.length;
|
|
227
|
+
if (mappings.weight instanceof Array) {
|
|
228
|
+
mappings.weight.forEach((w, i) => {
|
|
229
|
+
this.columns.push(w);
|
|
230
|
+
this.columnsIdx[i === 0 ? "weight" : "weight_" + i] = i + weightOffset;
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
this.init();
|
|
234
|
+
}
|
|
235
|
+
ChoroMappings2.prototype = Object.create(SourceMappings.prototype);
|
|
236
|
+
|
|
237
|
+
function HeatMapMappings(this: any, visualization, mappings) {
|
|
238
|
+
SourceMappings.call(this, visualization, mappings);
|
|
239
|
+
this.columns = ["x", "y", "weight"];
|
|
240
|
+
this.columnsIdx = { x: 0, y: 1, weight: 2 };
|
|
241
|
+
this.init();
|
|
242
|
+
}
|
|
243
|
+
HeatMapMappings.prototype = Object.create(SourceMappings.prototype);
|
|
244
|
+
|
|
245
|
+
function LineMappings(this: any, visualization, mappings) {
|
|
246
|
+
const newMappings = {
|
|
247
|
+
label: mappings.x[0]
|
|
248
|
+
};
|
|
249
|
+
mappings.y.forEach(function (item, idx) {
|
|
250
|
+
newMappings[item] = item;
|
|
251
|
+
});
|
|
252
|
+
SourceMappings.call(this, visualization, newMappings);
|
|
253
|
+
this.init();
|
|
254
|
+
}
|
|
255
|
+
LineMappings.prototype = Object.create(SourceMappings.prototype);
|
|
256
|
+
|
|
257
|
+
function TableMappings(this: any, visualization, mappings) {
|
|
258
|
+
const newMappings = {};
|
|
259
|
+
for (const key in mappings) {
|
|
260
|
+
mappings[key].forEach(function (mapingItem, idx) {
|
|
261
|
+
newMappings[visualization.label[idx]] = mapingItem;
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
SourceMappings.call(this, visualization, newMappings);
|
|
265
|
+
this.init();
|
|
266
|
+
}
|
|
267
|
+
TableMappings.prototype = Object.create(SourceMappings.prototype);
|
|
268
|
+
|
|
269
|
+
TableMappings.prototype.init = function () {
|
|
270
|
+
this.visualization.label.forEach((label, idx) => {
|
|
271
|
+
this.reverseMappings[this.mappings[label]] = label;
|
|
272
|
+
this.columns.push(label);
|
|
273
|
+
this.columnsIdx[label] = idx;
|
|
274
|
+
this.columnsRHS[idx] = this.mappings[label];
|
|
275
|
+
this.columnsRHSIdx[this.mappings[label]] = idx;
|
|
276
|
+
this.hasMappings = true;
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
TableMappings.prototype.doMapAll = function (data) {
|
|
281
|
+
let retVal = SourceMappings.prototype.doMapAll.apply(this, arguments);
|
|
282
|
+
if (retVal instanceof Array) {
|
|
283
|
+
const columnsRHSIdx = this.visualization.source.getColumnsRHSIdx();
|
|
284
|
+
this.visualization.fields().forEach(field => {
|
|
285
|
+
const fieldType = field.jsType();
|
|
286
|
+
const colIdx = columnsRHSIdx[field.id()];
|
|
287
|
+
if (colIdx === undefined) {
|
|
288
|
+
console.warn("Invalid Mapping: " + field.id());
|
|
289
|
+
} else {
|
|
290
|
+
retVal = retVal.map((row) => {
|
|
291
|
+
let cell = row[colIdx];
|
|
292
|
+
if (cell && cell.Row) {
|
|
293
|
+
cell = cell.Row;
|
|
294
|
+
}
|
|
295
|
+
if (cell instanceof Array) {
|
|
296
|
+
switch (fieldType) {
|
|
297
|
+
case "dataset":
|
|
298
|
+
const columns = [];
|
|
299
|
+
const columnsIdx = {};
|
|
300
|
+
const data2 = cell.map(function (row2, idx) {
|
|
301
|
+
const retVal2 = [];
|
|
302
|
+
retVal2.length = columns.length;
|
|
303
|
+
for (const key in row2) {
|
|
304
|
+
if (idx === 0) {
|
|
305
|
+
columnsIdx[key] = columns.length;
|
|
306
|
+
columns.push(key);
|
|
307
|
+
}
|
|
308
|
+
retVal2[columnsIdx[key]] = row2[key];
|
|
309
|
+
}
|
|
310
|
+
return retVal2;
|
|
311
|
+
});
|
|
312
|
+
const table = new Table()
|
|
313
|
+
.columns(columns)
|
|
314
|
+
.data(data2)
|
|
315
|
+
;
|
|
316
|
+
row[colIdx] = table;
|
|
317
|
+
break;
|
|
318
|
+
case "widget":
|
|
319
|
+
const viz = this.visualization.vizDeclarations[field.localVisualizationID()];
|
|
320
|
+
const output = viz.source.getOutput();
|
|
321
|
+
const db = output.db;
|
|
322
|
+
output.setData(cell, []);
|
|
323
|
+
const widget = viz.widget;
|
|
324
|
+
const newWidget = new widget.constructor()
|
|
325
|
+
.showToolbar(false)
|
|
326
|
+
.chartType(widget.chartType())
|
|
327
|
+
.chartTypeDefaults(widget.chartTypeDefaults())
|
|
328
|
+
.columns(viz.source.getColumns())
|
|
329
|
+
.data(viz.source.getData())
|
|
330
|
+
;
|
|
331
|
+
output.db = db;
|
|
332
|
+
row[colIdx] = newWidget;
|
|
333
|
+
break;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return row;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return retVal;
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
function GraphMappings(this: any, visualization, mappings, link) {
|
|
345
|
+
SourceMappings.call(this, visualization, mappings);
|
|
346
|
+
this.icon = visualization.icon || {};
|
|
347
|
+
this.fields = visualization.fields();
|
|
348
|
+
this.columns = ["uid", "label", "weight", "flags"];
|
|
349
|
+
this.columnsIdx = { uid: 0, label: 1, weight: 2, flags: 3 };
|
|
350
|
+
this.init();
|
|
351
|
+
this.link = link;
|
|
352
|
+
this.linkMappings = new SourceMappings(visualization, this.link.mappings);
|
|
353
|
+
this.linkMappings.columns = ["uid"];
|
|
354
|
+
this.linkMappings.columnsIdx = { uid: 0, label: 1 };
|
|
355
|
+
this.visualization = visualization;
|
|
356
|
+
}
|
|
357
|
+
GraphMappings.prototype = Object.create(SourceMappings.prototype);
|
|
358
|
+
|
|
359
|
+
GraphMappings.prototype.calcIconInfo = function (flag, origItem, forAnnotation) {
|
|
360
|
+
const retVal = {};
|
|
361
|
+
function mapStruct(struct, retVal2) {
|
|
362
|
+
if (struct) {
|
|
363
|
+
for (const key in struct) {
|
|
364
|
+
switch (key) {
|
|
365
|
+
case "faChar":
|
|
366
|
+
retVal2.faChar = faCharFix(struct.faChar);
|
|
367
|
+
break;
|
|
368
|
+
default:
|
|
369
|
+
if (forAnnotation && key.indexOf("icon_") === 0) { // Backward compatability
|
|
370
|
+
console.warn("Deprecated flag property: " + key);
|
|
371
|
+
retVal2[key.split("icon_")[1]] = struct[key];
|
|
372
|
+
} else {
|
|
373
|
+
retVal2[key] = struct[key];
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
if (origItem && origItem[flag.fieldid] && flag.valuemappings) {
|
|
380
|
+
const annotationInfo = flag.valuemappings[origItem[flag.fieldid]];
|
|
381
|
+
mapStruct(annotationInfo, retVal);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
for (const _key in retVal) { // jshint ignore:line
|
|
385
|
+
return retVal;
|
|
386
|
+
}
|
|
387
|
+
return null;
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
GraphMappings.prototype.doMapAll = function (db) {
|
|
391
|
+
const data = db.jsonObj();
|
|
392
|
+
const context = this;
|
|
393
|
+
const vertexMap = {};
|
|
394
|
+
const vertices = [];
|
|
395
|
+
const megaChart = this.visualization.widget;
|
|
396
|
+
const graph = megaChart.chart();
|
|
397
|
+
function getVertex(item, origItem?) {
|
|
398
|
+
const id = "uid_" + item[0];
|
|
399
|
+
let retVal = vertexMap[id];
|
|
400
|
+
if (!retVal && origItem) {
|
|
401
|
+
retVal = new graph.Vertex()
|
|
402
|
+
.faChar((context.icon && context.icon.faChar ? faCharFix(context.icon.faChar) : "\uf128"))
|
|
403
|
+
.text(item[1] ? item[1] : "")
|
|
404
|
+
.data(item)
|
|
405
|
+
;
|
|
406
|
+
retVal.__hpcc_uid = item[0];
|
|
407
|
+
vertexMap[id] = retVal;
|
|
408
|
+
vertices.push(retVal);
|
|
409
|
+
|
|
410
|
+
// Icon ---
|
|
411
|
+
const iconInfo = context.calcIconInfo(context.visualization.icon, origItem, false);
|
|
412
|
+
if (iconInfo) {
|
|
413
|
+
for (const key in iconInfo) {
|
|
414
|
+
if (retVal[key]) {
|
|
415
|
+
retVal[key](iconInfo[key]);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Annotations ---
|
|
421
|
+
const annotations = [];
|
|
422
|
+
context.visualization.flags.forEach(function (flag) {
|
|
423
|
+
const iconInfo2 = context.calcIconInfo(flag, origItem, true);
|
|
424
|
+
if (iconInfo2) {
|
|
425
|
+
annotations.push(iconInfo2);
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
retVal.annotationIcons(annotations);
|
|
429
|
+
}
|
|
430
|
+
return retVal;
|
|
431
|
+
}
|
|
432
|
+
const edges = [];
|
|
433
|
+
data.forEach(function (item) {
|
|
434
|
+
const mappedItem = context.doMap(item);
|
|
435
|
+
getVertex(mappedItem, item);
|
|
436
|
+
});
|
|
437
|
+
data.forEach(function (item) {
|
|
438
|
+
const mappedItem = context.doMap(item);
|
|
439
|
+
const vertex = getVertex(mappedItem, item);
|
|
440
|
+
if (item[context.link.childfile] && item[context.link.childfile] instanceof Array) {
|
|
441
|
+
const childItems = item[context.link.childfile];
|
|
442
|
+
childItems.forEach(function (childItem, i) {
|
|
443
|
+
const childMappedItem = context.linkMappings.doMap(childItem);
|
|
444
|
+
const childVertex = getVertex(childMappedItem);
|
|
445
|
+
if (childVertex && vertex.id() !== childVertex.id()) {
|
|
446
|
+
const edge = new graph.Edge()
|
|
447
|
+
.sourceVertex(vertex)
|
|
448
|
+
.targetVertex(childVertex)
|
|
449
|
+
.sourceMarker("circle")
|
|
450
|
+
.targetMarker("arrow")
|
|
451
|
+
.text(childMappedItem[1] ? childMappedItem[1] : "")
|
|
452
|
+
.data(childMappedItem)
|
|
453
|
+
;
|
|
454
|
+
const linkcolor = graph.linkcolor_default();
|
|
455
|
+
if (linkcolor && linkcolor.fieldid) {
|
|
456
|
+
edge.strokeColor(childItem[linkcolor.fieldid]);
|
|
457
|
+
}
|
|
458
|
+
const linktooltip = graph.linkcolor_default();
|
|
459
|
+
if (linktooltip && linktooltip.fieldid) {
|
|
460
|
+
edge.tooltip(childItem[linktooltip.fieldid]);
|
|
461
|
+
}
|
|
462
|
+
edges.push(edge);
|
|
463
|
+
}
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
return { vertices, edges, merge: false };
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
// Viz Source ---
|
|
471
|
+
function Source(this: any, visualization, source) {
|
|
472
|
+
this.visualization = visualization;
|
|
473
|
+
if (source) {
|
|
474
|
+
this._id = source.id;
|
|
475
|
+
this._output = source.output;
|
|
476
|
+
this.mappings = null;
|
|
477
|
+
if (!source.mappings) {
|
|
478
|
+
console.warn("no mappings for:" + visualization.id + "->" + source.id);
|
|
479
|
+
}
|
|
480
|
+
switch (this.visualization.type) {
|
|
481
|
+
case "LINE":
|
|
482
|
+
this.mappings = new LineMappings(this.visualization, source.mappings);
|
|
483
|
+
break;
|
|
484
|
+
case "TABLE":
|
|
485
|
+
this.mappings = new TableMappings(this.visualization, source.mappings);
|
|
486
|
+
break;
|
|
487
|
+
case "GRAPH":
|
|
488
|
+
this.mappings = new GraphMappings(this.visualization, source.mappings, source.link);
|
|
489
|
+
break;
|
|
490
|
+
case "CHORO":
|
|
491
|
+
if (source.mappings.weight instanceof Array && source.mappings.weight.length) {
|
|
492
|
+
this.mappings = new ChoroMappings2(this.visualization, source.mappings);
|
|
493
|
+
if (source.mappings.weight.length > 1) {
|
|
494
|
+
this.visualization.type = "LINE";
|
|
495
|
+
}
|
|
496
|
+
} else {
|
|
497
|
+
this.mappings = new ChoroMappings(this.visualization, source.mappings);
|
|
498
|
+
}
|
|
499
|
+
break;
|
|
500
|
+
case "HEAT_MAP":
|
|
501
|
+
this.mappings = new HeatMapMappings(this.visualization, source.mappings);
|
|
502
|
+
break;
|
|
503
|
+
default:
|
|
504
|
+
this.mappings = new ChartMappings(this.visualization, source.mappings);
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
this.first = source.first;
|
|
508
|
+
this.reverse = source.reverse;
|
|
509
|
+
this.sort = source.sort;
|
|
510
|
+
this.properties = source.properties;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
Source.prototype.getQualifiedID = function () {
|
|
515
|
+
return this.visualization.getQualifiedID() + "." + this._id;
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
Source.prototype.exists = function () {
|
|
519
|
+
return this._id;
|
|
520
|
+
};
|
|
521
|
+
|
|
522
|
+
Source.prototype.getDatasource = function () {
|
|
523
|
+
return this.visualization.dashboard.getDatasource(this._id);
|
|
524
|
+
};
|
|
525
|
+
|
|
526
|
+
Source.prototype.getOutput = function () {
|
|
527
|
+
const datasource = this.getDatasource();
|
|
528
|
+
if (datasource && datasource._outputs) {
|
|
529
|
+
return datasource._outputs[this._output];
|
|
530
|
+
}
|
|
531
|
+
return null;
|
|
532
|
+
};
|
|
533
|
+
|
|
534
|
+
Source.prototype.hasData = function () {
|
|
535
|
+
return this.getOutput().db ? true : false;
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
Source.prototype.getFields = function () {
|
|
539
|
+
return this.mappings.getFields();
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
Source.prototype.getColumnsRHS = function () {
|
|
543
|
+
return this.mappings.columnsRHS;
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
Source.prototype.getColumnsRHSIdx = function () {
|
|
547
|
+
return this.mappings.columnsRHSIdx;
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
Source.prototype.getColumns = function () {
|
|
551
|
+
return this.mappings && this.mappings.columns ? this.mappings.columns : [];
|
|
552
|
+
};
|
|
553
|
+
|
|
554
|
+
Source.prototype.getData = function () {
|
|
555
|
+
const db = this.getOutput().db;
|
|
556
|
+
const retVal = this.mappings.doMapAll(db);
|
|
557
|
+
if (retVal.length && this.sort) {
|
|
558
|
+
Utility.multiSort(retVal, this.mappings.hipieMapSortArray(this.sort));
|
|
559
|
+
}
|
|
560
|
+
if (this.reverse) {
|
|
561
|
+
retVal.reverse();
|
|
562
|
+
}
|
|
563
|
+
if (this.first && retVal.length > this.first) {
|
|
564
|
+
retVal.length = this.first;
|
|
565
|
+
}
|
|
566
|
+
return retVal;
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
Source.prototype.getXTitle = function () {
|
|
570
|
+
return this.mappings.columns[0];
|
|
571
|
+
};
|
|
572
|
+
|
|
573
|
+
Source.prototype.getYTitle = function () {
|
|
574
|
+
return this.mappings.columns.filter(function (d, i) { return i > 0; }).join(" / ");
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
Source.prototype.getMap = function (col) {
|
|
578
|
+
return (this.mappings && this.mappings.hasMappings) ? this.mappings.getMap(col) : col;
|
|
579
|
+
};
|
|
580
|
+
|
|
581
|
+
Source.prototype.getReverseMap = function (col) {
|
|
582
|
+
return (this.mappings && this.mappings.hasMappings) ? this.mappings.getReverseMap(col) : col;
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
// Viz Events ---
|
|
586
|
+
function EventUpdate(this: any, event, update, defMappings) {
|
|
587
|
+
this.event = event;
|
|
588
|
+
this.dashboard = event.visualization.dashboard;
|
|
589
|
+
this._col = update.col;
|
|
590
|
+
this._visualization = update.visualization;
|
|
591
|
+
this._instance = update.instance;
|
|
592
|
+
this._datasource = update.datasource;
|
|
593
|
+
this._merge = update.merge;
|
|
594
|
+
this._mappings = update.mappings || defMappings;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
EventUpdate.prototype.getDatasource = function () {
|
|
598
|
+
return this.dashboard.getDatasource(this._datasource);
|
|
599
|
+
};
|
|
600
|
+
|
|
601
|
+
EventUpdate.prototype.getVisualization = function () {
|
|
602
|
+
return this.dashboard.getVisualization(this._visualization);
|
|
603
|
+
};
|
|
604
|
+
|
|
605
|
+
EventUpdate.prototype.mapData = function (row) {
|
|
606
|
+
const retVal = {};
|
|
607
|
+
if (row) {
|
|
608
|
+
for (const key in this._mappings) {
|
|
609
|
+
const origKey = this.getReverseMap(key);
|
|
610
|
+
retVal[this._mappings[key]] = row[origKey];
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return retVal;
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
EventUpdate.prototype.getMap = function (col) {
|
|
617
|
+
return this.event.visualization.source.getMap(col);
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
EventUpdate.prototype.getReverseMap = function (col) {
|
|
621
|
+
return this.event.visualization.source.getReverseMap(col);
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
EventUpdate.prototype.selectedRow = function () {
|
|
625
|
+
if (this.event.visualization.hasSelection()) {
|
|
626
|
+
return this.event.visualization._widgetState.row;
|
|
627
|
+
}
|
|
628
|
+
return {};
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
EventUpdate.prototype.mapSelected = function () {
|
|
632
|
+
return this.mapData(this.selectedRow());
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
EventUpdate.prototype.calcRequestFor = function (visualization) {
|
|
636
|
+
const retVal = {};
|
|
637
|
+
const updateVisualization = this.getVisualization();
|
|
638
|
+
updateVisualization.getInputVisualizations().forEach(function (inViz, idx) {
|
|
639
|
+
// Calc request for each visualization to be updated ---
|
|
640
|
+
const changed = inViz === visualization;
|
|
641
|
+
inViz.getUpdatesForVisualization(updateVisualization).forEach(function (inVizUpdateObj) {
|
|
642
|
+
// Gather all contributing "input visualization events" for the visualization that is to be updated ---
|
|
643
|
+
const inVizRequest = inVizUpdateObj.mapSelected();
|
|
644
|
+
for (const key in inVizRequest) {
|
|
645
|
+
if (retVal[key] && retVal[key] !== inVizRequest[key]) {
|
|
646
|
+
console.warn("Duplicate Filter with mismatched value (defaulting to 'first' or 'first changed' instance): " + key);
|
|
647
|
+
if (changed) {
|
|
648
|
+
retVal[key] = inVizRequest[key];
|
|
649
|
+
retVal[key + _CHANGED] = changed;
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
retVal[key] = inVizRequest[key];
|
|
653
|
+
retVal[key + _CHANGED] = changed;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
});
|
|
658
|
+
return retVal;
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
function Event(this: any, visualization, eventID, event) {
|
|
662
|
+
this.visualization = visualization;
|
|
663
|
+
this.eventID = eventID;
|
|
664
|
+
this._updates = [];
|
|
665
|
+
this._mappings = event.mappings;
|
|
666
|
+
if (event) {
|
|
667
|
+
this._updates = event.updates.map(updateInfo => {
|
|
668
|
+
return new EventUpdate(this, updateInfo, event.mappings);
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
Event.prototype.exists = function () {
|
|
674
|
+
return this._updates.length;
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
Event.prototype.getUpdates = function () {
|
|
678
|
+
return this._updates.filter(updateInfo => {
|
|
679
|
+
if (!updateInfo._col) return true;
|
|
680
|
+
return updateInfo._col === updateInfo.getMap(this.visualization._widgetState.col);
|
|
681
|
+
});
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
Event.prototype.getUpdatesDatasources = function () {
|
|
685
|
+
const dedup = {};
|
|
686
|
+
const retVal = [];
|
|
687
|
+
this.getUpdatesVisualizations().forEach(function (item, idx) {
|
|
688
|
+
const datasource = item.source.getDatasource();
|
|
689
|
+
if (datasource && !dedup[datasource.id]) {
|
|
690
|
+
dedup[datasource.id] = true;
|
|
691
|
+
retVal.push(datasource);
|
|
692
|
+
}
|
|
693
|
+
}, this);
|
|
694
|
+
return retVal;
|
|
695
|
+
};
|
|
696
|
+
|
|
697
|
+
Event.prototype.getUpdatesVisualizations = function () {
|
|
698
|
+
const dedup = {};
|
|
699
|
+
const retVal = [];
|
|
700
|
+
this._updates.forEach(function (updateObj, idx) {
|
|
701
|
+
const visualization = updateObj.getVisualization();
|
|
702
|
+
if (!dedup[visualization.id]) {
|
|
703
|
+
dedup[visualization.id] = true;
|
|
704
|
+
retVal.push(visualization);
|
|
705
|
+
}
|
|
706
|
+
}, this);
|
|
707
|
+
return retVal;
|
|
708
|
+
};
|
|
709
|
+
|
|
710
|
+
Event.prototype.fetchData = function () {
|
|
711
|
+
const fetchDataOptimizer = new VisualizationRequestOptimizer();
|
|
712
|
+
this.getUpdates().forEach(updateObj => {
|
|
713
|
+
fetchDataOptimizer.appendRequest(updateObj.getDatasource(), updateObj.calcRequestFor(this.visualization), updateObj.getVisualization());
|
|
714
|
+
});
|
|
715
|
+
return fetchDataOptimizer.fetchData();
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
function Events(this: any, visualization, events) {
|
|
719
|
+
this.visualization = visualization;
|
|
720
|
+
this.events = {};
|
|
721
|
+
for (const key in events) {
|
|
722
|
+
this.events[key] = new Event(visualization, key, events[key]);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
Events.prototype.setWidget = function (widget) {
|
|
727
|
+
const context = this;
|
|
728
|
+
for (const key in this.events) {
|
|
729
|
+
if (widget["vertex_" + key]) {
|
|
730
|
+
widget["vertex_" + key] = function (row, col, selected) {
|
|
731
|
+
context.visualization.processEvent(key, context.events[key], row, col, selected);
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
if (widget[key]) {
|
|
735
|
+
widget[key] = function (row, col, selected) {
|
|
736
|
+
context.visualization.processEvent(key, context.events[key], row, col, selected);
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
Events.prototype.exists = function () {
|
|
743
|
+
return this._updates !== undefined;
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
Events.prototype.getUpdates = function () {
|
|
747
|
+
let retVal = [];
|
|
748
|
+
for (const key in this.events) {
|
|
749
|
+
retVal = retVal.concat(this.events[key].getUpdates());
|
|
750
|
+
}
|
|
751
|
+
return retVal;
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
Events.prototype.getUpdatesDatasources = function () {
|
|
755
|
+
let retVal = [];
|
|
756
|
+
for (const key in this.events) {
|
|
757
|
+
retVal = retVal.concat(this.events[key].getUpdatesDatasources());
|
|
758
|
+
}
|
|
759
|
+
return retVal;
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
Events.prototype.getUpdatesVisualizations = function () {
|
|
763
|
+
let retVal = [];
|
|
764
|
+
for (const key in this.events) {
|
|
765
|
+
retVal = retVal.concat(this.events[key].getUpdatesVisualizations());
|
|
766
|
+
}
|
|
767
|
+
return retVal;
|
|
768
|
+
};
|
|
769
|
+
|
|
770
|
+
// Visualization Field---
|
|
771
|
+
function Field(this: any, ddlField) {
|
|
772
|
+
this._id = ddlField.id;
|
|
773
|
+
this._label = ddlField.label;
|
|
774
|
+
this._properties = ddlField.properties || {};
|
|
775
|
+
}
|
|
776
|
+
Field.prototype = Object.create(Class.prototype);
|
|
777
|
+
Field.prototype.constructor = Field;
|
|
778
|
+
|
|
779
|
+
Field.prototype.id = function () {
|
|
780
|
+
return this._id;
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
Field.prototype.label = function () {
|
|
784
|
+
return this._properties.label || this._label;
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
Field.prototype.type = function () {
|
|
788
|
+
return this._properties.type || "";
|
|
789
|
+
};
|
|
790
|
+
|
|
791
|
+
Field.prototype.jsType = function () {
|
|
792
|
+
return hipieType2DBType(this.type());
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
Field.prototype.charttype = function (_) {
|
|
796
|
+
if (!arguments.length) return this._properties.charttype || "";
|
|
797
|
+
this._properties.charttype = _;
|
|
798
|
+
return this;
|
|
799
|
+
};
|
|
800
|
+
|
|
801
|
+
Field.prototype.localVisualizationID = function () {
|
|
802
|
+
return this._properties.localVisualizationID || "";
|
|
803
|
+
};
|
|
804
|
+
|
|
805
|
+
Field.prototype.enumvals = function () {
|
|
806
|
+
return this._properties.enumvals; // Return undefined if non existent
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
Field.prototype.hasDefault = function () {
|
|
810
|
+
return this.default() !== undefined;
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
Field.prototype.default = function () {
|
|
814
|
+
if (this.type() === "range") {
|
|
815
|
+
return this._properties.default || ["", ""];
|
|
816
|
+
}
|
|
817
|
+
if (this._properties.default instanceof Array && this._properties.default.length) {
|
|
818
|
+
return this._properties.default[0];
|
|
819
|
+
}
|
|
820
|
+
return this._properties.default || "";
|
|
821
|
+
};
|
|
822
|
+
|
|
823
|
+
Field.prototype.hasFunction = function () {
|
|
824
|
+
return this.function() !== undefined;
|
|
825
|
+
};
|
|
826
|
+
|
|
827
|
+
Field.prototype.function = function () {
|
|
828
|
+
return this._properties.function;
|
|
829
|
+
};
|
|
830
|
+
|
|
831
|
+
Field.prototype.params = function () {
|
|
832
|
+
const retVal = [];
|
|
833
|
+
const params = this._properties.params || {};
|
|
834
|
+
for (const key in params) {
|
|
835
|
+
retVal.push(params[key]);
|
|
836
|
+
}
|
|
837
|
+
return retVal;
|
|
838
|
+
};
|
|
839
|
+
|
|
840
|
+
Field.prototype.properties = function () {
|
|
841
|
+
return this._properties;
|
|
842
|
+
};
|
|
843
|
+
|
|
844
|
+
// Visualization ---
|
|
845
|
+
function requirePromise(this: any, packageID) {
|
|
846
|
+
return new Promise((resolve, reject) => {
|
|
847
|
+
if (require) {
|
|
848
|
+
require([packageID], Package => {
|
|
849
|
+
resolve.call(this, Package);
|
|
850
|
+
});
|
|
851
|
+
} else {
|
|
852
|
+
reject("No require.");
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function legacyRequire(this: any, packageArr, callback) {
|
|
858
|
+
const promises = packageArr.map(function (packageID) {
|
|
859
|
+
if (packageID.indexOf("../") === 0) {
|
|
860
|
+
const parts = packageID.split("/");
|
|
861
|
+
return requirePromise("@hpcc-js/" + parts[1]).then(function (Package) {
|
|
862
|
+
return Package[parts[2]];
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
return requirePromise(packageID);
|
|
866
|
+
});
|
|
867
|
+
Promise.all(promises).then(packages => {
|
|
868
|
+
callback.apply(this, packages);
|
|
869
|
+
});
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
export class Visualization extends Class {
|
|
873
|
+
protected dashboard;
|
|
874
|
+
parentVisualization;
|
|
875
|
+
protected type;
|
|
876
|
+
protected id;
|
|
877
|
+
protected label;
|
|
878
|
+
protected icon;
|
|
879
|
+
protected flags;
|
|
880
|
+
protected title;
|
|
881
|
+
protected _fields;
|
|
882
|
+
protected _fieldsMap;
|
|
883
|
+
properties;
|
|
884
|
+
protected source;
|
|
885
|
+
protected events;
|
|
886
|
+
protected layers;
|
|
887
|
+
protected hasVizDeclarations;
|
|
888
|
+
protected vizDeclarations;
|
|
889
|
+
widget;
|
|
890
|
+
protected _widgetState;
|
|
891
|
+
|
|
892
|
+
constructor(dashboard, visualization, parentVisualization) {
|
|
893
|
+
super();
|
|
894
|
+
|
|
895
|
+
this.dashboard = dashboard;
|
|
896
|
+
this.parentVisualization = parentVisualization;
|
|
897
|
+
this.type = visualization.type;
|
|
898
|
+
this.id = visualization.id;
|
|
899
|
+
|
|
900
|
+
switch (this.type) {
|
|
901
|
+
case "TABLE":
|
|
902
|
+
this.label = (visualization).label;
|
|
903
|
+
break;
|
|
904
|
+
case "GRAPH":
|
|
905
|
+
this.label = (visualization).label;
|
|
906
|
+
this.icon = (visualization).icon || { faChar: "\uf128" };
|
|
907
|
+
this.flags = (visualization).flag || [];
|
|
908
|
+
break;
|
|
909
|
+
}
|
|
910
|
+
this.title = visualization.title || visualization.id;
|
|
911
|
+
this._fields = (visualization.fields || []).map(function (field) {
|
|
912
|
+
return new Field(field);
|
|
913
|
+
});
|
|
914
|
+
this._fieldsMap = {};
|
|
915
|
+
this._fields.forEach(field => {
|
|
916
|
+
this._fieldsMap[field.id()] = field;
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
this.properties = visualization.properties || (visualization.source ? visualization.source.properties : null) || {};
|
|
920
|
+
this.source = new Source(this, visualization.source);
|
|
921
|
+
this.events = new Events(this, visualization.events);
|
|
922
|
+
this.layers = [];
|
|
923
|
+
this.hasVizDeclarations = false;
|
|
924
|
+
this.vizDeclarations = {};
|
|
925
|
+
if (this.type === "CHORO") {
|
|
926
|
+
this.layers = (visualization.visualizations || []).map(innerViz => {
|
|
927
|
+
return dashboard.createVisualization(innerViz, this);
|
|
928
|
+
});
|
|
929
|
+
} else {
|
|
930
|
+
(visualization.visualizations || []).forEach(innerViz => {
|
|
931
|
+
this.vizDeclarations[innerViz.id] = dashboard.createVisualization(innerViz, this);
|
|
932
|
+
this.hasVizDeclarations = true;
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
const context = this;
|
|
936
|
+
switch (this.type) {
|
|
937
|
+
case "CHORO":
|
|
938
|
+
let chartType = visualization.properties && visualization.properties.charttype ? visualization.properties.charttype : "";
|
|
939
|
+
if (parentVisualization) {
|
|
940
|
+
switch (chartType) {
|
|
941
|
+
case "MAP_PINS":
|
|
942
|
+
this.loadWidget("../map/Pins", function (widget) {
|
|
943
|
+
try {
|
|
944
|
+
widget
|
|
945
|
+
.id(visualization.id)
|
|
946
|
+
.columns(context.source.getColumns())
|
|
947
|
+
.geohashColumn("geohash")
|
|
948
|
+
.tooltipColumn("label")
|
|
949
|
+
.fillColor(visualization.color ? visualization.color : null)
|
|
950
|
+
.projection("albersUsaPr")
|
|
951
|
+
;
|
|
952
|
+
} catch (e) {
|
|
953
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
954
|
+
}
|
|
955
|
+
});
|
|
956
|
+
break;
|
|
957
|
+
}
|
|
958
|
+
} else {
|
|
959
|
+
chartType = chartType || "CHORO";
|
|
960
|
+
if (chartType === "CHORO") {
|
|
961
|
+
if (this.source.mappings.contains("state")) {
|
|
962
|
+
chartType = "CHORO_USSTATES";
|
|
963
|
+
} else if (this.source.mappings.contains("county")) {
|
|
964
|
+
chartType = "CHORO_USCOUNTIES";
|
|
965
|
+
} else if (this.source.mappings.contains("country")) {
|
|
966
|
+
chartType = "CHORO_COUNTRIES";
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
Promise.all(context.layers.map(function (layer) { return layer.loadedPromise(); })).then(function () {
|
|
970
|
+
context.loadWidget("../composite/MegaChart", function (widget) {
|
|
971
|
+
const layers = context.layers.map(function (layer) { return layer.widget; });
|
|
972
|
+
try {
|
|
973
|
+
switch (widget.classID()) {
|
|
974
|
+
case "composite_MegaChart":
|
|
975
|
+
widget
|
|
976
|
+
.id(visualization.id)
|
|
977
|
+
.showChartSelect_default(false)
|
|
978
|
+
.chartType_default(chartType)
|
|
979
|
+
.chartTypeDefaults({
|
|
980
|
+
autoScaleMode: layers.length ? "data" : "mesh"
|
|
981
|
+
})
|
|
982
|
+
.chartTypeProperties({
|
|
983
|
+
layers
|
|
984
|
+
})
|
|
985
|
+
;
|
|
986
|
+
break;
|
|
987
|
+
default:
|
|
988
|
+
widget
|
|
989
|
+
.id(visualization.id)
|
|
990
|
+
.autoScaleMode(layers.length ? "data" : "mesh")
|
|
991
|
+
.layers(layers)
|
|
992
|
+
;
|
|
993
|
+
break;
|
|
994
|
+
}
|
|
995
|
+
} catch (e) {
|
|
996
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
997
|
+
}
|
|
998
|
+
});
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
break;
|
|
1002
|
+
case "2DCHART":
|
|
1003
|
+
case "PIE":
|
|
1004
|
+
case "BUBBLE":
|
|
1005
|
+
case "BAR":
|
|
1006
|
+
case "WORD_CLOUD":
|
|
1007
|
+
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1008
|
+
try {
|
|
1009
|
+
widget
|
|
1010
|
+
.id(visualization.id)
|
|
1011
|
+
.chartType_default(context.properties.chartType || context.properties.charttype || context.type)
|
|
1012
|
+
;
|
|
1013
|
+
} catch (e) {
|
|
1014
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
break;
|
|
1018
|
+
case "LINE":
|
|
1019
|
+
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1020
|
+
try {
|
|
1021
|
+
widget
|
|
1022
|
+
.id(visualization.id)
|
|
1023
|
+
.chartType_default(context.properties.chartType || context.properties.charttype || context.type)
|
|
1024
|
+
;
|
|
1025
|
+
} catch (e) {
|
|
1026
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
break;
|
|
1030
|
+
case "TABLE":
|
|
1031
|
+
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1032
|
+
try {
|
|
1033
|
+
widget
|
|
1034
|
+
.id(visualization.id)
|
|
1035
|
+
.showChartSelect_default(false)
|
|
1036
|
+
.chartType_default("TABLE")
|
|
1037
|
+
;
|
|
1038
|
+
} catch (e) {
|
|
1039
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1040
|
+
}
|
|
1041
|
+
});
|
|
1042
|
+
break;
|
|
1043
|
+
case "SLIDER":
|
|
1044
|
+
this.loadWidget("../form/Slider", function (widget) {
|
|
1045
|
+
try {
|
|
1046
|
+
widget
|
|
1047
|
+
.id(visualization.id)
|
|
1048
|
+
;
|
|
1049
|
+
if (visualization.range) {
|
|
1050
|
+
let selectionLabel = "";
|
|
1051
|
+
if (Utility.exists("events.click.updates", visualization) && visualization.events.click.updates.length) {
|
|
1052
|
+
for (const key in visualization.events.click.updates[0].mappings) {
|
|
1053
|
+
selectionLabel = key;
|
|
1054
|
+
break;
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
widget
|
|
1058
|
+
.low_default(+visualization.range[0])
|
|
1059
|
+
.high_default(+visualization.range[1])
|
|
1060
|
+
.step_default(+visualization.range[2])
|
|
1061
|
+
.selectionLabel_default(selectionLabel)
|
|
1062
|
+
.selectionLabel(selectionLabel)
|
|
1063
|
+
;
|
|
1064
|
+
}
|
|
1065
|
+
} catch (e) {
|
|
1066
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
break;
|
|
1070
|
+
case "GRAPH":
|
|
1071
|
+
this.loadWidget("../composite/MegaChart", function (widget) {
|
|
1072
|
+
try {
|
|
1073
|
+
widget
|
|
1074
|
+
.id(visualization.id)
|
|
1075
|
+
.showChartSelect_default(false)
|
|
1076
|
+
.chartType_default("GRAPH")
|
|
1077
|
+
.chartTypeDefaults({
|
|
1078
|
+
layout: "ForceDirected2",
|
|
1079
|
+
applyScaleOnLayout: true
|
|
1080
|
+
})
|
|
1081
|
+
;
|
|
1082
|
+
} catch (e) {
|
|
1083
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
break;
|
|
1087
|
+
case "FORM":
|
|
1088
|
+
this.loadWidgets(["../form/Form", "../form/Input", "../form/Button", "../form/CheckBox", "../form/ColorInput", "../form/Radio", "../form/Range", "../form/Select", "../form/Slider", "../form/TextArea", "../form/InputRange"], function (widget, widgetClasses) {
|
|
1089
|
+
const Input = widgetClasses[1];
|
|
1090
|
+
const CheckBox = widgetClasses[3];
|
|
1091
|
+
const Radio = widgetClasses[5];
|
|
1092
|
+
const Select = widgetClasses[7];
|
|
1093
|
+
const TextArea = widgetClasses[9];
|
|
1094
|
+
const InputRange = widgetClasses[10];
|
|
1095
|
+
|
|
1096
|
+
try {
|
|
1097
|
+
widget
|
|
1098
|
+
.id(visualization.id)
|
|
1099
|
+
.inputs(context.fields().map(function (field) {
|
|
1100
|
+
|
|
1101
|
+
const selectOptions = [];
|
|
1102
|
+
let options = [];
|
|
1103
|
+
let inp;
|
|
1104
|
+
if (!field.charttype() && field.type() === "range") {
|
|
1105
|
+
// TODO - Verify with @DL
|
|
1106
|
+
field.charttype("RANGE");
|
|
1107
|
+
}
|
|
1108
|
+
switch (field.charttype()) {
|
|
1109
|
+
case "TEXT":
|
|
1110
|
+
inp = new Input()
|
|
1111
|
+
.type_default("text")
|
|
1112
|
+
;
|
|
1113
|
+
break;
|
|
1114
|
+
case "TEXTAREA":
|
|
1115
|
+
inp = new TextArea();
|
|
1116
|
+
break;
|
|
1117
|
+
case "CHECKBOX":
|
|
1118
|
+
inp = new CheckBox();
|
|
1119
|
+
break;
|
|
1120
|
+
case "RADIO":
|
|
1121
|
+
inp = new Radio();
|
|
1122
|
+
break;
|
|
1123
|
+
case "HIDDEN":
|
|
1124
|
+
inp = new Input()
|
|
1125
|
+
.type_default("hidden")
|
|
1126
|
+
;
|
|
1127
|
+
break;
|
|
1128
|
+
case "RANGE":
|
|
1129
|
+
inp = new InputRange();
|
|
1130
|
+
break;
|
|
1131
|
+
default:
|
|
1132
|
+
if (field.enumvals()) {
|
|
1133
|
+
inp = new Select();
|
|
1134
|
+
options = field.enumvals();
|
|
1135
|
+
for (const val in options) {
|
|
1136
|
+
selectOptions.push([val, options[val]]);
|
|
1137
|
+
}
|
|
1138
|
+
} else {
|
|
1139
|
+
inp = new Input()
|
|
1140
|
+
.type_default("text")
|
|
1141
|
+
;
|
|
1142
|
+
}
|
|
1143
|
+
break;
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
inp
|
|
1147
|
+
.name_default(field.id())
|
|
1148
|
+
.label_default(field.label())
|
|
1149
|
+
.value_default(field.default()) // TODO Hippie support for multiple default values (checkbox only)
|
|
1150
|
+
;
|
|
1151
|
+
|
|
1152
|
+
if (inp instanceof CheckBox || inp instanceof Radio) { // change this to instanceof?
|
|
1153
|
+
const vals = Object.keys(field.enumvals());
|
|
1154
|
+
inp.selectOptions_default(vals);
|
|
1155
|
+
} else if (selectOptions.length) {
|
|
1156
|
+
inp.selectOptions_default(selectOptions);
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
return inp;
|
|
1160
|
+
}))
|
|
1161
|
+
;
|
|
1162
|
+
} catch (e) {
|
|
1163
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1164
|
+
}
|
|
1165
|
+
});
|
|
1166
|
+
break;
|
|
1167
|
+
case "HEAT_MAP":
|
|
1168
|
+
this.loadWidgets(["../other/HeatMap"], function (widget) {
|
|
1169
|
+
try {
|
|
1170
|
+
widget
|
|
1171
|
+
.id(visualization.id)
|
|
1172
|
+
.image_default(context.properties.imageUrl)
|
|
1173
|
+
;
|
|
1174
|
+
} catch (e) {
|
|
1175
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1176
|
+
}
|
|
1177
|
+
});
|
|
1178
|
+
break;
|
|
1179
|
+
default:
|
|
1180
|
+
this.loadWidget("../common/TextBox", function (widget) {
|
|
1181
|
+
try {
|
|
1182
|
+
widget
|
|
1183
|
+
.id(visualization.id)
|
|
1184
|
+
.text_default(context.id + "\n" + "TODO: " + context.type)
|
|
1185
|
+
;
|
|
1186
|
+
} catch (e) {
|
|
1187
|
+
console.warn("Unexpected widget type: " + widget.classID());
|
|
1188
|
+
}
|
|
1189
|
+
});
|
|
1190
|
+
break;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
getQualifiedID() {
|
|
1195
|
+
return this.id;
|
|
1196
|
+
}
|
|
1197
|
+
|
|
1198
|
+
fields() {
|
|
1199
|
+
return this._fields;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
hasField(id) {
|
|
1203
|
+
return this.field[id] !== undefined;
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
field(id) {
|
|
1207
|
+
return this._fieldsMap[id];
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
loadedPromise() {
|
|
1211
|
+
const context = this;
|
|
1212
|
+
return new Promise<void>(function (resolve, reject) {
|
|
1213
|
+
const intervalHandle = setInterval(function () {
|
|
1214
|
+
if (context.isLoaded()) {
|
|
1215
|
+
clearInterval(intervalHandle);
|
|
1216
|
+
resolve();
|
|
1217
|
+
}
|
|
1218
|
+
}, 100);
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
isLoading() {
|
|
1223
|
+
return this.widget === null;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
isLoaded() {
|
|
1227
|
+
return this.widget instanceof Widget;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
loadMegaChartWidget(widgetPath, callback) {
|
|
1231
|
+
this.loadWidgets(["../composite/MegaChart", widgetPath], function (megaChart, widgets) {
|
|
1232
|
+
const chart = new widgets[1]();
|
|
1233
|
+
megaChart
|
|
1234
|
+
.chartType_default(MultiChart.prototype._allChartTypesByClass[chart.classID()].id)
|
|
1235
|
+
.chart(chart)
|
|
1236
|
+
;
|
|
1237
|
+
if (callback) {
|
|
1238
|
+
callback(megaChart, chart, widgets);
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
loadWidget(widgetPath, callback) {
|
|
1244
|
+
this.loadWidgets([widgetPath], callback);
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
loadWidgets(widgetPaths, callback) {
|
|
1248
|
+
this.widget = null;
|
|
1249
|
+
|
|
1250
|
+
const context = this;
|
|
1251
|
+
legacyRequire(widgetPaths, function (WidgetClass) {
|
|
1252
|
+
const existingWidget = context.dashboard.marshaller.getWidget(context.id);
|
|
1253
|
+
if (existingWidget) {
|
|
1254
|
+
if (WidgetClass.prototype._class !== existingWidget.classID()) {
|
|
1255
|
+
console.warn("Unexpected persisted widget type (old persist string?)");
|
|
1256
|
+
}
|
|
1257
|
+
context.setWidget(existingWidget);
|
|
1258
|
+
} else {
|
|
1259
|
+
context.setWidget(new WidgetClass());
|
|
1260
|
+
}
|
|
1261
|
+
if (callback) {
|
|
1262
|
+
callback(context.widget, arguments);
|
|
1263
|
+
}
|
|
1264
|
+
});
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
setWidget(widget) {
|
|
1268
|
+
this.widget = widget;
|
|
1269
|
+
this.events.setWidget(widget);
|
|
1270
|
+
if (this.widget.columns) {
|
|
1271
|
+
const columns = this.source.getColumns();
|
|
1272
|
+
this.widget.columns(columns, true);
|
|
1273
|
+
}
|
|
1274
|
+
for (const key in this.properties) {
|
|
1275
|
+
switch (widget.classID()) {
|
|
1276
|
+
case "chart_MultiChart":
|
|
1277
|
+
case "composite_MegaChart":
|
|
1278
|
+
if (widget[key + "_default"]) {
|
|
1279
|
+
widget[key + "_default"](this.properties[key]);
|
|
1280
|
+
}
|
|
1281
|
+
widget.chartTypeDefaults()[key] = this.properties[key];
|
|
1282
|
+
break;
|
|
1283
|
+
default:
|
|
1284
|
+
if (this.widget[key + "_default"]) {
|
|
1285
|
+
try {
|
|
1286
|
+
this.widget[key + "_default"](this.properties[key]);
|
|
1287
|
+
} catch (e) {
|
|
1288
|
+
console.warn("Invalid Property:" + this.id + ".properties." + key);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
return this.widget;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
accept(visitor) {
|
|
1297
|
+
visitor.visit(this);
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
getUpdates() {
|
|
1301
|
+
return this.events.getUpdates();
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
getUpdatesForDatasource(otherDatasource) {
|
|
1305
|
+
return this.events.getUpdates().filter(function (updateObj) {
|
|
1306
|
+
return updateObj.getDatasource() === otherDatasource;
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
getUpdatesForVisualization(otherViz) {
|
|
1311
|
+
return this.events.getUpdates().filter(function (updateObj) {
|
|
1312
|
+
return updateObj.getVisualization() === otherViz;
|
|
1313
|
+
});
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
getInputFields(mapped?): any {
|
|
1317
|
+
const retVal = {};
|
|
1318
|
+
const updatedBy = this.getInputVisualizations();
|
|
1319
|
+
updatedBy.forEach(viz => {
|
|
1320
|
+
if (viz.hasSelection()) {
|
|
1321
|
+
viz.getUpdatesForVisualization(this).forEach(function (updateObj) {
|
|
1322
|
+
const sel = mapped ? updateObj.mapSelected() : updateObj.selectedRow();
|
|
1323
|
+
for (const key in sel) {
|
|
1324
|
+
retVal[key] = sel[key];
|
|
1325
|
+
}
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
});
|
|
1329
|
+
return retVal;
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
update(params?) {
|
|
1333
|
+
let titleWidget = null;
|
|
1334
|
+
if (!this.parentVisualization) {
|
|
1335
|
+
titleWidget = this.widget;
|
|
1336
|
+
while (titleWidget && !titleWidget.title) {
|
|
1337
|
+
titleWidget = titleWidget.locateParentWidget();
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
if (!params) {
|
|
1342
|
+
params = "";
|
|
1343
|
+
let titleFormatStr = "";
|
|
1344
|
+
if (titleWidget && titleWidget.ddlParamsFormat) {
|
|
1345
|
+
titleFormatStr = titleWidget.ddlParamsFormat();
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
const dedupParams = {};
|
|
1349
|
+
if (titleFormatStr) {
|
|
1350
|
+
params = Utility.template(titleFormatStr, this.getInputFields());
|
|
1351
|
+
} else {
|
|
1352
|
+
const paramsArr = [];
|
|
1353
|
+
const mappedData = this.getInputFields(true);
|
|
1354
|
+
for (const key in mappedData) {
|
|
1355
|
+
if (mappedData[key]) {
|
|
1356
|
+
if (!dedupParams[key]) {
|
|
1357
|
+
dedupParams[key] = true;
|
|
1358
|
+
paramsArr.push(mappedData[key]);
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
params = paramsArr.join(", ");
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
const context = this;
|
|
1367
|
+
return new Promise<void>(function (resolve, reject) {
|
|
1368
|
+
if (titleWidget) {
|
|
1369
|
+
const title = titleWidget.title();
|
|
1370
|
+
const titleParts = title.split(" (");
|
|
1371
|
+
titleWidget
|
|
1372
|
+
.title(titleParts[0] + (params.trim() ? " (" + params + ")" : ""))
|
|
1373
|
+
.render(function () {
|
|
1374
|
+
resolve();
|
|
1375
|
+
})
|
|
1376
|
+
;
|
|
1377
|
+
} else {
|
|
1378
|
+
let ddlViz = context;
|
|
1379
|
+
while (ddlViz.parentVisualization) {
|
|
1380
|
+
ddlViz = ddlViz.parentVisualization;
|
|
1381
|
+
}
|
|
1382
|
+
ddlViz.widget.render(function () {
|
|
1383
|
+
resolve();
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
if (context.dashboard.marshaller.propogateClear()) {
|
|
1387
|
+
context.events.getUpdatesVisualizations().forEach(function (updatedViz) {
|
|
1388
|
+
updatedViz.update();
|
|
1389
|
+
});
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
notify() {
|
|
1395
|
+
if (this.widget) {
|
|
1396
|
+
const data = this.source.hasData() ? this.source.getData() : [];
|
|
1397
|
+
this.widget.data(data);
|
|
1398
|
+
if (this.type === "GRAPH" && data.vertices) {
|
|
1399
|
+
const ipFields = this.getInputFields(true);
|
|
1400
|
+
data.vertices.filter(function (v) {
|
|
1401
|
+
return v.__hpcc_uid === ipFields.treeuid;
|
|
1402
|
+
}).forEach(function (v) {
|
|
1403
|
+
v.centroid(true);
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
return this.update();
|
|
1407
|
+
}
|
|
1408
|
+
return Promise.resolve();
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
clear() {
|
|
1412
|
+
this._widgetState = {
|
|
1413
|
+
row: {},
|
|
1414
|
+
selected: false
|
|
1415
|
+
};
|
|
1416
|
+
this.fields().forEach(field => {
|
|
1417
|
+
if (field.hasDefault()) {
|
|
1418
|
+
this._widgetState.row[field.id()] = field.default();
|
|
1419
|
+
this._widgetState.selected = true;
|
|
1420
|
+
}
|
|
1421
|
+
});
|
|
1422
|
+
if (this.widget && this.dashboard.marshaller.clearDataOnUpdate()) {
|
|
1423
|
+
this.widget.data([]);
|
|
1424
|
+
}
|
|
1425
|
+
if (this.dashboard.marshaller.propogateClear()) {
|
|
1426
|
+
this.events.getUpdatesVisualizations().forEach(function (updatedViz) {
|
|
1427
|
+
updatedViz.clear();
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
on(eventID, func) {
|
|
1433
|
+
const context = this;
|
|
1434
|
+
this.overrideMethod(eventID, function (origFunc, args) {
|
|
1435
|
+
origFunc.apply(context, args);
|
|
1436
|
+
setTimeout(function () {
|
|
1437
|
+
func.apply(context, args);
|
|
1438
|
+
}, 0);
|
|
1439
|
+
});
|
|
1440
|
+
return this;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
calcRequestFor(visualization) {
|
|
1444
|
+
let retVal = {};
|
|
1445
|
+
this.getUpdatesForVisualization(visualization).forEach(function (updatesObj) {
|
|
1446
|
+
// TODO: When we support more than "click" this will need enhancment...
|
|
1447
|
+
retVal = updatesObj.calcRequestFor(visualization);
|
|
1448
|
+
});
|
|
1449
|
+
return retVal;
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1452
|
+
processEvent(eventID, event, row, col, selected) {
|
|
1453
|
+
this._widgetState = {
|
|
1454
|
+
row,
|
|
1455
|
+
col,
|
|
1456
|
+
selected: selected === undefined ? true : selected
|
|
1457
|
+
};
|
|
1458
|
+
const context = this;
|
|
1459
|
+
setTimeout(function () {
|
|
1460
|
+
event.fetchData().then(function (promises) {
|
|
1461
|
+
context.dashboard.marshaller.vizEvent(context.widget, "post_" + eventID, row, col, selected);
|
|
1462
|
+
});
|
|
1463
|
+
}, 0);
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
hasSelection() {
|
|
1467
|
+
return this._widgetState && this._widgetState.selected;
|
|
1468
|
+
}
|
|
1469
|
+
|
|
1470
|
+
selection() {
|
|
1471
|
+
if (this.hasSelection()) {
|
|
1472
|
+
return this._widgetState.row;
|
|
1473
|
+
}
|
|
1474
|
+
return null;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
reverseMappedSelection() {
|
|
1478
|
+
if (this.hasSelection()) {
|
|
1479
|
+
return this.source.mappings ? this.source.mappings.doReverseMap(this._widgetState.row) : this._widgetState.row;
|
|
1480
|
+
}
|
|
1481
|
+
return null;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
getInputVisualizations() {
|
|
1485
|
+
return this.dashboard.marshaller.getVisualizationArray().filter(viz => {
|
|
1486
|
+
const updates = viz.events.getUpdatesVisualizations();
|
|
1487
|
+
if (updates.indexOf(this) >= 0) {
|
|
1488
|
+
return true;
|
|
1489
|
+
}
|
|
1490
|
+
return false;
|
|
1491
|
+
});
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
serializeState() {
|
|
1495
|
+
const state: any = {
|
|
1496
|
+
widgetState: this._widgetState
|
|
1497
|
+
};
|
|
1498
|
+
if (this.widget) {
|
|
1499
|
+
if (this.widget.serializeState) {
|
|
1500
|
+
state.widget = this.widget.serializeState();
|
|
1501
|
+
} else if (this.widget.data) {
|
|
1502
|
+
state.widget = {
|
|
1503
|
+
data: this.widget.data()
|
|
1504
|
+
};
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
return state;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
deserializeState(state) {
|
|
1511
|
+
if (state) {
|
|
1512
|
+
this._widgetState = state.widgetState;
|
|
1513
|
+
if (this.widget && state.widget) {
|
|
1514
|
+
if (this.widget.deserializeState) {
|
|
1515
|
+
this.widget.deserializeState(state.widget);
|
|
1516
|
+
} else if (this.widget.data && state.widget.data) {
|
|
1517
|
+
this.widget.data(state.widget.data);
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
return this;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
// Output ---
|
|
1526
|
+
function Filter(this: any, datasource, ddlFilter: string | DDL1.IFilter) {
|
|
1527
|
+
this.datasource = datasource;
|
|
1528
|
+
if (typeof ddlFilter === "string") {
|
|
1529
|
+
ddlFilter = {
|
|
1530
|
+
fieldid: ddlFilter,
|
|
1531
|
+
nullable: true,
|
|
1532
|
+
rule: "=="
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
this.fieldid = ddlFilter.fieldid;
|
|
1536
|
+
this.nullable = ddlFilter.nullable;
|
|
1537
|
+
this.rule = ddlFilter.rule || "==";
|
|
1538
|
+
this.minid = ddlFilter.minid;
|
|
1539
|
+
this.maxid = ddlFilter.maxid;
|
|
1540
|
+
this.calcRequestFieldID();
|
|
1541
|
+
}
|
|
1542
|
+
|
|
1543
|
+
Filter.prototype.calcRequestFieldID = function () {
|
|
1544
|
+
this._requestFieldID = this.fieldid;
|
|
1545
|
+
this._requestMinID = this.minid;
|
|
1546
|
+
this._requestMaxID = this.maxid;
|
|
1547
|
+
switch (this.rule) {
|
|
1548
|
+
case "<":
|
|
1549
|
+
case "<=":
|
|
1550
|
+
if (Utility.endsWith(this.fieldid, "-max")) {
|
|
1551
|
+
this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
|
|
1552
|
+
}
|
|
1553
|
+
break;
|
|
1554
|
+
case ">":
|
|
1555
|
+
case ">=":
|
|
1556
|
+
if (Utility.endsWith(this.fieldid, "-min")) {
|
|
1557
|
+
this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
|
|
1558
|
+
}
|
|
1559
|
+
break;
|
|
1560
|
+
case "set":
|
|
1561
|
+
if (Utility.endsWith(this.fieldid, "-set")) {
|
|
1562
|
+
this._requestFieldID = this.fieldid.substring(0, this.fieldid.length - 4) + (this.datasource.isRoxie() ? "_set" : "");
|
|
1563
|
+
}
|
|
1564
|
+
break;
|
|
1565
|
+
case "range":
|
|
1566
|
+
if (Utility.endsWith(this.minid, "-min")) {
|
|
1567
|
+
this._requestMinID = this.minid.substring(0, this.minid.length - 4) + (this.datasource.isRoxie() ? "_min" : "");
|
|
1568
|
+
}
|
|
1569
|
+
if (Utility.endsWith(this.maxid, "-max")) {
|
|
1570
|
+
this._requestMaxID = this.maxid.substring(0, this.maxid.length - 4) + (this.datasource.isRoxie() ? "_max" : "");
|
|
1571
|
+
}
|
|
1572
|
+
break;
|
|
1573
|
+
}
|
|
1574
|
+
};
|
|
1575
|
+
|
|
1576
|
+
Filter.prototype.isRange = function () {
|
|
1577
|
+
return this.rule === "range";
|
|
1578
|
+
};
|
|
1579
|
+
|
|
1580
|
+
Filter.prototype.isSet = function () {
|
|
1581
|
+
return this.rule === "set";
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
Filter.prototype._calcRequest = function (filteredRequest, request, fieldid, requestFieldID, value) {
|
|
1585
|
+
if (!this.datasource.isRoxie()) {
|
|
1586
|
+
// Ignore requestFieldID, until filtering WU results
|
|
1587
|
+
// Otherwise there are many fieldID collisions
|
|
1588
|
+
requestFieldID = fieldid;
|
|
1589
|
+
}
|
|
1590
|
+
filteredRequest[requestFieldID + _CHANGED] = request[fieldid + _CHANGED] || false;
|
|
1591
|
+
if (filteredRequest[requestFieldID] !== value) {
|
|
1592
|
+
filteredRequest[requestFieldID] = value;
|
|
1593
|
+
}
|
|
1594
|
+
};
|
|
1595
|
+
|
|
1596
|
+
Filter.prototype.calcRequest = function (filteredRequest, request, fillInMissing) {
|
|
1597
|
+
if (!fillInMissing && request[this.fieldid] === undefined) {
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
const value = request[this.fieldid] === undefined ? null : request[this.fieldid];
|
|
1601
|
+
if (this.isRange()) {
|
|
1602
|
+
if (value instanceof Array && value.length === 2) {
|
|
1603
|
+
this._calcRequest(filteredRequest, request, this.minid, this._requestMinID, value[0]);
|
|
1604
|
+
this._calcRequest(filteredRequest, request, this.maxid, this._requestMaxID, value[1]);
|
|
1605
|
+
}
|
|
1606
|
+
} else {
|
|
1607
|
+
this._calcRequest(filteredRequest, request, this.fieldid, this._requestFieldID, value);
|
|
1608
|
+
if (this.isSet() && this.datasource.isRoxie()) {
|
|
1609
|
+
// TODO in the future the value should be an array ---
|
|
1610
|
+
filteredRequest[this._requestFieldID + ".Item$"] = filteredRequest[this._requestFieldID];
|
|
1611
|
+
delete filteredRequest[this._requestFieldID];
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
};
|
|
1615
|
+
|
|
1616
|
+
Filter.prototype.matches = function (row, value): boolean {
|
|
1617
|
+
if (value === undefined || value === null || value === "") {
|
|
1618
|
+
return this.nullable;
|
|
1619
|
+
}
|
|
1620
|
+
let rowValue = row[this._requestFieldID];
|
|
1621
|
+
if (rowValue === undefined) {
|
|
1622
|
+
rowValue = row[this._requestFieldID.toLowerCase()];
|
|
1623
|
+
}
|
|
1624
|
+
if (rowValue === undefined) {
|
|
1625
|
+
console.warn("Empty cell value: '" + this._requestFieldID + "'");
|
|
1626
|
+
return false;
|
|
1627
|
+
}
|
|
1628
|
+
switch (this.rule) {
|
|
1629
|
+
case "<":
|
|
1630
|
+
if (rowValue.localeCompare) {
|
|
1631
|
+
return rowValue.localeCompare(value) < 0;
|
|
1632
|
+
}
|
|
1633
|
+
return rowValue < value;
|
|
1634
|
+
case ">":
|
|
1635
|
+
if (rowValue.localeCompare) {
|
|
1636
|
+
return rowValue.localeCompare(value) > 0;
|
|
1637
|
+
}
|
|
1638
|
+
return rowValue > value;
|
|
1639
|
+
case "<=":
|
|
1640
|
+
if (rowValue.localeCompare) {
|
|
1641
|
+
return rowValue.localeCompare(value) <= 0;
|
|
1642
|
+
}
|
|
1643
|
+
return rowValue <= value;
|
|
1644
|
+
case ">=":
|
|
1645
|
+
if (rowValue.localeCompare) {
|
|
1646
|
+
return rowValue.localeCompare(value) >= 0;
|
|
1647
|
+
}
|
|
1648
|
+
return rowValue >= value;
|
|
1649
|
+
case "!=":
|
|
1650
|
+
case "notequals":
|
|
1651
|
+
return rowValue != value; // jshint ignore:line
|
|
1652
|
+
case "set":
|
|
1653
|
+
if (value instanceof Array) {
|
|
1654
|
+
return value.indexOf(rowValue) >= 0;
|
|
1655
|
+
}
|
|
1656
|
+
return value == rowValue; // jshint ignore:line
|
|
1657
|
+
case "==":
|
|
1658
|
+
return value == rowValue; // jshint ignore:line
|
|
1659
|
+
default:
|
|
1660
|
+
console.warn("Unknown filter rule: '" + this.rule + "'");
|
|
1661
|
+
return value == rowValue; // jshint ignore:line
|
|
1662
|
+
}
|
|
1663
|
+
};
|
|
1664
|
+
|
|
1665
|
+
export class Output {
|
|
1666
|
+
|
|
1667
|
+
datasource;
|
|
1668
|
+
id;
|
|
1669
|
+
from;
|
|
1670
|
+
protected notify;
|
|
1671
|
+
filters;
|
|
1672
|
+
protected db;
|
|
1673
|
+
|
|
1674
|
+
constructor(datasource, output) {
|
|
1675
|
+
this.datasource = datasource;
|
|
1676
|
+
this.id = output.id;
|
|
1677
|
+
this.from = output.from;
|
|
1678
|
+
this.notify = output.notify || [];
|
|
1679
|
+
this.filters = (output.filter || []).map(filter => {
|
|
1680
|
+
return new Filter(this.datasource, filter);
|
|
1681
|
+
});
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
getQualifiedID() {
|
|
1685
|
+
return this.datasource.getQualifiedID() + "." + this.id;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
getUpdatesVisualizations() {
|
|
1689
|
+
const retVal = [];
|
|
1690
|
+
this.notify.forEach(item => {
|
|
1691
|
+
retVal.push(this.datasource.marshaller.getVisualization(item));
|
|
1692
|
+
});
|
|
1693
|
+
return retVal;
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
accept(visitor) {
|
|
1697
|
+
visitor.visit(this);
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
vizNotify(updates) {
|
|
1701
|
+
const promises = [];
|
|
1702
|
+
this.notify.filter(function (item) {
|
|
1703
|
+
return !updates || updates.indexOf(item) >= 0;
|
|
1704
|
+
}).forEach(item => {
|
|
1705
|
+
const viz = this.datasource.marshaller.getVisualization(item);
|
|
1706
|
+
promises.push(viz.notify());
|
|
1707
|
+
});
|
|
1708
|
+
return Promise.all(promises);
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
setData(data, updates) {
|
|
1712
|
+
this.db = new Database.Grid().jsonObj(data);
|
|
1713
|
+
return this.vizNotify(updates);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
// FetchData Optimizers ---
|
|
1718
|
+
function DatasourceRequestOptimizer(this: any) {
|
|
1719
|
+
this.datasourceRequests = {
|
|
1720
|
+
};
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
DatasourceRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
|
|
1724
|
+
const datasourceRequestID = updateDatasource.id + "(" + JSON.stringify(request) + ")";
|
|
1725
|
+
if (!this.datasourceRequests[datasourceRequestID]) {
|
|
1726
|
+
this.datasourceRequests[datasourceRequestID] = {
|
|
1727
|
+
updateDatasource,
|
|
1728
|
+
request,
|
|
1729
|
+
updates: []
|
|
1730
|
+
};
|
|
1731
|
+
} else if ((window as any).__hpcc_debug) {
|
|
1732
|
+
console.warn("Optimized duplicate fetch: " + datasourceRequestID);
|
|
1733
|
+
}
|
|
1734
|
+
const datasourceOptimizedItem = this.datasourceRequests[datasourceRequestID];
|
|
1735
|
+
if (datasourceOptimizedItem.updates.indexOf(updateVisualization.id) < 0) {
|
|
1736
|
+
datasourceOptimizedItem.updates.push(updateVisualization.id);
|
|
1737
|
+
}
|
|
1738
|
+
};
|
|
1739
|
+
|
|
1740
|
+
DatasourceRequestOptimizer.prototype.fetchData = function () {
|
|
1741
|
+
const promises = [];
|
|
1742
|
+
for (const key in this.datasourceRequests) {
|
|
1743
|
+
const item = this.datasourceRequests[key];
|
|
1744
|
+
promises.push(item.updateDatasource.fetchData(item.request, item.updates));
|
|
1745
|
+
}
|
|
1746
|
+
return Promise.all(promises);
|
|
1747
|
+
};
|
|
1748
|
+
|
|
1749
|
+
function VisualizationRequestOptimizer(this: any, skipClear?) {
|
|
1750
|
+
this.skipClear = skipClear;
|
|
1751
|
+
this.visualizationRequests = {
|
|
1752
|
+
};
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
VisualizationRequestOptimizer.prototype.appendRequest = function (updateDatasource, request, updateVisualization) {
|
|
1756
|
+
if (updateDatasource && updateVisualization) {
|
|
1757
|
+
const visualizationRequestID = updateVisualization.id + "(" + updateDatasource.id + ")";
|
|
1758
|
+
if (!this.visualizationRequests[visualizationRequestID]) {
|
|
1759
|
+
this.visualizationRequests[visualizationRequestID] = {
|
|
1760
|
+
updateVisualization,
|
|
1761
|
+
updateDatasource,
|
|
1762
|
+
request: {}
|
|
1763
|
+
};
|
|
1764
|
+
} else if ((window as any).__hpcc_debug) {
|
|
1765
|
+
console.warn("Optimized duplicate fetch: " + visualizationRequestID);
|
|
1766
|
+
}
|
|
1767
|
+
const visualizationOptimizedItem = this.visualizationRequests[visualizationRequestID];
|
|
1768
|
+
Utility.mixin(visualizationOptimizedItem.request, request);
|
|
1769
|
+
}
|
|
1770
|
+
};
|
|
1771
|
+
|
|
1772
|
+
VisualizationRequestOptimizer.prototype.fetchData = function () {
|
|
1773
|
+
const datasourceRequestOptimizer = new DatasourceRequestOptimizer();
|
|
1774
|
+
for (const key in this.visualizationRequests) {
|
|
1775
|
+
const item = this.visualizationRequests[key];
|
|
1776
|
+
if (!this.skipClear && item.updateVisualization.type !== "GRAPH") {
|
|
1777
|
+
item.updateVisualization.clear();
|
|
1778
|
+
}
|
|
1779
|
+
item.updateVisualization.update(LOADING);
|
|
1780
|
+
datasourceRequestOptimizer.appendRequest(item.updateDatasource, item.request, item.updateVisualization);
|
|
1781
|
+
}
|
|
1782
|
+
return datasourceRequestOptimizer.fetchData();
|
|
1783
|
+
};
|
|
1784
|
+
|
|
1785
|
+
// Datasource ---
|
|
1786
|
+
let transactionID = 0;
|
|
1787
|
+
const transactionQueue = [];
|
|
1788
|
+
export class Datasource {
|
|
1789
|
+
|
|
1790
|
+
protected marshaller;
|
|
1791
|
+
id;
|
|
1792
|
+
protected WUID;
|
|
1793
|
+
protected URL;
|
|
1794
|
+
databomb;
|
|
1795
|
+
protected filters;
|
|
1796
|
+
protected _loadedCount;
|
|
1797
|
+
protected _outputs;
|
|
1798
|
+
protected _outputArray;
|
|
1799
|
+
comms;
|
|
1800
|
+
protected _loadedCount2;
|
|
1801
|
+
protected _loadedCount3;
|
|
1802
|
+
protected _loadedCount4;
|
|
1803
|
+
|
|
1804
|
+
constructor(marshaller, datasource: DDL1.IAnyDatasource, proxyMappings, timeout) {
|
|
1805
|
+
this.marshaller = marshaller;
|
|
1806
|
+
this.id = datasource.id;
|
|
1807
|
+
if (DDL1.isWorkunitDatasource(datasource)) {
|
|
1808
|
+
this.WUID = datasource.WUID;
|
|
1809
|
+
} else if (DDL1.isHipieDatasource(datasource)) {
|
|
1810
|
+
this.URL = (marshaller.espUrl && marshaller.espUrl.url()) ? marshaller.espUrl.url() : datasource.URL;
|
|
1811
|
+
} else if (DDL1.isDatabombDatasource(datasource)) {
|
|
1812
|
+
this.databomb = datasource.databomb;
|
|
1813
|
+
}
|
|
1814
|
+
this.filters = (datasource.filter || []).map(filter => {
|
|
1815
|
+
return new Filter(this, filter);
|
|
1816
|
+
});
|
|
1817
|
+
this._loadedCount = 0;
|
|
1818
|
+
|
|
1819
|
+
const context = this;
|
|
1820
|
+
this._outputs = {};
|
|
1821
|
+
this._outputArray = [];
|
|
1822
|
+
const hipieResults = [];
|
|
1823
|
+
datasource.outputs.forEach(item => {
|
|
1824
|
+
const output = new Output(context, item);
|
|
1825
|
+
context._outputs[item.id] = output;
|
|
1826
|
+
context._outputArray.push(output);
|
|
1827
|
+
hipieResults.push({
|
|
1828
|
+
id: item.id,
|
|
1829
|
+
from: item.from,
|
|
1830
|
+
filters: output.filters || this.filters
|
|
1831
|
+
});
|
|
1832
|
+
});
|
|
1833
|
+
|
|
1834
|
+
if (this.WUID) {
|
|
1835
|
+
this.comms = new Comms.HIPIEWorkunit()
|
|
1836
|
+
.url(this.URL)
|
|
1837
|
+
.proxyMappings(proxyMappings)
|
|
1838
|
+
.timeout(timeout)
|
|
1839
|
+
.hipieResults(hipieResults)
|
|
1840
|
+
;
|
|
1841
|
+
} else if (this.databomb) {
|
|
1842
|
+
this.comms = new Comms.HIPIEDatabomb()
|
|
1843
|
+
.hipieResults(hipieResults)
|
|
1844
|
+
;
|
|
1845
|
+
} else if (DDL1.isHipieDatasource(datasource)) {
|
|
1846
|
+
this.comms = new Comms.HIPIERoxie()
|
|
1847
|
+
.url(datasource.URL)
|
|
1848
|
+
.proxyMappings(proxyMappings)
|
|
1849
|
+
.timeout(timeout)
|
|
1850
|
+
.hipieResults(hipieResults)
|
|
1851
|
+
;
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
isRoxie() {
|
|
1856
|
+
return !this.WUID && !this.databomb;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
isWU() {
|
|
1860
|
+
return !!this.WUID;
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
isDatabomb() {
|
|
1864
|
+
return !!this.databomb;
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
getQualifiedID() {
|
|
1868
|
+
return this.id;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
getOutputs() {
|
|
1872
|
+
return this._outputs;
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
getUpdatesVisualizations() {
|
|
1876
|
+
const retVal = [];
|
|
1877
|
+
for (const key in this._outputs) {
|
|
1878
|
+
this._outputs[key].getUpdatesVisualizations().forEach(function (visualization) {
|
|
1879
|
+
retVal.push(visualization);
|
|
1880
|
+
});
|
|
1881
|
+
}
|
|
1882
|
+
return retVal;
|
|
1883
|
+
}
|
|
1884
|
+
|
|
1885
|
+
accept(visitor) {
|
|
1886
|
+
visitor.visit(this);
|
|
1887
|
+
for (const key in this._outputs) {
|
|
1888
|
+
this._outputs[key].accept(visitor);
|
|
1889
|
+
}
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1892
|
+
calcRequest(request, fillInMissing) {
|
|
1893
|
+
const retVal = {};
|
|
1894
|
+
this.filters.forEach(function (item) {
|
|
1895
|
+
item.calcRequest(retVal, request, fillInMissing);
|
|
1896
|
+
});
|
|
1897
|
+
// TODO - Workaround HIPIE issue where it omits filters at datasource level ---
|
|
1898
|
+
this._outputArray.forEach(function (output) {
|
|
1899
|
+
output.filters.forEach(function (item) {
|
|
1900
|
+
item.calcRequest(retVal, request, fillInMissing);
|
|
1901
|
+
});
|
|
1902
|
+
});
|
|
1903
|
+
return retVal;
|
|
1904
|
+
}
|
|
1905
|
+
|
|
1906
|
+
fetchData(request, updates) {
|
|
1907
|
+
const myTransactionID = ++transactionID;
|
|
1908
|
+
transactionQueue.push(myTransactionID);
|
|
1909
|
+
|
|
1910
|
+
let dsRequest = request;
|
|
1911
|
+
dsRequest = this.calcRequest(request, this.isRoxie());
|
|
1912
|
+
dsRequest.refresh = request.refresh || false;
|
|
1913
|
+
if ((window as any).__hpcc_debug) {
|
|
1914
|
+
console.warn("fetchData: " + JSON.stringify(updates) + "(" + JSON.stringify(request) + ")");
|
|
1915
|
+
}
|
|
1916
|
+
for (const key in dsRequest) {
|
|
1917
|
+
if (dsRequest[key] === undefined) {
|
|
1918
|
+
delete dsRequest[key];
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
const now = Date.now();
|
|
1922
|
+
this.marshaller.commsEvent(this, "request", dsRequest);
|
|
1923
|
+
const context = this;
|
|
1924
|
+
return new Promise(function (resolve, reject) {
|
|
1925
|
+
context.comms.call(dsRequest).then(function (_response) {
|
|
1926
|
+
const response = JSON.parse(JSON.stringify(_response));
|
|
1927
|
+
const intervalHandle = setInterval(function () {
|
|
1928
|
+
if (transactionQueue[0] === myTransactionID && Date.now() - now >= 500) { // 500 is to allow for all "clear" transitions to complete...
|
|
1929
|
+
clearTimeout(intervalHandle);
|
|
1930
|
+
context.processResponse(response, dsRequest, updates).then(function () {
|
|
1931
|
+
transactionQueue.shift();
|
|
1932
|
+
resolve(response);
|
|
1933
|
+
context.marshaller.commsEvent(context, "response", dsRequest, response);
|
|
1934
|
+
++context._loadedCount;
|
|
1935
|
+
});
|
|
1936
|
+
}
|
|
1937
|
+
}, 100);
|
|
1938
|
+
}).catch(function (e) {
|
|
1939
|
+
context.marshaller.commsEvent(context, "error", dsRequest, e);
|
|
1940
|
+
reject(e);
|
|
1941
|
+
});
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
processResponse(response, request, updates) {
|
|
1946
|
+
const lowerResponse = {};
|
|
1947
|
+
for (const responseKey in response) {
|
|
1948
|
+
lowerResponse[responseKey.toLowerCase()] = response[responseKey];
|
|
1949
|
+
}
|
|
1950
|
+
const promises = [];
|
|
1951
|
+
for (const key in this._outputs) {
|
|
1952
|
+
const from = this._outputs[key].id;
|
|
1953
|
+
if (Utility.exists(from, response)) {
|
|
1954
|
+
if (!Utility.exists(from + _CHANGED, response) || (Utility.exists(from + _CHANGED, response) && response[from + _CHANGED].length && response[from + _CHANGED][0][from + _CHANGED])) {
|
|
1955
|
+
promises.push(this._outputs[key].setData(response[from], updates));
|
|
1956
|
+
} else {
|
|
1957
|
+
// TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
|
|
1958
|
+
promises.push(this._outputs[key].vizNotify(updates));
|
|
1959
|
+
}
|
|
1960
|
+
} else if (Utility.exists(from, lowerResponse)) {
|
|
1961
|
+
console.warn("DDL 'Datasource.From' case is Incorrect");
|
|
1962
|
+
if (!Utility.exists(from + _CHANGED, lowerResponse) || (Utility.exists(from + _CHANGED, lowerResponse) && response[from + _CHANGED].length && lowerResponse[from + _CHANGED][0][from + _CHANGED])) {
|
|
1963
|
+
promises.push(this._outputs[key].setData(lowerResponse[from], updates));
|
|
1964
|
+
} else {
|
|
1965
|
+
// TODO - I Suspect there is a HIPIE/Roxie issue here (empty request)
|
|
1966
|
+
promises.push(this._outputs[key].vizNotify(updates));
|
|
1967
|
+
}
|
|
1968
|
+
} else {
|
|
1969
|
+
const responseItems = [];
|
|
1970
|
+
for (const responseKey2 in response) {
|
|
1971
|
+
responseItems.push(responseKey2);
|
|
1972
|
+
}
|
|
1973
|
+
console.warn("Unable to locate '" + from + "' in response {" + responseItems.join(", ") + "}");
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1976
|
+
return Promise.all(promises);
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
isLoaded() {
|
|
1980
|
+
return this._loadedCount > 0;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
serializeState() {
|
|
1984
|
+
return {
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
deserializeState(state) {
|
|
1989
|
+
if (!state) return;
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
|
|
1993
|
+
// Dashboard ---
|
|
1994
|
+
export function Dashboard(this: any, marshaller, dashboard, proxyMappings, timeout?) {
|
|
1995
|
+
this.marshaller = marshaller;
|
|
1996
|
+
this.id = dashboard.id;
|
|
1997
|
+
this.title = dashboard.title;
|
|
1998
|
+
|
|
1999
|
+
this._datasources = {};
|
|
2000
|
+
this._datasourceArray = [];
|
|
2001
|
+
this._datasourceTotal = 0;
|
|
2002
|
+
if (dashboard.datasources) {
|
|
2003
|
+
dashboard.datasources.forEach(item => {
|
|
2004
|
+
this.createDatasource(item, proxyMappings, timeout);
|
|
2005
|
+
});
|
|
2006
|
+
}
|
|
2007
|
+
this._datasourceTotal = this._datasourceArray.length;
|
|
2008
|
+
|
|
2009
|
+
this._visualizations = {};
|
|
2010
|
+
this._visualizationArray = [];
|
|
2011
|
+
dashboard.visualizations.forEach(item => {
|
|
2012
|
+
this.createVisualization(item);
|
|
2013
|
+
});
|
|
2014
|
+
this._visualizationTotal = this._visualizationArray.length;
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
Dashboard.prototype.createDatasource = function (ddlDatasouce) {
|
|
2018
|
+
let retVal = this._datasources[ddlDatasouce.id];
|
|
2019
|
+
if (!retVal) {
|
|
2020
|
+
retVal = this.marshaller.createDatasource(ddlDatasouce);
|
|
2021
|
+
this._datasources[ddlDatasouce.id] = retVal;
|
|
2022
|
+
this._datasourceArray.push(retVal);
|
|
2023
|
+
}
|
|
2024
|
+
this._datasourceTotal = this._datasourceArray.length;
|
|
2025
|
+
return retVal;
|
|
2026
|
+
};
|
|
2027
|
+
|
|
2028
|
+
Dashboard.prototype.createVisualization = function (ddlVisualization, parentVisualization) {
|
|
2029
|
+
const retVal = new Visualization(this, ddlVisualization, parentVisualization);
|
|
2030
|
+
this._visualizations[ddlVisualization.id] = retVal;
|
|
2031
|
+
this._visualizationArray.push(retVal);
|
|
2032
|
+
this.marshaller.appendVisualization(retVal);
|
|
2033
|
+
return retVal;
|
|
2034
|
+
};
|
|
2035
|
+
|
|
2036
|
+
Dashboard.prototype.loadedPromise = function () {
|
|
2037
|
+
return Promise.all(this._visualizationArray.map(function (visualization) { return visualization.loadedPromise(); }));
|
|
2038
|
+
};
|
|
2039
|
+
|
|
2040
|
+
Dashboard.prototype.getQualifiedID = function () {
|
|
2041
|
+
return this.id;
|
|
2042
|
+
};
|
|
2043
|
+
|
|
2044
|
+
Dashboard.prototype.getDatasources = function () {
|
|
2045
|
+
return this._datasources;
|
|
2046
|
+
};
|
|
2047
|
+
|
|
2048
|
+
Dashboard.prototype.getDatasourceArray = function () {
|
|
2049
|
+
return this._datasourceArray;
|
|
2050
|
+
};
|
|
2051
|
+
|
|
2052
|
+
Dashboard.prototype.getDatasource = function (id) {
|
|
2053
|
+
return this._datasources[id] || this.marshaller.getDatasource(id);
|
|
2054
|
+
};
|
|
2055
|
+
|
|
2056
|
+
Dashboard.prototype.getDataSourceArray = function () {
|
|
2057
|
+
return this._datasourceArray;
|
|
2058
|
+
};
|
|
2059
|
+
|
|
2060
|
+
Dashboard.prototype.getVisualization = function (id) {
|
|
2061
|
+
return this._visualizations[id] || this.marshaller.getVisualization(id);
|
|
2062
|
+
};
|
|
2063
|
+
|
|
2064
|
+
Dashboard.prototype.getVisualizations = function () {
|
|
2065
|
+
return this._visualizations;
|
|
2066
|
+
};
|
|
2067
|
+
|
|
2068
|
+
Dashboard.prototype.getVisualizationArray = function () {
|
|
2069
|
+
return this._visualizationArray;
|
|
2070
|
+
};
|
|
2071
|
+
|
|
2072
|
+
Dashboard.prototype.getVisualizationTotal = function () {
|
|
2073
|
+
return this._visualizationTotal;
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2076
|
+
Dashboard.prototype.accept = function (visitor) {
|
|
2077
|
+
visitor.visit(this);
|
|
2078
|
+
for (const key in this._datasources) {
|
|
2079
|
+
this._datasources[key].accept(visitor);
|
|
2080
|
+
}
|
|
2081
|
+
this._visualizationArray.forEach(function (item) {
|
|
2082
|
+
item.accept(visitor);
|
|
2083
|
+
}, this);
|
|
2084
|
+
};
|
|
2085
|
+
|
|
2086
|
+
Dashboard.prototype.primeData = function (state) {
|
|
2087
|
+
const fetchDataOptimizer = new VisualizationRequestOptimizer(true);
|
|
2088
|
+
this.getVisualizationArray().forEach(function (visualization) {
|
|
2089
|
+
// Clear all charts back to their default values ---
|
|
2090
|
+
visualization.clear();
|
|
2091
|
+
visualization.update();
|
|
2092
|
+
if (state && state[visualization.id]) {
|
|
2093
|
+
if (Utility.exists("source.mappings.mappings", visualization)) {
|
|
2094
|
+
for (const key in visualization.source.mappings.mappings) {
|
|
2095
|
+
if (state[visualization.id][visualization.source.mappings.mappings[key]]) {
|
|
2096
|
+
visualization._widgetState.row[key] = state[visualization.id][visualization.source.mappings.mappings[key]];
|
|
2097
|
+
visualization._widgetState.selected = true;
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
});
|
|
2103
|
+
this.getVisualizationArray().forEach(function (visualization) {
|
|
2104
|
+
const inputVisualizations = visualization.getInputVisualizations();
|
|
2105
|
+
const datasource = visualization.source.getDatasource();
|
|
2106
|
+
let hasInputSelection = false;
|
|
2107
|
+
inputVisualizations.forEach(function (inViz) {
|
|
2108
|
+
if (inViz.hasSelection()) {
|
|
2109
|
+
const request = inViz.calcRequestFor(visualization);
|
|
2110
|
+
request.refresh = true;
|
|
2111
|
+
fetchDataOptimizer.appendRequest(datasource, request, visualization);
|
|
2112
|
+
hasInputSelection = true;
|
|
2113
|
+
}
|
|
2114
|
+
});
|
|
2115
|
+
if (!hasInputSelection && ((datasource && datasource.isRoxie()) || inputVisualizations.length === 0)) {
|
|
2116
|
+
fetchDataOptimizer.appendRequest(datasource, { refresh: true }, visualization);
|
|
2117
|
+
}
|
|
2118
|
+
});
|
|
2119
|
+
return fetchDataOptimizer.fetchData();
|
|
2120
|
+
};
|
|
2121
|
+
|
|
2122
|
+
Dashboard.prototype.serializeState = function () {
|
|
2123
|
+
const retVal = {
|
|
2124
|
+
datasources: {},
|
|
2125
|
+
visualizations: {}
|
|
2126
|
+
};
|
|
2127
|
+
for (const key in this._datasources) {
|
|
2128
|
+
retVal.datasources[key] = this._datasources[key].serializeState();
|
|
2129
|
+
}
|
|
2130
|
+
for (const vizKey in this._visualizations) {
|
|
2131
|
+
retVal.visualizations[vizKey] = this._visualizations[vizKey].serializeState();
|
|
2132
|
+
}
|
|
2133
|
+
return retVal;
|
|
2134
|
+
};
|
|
2135
|
+
|
|
2136
|
+
Dashboard.prototype.deserializeState = function (state) {
|
|
2137
|
+
if (!state) return;
|
|
2138
|
+
for (const key in this._datasources) {
|
|
2139
|
+
if (state.datasources[key]) {
|
|
2140
|
+
this._datasources[key].deserializeState(state.datasources[key]);
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
for (const vizKey in this._visualizations) {
|
|
2144
|
+
if (state.visualizations[vizKey]) {
|
|
2145
|
+
this._visualizations[vizKey].deserializeState(state.visualizations[vizKey]);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
};
|
|
2149
|
+
|
|
2150
|
+
// Marshaller ---
|
|
2151
|
+
export function Marshaller(this: any) {
|
|
2152
|
+
Class.call(this);
|
|
2153
|
+
|
|
2154
|
+
this._proxyMappings = {};
|
|
2155
|
+
this._widgetMappings = d3Map();
|
|
2156
|
+
this._clearDataOnUpdate = true;
|
|
2157
|
+
this._propogateClear = false;
|
|
2158
|
+
this.id = "Marshaller";
|
|
2159
|
+
this._missingDataString = "";
|
|
2160
|
+
this.dashboards = {};
|
|
2161
|
+
this.dashboardArray = [];
|
|
2162
|
+
|
|
2163
|
+
this._datasources = {};
|
|
2164
|
+
this._datasourceArray = [];
|
|
2165
|
+
this._visualizations = {};
|
|
2166
|
+
this._visualizationArray = [];
|
|
2167
|
+
}
|
|
2168
|
+
Marshaller.prototype = Object.create(Class.prototype);
|
|
2169
|
+
Marshaller.prototype.constructor = Marshaller;
|
|
2170
|
+
|
|
2171
|
+
Marshaller.prototype.commsDataLoaded = function () {
|
|
2172
|
+
for (let i = 0; i < this.dashboardArray.length; i++) {
|
|
2173
|
+
for (const ds in this.dashboardArray[i].getDatasources()) {
|
|
2174
|
+
if (!this.dashboardArray[i].getDatasource(ds).isLoaded()) {
|
|
2175
|
+
return false;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
return true;
|
|
2180
|
+
};
|
|
2181
|
+
|
|
2182
|
+
Marshaller.prototype.accept = function (visitor) {
|
|
2183
|
+
visitor.visit(this);
|
|
2184
|
+
for (const key2 in this._datasources) {
|
|
2185
|
+
this._datasources[key2].accept(visitor);
|
|
2186
|
+
}
|
|
2187
|
+
this.dashboardTotal = 0;
|
|
2188
|
+
for (const key in this.dashboards) {
|
|
2189
|
+
this.dashboards[key].accept(visitor);
|
|
2190
|
+
++this.dashboardTotal;
|
|
2191
|
+
}
|
|
2192
|
+
};
|
|
2193
|
+
|
|
2194
|
+
Marshaller.prototype.url = function (url, callback) {
|
|
2195
|
+
this.espUrl = new Comms.ESPUrl()
|
|
2196
|
+
.url(url)
|
|
2197
|
+
;
|
|
2198
|
+
let transport = null;
|
|
2199
|
+
let hipieResultName = "HIPIE_DDL";
|
|
2200
|
+
if (this.espUrl.isWorkunitResult()) {
|
|
2201
|
+
hipieResultName = this.espUrl.param("ResultName");
|
|
2202
|
+
transport = new Comms.HIPIEWorkunit()
|
|
2203
|
+
.url(url)
|
|
2204
|
+
.proxyMappings(this._proxyMappings)
|
|
2205
|
+
.timeout(this._timeout)
|
|
2206
|
+
;
|
|
2207
|
+
} else {
|
|
2208
|
+
transport = new Comms.HIPIERoxie()
|
|
2209
|
+
.url(url)
|
|
2210
|
+
.proxyMappings(this._proxyMappings)
|
|
2211
|
+
.timeout(this._timeout)
|
|
2212
|
+
;
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
const context = this;
|
|
2216
|
+
transport.fetchResults().then(function (response) {
|
|
2217
|
+
if (Utility.exists(hipieResultName, response)) {
|
|
2218
|
+
return transport.fetchResult(hipieResultName).then(function (ddlResponse) {
|
|
2219
|
+
const json = ddlResponse[0][hipieResultName];
|
|
2220
|
+
context.parse(json, function () {
|
|
2221
|
+
callback(response);
|
|
2222
|
+
});
|
|
2223
|
+
}).catch(function (e) {
|
|
2224
|
+
context.commsEvent(context, "error", hipieResultName, e);
|
|
2225
|
+
});
|
|
2226
|
+
}
|
|
2227
|
+
}).catch(function (e) {
|
|
2228
|
+
context.commsEvent(context, "error", "fetchResults", e);
|
|
2229
|
+
});
|
|
2230
|
+
};
|
|
2231
|
+
|
|
2232
|
+
Marshaller.prototype.proxyMappings = function (_) {
|
|
2233
|
+
if (!arguments.length) return this._proxyMappings;
|
|
2234
|
+
this._proxyMappings = _;
|
|
2235
|
+
return this;
|
|
2236
|
+
};
|
|
2237
|
+
|
|
2238
|
+
Marshaller.prototype.timeout = function (_) {
|
|
2239
|
+
if (!arguments.length) return this._timeout;
|
|
2240
|
+
this._timeout = _;
|
|
2241
|
+
return this;
|
|
2242
|
+
};
|
|
2243
|
+
|
|
2244
|
+
Marshaller.prototype.widgetMappings = function (_) {
|
|
2245
|
+
if (!arguments.length) return this._widgetMappings;
|
|
2246
|
+
this._widgetMappings = _;
|
|
2247
|
+
return this;
|
|
2248
|
+
};
|
|
2249
|
+
|
|
2250
|
+
Marshaller.prototype.clearDataOnUpdate = function (_) {
|
|
2251
|
+
if (!arguments.length) return this._clearDataOnUpdate;
|
|
2252
|
+
this._clearDataOnUpdate = _;
|
|
2253
|
+
return this;
|
|
2254
|
+
};
|
|
2255
|
+
|
|
2256
|
+
Marshaller.prototype.propogateClear = function (_) {
|
|
2257
|
+
if (!arguments.length) return this._propogateClear;
|
|
2258
|
+
this._propogateClear = _;
|
|
2259
|
+
return this;
|
|
2260
|
+
};
|
|
2261
|
+
|
|
2262
|
+
Marshaller.prototype.missingDataString = function (_) {
|
|
2263
|
+
if (!arguments.length) return this._missingDataString;
|
|
2264
|
+
this._missingDataString = _;
|
|
2265
|
+
return this;
|
|
2266
|
+
};
|
|
2267
|
+
|
|
2268
|
+
Marshaller.prototype.parse = function (json, callback) {
|
|
2269
|
+
const context = this;
|
|
2270
|
+
this._json = json;
|
|
2271
|
+
this._jsonParsed = JSON.parse(this._json);
|
|
2272
|
+
|
|
2273
|
+
// Global Datasources ---
|
|
2274
|
+
this._datasources = {};
|
|
2275
|
+
this._datasourceArray = [];
|
|
2276
|
+
if (this._jsonParsed.datasources) {
|
|
2277
|
+
this._jsonParsed.datasources.forEach(function (item) {
|
|
2278
|
+
context.createDatasource(item);
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
this.dashboards = {};
|
|
2283
|
+
this.dashboardArray = [];
|
|
2284
|
+
this._visualizations = {};
|
|
2285
|
+
this._visualizationArray = [];
|
|
2286
|
+
const dashboards = this._jsonParsed.dashboards || this._jsonParsed;
|
|
2287
|
+
dashboards.forEach(function (item) {
|
|
2288
|
+
const newDashboard = new Dashboard(context, item, context._proxyMappings, context._timeout);
|
|
2289
|
+
context.dashboards[item.id] = newDashboard;
|
|
2290
|
+
context.dashboardArray.push(newDashboard);
|
|
2291
|
+
});
|
|
2292
|
+
this.dashboardTotal = this.dashboardArray.length;
|
|
2293
|
+
this._visualizationArray.forEach(function (ddlViz) {
|
|
2294
|
+
ddlViz.on("processEvent", function (eventID, event, row, col, selected) {
|
|
2295
|
+
context.vizEvent(ddlViz.widget, eventID, row, col, selected);
|
|
2296
|
+
});
|
|
2297
|
+
});
|
|
2298
|
+
this._datasourceTotal = this._datasourceArray.length;
|
|
2299
|
+
|
|
2300
|
+
this.ready(callback);
|
|
2301
|
+
return this;
|
|
2302
|
+
};
|
|
2303
|
+
|
|
2304
|
+
Marshaller.prototype.dashboardsLoaded = function () {
|
|
2305
|
+
return Promise.all(this.dashboardArray.map(function (dashboard) { return dashboard.loadedPromise(); }));
|
|
2306
|
+
};
|
|
2307
|
+
|
|
2308
|
+
Marshaller.prototype.createDatasource = function (ddlDatasouce: DDL1.IAnyDatasource) {
|
|
2309
|
+
let retVal = this._datasources[ddlDatasouce.id];
|
|
2310
|
+
if (!retVal) {
|
|
2311
|
+
retVal = new Datasource(this, ddlDatasouce, this._proxyMappings, this._timeout);
|
|
2312
|
+
this._datasources[ddlDatasouce.id] = retVal;
|
|
2313
|
+
this._datasourceArray.push(retVal);
|
|
2314
|
+
}
|
|
2315
|
+
this._datasourceTotal = this._datasourceArray.length;
|
|
2316
|
+
return retVal;
|
|
2317
|
+
};
|
|
2318
|
+
|
|
2319
|
+
Marshaller.prototype.getDatasource = function (id) {
|
|
2320
|
+
return this._datasources[id];
|
|
2321
|
+
};
|
|
2322
|
+
|
|
2323
|
+
Marshaller.prototype.getDatasources = function () {
|
|
2324
|
+
return this._datasources;
|
|
2325
|
+
};
|
|
2326
|
+
|
|
2327
|
+
Marshaller.prototype.getDatasourceArray = function () {
|
|
2328
|
+
return this._datasourceArray;
|
|
2329
|
+
};
|
|
2330
|
+
|
|
2331
|
+
Marshaller.prototype.appendVisualization = function (visualization) {
|
|
2332
|
+
this._visualizations[visualization.id] = visualization;
|
|
2333
|
+
this._visualizationArray.push(visualization);
|
|
2334
|
+
};
|
|
2335
|
+
|
|
2336
|
+
Marshaller.prototype.getVisualization = function (id) {
|
|
2337
|
+
return this._visualizations[id];
|
|
2338
|
+
};
|
|
2339
|
+
|
|
2340
|
+
Marshaller.prototype.appendDataSource = function (datasource) {
|
|
2341
|
+
this._datasources[datasource.id] = datasource;
|
|
2342
|
+
this._datasourceArray.push(datasource);
|
|
2343
|
+
};
|
|
2344
|
+
|
|
2345
|
+
Marshaller.prototype.getVisualizations = function () {
|
|
2346
|
+
return this._visualizations;
|
|
2347
|
+
};
|
|
2348
|
+
|
|
2349
|
+
Marshaller.prototype.getVisualizationArray = function () {
|
|
2350
|
+
return this._visualizationArray;
|
|
2351
|
+
};
|
|
2352
|
+
|
|
2353
|
+
Marshaller.prototype.getWidget = function (id) {
|
|
2354
|
+
return this._widgetMappings.get(id);
|
|
2355
|
+
};
|
|
2356
|
+
|
|
2357
|
+
Marshaller.prototype.on = function (eventID, func) {
|
|
2358
|
+
const context = this;
|
|
2359
|
+
this.overrideMethod(eventID, function (origFunc, args) {
|
|
2360
|
+
const retVal = origFunc.apply(context, args);
|
|
2361
|
+
return func.apply(context, args) || retVal;
|
|
2362
|
+
});
|
|
2363
|
+
return this;
|
|
2364
|
+
};
|
|
2365
|
+
|
|
2366
|
+
Marshaller.prototype.ready = function (callback) {
|
|
2367
|
+
if (!callback) {
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2370
|
+
this.dashboardsLoaded().then(function () {
|
|
2371
|
+
callback();
|
|
2372
|
+
});
|
|
2373
|
+
};
|
|
2374
|
+
|
|
2375
|
+
Marshaller.prototype.vizEvent = function (sourceWidget, eventID, row, col, selected) {
|
|
2376
|
+
console.warn("Marshaller.vizEvent: " + sourceWidget.id() + "-" + eventID);
|
|
2377
|
+
};
|
|
2378
|
+
|
|
2379
|
+
Marshaller.prototype.commsEvent = function (ddlSource, eventID, request, response) {
|
|
2380
|
+
switch (eventID) {
|
|
2381
|
+
case "request":
|
|
2382
|
+
if ((window as any).__hpcc_debug) {
|
|
2383
|
+
console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(request));
|
|
2384
|
+
}
|
|
2385
|
+
break;
|
|
2386
|
+
case "response":
|
|
2387
|
+
case "error":
|
|
2388
|
+
if ((window as any).__hpcc_debug) {
|
|
2389
|
+
console.warn("Marshaller.commsEvent: " + ddlSource.id + "-" + eventID + ": " + JSON.stringify(response));
|
|
2390
|
+
}
|
|
2391
|
+
break;
|
|
2392
|
+
default:
|
|
2393
|
+
if ((window as any).__hpcc_debug) {
|
|
2394
|
+
console.warn("Marshaller.commsEvent: " + JSON.stringify(arguments));
|
|
2395
|
+
}
|
|
2396
|
+
break;
|
|
2397
|
+
|
|
2398
|
+
}
|
|
2399
|
+
};
|
|
2400
|
+
|
|
2401
|
+
Marshaller.prototype.createDatabomb = function () {
|
|
2402
|
+
const retVal = {};
|
|
2403
|
+
this.dashboardArray.forEach(function (dashboard) {
|
|
2404
|
+
for (const key in dashboard.getDatasources()) {
|
|
2405
|
+
const comms = dashboard.getDatasource(key).comms;
|
|
2406
|
+
retVal[key] = {};
|
|
2407
|
+
for (const key2 in comms._hipieResults) {
|
|
2408
|
+
const hipieResult = comms._hipieResults[key2];
|
|
2409
|
+
retVal[key][key2] = comms._resultNameCache[hipieResult.from];
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2413
|
+
return retVal;
|
|
2414
|
+
};
|
|
2415
|
+
|
|
2416
|
+
Marshaller.prototype.primeData = function (state) {
|
|
2417
|
+
const promises = this.dashboardArray.map(function (dashboard) {
|
|
2418
|
+
return dashboard.primeData(state);
|
|
2419
|
+
});
|
|
2420
|
+
return Promise.all(promises);
|
|
2421
|
+
};
|
|
2422
|
+
|
|
2423
|
+
Marshaller.prototype.serializeState = function () {
|
|
2424
|
+
const retVal = {};
|
|
2425
|
+
this.dashboardArray.forEach(function (dashboard, idx) {
|
|
2426
|
+
retVal[dashboard.id] = dashboard.serializeState();
|
|
2427
|
+
});
|
|
2428
|
+
return retVal;
|
|
2429
|
+
};
|
|
2430
|
+
|
|
2431
|
+
Marshaller.prototype.deserializeState = function (state) {
|
|
2432
|
+
if (!state) return;
|
|
2433
|
+
this.dashboardArray.forEach(function (dashboard, idx) {
|
|
2434
|
+
dashboard.deserializeState(state[dashboard.id]);
|
|
2435
|
+
});
|
|
2436
|
+
return this;
|
|
2437
|
+
};
|