2024-04-01 16:49:47 +02:00
11 changed files with 327 additions and 137 deletions

View File

@@ -49,9 +49,9 @@ def loginDB():
) )
return mydb return mydb
def getData(node, dataType, MAC, dateStart, dateEnd): def getData(node, dataTypes, MAC, dateStart, dateEnd):
mydb = loginDB() mydb = loginDB()
query = get_query(node, dataType, MAC, False, False, dateStart, dateEnd) query = get_query(node, dataTypes, MAC, False, False, dateStart, dateEnd)
cursor = mydb.cursor(dictionary=True) # Enable dictionary output cursor = mydb.cursor(dictionary=True) # Enable dictionary output
cursor.execute(query) cursor.execute(query)
result = cursor.fetchall() # Fetch the results result = cursor.fetchall() # Fetch the results
@@ -62,7 +62,7 @@ def getData(node, dataType, MAC, dateStart, dateEnd):
def getNodeInfo(macAdress): def getNodeInfo(macAdress):
mydb = loginDB() mydb = loginDB()
query = get_query(False, False, macAdress, False, False) query = get_query(False, False, macAdress, False, False, False, False)
cursor = mydb.cursor(dictionary=True) # Enable dictionary output cursor = mydb.cursor(dictionary=True) # Enable dictionary output
cursor.execute(query) cursor.execute(query)
result = cursor.fetchall() # Fetch the results result = cursor.fetchall() # Fetch the results

View File

@@ -1,5 +1,9 @@
def get_query(node, dataType, MAC, questionID, replies, dateStart, dateEnd): def get_query(node, dataType, MAC, questionID, replies, dateStart, dateEnd):
if dateStart and dateEnd and node: if dateStart and dateEnd and node and dataType:
query = f'''SELECT *
FROM Measurement
WHERE TimeStamp BETWEEN '{dateStart}' AND '{dateEnd}' AND NodeID = {node} AND Type IN ('{dataType}');'''
elif dateStart and dateEnd and node:
query = f'''SELECT * query = f'''SELECT *
FROM Measurement FROM Measurement
WHERE TimeStamp BETWEEN '{dateStart}' AND '{dateEnd}' AND NodeID = {node};''' WHERE TimeStamp BETWEEN '{dateStart}' AND '{dateEnd}' AND NodeID = {node};'''
@@ -21,10 +25,7 @@ def get_query(node, dataType, MAC, questionID, replies, dateStart, dateEnd):
query = f"SELECT * FROM Question" query = f"SELECT * FROM Question"
elif replies: elif replies:
query = f"SELECT * FROM Reply" query = f"SELECT * FROM Reply"
elif dateStart and dateEnd and node:
query = f'''SELECT *
FROM Measurement
WHERE TimeStamp BETWEEN '{dateStart}' AND '{dateEnd}';'''
else: else:
query = "SELECT * FROM `Measurement`" query = "SELECT * FROM `Measurement`"
return query return query

View File

@@ -42,8 +42,7 @@ class Graph {
} }
updateData(type, value, timestamp) { updateData(type, value, timestamp) {
this.timeArray.push(timestamp); // this.timeArray.push(timestamp);
switch (type) { switch (type) {
case "Temp": case "Temp":
this.tempArray.push(value); this.tempArray.push(value);
@@ -67,7 +66,7 @@ class Graph {
x: [this.timeArray], x: [this.timeArray],
y: [this.tempArray, this.humiArray, this.eco2Array, this.tvocArray], y: [this.tempArray, this.humiArray, this.eco2Array, this.tvocArray],
}; };
console.log(update);
Plotly.update(this.id, update); Plotly.update(this.id, update);
} }
} }
@@ -140,10 +139,19 @@ class DataProcessor {
} }
updateGraph() { updateGraph() {
this.graph.timeArray = [];
this.graph.tempArray = [];
this.graph.humiArray = [];
this.graph.eco2Array = [];
this.graph.tvocArray = [];
for (let i = 0; i < this.data.length; i++) { for (let i = 0; i < this.data.length; i++) {
if (i % 4 == 0){
this.graph.timeArray.push(this.data[i].TimeStamp);
}
this.graph.updateData(this.data[i].Type, this.data[i].Value, this.data[i].TimeStamp); this.graph.updateData(this.data[i].Type, this.data[i].Value, this.data[i].TimeStamp);
console.log(this.data[i].Type, this.data[i].Value, this.data[i].TimeStamp); console.log(this.data[i].Type, this.data[i].Value, this.data[i].TimeStamp);
this.graph.updateGraph();
} }
} this.graph.updateGraph();
}
} }

