Projekt

Obecné

Profil

« Předchozí | Další » 

Revize 8cca41c0

Přidáno uživatelem Štěpán Červenka před více než 3 roky(ů)

Re #8775 - Agregovat grafy se stejným typem sensoru

  • graph loading decomposition
  • some bugs fixed

Zobrazit rozdíly:

src/app/sensor/components/sensor.component.ts
88 88
    ).subscribe(
89 89
      observations => {
90 90
        if (observations) {
91
          GraphLoader.getGraph(this.sensorId, observations[this.sensorId].data, observations[this.sensorId].interval, '#view');
91
        //  GraphLoader.getGraph(this.sensorId, observations[this.sensorId].data, observations[this.sensorId].interval, '#view');
92
          GraphLoader.getGraph(this.sensorId, observations[this.sensorId].data, '#view', true);
92 93
        } else {
93
          GraphLoader.getGraph(null, null, null, null);
94
          GraphLoader.getGraph(null, null, '#view', null);
94 95
        }
95 96
      }, err => this.toastService.showError(err.error.message));
96 97
  }
......
115 116
    ).subscribe(
116 117
      observations => {
117 118
        if (observations) {
118
          GraphLoader.getObservationGraph(this.sensorId, observations, '#view');
119
         // GraphLoader.getObservationGraph(this.sensorId, observations, '#view');
120
          GraphLoader.getGraph(this.sensorId, observations[this.sensorId].data, '#view', false);
119 121
        } else {
120
          GraphLoader.getObservationGraph(null, null, null);
122
         // GraphLoader.getObservationGraph(null, null, null);
123
          GraphLoader.getGraph(null, null, '#view', null);
121 124
        }
122 125
      }, err => this.toastService.showError(err.error.message));
123 126
  }
