Commit 90443acc authored by JOE XMG's avatar JOE XMG
Browse files

update

parent 4c68f557
Pipeline #9120 passed with stage
in 19 seconds
{
"liveServer.settings.port": 5501
}
\ No newline at end of file
<!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>
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
...@@ -11,7 +12,7 @@ ...@@ -11,7 +12,7 @@
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script> <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> <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" /> <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> <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 @@ ...@@ -54,12 +55,38 @@
margin-bottom: 5px; margin-bottom: 5px;
} }
#mainMenu label {
color: white;
}
#mainMenu button { #mainMenu button {
margin-top: 10px; margin-top: 10px;
padding: 5px 10px; padding: 5px 10px;
cursor: pointer; 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 { #main-menu {
width: 20%; width: 20%;
height: 100%; height: 100%;
...@@ -80,15 +107,22 @@ ...@@ -80,15 +107,22 @@
#main { #main {
width: 36%; width: 60%;
height: 65%; height: 60%;
position:relative; position:relative;
top:35%; top: 36%;
right:0;
z-index: 1; z-index: 1;
} }
/* responsive */
#main canvas {
width: 100%;
height: 100%;
}
#viewDiv { #viewDiv {
width: 100%; width: 100%;
...@@ -103,6 +137,8 @@ ...@@ -103,6 +137,8 @@
display: none; display: none;
} }
.legend-building { .legend-building {
position: absolute; position: absolute;
bottom: 10px; bottom: 10px;
...@@ -116,13 +152,13 @@ ...@@ -116,13 +152,13 @@
} }
.legend { .legend {
position: absolute; position: relative;
top: 90%; top: 72%;
left: 36%; left: 51%;
padding: 5px; padding: 5px;
background-color: rgba(255, 255, 255, 0.8); background-color: rgba(255, 255, 255, 0.8);
border-radius: 5px; border-radius: 3px;
z-index: 1; z-index: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -166,11 +202,11 @@ ...@@ -166,11 +202,11 @@
#usage-pie-chart { #usage-pie-chart {
display: none; display: none;
width: 600px; width: 400px;
height: 400px; height: 300px;
z-index: 1; z-index: 0;
position: absolute; position: absolute;
top:65%; top:0%;
right: 0%; right: 0%;
bottom:0%; bottom:0%;
} }
...@@ -187,7 +223,7 @@ ...@@ -187,7 +223,7 @@
<div id="timeSlider"></div> <div id="timeSlider"></div>
<div id="usage-pie-chart"></div> <div id="usage-pie-chart"></div>
<div class="legend"></div>
<div class="legend-building"></div> <div class="legend-building"></div>
<div id="spaceTimeCubeContainer"> <div id="spaceTimeCubeContainer">
<div id="plotlyContainer"></div> <div id="plotlyContainer"></div>
...@@ -217,10 +253,12 @@ ...@@ -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="toggleSpaceTime">Bus Space-Time Visualization</button>
<button id="toggle3DButton">3D City Building</button> <button id="toggle3DButton">3D CityModel</button>
</div> </div>
...@@ -239,9 +277,39 @@ ...@@ -239,9 +277,39 @@
//to ensure if plotly and mapbox are loaded //to ensure if plotly and mapbox are loaded
if (window.Plotly && window.L) { if (window.Plotly && window.L) {
document.getElementById("loadDatastream").addEventListener("click", function () { document.getElementById("loadDatastream").addEventListener("click", function () {
var selectedMeasurementType = document.getElementById("measurementType").value; var selectedMeasurementType = document.getElementById("measurementType").value;
var selectedChartType = document.getElementById("chartType").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 @@ ...@@ -310,8 +378,8 @@
myChart.setOption({ myChart.setOption({
backgroundColor: 'dark-gray', backgroundColor: 'dark-gray',
title: { title: {
text: selectedMeasurementType.charAt(0).toUpperCase() + selectedMeasurementType.slice(1) + text: ' Data Stream Result Observing ' + selectedMeasurementType.charAt(0).toUpperCase() + selectedMeasurementType.slice(1),
' Results at Different Sensor Locations',
left: 'center', left: 'center',
textStyle: { textStyle: {
color: 'white', color: 'white',
...@@ -321,7 +389,7 @@ ...@@ -321,7 +389,7 @@
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.7)', backgroundColor: 'rgba(230, 230, 255, 0.9)',
formatter: function (params) { formatter: function (params) {
var timestamp = new Date(params[0].value[0]); var timestamp = new Date(params[0].value[0]);
var formattedTime = timestamp.toLocaleString(); var formattedTime = timestamp.toLocaleString();
...@@ -341,12 +409,12 @@ ...@@ -341,12 +409,12 @@
}, },
xAxis: { xAxis: {
name: 'Phenomenon Time', name: 'Date Time',
type: 'time', type: 'time',
boundaryGap: false, boundaryGap: false,
axisLabel: { axisLabel: {
color: 'green', color: 'green',
fontSize: 20, fontSize: 18,
}, },
}, },
yAxis: { yAxis: {
...@@ -363,7 +431,7 @@ ...@@ -363,7 +431,7 @@
itemStyle: { itemStyle: {
color: locationColors[locationData.location], color: locationColors[locationData.location],
emphasis: { emphasis: {
color: 'white', color: 'red',
fontWeight: 'bold', fontWeight: 'bold',
}, },
}, },
...@@ -427,7 +495,6 @@ ...@@ -427,7 +495,6 @@
function createLegendItem(color, label, id) { function createLegendItem(color, label, id) {
const legendItem = document.createElement("div"); const legendItem = document.createElement("div");
legendItem.className = "legend-item"; legendItem.className = "legend-item";
...@@ -450,123 +517,6 @@ ...@@ -450,123 +517,6 @@
return legendItem; 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 // Function to toggle space-time visualization
document.getElementById("toggleSpaceTime").addEventListener("click", function () { document.getElementById("toggleSpaceTime").addEventListener("click", function () {
...@@ -577,13 +527,21 @@ const layout = { ...@@ -577,13 +527,21 @@ const layout = {
console.error("Plotly or Mapbox not loaded. Check if the libraries are loaded correctly."); 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() { function loadHistoricalRoutes() {
// to fetch historical data and update the scene layer // 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'); animateHistoricalMovingFeatures('https://ogcapi.hft-stuttgart.de/ogc_api_moving_features/collections/bus_1/items', [226, 119, 40], 'Bus', 'Bus', 'busLegend');
} }
</script> </script>
<script> <script>
...@@ -916,22 +874,32 @@ document.getElementById("toggle3DButton").addEventListener("click", function () ...@@ -916,22 +874,32 @@ document.getElementById("toggle3DButton").addEventListener("click", function ()
// Toggle 3D building layer visibility // Toggle 3D building layer visibility
hostedLayer.visible = !hostedLayer.visible; 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 // Toggle pie chart visibility based on 3D building visibility
const pieChartContainer = document.getElementById("usage-pie-chart"); const pieChartContainer = document.getElementById("usage-pie-chart");
const echartContainer = document.getElementById("main");
const legendContainer = document.querySelector('.legend'); const legendContainer = document.querySelector('.legend');
const currentDisplay = pieChartContainer.style.display; const currentDisplay = pieChartContainer.style.display;
const loadDatastreamButton = document.getElementById("loadDatastream");
if (hostedLayer.visible) { if (hostedLayer.visible) {
// If 3D building is visible, show the pie chart // If 3D building is visible, show the pie chart
pieChartContainer.style.display = "block"; pieChartContainer.style.display = "block";
echartContainer.style.display = "none";
legendContainer.style.display = "none"; legendContainer.style.display = "none";
} else { } else {
// If 3D building is hidden, hide the pie chart // If 3D building is hidden, hide the pie chart
pieChartContainer.style.display = "none"; pieChartContainer.style.display = "none";
echartContainer.style.display = "block";
legendContainer.style.display = "block"; legendContainer.style.display = "block";
} }
}); });
...@@ -939,9 +907,6 @@ document.getElementById("toggle3DButton").addEventListener("click", function () ...@@ -939,9 +907,6 @@ document.getElementById("toggle3DButton").addEventListener("click", function ()
const graphicsLayer = new GraphicsLayer(); const graphicsLayer = new GraphicsLayer();
map.add(graphicsLayer); map.add(graphicsLayer);
...@@ -1115,74 +1080,6 @@ animateMovingFeatures("https://ogcapi.hft-stuttgart.de/ogc_api_moving_features/c ...@@ -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> </script>
......
Markdown is supported
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