Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MG-211 - Update horizontal bar chart fo fetch data from back-end #227

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 76 additions & 10 deletions ui/web/static/js/charts.js
Original file line number Diff line number Diff line change
Expand Up @@ -706,13 +706,10 @@ class HorizontalBarChart extends Echart {
},
dataset: {
source: [
['score', 'amount', 'product'],
[79.3,85212, 'thing1'],
[57.1, 78254, 'thing2'],
[14.4, 41032, 'thing3'],
[30.1, 12755, 'thing4'],
[18.7, 20145, 'thing5'],
[88.1, 89146, 'thing6'],
[
"thing",
"value"
],
]
},
grid: { containLabel: true },
Expand All @@ -731,9 +728,9 @@ class HorizontalBarChart extends Echart {
visualMap: {
orient: 'horizontal',
left: 'center',
min: 10,
min: 0,
max: 100,
text: ['High temperature', 'Low temperature'],
text: ['High', 'Low'],
// Map the score column to color
dimension: 0,
inRange: {
Expand All @@ -751,7 +748,76 @@ class HorizontalBarChart extends Echart {
]
};

horizontalBarChart.setOption(option);`;
horizontalBarChart.setOption(option);
var chartData = {
channels: '${this.chartData.channels}'.split(','),
things: '${this.chartData.things}'.split(','),
name: '${this.chartData.valueName}',
from: ${this.chartData.startTime},
to: ${this.chartData.stopTime},
aggregation: '${this.chartData.aggregationType}',
limit: 100,
};
fetchData(horizontalBarChart, chartData);

async function fetchData(horizontalBarChart, chartData) {
try {
const plotData = [['value', 'thing']];

for (let i = 0; i < chartData.channels.length; i++) {
const apiEndpoint = '${pathPrefix}/data?channel=' + chartData.channels[i] +
'&name=' + chartData.name +
'&from='+ chartData.from +
'&to=' + chartData.to +
'&aggregation=' + chartData.aggregation +
'&limit=10' +
'&interval=' + getInterval(chartData) +
'&publisher=' + chartData.things[i];

const response = await fetch(apiEndpoint);
if (!response.ok) {
throw new Error('HTTP request failed with status:', response.status)
}
const data = await response.json();
plotData.push([data.messages[0].value, 'thing'+i.toString()]);
}
updateChart(horizontalBarChart, plotData);
} catch (error) {
console.error("Error fetching data:", error);
}
}

function updateChart(horizontalBarChart, plotData) {
option = horizontalBarChart.getOption();
option.series[0].encode.x = 'value';
option.series[0].encode.y = 'thing';
option.visualMap.text = ['High', 'Low'];
option.dataset[0].source = plotData;
horizontalBarChart.setOption(option);
}

function getInterval(chartData) {
const interval = chartData.to - chartData.from;
const millisecondsPerSecond = 1e3;
const secondsPerMinute = 60;
const minutesPerHour = 60;
let minutes = 0;
let hours = 0;
let intervalString = "";

let seconds = parseInt(interval) / millisecondsPerSecond;
intervalString = Math.ceil(seconds).toString() +'s';
if (seconds >= secondsPerMinute) {
minutes = seconds/ secondsPerMinute;
intervalString = Math.ceil(minutes).toString() + 'm';
}
if (minutes >= minutesPerHour) {
hours = minutes /minutesPerHour;
intervalString = Math.ceil(hours).toString() + 'h';
}
return intervalString;
}
`;
}
}