src/app/shared/graph-loading/emptygraph.ts
1
import {Graph} from "./graph";
2

  
3
declare var require: any
4

  
5
export class EmptyGraph implements Graph{
6

  
7
  message: string;
8

  
9
  constructor(message) {
10
    this.message = message;
11
  }
12

  
13

  
14
  getConfig(): {} {
15
    return require('/src/vega/config/config.json');
16
  }
17

  
18
  getSpec(): {} {
19
    const lodash = require('lodash/object');
20
    const rvalue: any = {};
21
    let base = require('/src/vega/base/empty.json');
22
    lodash.merge(rvalue, base);
23
    rvalue.signals[0].value = this.message;
24
    return rvalue;
25
  }
26

  
27
}
src/app/shared/graph-loading/graph.ts
1
export interface Graph {
2
  getSpec(): {},
3
  getConfig(): {}
4
}
src/app/shared/graph-loading/graphcollection.ts
1
declare var require: any
2

  
3
export class GraphCollection {
4

  
5
  array;
6

  
7

  
8
  constructor() {
9
    this.array = [];
10
  }
11

  
12
  addGraph(sensorId, data) {
13
    let element : any = {};
14
    element.sensor = sensorId;
15
    element.data = data;
16
    this.array.push(element);
17
  }
18

  
19
  getObject() {
20
    return this.array();
21
  }
22

  
23
}
src/app/shared/graph-loading/graphloader.ts
1
declare var require: any
1
import {Graph} from './graph';
2
import {EmptyGraph} from "./emptygraph";
3
import {SingleGraph} from "./singlegraph";
4
import {MultiGraph} from "./multigraph";
2 5

  
3
export class GraphLoader {
6
declare var require: any
4 7

  
5 8

  
6
  static getGraphType(sensorId) {
7
    const lodash = require('lodash/object');
8 9

  
9
    if (sensorId >= 480000000 && sensorId < 490000000) {
10
export class GraphLoader {
10 11

  
11
      const rvalue: any = {};
12
      const base = require('/src/vega/base/default.json');
13
      const chart = require('/src/vega/body/barchart.json');
14
      const tooltip = require('/src/vega/tooltip/samm-tooltip.json')
15
      lodash.merge(rvalue, base, chart, tooltip);
16
      return rvalue;
17 12

  
18
    } else if ((sensorId >= 470020000 && sensorId < 470030000) || (sensorId >= 470060000 && sensorId < 470090000) ||
19
      (sensorId >= 470130000 && sensorId < 470140000) || (sensorId >= 470180000 && sensorId < 470190000)) {
13
  static getGraphType(sensors, data, isAnalytics): Graph {
14
    if (sensors == null) {
15
      return new EmptyGraph("Selected no sensors.");
20 16

  
21
      const rvalue: any = {};
22
      const base = require('/src/vega/base/default.json');
23
      const chart = require('/src/vega/body/windchart.json');
24
      const tooltip = require('/src/vega/tooltip/samm-tooltip.json')
25
      lodash.merge(rvalue, base, chart, tooltip);
26
      return rvalue;
17
    } else if (Array.isArray(sensors)) {
18
      if (sensors.length == 0) {
19
        return new EmptyGraph("Selected no sensors.");
20
      } else if (sensors.length == 1) {
21
        return new SingleGraph(sensors[0], isAnalytics, data, 10000);
22
      } else {
23
        return new MultiGraph(isAnalytics, data, 10000);
24
      }
27 25

  
28 26
    } else {
29

  
30
      const rvalue: any = {};
31
      const base = require('/src/vega/base/default.json');
32
      const chart = require('/src/vega/body/linechart.json');
33
      const tooltip = require('/src/vega/tooltip/samm-tooltip.json')
34
      lodash.merge(rvalue, base, chart, tooltip);
35
      return rvalue;
36

  
27
      return new SingleGraph(sensors, isAnalytics, data, 10000);
37 28
    }
38 29
  }
39 30

  
40
  static getObservationSpec(sensorId) {
41
    const lodash = require('lodash/object');
42

  
43
    const rvalue: any = {};
44
    const base = require('/src/vega/base/default.json');
45
    const chart = require('/src/vega/body/linechart-observations.json');
46
    const tooltip = require('/src/vega/tooltip/value-tooltip.json')
47
    lodash.merge(rvalue, base, chart, tooltip);
48
    return rvalue;
49

  
50
  }
51

  
52
  static getGraph(sensorId, data, interval, element) {
53
    const spec = this.getGraphType(sensorId);
54
    const config = require('/src/vega/config/config-analytics.json');
55

  
56
    spec.data[0].values = data;
57
    spec.signals[0].value = interval;
58

  
59

  
60
    this.showGraph(spec, config, element);
61

  
62

  
63

  
64
  }
65

  
66
  static getObservationGraph(sensorId, data, element) {
67 31

  
68
    const spec = this.getObservationSpec(sensorId);
69
    const config = require('/src/vega/config/config-observations.json');
70

  
71
    spec.data[0].values = data;
72
    spec.signals[0].value = 3600;
73

  
74

  
75
    this.showGraph(spec, config, element);
76

  
77

  
78
  }
79

  
80
  static getMultilineGraph(sensors, data, element) {
81
    let spec = this.getMultilineSpec(sensors);
82

  
83
    const config = require('/src/vega/config/config-multiline.json');
84

  
85
    spec.data[0].values = data;
86
    spec.signals[0].value = 3600;
32
  static getGraph(sensors, data, element, isAnalytics) {
33
    let graph = this.getGraphType(sensors,data, isAnalytics);
34
    let config = graph.getConfig();
35
    let spec = graph.getSpec();
36
    spec['data'][0].values = data;
87 37

  
88 38
    this.showGraph(spec, config, element);
89
  }
90

  
91
  static getMultilineSpec(sensors) {
92
    const lodash = require('lodash/object');
93

  
94
    const rvalue: any = {};
95
    const base = require('/src/vega/base/default.json');
96
    const chart = require('/src/vega/body/multilinechart.json');
97
    const tooltip = require('/src/vega/tooltip/multiline-tooltip.json')
98
    lodash.merge(rvalue, base, chart, tooltip);
99
    rvalue.marks[0].marks[0].marks[0].marks[2].encode.enter.tooltip.signal = this.getTooltipMessage(sensors);
100
    return rvalue;
101
  }
102

  
103
  static getTooltipMessage(sensors) {
104
    let message = "{title: timeFormat(datum.dateTime, '%A, %e. %B %Y, %X'), ";
105

  
106
    for(const key of sensors) {
107
      message += ("'" + key + "': datum['" + key + "'], ");
108
    }
109

  
110
    message += "}";
111

  
112
    return message;
113 39

  
114 40
  }
115 41

  
src/app/shared/graph-loading/multigraph.ts
1
import {Graph} from "./graph";
2

  
3
declare var require: any
4

  
5
export class MultiGraph implements Graph{
6

  
7
  isAnalytics: boolean;
8
  data: any [];
9
  interval: number;
10

  
11
  constructor(isAnalytics: boolean, data: any [], interval: number) {
12
    this.isAnalytics = isAnalytics;
13
    this.data = data;
14
    this.interval = interval;
15

  
16
  }
17

  
18

  
19
  getConfig(): {} {
20
    const lodash = require('lodash/object');
21
    const rvalue: any = {};
22
    let config1 = require('/src/vega/config/config.json');
23
    lodash.merge(rvalue, config1);
24
    let config2 = require('/src/vega/config/config-multiline.json');
25

  
26

  
27
    for(let key in config2.signals) {
28
      let obj = config2.signals[key];
29
      rvalue.signals.push(obj);
30
    }
31

  
32
    return config1;
33
  }
34

  
35
  getSpec(): {} {
36
    const lodash = require('lodash/object');
37
    const rvalue: any = {};
38
    const base = require('/src/vega/base/default.json');
39
    const body = require('/src/vega/body/multilinechart.json');
40
    const tooltip = require('/src/vega/tooltip/multiline-tooltip.json');
41

  
42
    lodash.merge(rvalue, base, body, tooltip);
43

  
44
    rvalue.data[0].values = this.data;
45
    rvalue.signals[0].value = this.interval;
46
    rvalue.marks[0].marks[0].marks[0].marks[2].encode.enter.tooltip.signal = this.getTooltipMessage();
47

  
48
    return rvalue;
49
  }
50

  
51
  private getTooltipMessage() {
52
    let message = "{title: timeFormat(datum.dateTime, '%A, %e. %B %Y, %X')";
53
    this.data.forEach(function (e) {
54
      message += (", '" + e.sensor.sensorName + "': datum['" + e.sensor.sensorName + "'] + ' " + e.sensor.phenomenon.unit +"' ");
55
    })
56

  
57
    message += "}";
58
    return message;
59
  }
60

  
61
}
src/app/shared/graph-loading/singlegraph.ts
1
import {Graph} from "./graph";
2

  
3
declare var require: any
4

  
5
export class SingleGraph implements Graph{
6
  isAnalytics: boolean;
7
  sensorId: number;
8
  interval: number;
9
  data: any [];
10

  
11
  constructor(sensorId: number, isAnalytics: boolean, data: any[], interval: number) {
12
    this.sensorId = sensorId;
13
    this.isAnalytics = isAnalytics;
14
    this.interval = interval;
15
    this.data = data;
16
  }
17

  
18
  getConfig(): {} {
19
    const lodash = require('lodash/object');
20
    const rvalue: any = {};
21
    let config1 = require('/src/vega/config/config.json');
22
    lodash.merge(rvalue, config1);
23
    let config2;
24
    if(this.isAnalytics) {
25
      config2 = require('/src/vega/config/config-analytics.json');
26
    } else {
27
      config2 = require('/src/vega/config/config-observations.json');
28
    }
29

  
30
    for(let key in config2.signals) {
31
      let obj = config2.signals[key];
32
      rvalue.signals.push(obj);
33
    }
34

  
35
    return config1;
36
  }
37

  
38
  getSpec(): {} {
39
    const lodash = require('lodash/object');
40
    const rvalue: any = {};
41
    const base = require('/src/vega/base/default.json');
42
    const body = this.getBodySpec();
43
    const tooltip = this.getTooltipSpec();
44
    lodash.merge(rvalue, base, body, tooltip);
45

  
46

  
47
    rvalue.data[0].values = this.data;
48
    rvalue.signals[0].value = this.interval;
49

  
50
    return rvalue;
51
  }
52

  
53

  
54
 private getBodySpec() {
55
    if (this.sensorId >= 480000000 && this.sensorId < 490000000) {
56
      return require('/src/vega/body/barchart.json');
57
    } else if ((this.sensorId >= 470020000 && this.sensorId < 470030000) || (this.sensorId >= 470060000 && this.sensorId < 470090000) ||
58
      (this.sensorId >= 470130000 && this.sensorId < 470140000) || (this.sensorId >= 470180000 && this.sensorId < 470190000)) {
59
      return require('/src/vega/body/windchart.json');
60
    } else {
61
      //TODO pridat min/max
62
      return require('/src/vega/body/linechart.json');
63
    }
64
  }
65

  
66

  
67
  private getTooltipSpec() {
68
      if(this.isAnalytics) {
69
        return require('/src/vega/tooltip/samm-tooltip.json');
70
      } else {
71
        return require('/src/vega/tooltip/value-tooltip.json');
72
      }
73
    }
74

  
75
}
src/app/unit/components/unit.component.ts
64 64
            if (!this.sensorGroups.some(group => group === sensorType)) {
65 65
              this.sensorGroups.push(sensorType);
66 66
              setTimeout(() => {
67
                GraphLoader.getGraph(null, null, null, '#vega_container_' + sensor.sensorId.toString().slice(0, 5));
67
                //GraphLoader.getAnalyticsGraph(null, null, null, '#vega_container_' + sensor.sensorId.toString().slice(0, 5));
68
                GraphLoader.getGraph(null, null, '#vega_container_' + sensor.sensorId.toString().slice(0, 5),null );
68 69
              }, 0);
69 70
            }
70 71
          });
......
109 110
            if (response.status === 200) {
110 111
              return response.body;
111 112
            } else if (response.status === 204) {
112
              GraphLoader.getGraph(null, null, null, '#vega_container_' + selectSens.toString().slice(0, 5));
113
              //GraphLoader.getAnalyticsGraph(null, null, null, '#vega_container_' + selectSens.toString().slice(0, 5));
114
              GraphLoader.getGraph(null, null, '#vega_container_' + selectSens.toString().slice(0, 5),null );
113 115
              this.toastService.showWarningNoData();
114 116
              return response.body;
115 117
            } else {
......
124 126
              if (data[key].data) {
125 127
                const view = '#vega_container_' + key.slice(0, 5);
126 128
                if (this.selectedSensors.some(sens => sens.toString() === key)) {
127
                  GraphLoader.getGraph(key, data[key].data, data[key].interval, view);
129
                  //GraphLoader.getAnalyticsGraph(key, data[key].data, data[key].interval, view);
130
                  //GraphLoader.getGraph(this.selectedSensors, this.filteredAnalyticsData(groupId), view, true);
128 131
                } else {
129
                  GraphLoader.getGraph(null, null, null, view);
132
                  GraphLoader.getGraph(null, null, view, null);
130 133
                }
131 134
              }
132 135
            }
......
155 158
            if (data[key].data) {
156 159
              const view = '#vega_container_' + key.slice(0, 5);
157 160
              if (this.selectedSensors.some(sens => sens.toString() === key)) {
158
                GraphLoader.getGraph(key, data[key].data, data[key].interval, view);
161
               // GraphLoader.getAnalyticsGraph(key, data[key].data, data[key].interval, view);
162
                GraphLoader.getGraph(this.selectedSensors, this.analyticsData, view, true);
159 163
              } else {
160
                GraphLoader.getGraph(null, null, null, view);
164
                //GraphLoader.getAnalyticsGraph(null, null, null, view);
165
                GraphLoader.getGraph(null, null, view, null);
161 166
              }
162 167
            }
163 168
          }
......
175 180
    const groupId = sensorId.toString().slice(0, 5);
176 181
    const sensorGroupElement = '#vega_container_' + groupId;
177 182
    if (!this.selectedSensors.find(sensId => sensId.toString().slice(0, 5) === groupId)) { // if group of sensors is empty show empty graph
178
      GraphLoader.getGraph(null, null, null, sensorGroupElement);
183
      //GraphLoader.getAnalyticsGraph(null, null, null, sensorGroupElement);
184
      GraphLoader.getGraph(null, null, sensorGroupElement, null);
179 185
    } else {
180 186
      if (this.useAnalyticsData) { // use analytics data
181 187
        if (event.checked) { // if checked > add to graph
182 188
          if (this.analyticsData.some(sens => sens.sensorId === sensorId)) { // if already data for selected sensor in memory
183
            GraphLoader.getGraph(sensorId, this.analyticsData.find(sens => sens.sensorId === sensorId).data,
184
              this.analyticsData.find(sens => sens.sensorId === sensorId).interval, sensorGroupElement);
189
            //GraphLoader.getAnalyticsGraph(sensorId, this.analyticsData.find(sens => sens.sensorId === sensorId).data,
190
            // this.analyticsData.find((sens => sens.sensorId === sensorId).interval, sensorGroupElement);
191
            GraphLoader.getGraph(this.selectedSensors, this.analyticsData, sensorGroupElement, true);
192

  
185 193
          } else { // get data from server for added sensor and show graph for selected sensors
186 194
            this.showGraph(false, sensorId);
187 195
          }
188 196
        } else { // remove sensor from graph
189
          GraphLoader.getGraph(sensorId, this.analyticsData.find(sens => sens.sensorId === sensorId).data,
190
            this.analyticsData.find(sens => sens.sensorId === sensorId).interval, sensorGroupElement);
197
          //GraphLoader.getAnalyticsGraph(sensorId, this.analyticsData.find(sens => sens.sensorId === sensorId).data,
198
          // this.analyticsData.find(sens => sens.sensorId === sensorId).interval, sensorGroupElement);
199
          GraphLoader.getGraph(this.selectedSensors, this.analyticsData, sensorGroupElement, true);
200

  
191 201
        }
192 202
      } else { // use observations data
193 203
        if (event.checked) { // if checked > add to graph
194 204
          if (this.observationsData.some(sens => sens.sensorId.toString() === sensorId)) { // if already data for selected sensor in memory
195
            GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(groupId), sensorGroupElement)
205
            GraphLoader.getGraph(this.selectedSensors, this.filteredObservationData(groupId), sensorGroupElement, false);
206
            //GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(groupId), sensorGroupElement)
196 207
          } else { // get data from server for added sensor and show graph for selected sensors
197 208
            this.showGraph(false, sensorId);
198 209
          }
199 210
        } else { // remove sensor from graph
200
          GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(groupId), sensorGroupElement)
211
          //GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(groupId), sensorGroupElement)
212
          GraphLoader.getGraph(this.selectedSensors, this.filteredObservationData(groupId), sensorGroupElement, false);
201 213
        }
202 214
      }
203 215
    }
