Heracles/static/lib.js

236 lines
7.4 KiB
JavaScript
Raw Normal View History

2024-02-12 15:50:35 -06:00
// Copyright 2023 Jeremy Wall
2024-02-11 19:08:15 -06:00
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2024-02-14 19:45:28 -06:00
class TimeseriesGraph extends HTMLElement {
2024-02-07 19:18:30 -06:00
#uri;
#width;
#height;
#intervalId;
#pollSeconds;
#label;
2024-02-14 19:45:28 -06:00
#end;
#duration;
#step_duration;
#targetNode = null;
constructor() {
super();
this.#width = 800;
this.#height = 600;
this.#pollSeconds = 30;
this.#targetNode = this.appendChild(document.createElement("div"));
}
2024-02-14 19:45:28 -06:00
static observedAttributes = ['uri', 'width', 'height', 'poll-seconds', 'end', 'duration', 'step-duration'];
2024-02-14 19:45:28 -06:00
attributeChangedCallback(name, _oldValue, newValue) {
switch (name) {
2024-02-12 16:22:57 -06:00
case 'uri':
this.#uri = newValue;
break;
2024-02-12 16:22:57 -06:00
case 'width':
this.#width = newValue;
break;
2024-02-12 16:22:57 -06:00
case 'height':
this.#height = newValue;
break;
2024-02-12 16:22:57 -06:00
case 'poll-seconds':
this.#pollSeconds = newValue;
break;
2024-02-12 16:22:57 -06:00
case 'label':
this.#label = newValue;
break;
2024-02-14 19:45:28 -06:00
case 'end':
this.#end = newValue;
break;
case 'duration':
this.#duration = newValue;
break;
case 'step-duration':
this.#step_duration = newValue;
break;
2024-02-12 16:22:57 -06:00
default: // do nothing;
break;
}
this.resetInterval();
}
connectedCallback() {
this.#uri = this.getAttribute('uri') || this.#uri;
this.#width = this.getAttribute('width') || this.#width;
this.#height = this.getAttribute('height') || this.#height;
this.#pollSeconds = this.getAttribute('poll-seconds') || this.#pollSeconds;
this.#label = this.getAttribute('label') || null;
2024-02-14 19:45:28 -06:00
this.#end = this.getAttribute('end') || null;
this.#duration = this.getAttribute('duration') || null;
this.#step_duration = this.getAttribute('step-duration') || null;
this.resetInterval()
}
2024-02-07 19:18:30 -06:00
disconnectedCallback() {
this.stopInterval()
2024-02-07 19:18:30 -06:00
}
static elementName = "timeseries-graph";
getTargetNode() {
return this.#targetNode;
}
2024-02-12 16:22:57 -06:00
stopInterval() {
if (this.#intervalId) {
clearInterval(this.#intervalId);
this.#intervalId = null;
}
}
2024-02-12 16:22:57 -06:00
resetInterval() {
this.stopInterval()
if (this.#uri) {
this.updateGraph();
}
this.#intervalId = setInterval(() => this.updateGraph(), 1000 * this.#pollSeconds);
}
static registerElement() {
if (!customElements.get(TimeseriesGraph.elementName)) {
customElements.define(TimeseriesGraph.elementName, TimeseriesGraph);
}
}
2024-02-12 16:22:57 -06:00
getUri() {
2024-02-14 19:45:28 -06:00
if (this.#end && this.#duration && this.#step_duration) {
return this.#uri + "?end=" + this.#end + "&duration=" + this.#duration + "&step_duration=" + this.#step_duration;
} else {
return this.#uri;
}
}
2024-02-07 19:18:30 -06:00
async fetchData() {
const response = await fetch(this.getUri());
2024-02-07 19:18:30 -06:00
const data = await response.json();
return data;
}
async updateGraph() {
const data = await this.fetchData();
const config = {
legend: {
orientation: 'h'
}
};
const layout = {
displayModeBar: false,
responsive: true
};
2024-02-07 19:18:30 -06:00
if (data.Series) {
// https://plotly.com/javascript/reference/scatter/
2024-02-07 19:18:30 -06:00
var traces = [];
for (const pair of data.Series) {
const series = pair[1];
const labels = pair[0];
2024-02-07 19:18:30 -06:00
var trace = {
type: "scatter",
mode: "lines+text",
2024-02-07 19:18:30 -06:00
x: [],
y: []
};
if (labels[this.#label]) {
trace.name = labels[this.#label];
};
2024-02-07 19:18:30 -06:00
for (const point of series) {
trace.x.push(new Date(point.timestamp * 1000));
2024-02-07 19:18:30 -06:00
trace.y.push(point.value);
}
traces.push(trace);
}
// https://plotly.com/javascript/plotlyjs-function-reference/#plotlyreact
Plotly.react(this.getTargetNode(), traces, config, layout);
2024-02-07 19:18:30 -06:00
} else if (data.Scalar) {
// https://plotly.com/javascript/reference/bar/
2024-02-11 19:08:15 -06:00
var traces = [];
for (const pair of data.Scalar) {
const series = pair[1];
const labels = pair[0];
var trace = {
type: "bar",
x: [],
y: []
};
if (labels[this.#label]) {
trace.x.push(labels[this.#label]);
};
trace.y.push(series.value);
traces.push(trace);
}
Plotly.react(this.getTargetNode(), traces, config, layout);
2024-02-07 19:18:30 -06:00
}
}
}
TimeseriesGraph.registerElement();
2024-02-14 19:45:28 -06:00
class SpanSelector extends HTMLElement {
#targetNode = null;
#endInput = null;
#durationInput = null;
#stepDurationInput = null;
#updateInput = null
constructor() {
super();
this.#targetNode = this.appendChild(document.createElement('div'));
this.#targetNode.appendChild(document.createElement('span')).innerText = "end: ";
this.#endInput = this.#targetNode.appendChild(document.createElement('input'));
this.#targetNode.appendChild(document.createElement('span')).innerText = "duration: ";
this.#durationInput = this.#targetNode.appendChild(document.createElement('input'));
this.#targetNode.appendChild(document.createElement('span')).innerText = "step duration: ";
this.#stepDurationInput = this.#targetNode.appendChild(document.createElement('input'));
this.#updateInput = this.#targetNode.appendChild(document.createElement('button'));
this.#updateInput.innerText = "Update";
}
connectedCallback() {
const self = this;
self.#updateInput.onclick = function(_evt) {
self.updateGraphs()
};
}
disconnectedCallback() {
this.#updateInput.onclick = undefined;
}
updateGraphs() {
for (var node of document.getElementsByTagName(TimeseriesGraph.elementName)) {
node.setAttribute('end', this.#endInput.value);
node.setAttribute('duration', this.#durationInput.value);
node.setAttribute('step-duration', this.#stepDurationInput.value);
}
}
static elementName = "span-selector";
static registerElement() {
if (!customElements.get(SpanSelector.elementName)) {
customElements.define(SpanSelector.elementName, SpanSelector);
}
}
}
SpanSelector.registerElement();