Expand Down
204 changes: 151 additions & 53 deletions ui/web/templates/charts/horizontalbarchartmodal.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ <h5 class="modal-title" id="horizontalBarChartModalLabel">Horizontal Bar Chart</
<button
type="button"
class="btn-close"
data-bs-dismiss="modal"
onclick="closeForm();"
aria-label="Close"
></button>
</div>
Expand Down Expand Up @@ -63,55 +63,81 @@ <h5 class="modal-title" id="horizontalBarChartModalLabel">Horizontal Bar Chart</
role="tabpanel"
aria-labelledby="data-tab"
>
<div class="mb-3">
<label for="channel-id" class="form-label">Channel ID</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="channel"
id="channel-id"
placeholder="Enter the channel ID"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
<div class="table-responsive-md mb-3 p-2 border rounded">
<h5>Data Source</h5>
<table class="table" id="horizontalbarchart-data">
<thead>
<tr>
<th scope="col">Channel</th>
<th scope="col">Thing</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control"
name="channel"
placeholder="channel ID"
required
/>
</td>
<td>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control"
name="thing"
placeholder="thing ID"
required
/>
</td>
<td class="text-center">
<button type="button" class="btn btn-sm" onclick="removeRow(this)">
<i class="fas fa-trash-alt"></i>
</button>
</td>
</tr>
</tbody>
</table>
<button type="button" class="btn body-button btn-sm" onclick="addRow()">
Add source
</button>
</div>
<div class="mb-3">
<label for="thing-id" class="form-label">Thing IDs</label>
<label for="value-name" class="form-label">Value name</label>
<input
type="text"
pattern="{{ .UUIDPattern }}"
class="form-control mb-3"
name="thing"
id="thing-id"
placeholder="Enter the thing IDs"
name="valueName"
id="value-name"
placeholder="Enter the value name eg. temperature"
required
/>
<div class="invalid-feedback">Please enter a valid uuid</div>
</div>
<div class="mb-3">
<label for="value-name" class="form-label">Value name</label>
<label for="start-time" class="form-label">Start time</label>
<input
type="text"
type="datetime-local"
class="form-control mb-3"
name="valueName"
id="value-name"
placeholder="Enter the value name eg. temperature"
name="startTime"
id="start-time"
required
/>
<div class="invalid-time"></div>
</div>
<div class="mb-3">
<label for="update-interval" class="form-label">Update interval</label>
<label for="stop-time" class="form-label">Stop time</label>
<input
type="text"
pattern="{{ .IntervalPattern }}"
type="datetime-local"
class="form-control mb-3"
name="updateInterval"
id="update-interval"
placeholder="Enter the update interval, eg. 5s, 10m, 1h, 1d"
name="stopTime"
id="stop-time"
required
/>
<div class="invalid-feedback">Please enter a valid interval</div>
</div>
<div class="mb-3">
<label for="aggregation-type" class="form-label">Aggregation</label>
Expand Down Expand Up @@ -167,14 +193,7 @@ <h5 class="modal-title" id="horizontalBarChartModalLabel">Horizontal Bar Chart</
</form>
</div>
<div class="modal-footer">
<button
type="button"
class="btn btn-secondary"
id="close-horizontalBarChart-button"
data-bs-dismiss="modal"
>
Close
</button>
<button type="button" class="btn btn-secondary" onclick="closeForm();">Close</button>
<button type="button" class="btn body-button" id="create-horizontalBarChart-button">
Create Chart
</button>
Expand All @@ -184,39 +203,118 @@ <h5 class="modal-title" id="horizontalBarChartModalLabel">Horizontal Bar Chart</
</div>
<script>
// horizontal bar chart form
const form = document.getElementById("create-horizontalBarChart-form");
document
.getElementById("create-horizontalBarChart-button")
.addEventListener("click", function () {
const form = document.getElementById("create-horizontalBarChart-form");
if (!form.checkValidity()) {
form.classList.add("was-validated");
return;
}

// Create an object to store the form data
let chartData = {};
const channels = [];
const things = [];
let formData = new FormData(form);
for (var pair of formData.entries()) {
chartData[pair[0]] = pair[1];
for (let [name, value] of formData) {
switch (name) {
case "startTime":
case "stopTime":
const inputDate = new Date(value);
chartData[name] = inputDate.getTime();
break;
case "channel":
channels.push(value);
break;
case "thing":
things.push(value);
break;
default:
chartData[name] = value;
break;
}
}

if (chartData.stopTime <= chartData.startTime) {
const invalidTimeFeedback = form.querySelector(".invalid-time");
invalidTimeFeedback.innerHTML = "Stop time should be greater than start time";
invalidTimeFeedback.style.color = "red";
const invalidTimeInput = form.querySelector("#stop-time");
invalidTimeInput.classList.remove("was-validated");
invalidTimeInput.classList.add("is-invalid");
return;
}

var widgetID = "horizontalBarchart-" + Date.now();

chartData["Type"] = "horizontalBarChart";
chartData["channels"] = channels;
chartData["things"] = things;
addWidget(chartData, widgetID);
metadataBuffer[widgetID] = chartData;

form.reset();
form.classList.remove("was-validated");
bootstrap.Modal.getInstance(document.getElementById("horizontalBarChartModal")).hide();
closeForm();
});

document
.getElementById("horizontalBarChartModal")
.addEventListener("hidden.bs.modal", function () {
const form = document.getElementById("create-horizontalBarChart-form");
form.reset();
form.classList.remove("was-validated");
});
function closeForm() {
form.classList.remove("was-validated");
form.querySelector(".invalid-time").innerHTML = "";
form.querySelector("#stop-time").classList.remove("is-invalid");
form.reset();
resetTable();
bootstrap.Modal.getInstance(document.getElementById("horizontalBarChartModal")).hide();
}

function addRow() {
const uuidPattern = "{{ .UUIDPattern }}";
const table = document.getElementById("horizontalbarchart-data");
const newRow = table.insertRow(-1);
newRow.innerHTML = ` <td>
<input type="text" pattern="${uuidPattern}" class="form-control" name="channel"
placeholder="channel ID" required />
</td>
<td>
<input type="text" pattern="${uuidPattern}" class="form-control" name="thing"
placeholder="thing ID" required />
</td>
<td class="text-center">
<button type="button" class="btn btn-sm" onclick="removeRow(this)">
<i class="fas fa-trash-alt"></i>
</button>
</td>`;
}

function removeRow(button) {
const row = button.parentNode.parentNode;
row.parentNode.removeChild(row);
}

function resetTable() {
const table = document.getElementById("horizontalbarchart-data");
table.innerHTML = ` <thead>
<tr>
<th scope="col">Channel</th>
<th scope="col">Thing</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="text" pattern="{{ .UUIDPattern }}" class="form-control" name="channel"
placeholder="channel ID" required />
</td>
<td>
<input type="text" pattern="{{ .UUIDPattern }}" class="form-control" name="thing"
placeholder="thing ID" required />
</td>
<td class="text-center">
<button type="button" class="btn btn-sm" onclick="removeRow(this)">
<i class="fas fa-trash-alt"></i>
</button>
</td>
</tr>
</tbody>`;
}
</script>
{{ end }}
Loading