......
215 227
  /**
216 228
   * Filter analytics data only fro selected sensors.
217 229
   */
218
  filteredAnalyticsData(): any {
219
    return this.analyticsData.filter(sen => this.selectedSensors.includes(sen.sensorId.toString()));
230
  filteredAnalyticsData(sensorGroupId: string): any {
231
    return this.analyticsData.filter(sen => this.selectedSensors.includes(sen.sensorId.toString()) &&
232
      sen.sensorId.toString().slice(0, 5) === sensorGroupId);
220 233
  }
221 234

  
222 235
  private getObservations(range: Date[], changedDate: boolean, changedSensorId: string) {
......
250 263
              const view = '#vega_container_' + selectSens.toString().slice(0, 5);
251 264
              setTimeout(() => {
252 265
                console.log(this.selectedSensors);
253
                GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(selectSens.toString().slice(0, 5)), view);
266
                //GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(selectSens.toString().slice(0, 5)), view);
267
                GraphLoader.getGraph(this.selectedSensors,  this.filteredObservationData(changedSensorId.toString().slice(0, 5)), view, false);
254 268
              }, 10);
255 269
            }
256 270
          })
......
280 294
          const view = '#vega_container_' + changedSensorId.toString().slice(0, 5);
281 295
          if (observations) {
282 296
            console.log(this.observationsData);
283
            GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(changedSensorId.toString().slice(0, 5)), view);
