Commit e32df817 authored by Santhanavanich's avatar Santhanavanich
Browse files

update

parent d0aa57bd
No related merge requests found
Showing with 377 additions and 0 deletions
+377 -0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SensorThings API Data Visualization</title>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.0.2/dist/echarts.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body { font-family: 'Montserrat', sans-serif; margin: 20px; }
#chart { width: 100%; height: 600px; }
.error { color: red; }
.btn-group { margin-bottom: 20px; }
.card-title { font-size: 1rem; font-weight: normal; }
.card-text { font-size: 2rem; font-weight: bold; }
.timestamp { font-size: 0.75rem; font-weight: normal; }
.card { margin: 15px 0; border: none; }
.card-container { margin-top: 20px; }
.card-average { background-color: #f0f9ff; color: #007bff; }
.card-max { background-color: #fff5f5; color: #dc3545; }
.card-min { background-color: #f9f8ff; color: #6f42c1; }
.card-count { background-color: #f5fff7; color: #28a745; }
</style>
</head>
<body>
<div class="container-fluid">
<h2 class="text-center" id="chart-title" style="display: none;">Sensor Data Visualization</h2>
<div class="btn-group w-100 d-flex justify-content-center" role="group">
<button type="button" class="btn btn-primary active" id="btn-1day">1 Day</button>
<button type="button" class="btn btn-secondary" id="btn-7days">7 Days</button>
<button type="button" class="btn btn-secondary" id="btn-30days">30 Days</button>
<button type="button" class="btn btn-secondary" id="btn-all">All</button>
</div>
<div id="chart"></div>
<p id="error-message" class="error text-center"></p>
<!-- Bootstrap Cards for statistics -->
<div class="card-container row">
<div class="col-6">
<div class="card text-center card-average">
<div class="card-body">
<h5 class="card-title">Average Value</h5>
<p class="card-text" id="average-value">--</p>
</div>
</div>
</div>
<div class="col-6">
<div class="card text-center card-count">
<div class="card-body">
<h5 class="card-title">Data Count</h5>
<p class="card-text" id="data-count">--</p>
</div>
</div>
</div>
<div class="col-6">
<div class="card text-center card-max">
<div class="card-body">
<h5 class="card-title">Maximum Value</h5>
<p class="card-text" id="max-value">--</p>
<p class="timestamp" id="max-timestamp">--</p>
</div>
</div>
</div>
<div class="col-6">
<div class="card text-center card-min">
<div class="card-body">
<h5 class="card-title">Minimum Value</h5>
<p class="card-text" id="min-value">--</p>
<p class="timestamp" id="min-timestamp">--</p>
</div>
</div>
</div>
</div>
</div>
<script>
const meta = {
10: { name: 'Illuminance - Bus stop', unit: 'lux' },
11: { name: 'Temperature - Bus stop', unit: '°C' },
12: { name: 'Humidity - Bus stop', unit: '%' },
13: { name: 'Illuminance - Information space', unit: 'lux' },
14: { name: 'Temperature - Information space', unit: '°C' },
15: { name: 'Humidity - Information space', unit: '%' },
16: { name: 'Illuminance - Reception counter', unit: 'lux' },
17: { name: 'Temperature - Reception counter', unit: '°C' },
18: { name: 'Humidity - Reception counter', unit: '%' }
};
const urlParams = new URLSearchParams(window.location.search);
let ds_id = urlParams.get('ds_id') || 10;
ds_id = parseInt(ds_id);
const apiUrlBase = `https://ogcapi.hft-stuttgart.de/sta/udigit4icity/v1.1/Datastreams(${ds_id})/Observations?$orderby=resultTime+desc`;
if (ds_id < 10 || ds_id > 18) {
document.getElementById('error-message').textContent = "Currently this client only supports ds_id 10 - 18";
throw new Error("Unsupported ds_id");
}
const chartTitle = meta[ds_id].name;
const chartUnit = meta[ds_id].unit;
// Set the chart title in the heading
document.getElementById('chart-title').textContent = chartTitle;
let chartDom = document.getElementById('chart');
let myChart = echarts.init(chartDom);
function fetchData(days) {
let topCount = 288 * days; // 288 records per day (5-minute intervals)
let apiUrl = `${apiUrlBase}&$top=${topCount}`;
fetch(apiUrl)
.then(response => response.json())
.then(data => {
const allData = data.value.map(item => ({
resultTime: item.resultTime,
result: item.result
}));
// Update Chart
renderChart(allData);
// Update Statistics
updateStatistics(allData);
})
.catch(error => {
document.getElementById('error-message').textContent = `Error: ${error.message}`;
});
}
function renderChart(data) {
const option = {
grid: {
bottom: 175 // Add more space at the bottom to accommodate the labels
},
xAxis: {
type: 'category',
data: data.map(item => new Date(item.resultTime).toLocaleString()),
axisLabel: {
rotate: 90, // Rotate the labels to prevent overlap
interval: 'auto', // Dynamically set the label interval
formatter: function (value) { // Shorten the date format if needed
return value.split(',')[0] + value.split(',')[1];
}
}
},
yAxis: {
type: 'value',
name: chartUnit
},
series: [{
data: data.map(item => item.result),
type: 'line',
smooth: true
}],
tooltip: {
trigger: 'axis',
formatter: function (params) {
const date = params[0].axisValue;
const value = params[0].data;
return `${date}<br/>Value: ${value} ${chartUnit}`;
}
}
};
myChart.setOption(option);
}
function updateStatistics(data) {
const values = data.map(item => item.result);
const sum = values.reduce((a, b) => a + b, 0);
const avg = values.length > 0 ? (sum / values.length).toFixed(2) : '0.00';
const max = values.length > 0 ? Math.max(...values).toFixed(2) : '--';
const min = values.length > 0 ? Math.min(...values).toFixed(2) : '--';
const count = values.length;
let maxTimestamp = '--';
let minTimestamp = '--';
if (values.length > 0) {
maxTimestamp = data[values.indexOf(Math.max(...values))].resultTime;
minTimestamp = data[values.indexOf(Math.min(...values))].resultTime;
}
document.getElementById('average-value').textContent = `${avg} ${chartUnit}`;
document.getElementById('max-value').textContent = `${max} ${chartUnit}`;
document.getElementById('max-timestamp').textContent = `Time: ${new Date(maxTimestamp).toLocaleString()}`;
document.getElementById('min-value').textContent = `${min} ${chartUnit}`;
document.getElementById('min-timestamp').textContent = `Time: ${new Date(minTimestamp).toLocaleString()}`;
document.getElementById('data-count').textContent = count;
}
// Load 1 day of data by default
fetchData(1);
// Button handlers
document.getElementById('btn-1day').addEventListener('click', () => {
activateButton('btn-1day');
fetchData(1);
});
document.getElementById('btn-7days').addEventListener('click', () => {
activateButton('btn-7days');
fetchData(7);
});
document.getElementById('btn-30days').addEventListener('click', () => {
activateButton('btn-30days');
fetchData(30);
});
document.getElementById('btn-all').addEventListener('click', () => {
activateButton('btn-all');
fetchData(365); // Assuming all data (can adjust this limit)
});
// Activate button styles
function activateButton(buttonId) {
const buttons = document.querySelectorAll('.btn-group .btn');
buttons.forEach(btn => {
btn.classList.remove('active', 'btn-primary');
btn.classList.add('btn-secondary');
});
const activeButton = document.getElementById(buttonId);
activeButton.classList.remove('btn-secondary');
activeButton.classList.add('active', 'btn-primary');
}
// Ensure full-width responsiveness
window.addEventListener('resize', () => {
myChart.resize();
});
</script>
</body>
</html>
\ No newline at end of file
public/munakata/hft.png

3.32 KB

body{font-family:Montserrat;font-weight:400}:root{--navbar-height:75px}::-webkit-scrollbar-track{background-color:#002544}#navbar{position:relative;top:0;left:0;width:100%;z-index:1000;height:var(--navbar-height);background-color:#fff}#menuContainer{width:600px;height:calc(100vh - var(--navbar-height));overflow:auto;background:#002544;color:#002544}#cesiumContainer{height:calc(100vh - var(--navbar-height) - 55px);width:100%;margin:15px;padding:0;border-radius:25px}.cesium-viewer{border-radius:25px}.ub-card{border-radius:20px;padding:20;background-color:#fff;margin:15px 5px}.cesium-viewer-animationContainer{display:none!important}.cesium-viewer-bottom{display:none!important}.chartFrame{width:100%;border:none;height:365px;background:#fff;overflow:hidden;scrollbar-width:none}.infoZum-text{font-size:.75em}.fellbach-note{color:red}.page-item .page-link{z-index:3;color:#6a6a6a}.page-item.active .page-link{z-index:3;color:#fff;background-color:#2b6b5b;border-color:#0d6efd}.form-check-input:checked{background-color:#2b6b5b;border-color:#2b6b5b}.headline-section{font-weight:800;font-size:1.25em}.fs-08{font-size:.8em}.btn-secondary{color:#fff;background-color:#424242;border-color:#6c757d}.btn-secondary:hover{color:#fff;background-color:#444968;border-color:#2b6b5b}.btn-secondary:focus{color:#fff;background-color:#444968;border-color:#2b6b5b}.compass{top:50px}.navigation-controls{top:150px;background:#00254457}.footer{display:flex;justify-content:space-between;align-items:center;font-size:15px;padding:10px 20px;background-color:#f1f1f1;position:fixed;bottom:0;width:100%;z-index:1000;margin-left:-10px}.footer h6{margin:0;padding:0;font-size:13px;font-weight:800}.footer ul{list-style-type:none;margin:0;padding:0;display:flex;gap:15px}.footer ul h6{margin:0}.footer a{text-decoration:none;color:#000}.footer a:hover{text-decoration:underline}.dot{border-width:.5px;border-color:#000;border-style:solid;height:12px;width:12px;background-color:#bbb;border-radius:50%;display:inline-block}#Trinkwasserbezug-legend{font-size:.7em;display:none;position:absolute;right:0;bottom:80px;z-index:1000;width:136.6px;background:#ffffffba;border-radius:15px;padding:10px;margin-right:40px}.highlight-scenario-number{font-weight:400;background:#e8eae8;padding:4px;border-radius:4px}.cesiumLegend{position:absolute;top:100px;left:430px;z-index:1000;background:#ffffffdb;border-radius:15px;padding:10px;font-size:.8em}#menuContainer{scrollbar-width:thin;scrollbar-color:#6d6d6d80 transparent}#menuContainer::-webkit-scrollbar{width:8px}#menuContainer::-webkit-scrollbar-track{background:0 0}#menuContainer::-webkit-scrollbar-thumb{background:rgba(184,184,184,.582)}#menuContainer::-webkit-scrollbar-thumb:hover{background:rgba(0,0,0,.2)}.chart-header{font-size:1.35em;font-weight:600}#menuContainer{transition:all .3s ease-in-out}
\ No newline at end of file
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://cesium.com/downloads/cesiumjs/releases/1.110/Build/Cesium/Cesium.js"></script>
<link href="https://cesium.com/downloads/cesiumjs/releases/1.110/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
<link rel="stylesheet" href="index.css">
<!-- <link rel="stylesheet" href="pagination.css"> -->
<link rel="icon" href="img/hft.png" type="image/png">
<!-- Add i18next library -->
<script src="https://unpkg.com/i18next@21.9.1/dist/umd/i18next.min.js"></script>
<script src="https://unpkg.com/jquery-i18next@1.2.1/dist/umd/jquery-i18next.min.js"></script>
</head>
<body>
<div id="navbar" class="navbar d-flex justify-content-between align-items-center">
<h4 class="fw-bold" style="margin-left: 20px;">iCity 2: UDigiT4iCity</h4>
<button class="btn btn-primary d-md-none" id="toggleMenuBtn" style="margin-right: 20px;">Toggle Menu</button>
<div class="d-flex align-items-center ms-auto top-right-menu d-none d-md-flex">
<img src="./hft.png" alt="" class="me-3">
<div class="me-3">
<select id="languageSwitcher" class="form-select">
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="ja">日本語</option>
</select>
</div>
</div>
</div>
<div class="row" style="overflow: hidden; margin: 0px;background: #002544;">
<div id="menuContainer" class="d-none d-md-block">
<div>
<div class="card ub-card">
<a class="btn btn-secondary headline-section" data-bs-toggle="collapse" href="#infoZumG"
role="button" aria-expanded="false" aria-controls="infoZumG">
<i class="bi bi-info-circle"></i> <span data-i18n="MenuHeading"></span>
</a>
<div class="collapse show" id="infoZumG">
<div class="card card-body">
<div>
<p style="font-size: 0.85em;" data-i18n="infoText"></p>
</div>
<!-- the iframe size is managed on index.css - chartFrame -->
</div>
</div>
<a class="btn btn-secondary headline-section" data-bs-toggle="collapse" href="#sensorData"
role="button" aria-expanded="false" aria-controls="sensorData">
<i class="bi bi-info-circle"></i> <span data-i18n="sensorData.title">Sensor Data</span>
</a>
<div class="collapse show" id="sensorData">
<div class="card card-body">
<div>
<p style="font-size: 0.85em;" data-i18n="sensorData.description">
The sensor data is collected from the iCity Urban Platform. The sensor data from
three sensor locations can be activated from the three menu items below. The data is
displayed in the form of a chart.
</p>
<div class="d-flex justify-content-between">
<button class="btn btn-secondary sensor-button" data-ds-id="10" id="sensor1-bus-stop">
<i class="bi bi-bus-front"></i>
<span data-i18n="sensorData.buttons.busStop">Bus Stop</span>
</button>
<button class="btn btn-secondary sensor-button" data-ds-id="13" id="sensor3-information-space">
<i class="bi bi-info-circle"></i>
<span data-i18n="sensorData.buttons.informationSpace">Information Space</span>
</button>
<button class="btn btn-secondary sensor-button" data-ds-id="16" id="sensor2-reception-counter">
<i class="bi bi-person-workspace"></i>
<span data-i18n="sensorData.buttons.receptionCounter">Reception Counter</span>
</button>
</div>
</div>
</div>
<div class="card card-body">
<div id="chart-area">
<div id="chart-illuminance" style="display: none;" class="text-center">
<h3 class="chart-header" data-i18n="chart.heading.illuminance" data-i18n-options='{"sensor": ""}'></h3>
<!-- iframe will be inserted here -->
</div>
<div id="chart-temperature" style="display: none;" class="text-center">
<h3 class="chart-header" data-i18n="chart.heading.temperature" data-i18n-options='{"sensor": ""}'></h3>
<!-- iframe will be inserted here -->
</div>
<div id="chart-humidity" style="display: none;" class="text-center">
<h3 class="chart-header" data-i18n="chart.heading.humidity" data-i18n-options='{"sensor": ""}'></h3>
<!-- iframe will be inserted here -->
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<h6 data-i18n="footer.copyright">Copyright 2024 HFT Stuttgart</h6>
<ul class="copyright">
<h6 class="footer-link"><a href="#" target="_blank" data-i18n="footer.aboutUs">About Us</a></h6>
<h6 class="impressum footer-link"><a href="https://www.hft-stuttgart.com/imprint"
target="_blank" data-i18n="footer.impressum">Impressum</a></h6>
<h6 class="footer-link"><a href="https://www.hft-stuttgart.com/privacy" target="_blank"
data-i18n="footer.datenschutz">Datenschutz</a></h6>
</ul>
</div>
</div>
</div>
<div id="cesiumContainer" class="col"></div>
</div>
<script src="https://code.jquery.com/jquery-3.7.1.min.js"
integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<script src="https://unpkg.com/jquery-i18next@1.2.1/dist/umd/jquery-i18next.min.js"></script>
<script src="pack-min.js"></script>
</body>
</html>
\ No newline at end of file
This diff is collapsed.
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment