Revize 583f8755
Přidáno uživatelem Štěpán Červenka před téměř 4 roky(ů)
src/app/shared/graph-loading/emptygraph.ts | ||
---|---|---|
2 | 2 |
|
3 | 3 |
declare var require: any |
4 | 4 |
|
5 |
/** |
|
6 |
* A graph with no sensors to display |
|
7 |
*/ |
|
5 | 8 |
export class EmptyGraph implements Graph{ |
6 | 9 |
|
10 |
/** |
|
11 |
* Message in the middle of the graph |
|
12 |
*/ |
|
7 | 13 |
message: string; |
8 | 14 |
|
9 | 15 |
constructor(message) { |
10 | 16 |
this.message = message; |
11 | 17 |
} |
12 | 18 |
|
13 |
|
|
19 |
/** |
|
20 |
* Returns vega configuration |
|
21 |
*/ |
|
14 | 22 |
getConfig(): {} { |
15 | 23 |
return require('/src/vega/config/config.json'); |
16 | 24 |
} |
17 | 25 |
|
26 |
/** |
|
27 |
* Returns vega specification |
|
28 |
*/ |
|
18 | 29 |
getSpec(): {} { |
19 | 30 |
const lodash = require('lodash/object'); |
20 | 31 |
const rvalue: any = {}; |
... | ... | |
24 | 35 |
return rvalue; |
25 | 36 |
} |
26 | 37 |
|
27 |
setData(spec, data) { |
|
28 |
//DO NOTHING |
|
29 |
} |
|
30 |
|
|
31 |
setLegendInfo(spec, legend) { |
|
32 |
//DO NOTHING |
|
33 |
} |
|
34 |
|
|
35 | 38 |
} |
src/app/shared/graph-loading/graph.ts | ||
---|---|---|
1 | 1 |
export interface Graph { |
2 |
/** |
|
3 |
* Gets vega specification |
|
4 |
*/ |
|
2 | 5 |
getSpec(): {}, |
6 |
|
|
7 |
/** |
|
8 |
* Gets vega configuration |
|
9 |
*/ |
|
3 | 10 |
getConfig(): {} |
4 | 11 |
} |
src/app/shared/graph-loading/graphloader.ts | ||
---|---|---|
9 | 9 |
|
10 | 10 |
export class GraphLoader { |
11 | 11 |
|
12 |
/** |
|
13 |
* Loads graph with default interval value (e.g. for observation service) |
|
14 |
* @param sensors array of sensors to display |
|
15 |
* @param data source of values for vega graph |
|
16 |
* @param legendInfo source of legend info for graph (e.g. sensor phenomenon) |
|
17 |
* @param element name of html element for graph display |
|
18 |
* @param isAnalytics true/false analytics/observations |
|
19 |
*/ |
|
20 |
static getGraph(sensors, data, legendInfo, element, isAnalytics) { |
|
21 |
this.getGraphWithInterval(sensors, data, 1800000, legendInfo, element, isAnalytics); |
|
22 |
} |
|
23 |
|
|
24 |
|
|
25 |
|
|
26 |
/** |
|
27 |
* Loads graph with specified interval (e.g. for analytics service) |
|
28 |
* @param sensors array of sensors to display |
|
29 |
* @param data source of values for vega graph |
|
30 |
* @param interval default graph interval used for different purposes (in milliseconds) (see timeWindow and maxTimeDifference in vega specification) |
|
31 |
* @param legendInfo source of legend info for graph (e.g. sensor phenomenon) |
|
32 |
* @param element name of html element for graph display |
|
33 |
* @param isAnalytics true/false analytics/observations |
|
34 |
*/ |
|
35 |
static getGraphWithInterval(sensors, data, interval, legendInfo, element, isAnalytics) { |
|
36 |
//gets uses sensors array to get graph type |
|
37 |
//then gets configuration and specification from corresponding class |
|
38 |
let graph = this.getGraphType(sensors,data, interval, legendInfo, isAnalytics); |
|
39 |
let config = graph.getConfig(); |
|
40 |
let spec = graph.getSpec(); |
|
41 |
|
|
42 |
//then displays the graph |
|
43 |
this.showGraph(spec, config, element); |
|
44 |
} |
|
45 |
|
|
12 | 46 |
|
13 |
static getGraphType(sensors, data, interval, legend, isAnalytics): Graph { |
|
47 |
/** |
|
48 |
* Create graph of specific type according to selected sensors |
|
49 |
* @param sensors array of sensors to display |
|
50 |
* @param data source of values for vega graph |
|
51 |
* @param interval default graph interval used for different purposes (in milliseconds) (see timeWindow and maxTimeDifference in vega specification) |
|
52 |
* @param legendInfo source of legend info for graph (e.g. sensor phenomenon) |
|
53 |
* @param isAnalytics isAnalytics true/false analytics/observations |
|
54 |
*/ |
|
55 |
static getGraphType(sensors, data, interval, legendInfo, isAnalytics): Graph { |
|
14 | 56 |
if (sensors == null) { |
15 | 57 |
return new EmptyGraph("No sensors selected."); |
16 | 58 |
|
... | ... | |
18 | 60 |
if (sensors.length == 0) { |
19 | 61 |
return new EmptyGraph("No sensors selected."); |
20 | 62 |
} else if (sensors.length == 1) { |
21 |
return new SingleGraph(sensors[0], isAnalytics, data, legend,interval); |
|
63 |
return new SingleGraph(sensors[0], isAnalytics, data, legendInfo,interval);
|
|
22 | 64 |
} else { |
23 |
return new MultiGraph(isAnalytics, data, legend,interval); |
|
65 |
return new MultiGraph(isAnalytics, data, legendInfo,interval);
|
|
24 | 66 |
} |
25 | 67 |
|
26 | 68 |
} else { |
27 |
return new SingleGraph(sensors, isAnalytics, data, legend, interval); |
|
69 |
return new SingleGraph(sensors, isAnalytics, data, legendInfo, interval);
|
|
28 | 70 |
} |
29 | 71 |
} |
30 | 72 |
|
31 | 73 |
|
32 |
static getGraphWithInterval(sensors, data, interval, legendInfo, element, isAnalytics) { |
|
33 |
let graph = this.getGraphType(sensors,data, interval, legendInfo, isAnalytics); |
|
34 |
let config = graph.getConfig(); |
|
35 |
let spec = graph.getSpec(); |
|
36 |
|
|
37 |
|
|
38 |
this.showGraph(spec, config, element); |
|
39 |
} |
|
40 |
|
|
41 |
static getGraph(sensors, data, legendInfo, element, isAnalytics) { |
|
42 |
this.getGraphWithInterval(sensors, data, 1800000, legendInfo, element, isAnalytics); |
|
43 |
} |
|
44 |
|
|
45 |
|
|
74 |
/** |
|
75 |
* Displays the graph |
|
76 |
* @param spec vega specification |
|
77 |
* @param config vega configuration |
|
78 |
* @param element name of html element for graph display |
|
79 |
*/ |
|
46 | 80 |
static showGraph(spec, config, element) { |
47 | 81 |
const vega = require('vega'); |
48 | 82 |
const vegaTooltip = require('vega-tooltip'); |
src/app/shared/graph-loading/multigraph.ts | ||
---|---|---|
2 | 2 |
|
3 | 3 |
declare var require: any |
4 | 4 |
|
5 |
/** |
|
6 |
* Graph with multiple sensors. (Only linechart) |
|
7 |
*/ |
|
5 | 8 |
export class MultiGraph implements Graph{ |
6 | 9 |
|
10 |
|
|
7 | 11 |
isAnalytics: boolean; |
8 | 12 |
data: any []; |
9 | 13 |
interval: number; |
10 | 14 |
legend: {}; |
11 | 15 |
|
16 |
/** |
|
17 |
* Instantiates new multigraph |
|
18 |
* @param isAnalytics true/false analytics/observations |
|
19 |
* @param data source of values for vega graph |
|
20 |
* @param legend source of legend for graph (e.g. sensors phenomenon) |
|
21 |
* @param interval default graph interval used for different purposes (in milliseconds) (see timeWindow and maxTimeDifference in vega specification) |
|
22 |
*/ |
|
12 | 23 |
constructor(isAnalytics: boolean, data: any [], legend: {}, interval: number) { |
13 | 24 |
this.isAnalytics = isAnalytics; |
14 | 25 |
this.data = data; |
... | ... | |
17 | 28 |
|
18 | 29 |
} |
19 | 30 |
|
20 |
|
|
31 |
/** |
|
32 |
* Returns vega configuration (see readme.txt in vega folder) |
|
33 |
*/ |
|
21 | 34 |
getConfig(): {} { |
35 |
//from folder vega/config merge corresponding files |
|
36 |
|
|
22 | 37 |
const lodash = require('lodash/object'); |
23 | 38 |
const rvalue: any = {}; |
24 | 39 |
let config1 = require('/src/vega/config/config.json'); |
... | ... | |
47 | 62 |
return rvalue; |
48 | 63 |
} |
49 | 64 |
|
65 |
|
|
66 |
/** |
|
67 |
* returns vega specification (see readme.txt in vega folder) |
|
68 |
*/ |
|
50 | 69 |
getSpec(): {} { |
51 | 70 |
const lodash = require('lodash/object'); |
52 | 71 |
const rvalue: any = {}; |
... | ... | |
57 | 76 |
|
58 | 77 |
lodash.merge(rvalue, base, body, legend, tooltip); |
59 | 78 |
|
60 |
rvalue.data[1].values = this.data;
|
|
79 |
//setting legend to result
|
|
61 | 80 |
rvalue.data[0].values = this.legend; |
81 |
|
|
82 |
//setting data to result |
|
83 |
rvalue.data[1].values = this.data; |
|
84 |
|
|
85 |
//setting interval to json |
|
86 |
//interval used for |
|
87 |
// 1) appending graph domain |
|
88 |
// 2) 5 * interval is max difference for connecting the dots |
|
89 |
// 3) setting zoom in windcharts |
|
62 | 90 |
rvalue.signals[0].value = this.interval; |
91 |
|
|
92 |
//setting tooltip message |
|
63 | 93 |
rvalue.marks[0].marks[0].marks[0].marks[2].encode.enter.tooltip.signal = this.getTooltipMessage(); |
64 | 94 |
|
65 | 95 |
return rvalue; |
66 | 96 |
} |
67 | 97 |
|
98 |
/** |
|
99 |
* Generates the tooltip message |
|
100 |
*/ |
|
68 | 101 |
private getTooltipMessage() { |
69 | 102 |
let message = "{title: timeFormat(datum.dateTime, '%A, %B %e, %Y %X')"; |
70 | 103 |
this.data.forEach(function (e) { |
... | ... | |
75 | 108 |
return message; |
76 | 109 |
} |
77 | 110 |
|
111 |
/** |
|
112 |
* If legend is array of phenomenons, it selects the first element |
|
113 |
* @param legend info for displaying legend |
|
114 |
*/ |
|
78 | 115 |
private getLegend(legend: any) { |
79 | 116 |
if(Array.isArray(legend)) { |
80 | 117 |
return legend[0]; |
src/app/shared/graph-loading/singlegraph.ts | ||
---|---|---|
3 | 3 |
|
4 | 4 |
declare var require: any |
5 | 5 |
|
6 |
/** |
|
7 |
* Graph with single sensors (linechart, barchart, windchart) |
|
8 |
*/ |
|
6 | 9 |
export class SingleGraph implements Graph { |
7 | 10 |
isAnalytics: boolean; |
8 | 11 |
sensorId: number; |
... | ... | |
11 | 14 |
legend: {}; |
12 | 15 |
type: SingleGraphType; |
13 | 16 |
|
17 |
/** |
|
18 |
* |
|
19 |
* @param sensorId id of sensor |
|
20 |
* @param isAnalytics true for analytics, false for observations |
|
21 |
* @param data source of values for vega graph |
|
22 |
* @param legend source of legend info for graph (e.g. sensor phenomenon) |
|
23 |
* @param interval default graph interval used for different purposes (in milliseconds) (see timeWindow and maxTimeDifference in vega specification) |
|
24 |
*/ |
|
14 | 25 |
constructor(sensorId: number, isAnalytics: boolean, data: any[], legend: {}, interval: number) { |
15 | 26 |
this.sensorId = sensorId; |
16 | 27 |
this.isAnalytics = isAnalytics; |
... | ... | |
21 | 32 |
|
22 | 33 |
} |
23 | 34 |
|
24 |
|
|
35 |
/** |
|
36 |
* Returns vega configuration (see readme.txt in vega folder) |
|
37 |
*/ |
|
25 | 38 |
getConfig(): {} { |
26 | 39 |
const lodash = require('lodash/object'); |
27 | 40 |
const rvalue: any = {}; |
... | ... | |
60 | 73 |
return rvalue; |
61 | 74 |
} |
62 | 75 |
|
76 |
/** |
|
77 |
* Gets vega specification (see readme.txt in vega folder) |
|
78 |
*/ |
|
63 | 79 |
getSpec(): {} { |
64 | 80 |
const lodash = require('lodash/object'); |
65 | 81 |
const rvalue: any = {}; |
... | ... | |
69 | 85 |
const tooltip = this.getTooltipSpec(); |
70 | 86 |
lodash.merge(rvalue, base, body, legend, tooltip); |
71 | 87 |
|
72 |
|
|
88 |
//setting data to result |
|
73 | 89 |
this.setData(rvalue, this.data); |
90 |
|
|
91 |
//setting legend to result |
|
74 | 92 |
rvalue['data'][0].values = this.legend; |
93 |
|
|
94 |
//setting interval to result |
|
75 | 95 |
rvalue.signals[0].value = this.interval; |
76 | 96 |
|
77 | 97 |
return rvalue; |
78 | 98 |
} |
79 | 99 |
|
80 |
|
|
100 |
/** |
|
101 |
* Gets legend specification (windchart does not have a legend) |
|
102 |
*/ |
|
81 | 103 |
private getLegendSpec() { |
82 | 104 |
switch (this.type) { |
83 | 105 |
case SingleGraphType.BARCHART: |
... | ... | |
88 | 110 |
} |
89 | 111 |
} |
90 | 112 |
|
113 |
/** |
|
114 |
* Gets body specification |
|
115 |
*/ |
|
91 | 116 |
private getBodySpec() { |
92 | 117 |
switch (this.type) { |
93 | 118 |
case SingleGraphType.BARCHART: |
... | ... | |
95 | 120 |
case SingleGraphType.WINDCHART: |
96 | 121 |
return require('/src/vega/body/windchart.json'); |
97 | 122 |
case SingleGraphType.LINECHART: |
98 |
//TODO pridat min/max |
|
99 | 123 |
return require('/src/vega/body/linechart.json'); |
100 | 124 |
} |
101 | 125 |
} |
102 | 126 |
|
103 | 127 |
|
128 |
/** |
|
129 |
* Get tooltip specification |
|
130 |
*/ |
|
104 | 131 |
private getTooltipSpec() { |
105 | 132 |
let lodash = require('lodash'); |
106 | 133 |
let tooltipMessage; |
... | ... | |
113 | 140 |
tooltipMessage = this.getValueTooltip(); |
114 | 141 |
} |
115 | 142 |
|
143 |
//sets the tooltip message |
|
116 | 144 |
rvalue.marks[0].marks[0].marks[0].encode.enter.tooltip.signal = tooltipMessage; |
117 | 145 |
return rvalue; |
118 | 146 |
} |
119 | 147 |
|
120 |
|
|
148 |
/** |
|
149 |
* |
|
150 |
*/ |
|
121 | 151 |
private getValueTooltip() { |
122 | 152 |
return "{title: timeFormat(datum.dateTime, '%A, %B %e, %Y %X') , 'value': datum.value + ' " + this.legend['phenomenon']['unit'] + "'}" |
123 | 153 |
} |
... | ... | |
131 | 161 |
} |
132 | 162 |
|
133 | 163 |
|
164 |
/** |
|
165 |
* Sets data to specification. If data is array, it selects only the first element |
|
166 |
* @param spec specification to insert into |
|
167 |
* @param data data to insert |
|
168 |
*/ |
|
134 | 169 |
private setData(spec: any, data: any) { |
135 | 170 |
if(data.length > 0 && 'data' in data[0]) { |
136 | 171 |
spec['data'][1].values = data[0].data; |
... | ... | |
139 | 174 |
} |
140 | 175 |
} |
141 | 176 |
|
177 |
/** |
|
178 |
* If legend is array of phenomenons, it selects the first element |
|
179 |
* @param legend info for displaying legend |
|
180 |
*/ |
|
142 | 181 |
private getLegend(legend: any) { |
143 | 182 |
if (Array.isArray(legend)) { |
144 | 183 |
return legend[0]; |
... | ... | |
147 | 186 |
} |
148 | 187 |
} |
149 | 188 |
|
189 |
/** |
|
190 |
* Select the graph type from id |
|
191 |
*/ |
|
150 | 192 |
private getGraphType() { |
151 | 193 |
if (this.sensorId >= 480000000 && this.sensorId < 490000000) { |
152 | 194 |
return SingleGraphType.BARCHART; |
src/vega/readme.txt | ||
---|---|---|
1 |
1) Getting vega specification |
|
2 |
|
|
3 |
a) getting the base |
|
4 |
empty -> for empty graphs |
|
5 |
default -> for other graphs |
|
6 |
|
|
7 |
b) getting the body |
|
8 |
barchart / linechart / multilinechart / windchart |
|
9 |
|
|
10 |
c) getting the legend specification |
|
11 |
|
|
12 |
d) getting the tooltip specification |
|
13 |
(samm -> sum, avg, min, max) |
|
14 |
|
|
15 |
e) merging the files into result |
|
16 |
|
|
17 |
|
|
18 |
2) Vega configurations. |
|
19 |
|
|
20 |
Process of getting configuration: |
|
21 |
a) gets config.json |
|
22 |
b) gets other config file for corresponding graphs |
|
23 |
c) merge signals array from other graph to config.json |
|
24 |
|
|
25 |
(barline = bar + line) |
|
26 |
|
|
27 |
note: config signals typically contain path to values |
|
28 |
|
Také k dispozici: Unified diff
Re #9006 - Přidat komentáře ke kódu