297
            GraphLoader.getGraph(this.selectedSensors,  this.filteredObservationData(changedSensorId.toString().slice(0, 5)), view, false);
298
            //GraphLoader.getMultilineGraph(this.selectedSensors, this.filteredObservationData(changedSensorId.toString().slice(0, 5)), view);
284 299
          } else {
285
            GraphLoader.getMultilineGraph(null, null, null);
300
            //GraphLoader.getMultilineGraph(null, null, null);
301
            GraphLoader.getGraph(this.selectedSensors,  this.filteredObservationData(changedSensorId.toString().slice(0, 5)), view, false);
286 302
          }
287 303
        }, err => this.toastService.showError(err.error.message));
288 304
    }
src/vega/base/empty.json
1
{
2

  
3
  "data":[
4
    {
5
      "name": "source",
6
      "values": null
7
    }
8
  ],
9

  
10
  "signals": [
11
    {
12
      "name": "text",
13
      "value": "Sample text."
14
    }
15
  ],
16

  
17
  "scales": [
18
    {
19
      "name": "xscale",
20
      "domain": [0,0],
21
      "range": "width"
22
    },
23
    {
24
      "name": "yscale",
25
      "domain": [0,0],
26
      "range": "height"
27
    }
28
  ],
29

  
30
  "axes":[
31
    {
32
      "orient": "bottom",
33
      "scale": "xscale"
34
    },
35
    {
36
      "orient": "left",
37
      "scale": "yscale"
38
    }
39
  ],
40

  
41
  "marks": [
42

  
43

  
44
    {
45
      "type": "text",
46
      "align": "center",
47
      "baseline": "middle",
48
      "encode": {
49
        "enter": {
50
          "text": {"signal": "text"},
51
          "x": {"scale": "xscale", "value": 0},
52
          "y": {"scale": "yscale", "value": 0},
53
          "align": {"value": "center"},
54
          "baseline": {"value": "middle"}
55
        }
56
      }
57
    }
58
  ]
59
}
src/vega/body/linechart-observations.json
1
{
2
  "data": [
3
    {},
4
    {},
5
    {},
6
    {},
7
    {
8
      "name": "ranks",
9
      "source": "table",
10
      "transform": [
11
        {
12
          "type": "window",
13
          "sort": {
14
            "field": "dateTime",
15
            "order": "ascending"
16
          },
17
          "ops": [
18
            "rank"
19
          ],
20
          "fields": [
21
            "value"
22
          ],
23
          "as": [
24
            "rank"
25
          ]
26
        },
27
        {
28
          "type": "formula",
29
          "expr": "datum.rank + 1",
30
          "as": "nextRank"
31
        }
32
      ]
33
    },
34
    {
35
      "name": "lookup",
36
      "source": "ranks",
37
      "transform": [
38
        {
39
          "type": "lookup",
40
          "from": "ranks",
41
          "key": "rank",
42
          "fields": [
43
            "nextRank"
44
          ],
45
          "as": [
46
            "tempObj"
47
          ]
48
        },
49
        {
50
          "type": "formula",
51
          "expr": "(datum.tempObj == null || datum.tempObj.dateTime - datum.dateTime > maxTimeDifference) ? null : datum.tempObj",
52
          "as": "obj"
53
        }
54
      ]
55
    }
56
  ],
57
  "marks": [
58
    {
59
      "scales": [
60
        {},
61
        {
62
          "name": "yDetail",
63
          "type": "linear",
64
          "range": [390, 0],
65
          "domain": {
66
            "fields": [
67
              {"data": "range", "field": "valueMax"},
68
              {"data":  "table", "field": "value"}
69
            ]
70
          },
71
          "nice": true, "zero": true
72
        }
73
      ],
74
      "axes": [
75
        {},
76
        {"orient": "left", "scale": "yDetail"}
77
      ],
78
      "marks": [
79
        {
80
          "marks": [
81
            {
82
              "type": "symbol",
83
              "from": {"data":"lookup"},
84
              "encode": {
85
                "enter": {
86
                  "tooltip": {
87
                    "signal": "{title: timeFormat(datum.dateTime, '%A, %e. %B %Y, %X') }"
88
                  }},
89
                "update": {
90
                  "shape": {"value": "circle"},
91
                  "size": {"value": 30},
92
                  "x": {"scale": "xDetail", "field": "dateTime"},
93
                  "y": {"scale": "yDetail", "field": "value"},
94
                  "color": {"value": "both"},
95
                  "strokeWidth": {"value": 4},
96
                  "fill": {"value": "steelblue"}
97
                },
98
                "hover": {
99
                  "fill": {"value": "red"},
100
                  "size": {"value": 60}
101
                }
102
              }
103
            },
104
            {
105
              "type": "rule",
106
              "from": {
107
                "data": "lookup"
108
              },
109
              "encode": {
110
                "update": {
111
                  "x": {
112
                    "scale": "xDetail",
113
                    "field": "dateTime"
114
                  },
115
                  "x2": [
116
                    {
117
                      "test": "isValid(datum.obj)",
118
                      "scale": "xDetail",
119
                      "field": "obj.dateTime"
120
                    },
121
                    {
122
                      "scale": "xDetail",
123
                      "field": "dateTime"
124
                    }
125
                  ],
126
                  "y": {
127
                    "scale": "yDetail",
128
                    "field": "value"
129
                  },
130
                  "y2": [
131
                    {
132
                      "test": "isValid(datum.obj)",
133
                      "scale": "yDetail",
134
                      "field": "obj.value"
135
                    },
136
                    {
137
                      "scale": "yDetail",
138
                      "field": "value"
139
                    }
140
                  ],
141
                  "stroke": {
142
                    "value": "steelblue"
143
                  },
144
                  "strokeWidth": {
145
                    "value": 1
146
                  }
147
                }
148
              }
149
            }
150
          ]
151
        }
152
      ]
153
    },
154
    {
155
      "signals": [
156
        {
157
          "value": 0,
158
          "on": [
159
            {},
160
            {
161
              "events": "@overview:mousedown",
162
              "update": "[x(), x()]"
163
            },
164
            {
165
              "events": "[@overview:mousedown, window:mouseup] > window:mousemove!",
166
              "update": "[brush[0], clamp(x(), 0, width)]"
167
            }
168
          ]
169
        }
170
      ],
171
      "marks": [
172
        {},
173
        {},
174
        {},
175
        {
176
          "type": "symbol",
177
          "from": {"data":"table"},
178
          "encode": {
179
            "update": {
180
              "shape": {"value": "circle"},
181
              "size": {"value": 10},
182
              "x": {"scale": "xOverview", "field": "dateTime"},
183
              "y": {"scale": "yOverview", "field": "value"},
184
              "color": {"value": "both"},
185
              "strokeWidth": {"value": 4}
186
            }
187
          }
188
        },
189
        {
190
          "type": "rule",
191
          "from": {
192
            "data": "lookup"
193
          },
194
          "encode": {
195
            "update": {
196
              "x": {
197
                "scale": "xOverview",
198
                "field": "dateTime"
199
              },
200
              "x2": [
201
                {
202
                  "test": "isValid(datum.obj)",
203
                  "scale": "xOverview",
204
                  "field": "obj.dateTime"
205
                },
206
                {
207
                  "scale": "xOverview",
208
                  "field": "dateTime"
209
                }
210
              ],
211
              "y": {
212
                "scale": "yOverview",
213
                "field": "value"
214
              },
215
              "y2": [
216
                {
217
                  "test": "isValid(datum.obj)",
218
                  "scale": "yOverview",
219
                  "field": "obj.value"
220
                },
221
                {
222
                  "scale": "yOverview",
223
                  "field": "value"
224
                }
225
              ],
226
              "stroke": {
227
                "value": "steelblue"
228
              },
229
              "strokeWidth": {
230
                "value": 1
231
              }
232
            }
233
          }
234
        }
235
      ]
236
    }
237
  ]
238
}
src/vega/body/linechart.json
5 5
    {},
