From 90443acc5f0530bc9ecbe8d0a247de379c4876be Mon Sep 17 00:00:00 2001 From: JOE XMG <thunyathep.s@outlook.com> Date: Tue, 20 Feb 2024 18:07:51 +0100 Subject: [PATCH] update --- public/udigit4icity/.vscode/settings.json | 3 + public/udigit4icity/STC.html | 175 ++++++++++++ public/udigit4icity/index.html | 329 ++++++++-------------- 3 files changed, 291 insertions(+), 216 deletions(-) create mode 100644 public/udigit4icity/.vscode/settings.json create mode 100644 public/udigit4icity/STC.html diff --git a/public/udigit4icity/.vscode/settings.json b/public/udigit4icity/.vscode/settings.json new file mode 100644 index 0000000..6f3a291 --- /dev/null +++ b/public/udigit4icity/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/public/udigit4icity/STC.html b/public/udigit4icity/STC.html new file mode 100644 index 0000000..d2dedca --- /dev/null +++ b/public/udigit4icity/STC.html @@ -0,0 +1,175 @@ +<!DOCTYPE html> +<html lang="en"> + +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>Space-Time Cube Visualization</title> + <!-- Include necessary libraries --> + <script src="https://cdn.jsdelivr.net/npm/@arcgis/core@latest"></script> + <script src="https://cdn.jsdelivr.net/npm/plotly.js-dist@latest"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.1.2/echarts.min.js"></script> + <style> + + #plotlyContainer { + height: 100vh; + position: absolute; + bottom: 0; + left: 0; + top: 6%; + right:100; + width: 100%; + z-index: 3; +} + + + </style> +</head> + +<body> + <!-- Add your HTML content here --> + <button id="toggleSpaceTime">Toggle Space-Time Cube</button> + <div id="spaceTimeCubeContainer" style="display: none;"> + <!-- Container for the space-time cube visualization --> + <div id="spaceTimeCube"></div> + </div> + + <!-- Container for Plotly visualization --> + <div id="plotlyContainer"></div> + + <script> + + document.getElementById("toggleSpaceTime").addEventListener("click", function () { + const spaceTimeContainer = document.getElementById("spaceTimeCubeContainer"); + console.log("Toggle button clicked"); + console.log("Current display style:", spaceTimeContainer.style.display); + spaceTimeContainer.style.display = spaceTimeContainer.style.display === "none" ? "block" : "none"; + console.log("New display style:", spaceTimeContainer.style.display); + + // If the space-time container is set to block initialize/reload the space-time visualization + if (spaceTimeContainer.style.display === "block") { + console.log("Initializing space-time visualization..."); + animateSpaceTimeRoute('https://ogcapi.hft-stuttgart.de/ogc_api_moving_features/collections/bus_1/items', 'spaceTimeCube', 'black', 'Bus'); + } + }); + + function animateSpaceTimeRoute(url, containerId, trainColor, trainName) { + fetch(url) + .then(response => response.json()) + .then(data => { + if (!data || !data.features) { + console.error('Invalid data format:', data); + return; + } +const frames = data.features.map((feature, index) => { + const coordinates = feature.geometry.coordinates; + const timestamps = feature.properties.datetimes; + + if (!Array.isArray(coordinates) || !Array.isArray(timestamps)) { + console.error('Invalid feature format:', feature); + return; + } + + const lineColors = Array.from({ length: coordinates.length - 1 }, () => 'orange'); // Create an array of orange colors + + return { + data: [ + { + type: 'scattermapbox', + lat: coordinates.map(coord => coord[1]), + lon: coordinates.map(coord => coord[0]), + mode: 'lines+markers', // Display both points and lines + marker: { size: 6, color: 'black' }, + line: { color: 'black' }, // This line is not used when mode is 'lines+markers' + name: 'Bus route', + }, + { + type: 'scatter3d', + x: coordinates.map(coord => coord[0]), + y: coordinates.map(coord => coord[1]), + z: timestamps.map((time, i) => new Date(time).toISOString()), + mode: 'lines+markers', // Change mode to display both points and lines + marker: { color: 'black', size: 5 }, + line: { color: 'red', size: 3 }, + name: 'Bus trajectory line', + }, + ], + name: `frame${index + 1}`, + }; +}); + + // Set the layout with mapbox style and access token + const layout = { + mapbox: { + style: 'light', + center: { lon: frames[0].data[0].lon[0], lat: frames[0].data[0].lat[0] }, + zoom: 10, + accesstoken: 'pk.eyJ1IjoicmVkaWV0OTk2MyIsImEiOiJjbHJ1cmk5aGUwaDRvMmpuYWM4Z2NqcmZuIn0.c11HYT-5ucd6g6mL03bp3Q', // Mapbox access token + }, + margin: { t: 0, b: 0, l: 0, r: 0 }, + scene: { + xaxis: { + title: 'Long', + titlefont: { + family: 'Arial, sans-serif', + size: 15, + color: 'black' + }, + tickfont: { + family: 'Arial, sans-serif', + size: 15, + color: 'black', + bold: true + } + }, + yaxis: { + title: 'Lat', + titlefont: { + family: 'Arial, sans-serif', + size: 15, + color: 'black' + }, + tickfont: { + family: 'Arial, sans-serif', + size: 15, + color: 'black', + bold: true + } + }, + zaxis: { + title: 'Time', + titlefont: { + family: 'Arial, sans-serif', + size: 16, + color: 'black' + }, + tickfont: { + family: 'Arial, sans-serif', + size: 15, + color: 'black', + bold: true + } + }, + // Common font settings for both + font: { + family: 'Arial, sans-serif', + size: 12, + color: 'black', + bold: true + } + } + }; + + // Initialize Plotly container + Plotly.newPlot('plotlyContainer', frames[0].data, layout); + Plotly.addFrames('plotlyContainer', frames); + }) + .catch(error => { + console.error('Error fetching data:', error); + }); + } + + </script> +</body> + +</html> diff --git a/public/udigit4icity/index.html b/public/udigit4icity/index.html index 8818943..22ac050 100644 --- a/public/udigit4icity/index.html +++ b/public/udigit4icity/index.html @@ -1,3 +1,4 @@ + <!DOCTYPE html> <html lang="en"> @@ -11,7 +12,7 @@ <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <script src="https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.js"></script> <link href="https://api.mapbox.com/mapbox.js/v3.3.1/mapbox.css" rel="stylesheet" /> - <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.common.min.js" integrity="sha512-klHlINboj5r1sfTjdyb2PJn7ixcYb5zN+WC/gbFlK3r8/nmhmwQ3yvi5q49tX39DcHX/HwPnXTIblG5/cb6IEA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> + <script src="https://cdn.jsdelivr.net/npm/echarts@5.2.2/dist/echarts.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.5.0/echarts.min.js" integrity="sha512-k37wQcV4v2h6jgYf5IUz1MoSKPpDs630XGSmCaCCOXxy2awgAWKHGZWr9nMyGgk3IOxA1NxdkN8r1JHgkUtMoQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> @@ -54,12 +55,38 @@ margin-bottom: 5px; } + #mainMenu label { + color: white; + } + #mainMenu button { margin-top: 10px; padding: 5px 10px; cursor: pointer; + color: white; /* Set the color of the text to white */ + margin-bottom: 10px; } + #mainMenu button { + border: none; /* Remove default button border */ + background: none; /* Remove default button background */ + cursor: pointer; + position: relative; /* Position for the separator line */ +} + +#mainMenu button:after { + content: ""; + position: absolute; + bottom: -5px; /* Adjust position of the separator line */ + left: 0; + width: 100%; + height: 2px; /* Adjust thickness of the separator line */ + background-color: red; /* Color of the separator line */ +} + + + + #main-menu { width: 20%; height: 100%; @@ -80,15 +107,22 @@ #main { - width: 36%; - height: 65%; + width: 60%; + height: 60%; position:relative; - top:35%; - right:0; + top: 36%; + z-index: 1; } + /* responsive */ + #main canvas { + width: 100%; + height: 100%; + } + + #viewDiv { width: 100%; @@ -103,6 +137,8 @@ display: none; } + + .legend-building { position: absolute; bottom: 10px; @@ -116,13 +152,13 @@ } .legend { - position: absolute; - top: 90%; - left: 36%; + position: relative; + top: 72%; + left: 51%; padding: 5px; background-color: rgba(255, 255, 255, 0.8); - border-radius: 5px; + border-radius: 3px; z-index: 1; display: flex; flex-direction: column; @@ -166,11 +202,11 @@ #usage-pie-chart { display: none; - width: 600px; - height: 400px; - z-index: 1; + width: 400px; + height: 300px; + z-index: 0; position: absolute; - top:65%; + top:0%; right: 0%; bottom:0%; } @@ -187,7 +223,7 @@ <div id="timeSlider"></div> <div id="usage-pie-chart"></div> - <div class="legend"></div> + <div class="legend-building"></div> <div id="spaceTimeCubeContainer"> <div id="plotlyContainer"></div> @@ -217,10 +253,12 @@ - <button id="loadDatastream">Load Datastream</button> + <button id="loadDatastream">Load Chart</button> + + <button id="toggleSpaceTime">Bus Space-Time Visualization</button> - <button id="toggle3DButton">3D City Building</button> + <button id="toggle3DButton">3D CityModel</button> </div> @@ -239,9 +277,39 @@ //to ensure if plotly and mapbox are loaded if (window.Plotly && window.L) { + + document.getElementById("loadDatastream").addEventListener("click", function () { var selectedMeasurementType = document.getElementById("measurementType").value; var selectedChartType = document.getElementById("chartType").value; + document.getElementById("loadDatastream").addEventListener("click", function() { + var chartContainer = document.getElementById("main"); + if (chartContainer.style.display === "none") { + // Datastream is not loaded, load it + loadDatastream(); + // Change the button text to "Close Chart" + this.innerText = "Close Chart"; + } else { + // Datastream is loaded, close it + closeDatastream(); + // Change the button text back to "Load Chart" + this.innerText = "Load Chart"; + } +}); + +function loadDatastream() { + // Code to load the datastream and display the chart + var chartContainer = document.getElementById("main"); + chartContainer.style.display = "block"; +} + +function closeDatastream() { + // Code to close the datastream and hide the chart + var chartContainer = document.getElementById("main"); + chartContainer.style.display = "none"; +} + +// Your existing code continues here... @@ -310,8 +378,8 @@ myChart.setOption({ backgroundColor: 'dark-gray', title: { - text: selectedMeasurementType.charAt(0).toUpperCase() + selectedMeasurementType.slice(1) + - ' Results at Different Sensor Locations', + text: ' Data Stream Result Observing ' + selectedMeasurementType.charAt(0).toUpperCase() + selectedMeasurementType.slice(1), + left: 'center', textStyle: { color: 'white', @@ -321,7 +389,7 @@ }, tooltip: { trigger: 'axis', - backgroundColor: 'rgba(0, 0, 0, 0.7)', + backgroundColor: 'rgba(230, 230, 255, 0.9)', formatter: function (params) { var timestamp = new Date(params[0].value[0]); var formattedTime = timestamp.toLocaleString(); @@ -341,12 +409,12 @@ }, xAxis: { - name: 'Phenomenon Time', + name: 'Date Time', type: 'time', boundaryGap: false, axisLabel: { color: 'green', - fontSize: 20, + fontSize: 18, }, }, yAxis: { @@ -363,7 +431,7 @@ itemStyle: { color: locationColors[locationData.location], emphasis: { - color: 'white', + color: 'red', fontWeight: 'bold', }, }, @@ -427,7 +495,6 @@ - function createLegendItem(color, label, id) { const legendItem = document.createElement("div"); legendItem.className = "legend-item"; @@ -450,123 +517,6 @@ return legendItem; } - // To animating space-time routes directly - animateSpaceTimeRoutes('https://ogcapi.hft-stuttgart.de/ogc_api_moving_features/collections/bus_1/items'); - function animateSpaceTimeRoutes(url) { - fetch(url) - .then(response => response.json()) - .then(data => { - if (!data || !data.features) { - console.error('Invalid data format:', data); - return; - } - - const frames = data.features.map((feature, index) => { - const coordinates = feature.geometry.coordinates; - const timestamps = feature.properties.datetimes; - - if (!Array.isArray(coordinates) || !Array.isArray(timestamps)) { - console.error('Invalid feature format:', feature); - return; - } - - return { - data: [ - { - type: 'scattermapbox', - lat: coordinates.map(coord => coord[1]), - lon: coordinates.map(coord => coord[0]), - mode: 'lines+markers', - marker: { size: 6, color: 'black' }, - line: { color: 'black' }, - name: 'Bus route', - }, - { - type: 'scatter3d', - x: coordinates.map(coord => coord[0]), - y: coordinates.map(coord => coord[1]), - z: timestamps.map((time, i) => new Date(time).toISOString()), - - mode: 'lines+markers', - line: { color: 'dark' }, - name: 'Bus trajectory line', - }, - ], - name: `frame${index + 1}`, - }; - }); - - // to set the layout with mapbox _ access token - -const layout = { - mapbox: { - style: 'light', - center: { lon: frames[0].data[0].lon[0], lat: frames[0].data[0].lat[0] }, - zoom: 10, - accesstoken: 'pk.eyJ1IjoicmVkaWV0OTk2MyIsImEiOiJjbHJ1cmk5aGUwaDRvMmpuYWM4Z2NqcmZuIn0.c11HYT-5ucd6g6mL03bp3Q', // Mapbox access token - }, - margin: { t: 0, b: 0, l: 0, r: 0 }, - scene: { - xaxis: { - title: 'X Axis', - titlefont: { - family: 'Arial, sans-serif', - size: 15, - color: 'black' - }, - tickfont: { - family: 'Arial, sans-serif', - size: 15, - color: 'black', - bold: true - } - }, - yaxis: { - title: 'Y Axis', - titlefont: { - family: 'Arial, sans-serif', - size: 15, - color: 'black' - }, - tickfont: { - family: 'Arial, sans-serif', - size: 15, - color: 'black', - bold: true - } - }, - zaxis: { - title: 'Time', - titlefont: { - family: 'Arial, sans-serif', - size: 16, - color: 'black' - }, - tickfont: { - family: 'Arial, sans-serif', - size: 15, - color: 'black', - bold: true - } - }, - // Common font settings for both - font: { - family: 'Arial, sans-serif', - size: 12, - color: 'black', - bold: true - } - } -}; - - // Initialize Plotly container - Plotly.newPlot('plotlyContainer', frames[0].data, layout); - Plotly.addFrames('plotlyContainer', frames); - }) - .catch(error => { - console.error('Error fetching data:', error); - }); - } // Function to toggle space-time visualization document.getElementById("toggleSpaceTime").addEventListener("click", function () { @@ -577,13 +527,21 @@ const layout = { console.error("Plotly or Mapbox not loaded. Check if the libraries are loaded correctly."); } + document.getElementById("toggleSpaceTime").addEventListener("click", function () { + // URL for the space-time visualization page + var spaceTimeURL = "/STC.html"; + + // Open the space-time visualization page in a new window + window.open(spaceTimeURL, "_blank"); +}); + + function loadHistoricalRoutes() { // to fetch historical data and update the scene layer animateHistoricalMovingFeatures('https://ogcapi.hft-stuttgart.de/ogc_api_moving_features/collections/bus_1/items', [226, 119, 40], 'Bus', 'Bus', 'busLegend'); } - </script> <script> @@ -916,22 +874,32 @@ document.getElementById("toggle3DButton").addEventListener("click", function () // Toggle 3D building layer visibility hostedLayer.visible = !hostedLayer.visible; + // Update button text based on 3D building visibility + const button = document.getElementById("toggle3DButton"); + if (hostedLayer.visible) { + // If 3D building is visible, change button text to "Hide 3D CityModel" + button.innerText = "Hide 3D CityModel"; + } else { + // If 3D building is hidden, change button text to "Show 3D CityModel" + button.innerText = "Show 3D CityModel"; + } + // Toggle pie chart visibility based on 3D building visibility const pieChartContainer = document.getElementById("usage-pie-chart"); - const echartContainer = document.getElementById("main"); + const legendContainer = document.querySelector('.legend'); const currentDisplay = pieChartContainer.style.display; - const loadDatastreamButton = document.getElementById("loadDatastream"); + if (hostedLayer.visible) { // If 3D building is visible, show the pie chart pieChartContainer.style.display = "block"; - echartContainer.style.display = "none"; + legendContainer.style.display = "none"; } else { // If 3D building is hidden, hide the pie chart pieChartContainer.style.display = "none"; - echartContainer.style.display = "block"; + legendContainer.style.display = "block"; } }); @@ -939,9 +907,6 @@ document.getElementById("toggle3DButton").addEventListener("click", function () - - - const graphicsLayer = new GraphicsLayer(); map.add(graphicsLayer); @@ -1115,74 +1080,6 @@ animateMovingFeatures("https://ogcapi.hft-stuttgart.de/ogc_api_moving_features/c }); - function animateSpaceTimeRoute(url, containerId, trainColor, trainName) { - fetch(url) - .then(response => response.json()) - .then(data => { - if (!data || !data.features) { - console.error('Invalid data format:', data); - return; - } - - const features = Array.isArray(data.features) ? data.features : [data.features]; - - const frames = features.map((feature, index) => { - const coordinates = feature.geometry.coordinates; - const timestamps = feature.properties.datetimes; - - if (!Array.isArray(coordinates) || !Array.isArray(timestamps)) { - console.error('Invalid feature format:', feature); - return; - } - - return { - data: [ - { - type: 'scattermapbox', - lat: coordinates.map(coord => coord[1]), - lon: coordinates.map(coord => coord[0]), - mode: 'lines+markers', - marker: { size: 20, color: trainColor }, - line: { color: trainColor }, - name: `Bus route`, - }, - { - type: 'scatter3d', - x: coordinates.map(coord => coord[0]), - y: coordinates.map(coord => coord[1]), - z: timestamps.map((time, i) => new Date(time).toISOString()), // convert to ISO format - mode: 'lines+markers', - line: { color: trainColor }, - text: timestamps.map((time) => new Date(time).toLocaleTimeString()), // labels on the points - name: `Bus Space-Time - ${index + 1}`, - }, - ], - name: `Frame ${index + 1}`, - }; - }); - - // Set the layout with mapbox style and access token - const layout = { - mapbox: { - style: 'light', - center: { lon: features[0].geometry.coordinates[0][0], lat: features[0].geometry.coordinates[0][1] }, - zoom: 10, - accesstoken: 'pk.eyJ1IjoicmVkaWV0OTk2MyIsImEiOiJjbHJ1cmk5aGUwaDRvMmpuYWM4Z2NqcmZuIn0.c11HYT-5ucd6g6mL03bp3Q', - }, - margin: { t: 0, b: 0, l: 0, r: 0 }, - - }; - - // initialize Plotly container - Plotly.newPlot(containerId, frames[0].data, layout); - - // adding frames - Plotly.addFrames(containerId, frames); - }) - .catch(error => { - console.error('Error fetching data:', error); - }); - } </script> -- GitLab