View File

@@ -24,10 +24,10 @@ container.setAttribute("class", "container");
const dataTypesContainer = document.createElement("div"); const dataTypesContainer = document.createElement("div");
dataTypesContainer.setAttribute("class", "data-types"); dataTypesContainer.setAttribute("class", "data-types");
const temperatureCheckbox = createCheckBox("temperature", "Temperature"); const temperatureCheckbox = createCheckBox("Temp", "Temperature");
const humidityCheckbox = createCheckBox("humidity", "Humidity"); const humidityCheckbox = createCheckBox("Humi", "Humidity");
const eco2Checkbox = createCheckBox("eco2", "eCO2"); const eco2Checkbox = createCheckBox("eCO2", "eCO2");
const tvocCheckbox = createCheckBox("tvoc", "TVOC"); const tvocCheckbox = createCheckBox("TVOC", "TVOC");
dataTypesContainer.appendChild(temperatureCheckbox.checkbox); dataTypesContainer.appendChild(temperatureCheckbox.checkbox);
dataTypesContainer.appendChild(temperatureCheckbox.checkboxLabel); dataTypesContainer.appendChild(temperatureCheckbox.checkboxLabel);
@@ -55,24 +55,30 @@ filterButton.addEventListener("click", () => {
temperatureCheckbox, temperatureCheckbox,
humidityCheckbox, humidityCheckbox,
eco2Checkbox, eco2Checkbox,
tvocCheckbox, tvocCheckbox
]; ];
checkboxes.forEach((checkbox) => { checkboxes.forEach((checkbox) => {
if (checkbox.checkbox.checked) { if (checkbox.checkbox.checked) {
selectedFields.push(checkbox.checkbox.id); selectedFields.push(String(checkbox.checkbox.id));
} }
}); });
let selectedFieldsString = selectedFields.map(String);
let formattedString = '(' + selectedFieldsString.map(item => `'${item}'`).join(', ') + ')';
const filteredData = [ const filteredData = [
startDate, startDate,
endDate, endDate,
selectedNodes, selectedNodes,
selectedFields formattedString
]; ];
console.log(filteredData); console.log(filteredData);
console.log(startDate, endDate, selectedNodes); console.log(startDate, endDate, selectedNodes);
generateLink(startDate, endDate, selectedNodes); generateLink(startDate, endDate, selectedNodes, formattedString);
fetchData(); fetchData();
}); });
@@ -98,7 +104,7 @@ nodeFilter.setAttribute("class", "node-filter");
const nodeInput = document.createElement("input"); const nodeInput = document.createElement("input");
nodeInput.setAttribute("type", "text"); nodeInput.setAttribute("type", "text");
nodeInput.setAttribute("placeholder", "Enter node (A, B, etc.)"); nodeInput.setAttribute("placeholder", "Enter Node Name (* for all)");
nodeInput.setAttribute("id", "node-input"); nodeInput.setAttribute("id", "node-input");
nodeInput.setAttribute("class", "input-field"); nodeInput.setAttribute("class", "input-field");
@@ -110,12 +116,12 @@ container.appendChild(filterButton);
document.body.appendChild(container); document.body.appendChild(container);
// Function to get the link for the get request // Function to get the link for the get request
function generateLink(dateStart, dateEnd, node) { function generateLink(dateStart, dateEnd, node, dataTypes) {
const baseUrl = 'http://145.92.8.114/getMeasurements'; const baseUrl = 'http://145.92.8.114/getMeasurements';
const formattedDateStart = new Date(dateStart).toISOString().replace('T', '%20'); const formattedDateStart = new Date(dateStart).toISOString().replace('T', '%20');
const formattedDateEnd = new Date(dateEnd).toISOString().replace('T', '%20'); const formattedDateEnd = new Date(dateEnd).toISOString().replace('T', '%20');
link = `${baseUrl}?dateStart=${formattedDateStart}&dateEnd=${formattedDateEnd}&node=${node}`; link = `${baseUrl}?dateStart=${formattedDateStart}&dateEnd=${formattedDateEnd}&node=${node}&dataType=${dataTypes}`;
console.log(link); console.log(link);
} }