6 6
    {},
7 7
    {
8
      "name": "timeunit",
8
      "name": "ranks",
9 9
      "source": "table",
10 10
      "transform": [
11 11
        {
12
          "type": "timeunit",
13
          "field": "dateTime",
14
          "units": ["year","month", "date", "hours", "minutes", "seconds"],
15
          "step": {"signal": "timeStep"}
12
          "type": "window",
13
          "sort": {
14
            "field": "dateTime",
15
            "order": "ascending"
16
          },
17
          "ops": [
18
            "rank"
19
          ],
20
          "fields": [
21
            "value"
22
          ],
23
          "as": [
24
            "rank"
25
          ]
26
        },
27
        {
28
          "type": "formula",
29
          "expr": "datum.rank + 1",
30
          "as": "nextRank"
16 31
        }
17 32
      ]
18 33
    },
19 34
    {
20 35
      "name": "lookup",
21
      "source": "timeunit",
22
      "transform":[
36
      "source": "ranks",
37
      "transform": [
23 38
        {
24 39
          "type": "lookup",
25
          "from": "timeunit",
26
          "key": "unit0",
27
          "fields": ["unit1"],
28
          "as": ["obj"]
40
          "from": "table",
41
          "key": "rank",
42
          "fields": [
43
            "nextRank"
44
          ],
45
          "as": [
46
            "nextObj"
47
          ]
48
        },
49
        {
50
          "type": "lookup",
51
          "from": "table",
52
          "key": "rank",
53
          "fields": [
54
            "prevRank"
55
          ],
56
          "as": [
57
            "prevObj"
58
          ]
59
        },
60
        {
61
          "type": "formula",
62
          "expr": "(datum.nextObj == null || datum.nextObj.dateTime - datum.dateTime > maxTimeDifference) ? null : datum.nextObj",
63
          "as": "obj"
64
        },
65
        {
66
          "type": "formula",
67
          "expr": "datum.prevObj == null ?  data('range')[0].dateMin : (time(datum.prevObj.dateTime) + time(datum.dateTime)) / 2",
68
          "as": "dateStart"
69
        },
70
        {
71
          "type": "formula",
72
          "expr": "datum.nextObj == null ?  data('range')[0].dateMax : (time(datum.nextObj.dateTime) + time(datum.dateTime)) / 2",
73
          "as": "dateEnd"
29 74
        }
30 75
      ]
31 76
    }
32 77
  ],
78

  
79
  "signals": [
80
    {},
81
    {},
82
    {
83
      "name": "tooltipSignal",
84
      "value": {},
85
      "on": [
86
        {
87
          "events": "@tooltip-hitarea:mouseover",
88
          "update": "datum"
89
        },
90
        {
91
          "events": "@tooltip-hitarea:mouseout",
92
          "update": "{}"
93
        }
94
      ]
95
    }
96
  ],
97

  
33 98
  "marks": [
34 99
    {
35 100
      "scales": [
......
38 103
          "name": "yDetail",
39 104
          "type": "linear",
40 105
          "range": [390, 0],
41
          "domain": {"data": "range", "field": "valueMax"},
106
          "domain": {
107
            "fields": [
108
              {"data": "range", "field": "valueMax"},
109
              {"data":  "table", "field": "value"}
110
            ]
111
          },
42 112
          "nice": true, "zero": true
43 113
        }
44 114
      ],
......
49 119
      "marks": [
50 120
        {
51 121
          "marks": [
122
            {
123
              "name": "tooltip-hitarea",
124
              "type": "rect",
125
              "interactive": true,
126
              "from": {
127
                "data": "lookup"
128
              },
129
              "encode": {
130
                "enter": {
131
                  "tooltip": {
132
                    "signal": null
133
                  }
134
                },
135
                "update": {
136
                  "x": {
137
                    "scale": "xDetail",
138
                    "field": "dateStart"
139
                  },
140
                  "x2": {
141
                    "scale": "xDetail",
142
                    "field": "dateEnd"
143
                  },
144
                  "y": {
145
                    "scale": "yDetail",
146
                    "band": 1
147
                  },
148
                  "y2": {
149
                    "scale": "yDetail",
150
                    "value": 0
151
                  },
152
                  "fill": {
153
                    "value": "#00ff00"
154
                  },
155
                  "fillOpacity": {
156
                    "value": 0.0
157
                  }
158
                }
159
              }
160
            },
52 161
            {
53 162
              "type": "symbol",
54
              "from": {"data":"table"},
163
              "from": {"data":"lookup"},
55 164
              "encode": {
56 165
                "enter": {
57 166
                  "tooltip": {
......
65 174
                  "color": {"value": "both"},
66 175
                  "strokeWidth": {"value": 4},
67 176
                  "fill": {"value": "steelblue"}
68
                },
69
                "hover": {
70
                  "fill": {"value": "red"},
71
                  "size": {"value": 60}
72 177
                }
73 178
              }
74 179
            },
......
81 186
                "update": {
82 187
                  "x": {
83 188
                    "scale": "xDetail",
84
                    "field": "unit0"
189
                    "field": "dateTime"
85 190
                  },
86 191
                  "x2": [
87 192
                    {
88 193
                      "test": "isValid(datum.obj)",
89 194
                      "scale": "xDetail",
90
                      "field": "obj.unit0"
195
                      "field": "obj.dateTime"
91 196
                    },
92 197
                    {
93 198
                      "scale": "xDetail",
94
                      "field": "unit0"
199
                      "field": "dateTime"
95 200
                    }
96 201
                  ],
97 202
                  "y": {
......
117 222
                  }
118 223
                }
119 224
              }
225
            },
226

  
227
            {
228
              "type": "rule",
229
              "interactive": false,
230
              "zindex": 20,
231
              "encode": {
232
                "enter": {
233
                },
234
                "update": {
235
                  "x": {
236
                    "scale": "xDetail",
237
                    "signal": "tooltipSignal.dateTime"
238
                  },
239
                  "y": {
240
                    "scale": "yDetail",
241
                    "band": 1
242
                  },
243
                  "y2": {
244
                    "scale": "yDetail",
245
                    "value": 0
246
                  },
247
                  "strokeOpacity": [
248
                    {
249
                      "test": "tooltipSignal.dateTime > 1",
250
                      "value": 1
251
                    },
252
                    {
253
                      "value": 0
254
                    }
255
                  ]
256
                }
257
              }
120 258
            }
121 259
          ]
122 260
        }
......
166 304
            "update": {
167 305
              "x": {
168 306
                "scale": "xOverview",
169
                "field": "unit0"
307
                "field": "dateTime"
170 308
              },
171 309
              "x2": [
172 310
                {
173 311
                  "test": "isValid(datum.obj)",
174 312
                  "scale": "xOverview",
175
                  "field": "obj.unit0"
313
                  "field": "obj.dateTime"
176 314
                },
177 315
                {
178 316
                  "scale": "xOverview",
179
                  "field": "unit0"
317
                  "field": "dateTime"
180 318
                }
181 319
              ],
182 320
              "y": {
src/vega/body/multilinechart.json
26 26
            },
27 27
            {
28 28
              "signal": "sensorPath"
29
            },
30
            {
31
              "signal": "axeLegendPath"
32
            },
33
            {
34
              "signal": "axeLegendUnit"
29 35
            }
30 36
          ],
31 37
          "as": [
32 38
            "value",
33 39
            "timestamp",
34
            "sensor"
40
            "sensor",
41
            "axeLegend",
42
            "axeUnit"
35 43
          ]
36 44
        }