View File

@@ -0,0 +1,27 @@
class ChartConfigClass{
constructor(data, text){
this.data = data
this.text = text
}
get chartConfig() {
return{
type: 'pie',
data: this.data,
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: this.text
},
animation: {
animateScale: true,
animateRotate: true
}
}
}
}
}

View File

@@ -30,24 +30,30 @@
<body> <body>
<div class="chart-container"> <div class="chart-container">
<div class="chart">
<h2>Question 1: How clean are the toilets?</h2> <h2>Question 1: How clean are the toilets?</h2>
<canvas id="chart1"></canvas> <canvas id="chart1"></canvas>
</div>
<div class="chart">
<h2>Question 2: How clean is the study area?</h2> <h2>Question 2: How clean is the study area?</h2>
<canvas id="chart2"></canvas> <canvas id="chart2"></canvas>
</div>
<div class="chart">
<h2>Question 3: What do you think of the temperature in the study area?</h2> <h2>Question 3: What do you think of the temperature in the study area?</h2>
<canvas id="chart3"></canvas> <canvas id="chart3"></canvas>
</div>
<div class="chart">
<h2>Question 4: How crowded would you say the study area is?</h2> <h2>Question 4: How crowded would you say the study area is?</h2>
<canvas id="chart4"></canvas> <canvas id="chart4"></canvas>
</div>
<div class="chart">
<h2>Question 5: Is there enough help available on the 5th floor?</h2> <h2>Question 5: Is there enough help available on the 5th floor?</h2>
<canvas id="chart5"></canvas> <canvas id="chart5"></canvas>
</div>
<!-- Add more questions and canvas elements as needed --> <!-- Add more questions and canvas elements as needed -->
</div> </div>
<script src="questions-main-class.js"></script> <script src="questions-chart-class.js"></script>
<script src="questions-creation-class.js"></script>
<script src="questions-main.js"></script> <script src="questions-main.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,3 +1,4 @@
//For now create dummy data to show on the website.
let dummydata1 = [40, 30, 20]; let dummydata1 = [40, 30, 20];
let questionOptionsDummy1 = ['disgusting','clean', 'fine']; let questionOptionsDummy1 = ['disgusting','clean', 'fine'];
@@ -13,119 +14,41 @@ let questionOptionsDummy4 = ['really crowded','not at all', 'its fine', ];
let dummydata5 = [30, 20, 20]; let dummydata5 = [30, 20, 20];
let questionOptionsDummy5 = ['no','yes', 'decently']; let questionOptionsDummy5 = ['no','yes', 'decently'];
const question1Data = new QuestionCreationClass(dummydata1,questionOptionsDummy1) //make arrays to store data.
const question2Data = new QuestionCreationClass(dummydata2,questionOptionsDummy2) let chartConfigArray = [];
const question3Data = new QuestionCreationClass(dummydata3, questionOptionsDummy3); let textArray = [];
const question4Data = new QuestionCreationClass(dummydata4, questionOptionsDummy4);
const question5Data = new QuestionCreationClass(dummydata5, questionOptionsDummy5);
const chartConfig1 = { let questionArray = [];
type: 'pie', let questionOptionsDummy = [];
data: question1Data.questionData, let dummydata = [];
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Question 1 Responses'
},
animation: {
animateScale: true,
animateRotate: true
}
}
};
const chartConfig2 = { //Go along the array's to fetch data, and push this in a class.
type: 'pie', for (let i = 0; i < 5; i++) {
data: question2Data.questionData, dummydata.push(dummydata1, dummydata2, dummydata3, dummydata4, dummydata5);
options: { questionOptionsDummy.push(questionOptionsDummy1, questionOptionsDummy2, questionOptionsDummy3, questionOptionsDummy4, questionOptionsDummy5);
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Question 2 Responses'
},
animation: {
animateScale: true,
animateRotate: true
}
}
};
const chartConfig3 = { questionArray.push(new QuestionCreationClass(dummydata[i], questionOptionsDummy[i]));
type: 'pie', }
data: question3Data.questionData,
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Question 3 Responses'
},
animation: {
animateScale: true,
animateRotate: true
}
}
};
const chartConfig4 = { //Go allong another array to also give the class that creates the charts the data collected by the previous array.
type: 'pie', for (let i = 0; i < 5; i++){
data: question4Data.questionData, textArray.push('Question 1 Responses', 'Question 2 Responses', 'Question 3 Responses', 'Question 4 Responses', 'Question 5 Responses');
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Question 4 Responses'
},
animation: {
animateScale: true,
animateRotate: true
}
}
};
const chartConfig5 = { chartConfigArray.push(new ChartConfigClass(questionArray[i].questionData, textArray[i]));
type: 'pie', }
data: question5Data.questionData,
options: {
responsive: true,
legend: {
position: 'top',
},
title: {
display: true,
text: 'Question 5 Responses'
},
animation: {
animateScale: true,
animateRotate: true
}
}
};
// Create the charts // Create the charts
const ctx1 = document.getElementById('chart1').getContext('2d'); const ctx1 = document.getElementById('chart1').getContext('2d');
const myChart1 = new Chart(ctx1, chartConfig1); const myChart1 = new Chart(ctx1, chartConfigArray[0].chartConfig);
const ctx2 = document.getElementById('chart2').getContext('2d'); const ctx2 = document.getElementById('chart2').getContext('2d');
const myChart2 = new Chart(ctx2, chartConfig2); const myChart2 = new Chart(ctx2, chartConfigArray[1].chartConfig);
const ctx3 = document.getElementById('chart3').getContext('2d'); const ctx3 = document.getElementById('chart3').getContext('2d');
const myChart3 = new Chart(ctx3, chartConfig3); const myChart3 = new Chart(ctx3, chartConfigArray[2].chartConfig);
const ctx4 = document.getElementById('chart4').getContext('2d'); const ctx4 = document.getElementById('chart4').getContext('2d');
const myChart4 = new Chart(ctx4, chartConfig4); const myChart4 = new Chart(ctx4, chartConfigArray[3].chartConfig);
const ctx5 = document.getElementById('chart5').getContext('2d'); const ctx5 = document.getElementById('chart5').getContext('2d');
const myChart5 = new Chart(ctx5, chartConfig5); const myChart5 = new Chart(ctx5, chartConfigArray[4].chartConfig);