37 45
      ]
......
261 269
        {},
262 270
        {
263 271
          "orient": "left",
264
          "scale": "yDetail"
272
          "scale": "yDetail",
273
          "grid": true,
274
          "title": {"signal":  "data('table')[0].axeLegend"},
275
          "encode": {
276
          "labels": {
277
            "update": {
278
              "text":  {"signal": "datum.value + ' ' + data('table')[0].axeUnit"}
279
            }
280
          }
281
        }
265 282
        }
266 283
      ],
267 284
      "marks": [
......
368 385
                  "encode": {
369 386
                    "enter": {
370 387
                      "tooltip": {
371
                        "signal": "{title: timeFormat(datum.dateTime, '%A, %e. %B %Y, %X')  ,  '123': datum['123'], '456': datum['456'], '789': datum['789'] }"
388
                        "signal": null
372 389
                      }
373 390
                    },
374 391
                    "update": {
src/vega/config/config-analytics.json
1 1
{
2
  "$schema": "https://vega.github.io/schema/vega/v5.json",
3
  "width": 800,
4
  "height": 200,
5
  "padding": 5,
6 2
  "signals": [
7 3
    {"name": "valuePath", "value": "avg"},
8
    {"name":  "timestampPath", "value":  "timestamp"},
9
    {"name":  "detailHeight", "value": 390},
10
    {"name": "overviewHeight", "value":  70},
11
    {"name":  "overviewHeightStart", "value" : 430},
12
    {"name":  "maxTimeDifference", "value": 10000000}
13
  ]
4
    {"name":  "timestampPath", "value":  "timestamp"}
5
    ]
14 6
}
src/vega/config/config-multiline.json
1 1
{
2
  "$schema": "https://vega.github.io/schema/vega/v5.json",
3
  "width": 800,
4
  "height": 200,
5
  "padding": 5,
6 2
  "signals": [
7 3
    {"name":  "dataPath", "value":  "data"},
8 4
    {"name": "valuePath", "value": "data.value"},
9 5
    {"name":  "timestampPath", "value":  "data.time"},
10
    {"name":  "sensorPath", "value":  "sensorId"},
11
    {"name":  "detailHeight", "value": 390},
12
    {"name": "overviewHeight", "value":  70},
13
    {"name":  "overviewHeightStart", "value" : 430},
14
    {"name":  "maxTimeDifference", "value": 10000000}
6
    {"name":  "sensorPath", "value":  "sensor.sensorName"},
7
    {"name":  "axeLegendPath", "value":  "sensor.phenomenon.phenomenonName"},
8
    {"name":  "axeLegendUnit", "value":  "sensor.phenomenon.unit"}
15 9
  ]
16 10
}
src/vega/config/config-observations.json
1 1
{
2
  "$schema": "https://vega.github.io/schema/vega/v5.json",
3
  "width": 800,
4
  "height": 200,
5
  "padding": 5,
6 2
  "signals": [
7 3
    {"name": "valuePath", "value": "value"},
8 4
    {"name":  "timestampPath", "value":  "time"},
9
    {"name":  "detailHeight", "value": 390},
10
    {"name": "overviewHeight", "value":  70},
11
    {"name":  "overviewHeightStart", "value" : 430},
12
    {"name":  "maxTimeDifference", "value": 10000000}
5
    {"name":  "gidPath", "value":  "gid"}
13 6
  ]
14 7
}
src/vega/config/config.json
1
{
2
  "$schema": "https://vega.github.io/schema/vega/v5.json",
3
  "width": 800,
4
  "height": 200,
5
  "padding": 5,
6
  "signals": [
7
    {"name":  "detailHeight", "value": 390},
8
    {"name": "overviewHeight", "value":  70},
9
    {"name":  "overviewHeightStart", "value" : 430},
10
    {"name":  "maxTimeDifference", "value": 10000000}
11
  ]
12
}
src/vega/tooltip/value-tooltip.json
8 8
          "fields": [
9 9
            {"signal" :  "valuePath"},
10 10
            {"signal":  "timestampPath"},
11
            "gid"
12

  
11
            {"signal":  "gidPath"}
13 12
          ],
14 13
          "as": [
15 14
            "value",
src/vega/trashbin/linechart.json
1
{
2
  "data": [
3
    {},
4
    {},
5
    {},
6
    {},
7
    {
8
      "name": "timeunit",
9
      "source": "table",
10
      "transform": [
11
        {
12
          "type": "timeunit",
13
          "field": "dateTime",
14
          "units": ["year","month", "date", "hours", "minutes", "seconds"],
15
          "step": {"signal": "timeStep"}
16
        }
17
      ]
18
    },
19
    {
20
      "name": "lookup",
21
      "source": "timeunit",
22
      "transform":[
23
        {
24
          "type": "lookup",
25
          "from": "timeunit",
26
          "key": "unit0",
27
          "fields": ["unit1"],
28
          "as": ["obj"]
29
        }
30
      ]
31
    }
32
  ],
33
  "marks": [
34
    {
35
      "scales": [
36
        {},
37
        {
38
          "name": "yDetail",
39
          "type": "linear",
40
          "range": [390, 0],
41
          "domain": {"data": "range", "field": "valueMax"},
42
          "nice": true, "zero": true
43
        }
44
      ],
45
      "axes": [
46
        {},
47
        {"orient": "left", "scale": "yDetail"}
48
      ],
49
      "marks": [
50
        {
51
          "marks": [
52
            {
53
              "type": "symbol",
54
              "from": {"data":"table"},
55
              "encode": {
56
                "enter": {
57
                  "tooltip": {
58
                    "signal": "{title: timeFormat(datum.dateTime, '%A, %e. %B %Y, %X') }"
59
                  }},
60
                "update": {
61
                  "shape": {"value": "circle"},
62
                  "size": {"value": 30},
63
                  "x": {"scale": "xDetail", "field": "dateTime"},
64
                  "y": {"scale": "yDetail", "field": "value"},
65
                  "color": {"value": "both"},
66
                  "strokeWidth": {"value": 4},
67
                  "fill": {"value": "steelblue"}
68
                },
69
                "hover": {
70
                  "fill": {"value": "red"},
71
                  "size": {"value": 60}
72
                }
73
              }
74
            },
75
            {
76
              "type": "rule",
77
              "from": {
78
                "data": "lookup"
79
              },
80
              "encode": {
81
                "update": {
82
                  "x": {
83
                    "scale": "xDetail",
84
                    "field": "unit0"
85
                  },
86
                  "x2": [
87
                    {
88
                      "test": "isValid(datum.obj)",
89
                      "scale": "xDetail",
90
                      "field": "obj.unit0"
91
                    },
92
                    {
93
                      "scale": "xDetail",
94
                      "field": "unit0"
95
                    }
96
                  ],
97
                  "y": {
98
                    "scale": "yDetail",
99
                    "field": "value"
100
                  },
101
                  "y2": [
102
                    {
103
                      "test": "isValid(datum.obj)",
104
                      "scale": "yDetail",
105
                      "field": "obj.value"
106
                    },
107
                    {
108
                      "scale": "yDetail",
109
                      "field": "value"
110
                    }
111
                  ],
112
                  "stroke": {
113
                    "value": "steelblue"
114
                  },
115
                  "strokeWidth": {
116
                    "value": 1
117
                  }
118
                }
119
              }
120
            }
121
          ]
122
        }
123
      ]
124
    },
125
    {
126
      "signals": [
127
        {
128
          "value": 0,
129
          "on": [
130
            {},
131
            {
132
              "events": "@overview:mousedown",
133
              "update": "[x(), x()]"
134
            },
135
            {
136
              "events": "[@overview:mousedown, window:mouseup] > window:mousemove!",
137
              "update": "[brush[0], clamp(x(), 0, width)]"
138
            }
139
          ]
140
        }
141
      ],
142
      "marks": [
143
        {},
144
        {},
145
        {},
146
        {
147
          "type": "symbol",
148
          "from": {"data":"table"},
149
          "encode": {
150
            "update": {
151
              "shape": {"value": "circle"},
152
              "size": {"value": 10},
153
              "x": {"scale": "xOverview", "field": "dateTime"},
154
              "y": {"scale": "yOverview", "field": "value"},
155
              "color": {"value": "both"},
156
              "strokeWidth": {"value": 4}
157
            }
158
          }
159
        },
160
        {
161
          "type": "rule",
162
          "from": {
163
            "data": "lookup"
164
          },
165
          "encode": {
166
            "update": {
167
              "x": {
168
                "scale": "xOverview",
169
                "field": "unit0"
170
              },
171
              "x2": [
172
                {
173
                  "test": "isValid(datum.obj)",
174
                  "scale": "xOverview",
175
                  "field": "obj.unit0"
176
                },
177
                {
178
                  "scale": "xOverview",
179
                  "field": "unit0"
180
                }
181
              ],
182
              "y": {
183
                "scale": "yOverview",
184
                "field": "value"
185
              },
186
              "y2": [
187
                {
188
                  "test": "isValid(datum.obj)",
189
                  "scale": "yOverview",
190
                  "field": "obj.value"
191
                },
192
                {
193
                  "scale": "yOverview",
194
                  "field": "value"
195
                }
196
              ],
197
              "stroke": {
198
                "value": "steelblue"
199
              },
200
              "strokeWidth": {
201
                "value": 1
202
              }
203
            }
204
          }
205
        }
206
      ]
207
    }
208
  ]
209
}

Také k dispozici: Unified diff