View File

@@ -50,7 +50,7 @@ body {
border-radius: 10px; border-radius: 10px;
margin: 20px; margin: 20px;
padding: 20px; padding: 20px;
width: 100%; width: 90;
box-sizing: border-box; box-sizing: border-box;
} }
@@ -98,8 +98,7 @@ body {
} }
.filter-button { .filter-button {
flex: 1; width: 10%;
width: 20%;
background-color: #007bff; background-color: #007bff;
color: white; color: white;
padding: 10px; padding: 10px;
@@ -108,4 +107,10 @@ body {
cursor: pointer; cursor: pointer;
} }
.js-plotly-plot {
align-self: center;
width: 95%;
height: 100%;
margin: 10px;
}
/* Additional styling as needed */ /* Additional styling as needed */

View File

@@ -4,6 +4,7 @@
} }
body { body {
flex-direction: row;
padding-top: 5vw; padding-top: 5vw;
display: flex; display: flex;
background-color: #dbd7d7; background-color: #dbd7d7;
@@ -42,16 +43,27 @@
} }
#data-container { #data-container {
width: 80%;
margin: 0 auto;
padding: 20px; padding: 20px;
background-color: #f5f5f5; background-color: #f5f5f5;
border: 1px solid #ccc; border: 1px solid #ccc;
} }
.chart-container { .chart-container {
width: 80%; justify-content: center;
margin: 20px auto; align-self: start;
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.chart {
width: 30%;
margin: 20px;
padding: 20px;
background-color: #dbd7d7;
border: 3px solid #000;
border-radius: 30px;
} }
canvas { canvas {
margin-bottom: 20px; margin-bottom: 20px;

View File

@@ -0,0 +1,202 @@
* {
box-sizing: border-box;
font-family: "Roboto", sans-serif;
}
body {
display: flex;
justify-content: center;
margin: 0;
margin-top: 8vh;
background-color: #f0f0f0;
flex-direction: column;
background-color: #afafaf;
align-items: center;
}
.gaugeGroup {
width: 98vw;
height: auto;
display: flex;
flex-direction: column; /* Keep as column */
justify-content: flex-start;
background-color: #333;
color: #fff;
padding: 10px;
border-radius: 50px;
border: 2px solid #333;
clear: both;
margin-bottom: 10px;
position: relative;
}
.groupTitle {
width: 100%;
text-align: center;
font-size: 24px;
}
.Node {
display: flex;
justify-content: space-around;
align-items: center;
width: 100%;
height: 100%;
}
.Sensorvalues {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
flex-wrap: wrap;
width: 15%;
height: 110%;
background-color: #ddd;
color: #333;
padding: 10px;
margin: 10px;
border-radius: 10px;
text-align: center;
position: relative;
padding-top: 3vh; /* Increase bottom padding */
}
.gaugeContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
height: 80%; /* Increase the height from 70% to 80% */
position: relative;
overflow: visible;
height: 5vh;
margin-bottom: 1vh;
}
.gaugeImage {
width: 100%;
height: auto;
max-height: 120%;
object-fit: contain;
position: absolute; /* Make the image position absolute */
top: 0;
left: 0;
z-index: 1; /* Make the image display below the needle */
bottom: 0;
}
.gaugeValue, .gaugeText {
width: 100%;
text-align: center;
font-size: 24px;
z-index: 2;
}
.gaugeText {
width: 100%;
text-align: center;
font-size: 1.4vw;
z-index: 2;
position: absolute;
top: -1.4vw; /* Adjust this value to move the text further down */
}
.arrowimg {
width: 3vh;
height: auto;
max-height: 100%;
object-fit: contain;
position: absolute;
top: 0.5vw;
right: 1.2vw;
z-index: 2;
}
.valueContainer {
display: flex;
justify-content: center;
margin-top: 10px;
}
#valueText {
font-size: 20px;
}
.needle {
position: absolute;
bottom: -10%; /* Lower the needle to the bottom */
left: 50%;
width: 2px;
height: 100%;
background-color: black;
transform-origin: bottom;
z-index: 3; /* Make the needle display above the image */
transition: transform 0.1s ease-out;
}
.contentContainer {
display: flex;
flex-direction: row; /* Layout children side by side */
width: 100%;
height: 100%;
}
.navbar {
background-color: #333;
height: 60px;
display: flex;
align-items: center;
padding: 0 20px;
position: fixed; /* Fix the navbar at the top of the page */
top: 0; /* Position it at the very top */
width: 100%; /* Make it span the full width of the page */
z-index: 1000; /* Make sure it's above all other elements */
}
.navbar-nav {
list-style: none;
display: flex;
align-items: center;
justify-content: center; /* Center the links horizontally */
height: 100%;
width: 100%; /* Make it span the full width of the navbar */
}
.nav-item {
margin-right: 20px;
}
.nav-link {
color: #fff;
text-decoration: none;
font-size: 18px;
}
.plotly-container {
width: 100%;
float: bottom;
padding: 1vw;
align-items: center;
justify-content: center;
display: flex;
}
.js-plotly-plot {
width: 90%;
height: 100%;
}
.disabled {
opacity: 0;
height: 0;
}