jlpoolen commented on issue #20229:
URL: https://github.com/apache/echarts/issues/20229#issuecomment-2270350084
Here's the HTML and JavaScript, with redactions:
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chart with Map 2</title>
<link rel="stylesheet" type="text/css" href="REDACTED/maplibre-gl.css">
<script src="REDACTED/maplibre-gl.js"></script>
<script
src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
<style>
body {
background: #fff;
color: #333;
font-family: Arial, sans-serif;
}
#map-container {
width: 100%;
height: 80vh;
position: absolute;
top: 0;
left: 0;
z-index: 1;
}
#map {
width: 100%;
height: 100%;
}
#chart-container {
width: 100%;
height: 80vh;
position: absolute;
top: 0;
left: 0;
background-color: rgba(255, 255, 255, 0); /* Semi-transparent
background */
z-index: 2;
}
#plane-icon {
position: absolute;
width: 30px;
height: 30px;
display: none;
z-index: 3; /* Ensure the icon is above other elements */
}
#control-button, #restart-button {
position: fixed;
bottom: 20px; /* Adjust this value as needed */
left: 50%;
transform: translateX(-50%);
z-index: 4; /* Ensure the buttons are above other elements */
margin-top: 20px;
}
#restart-button {
display: none;
}
#widget-container {
position: fixed;
bottom: 0;
width: 100%;
height: 20vh; /* Adjust this value based on your needs */
background-color: #fff; /* Optional: Set a background color */
z-index: 4; /* Ensure the widget area is above other elements */
display: flex;
justify-content: center; /* Center widgets horizontally */
align-items: center; /* Center widgets vertically */
}
#map-plane-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 50px; /* Set a width */
height: 50px; /* Set a height */
z-index: 10; /* Ensure the icon is above other elements */
}
</style>
</head>
<body>
<div id="map-container">
<div id="map"></div>
<img id="map-plane-icon" src="map_plane.svg" alt="Map Jet">
</div>
<div id="chart-container"></div>
<div id="widget-container">
<button id="control-button">Halt Animation</button>
<button id="restart-button">Restart Animation</button>
</div>
<img id="plane-icon" src="plane_cropped.png" alt="Chart Jet">
<script type="module" src="./map_anim.js"></script>
<script>
// Initialize the MapLibre GL JS map
var map = new maplibregl.Map({
container: 'map',
style: 'https://[REDACTED]',
center: [REDACTED, REDACTED], // starting position [lng, lat]
zoom: 14 // starting zoom
});
</script>
</body>
</html>
```
```
map_anim.js:
import { tsv } from "https://cdn.skypack.dev/d3-fetch@3";
const animationSpeed = 1000; // 1,000 = 1 second which aligns with data
subset
const ZoomTopLimit = 12;
const ZoomBottomLimit = 19;
const altTopLimit = 4000;
const altBottomLimit = 200;
function calculateZoomLevel(altitude) {
if (altitude >= altTopLimit) {
return ZoomTopLimit;
}
if (altitude <= altBottomLimit) {
return ZoomBottomLimit;
}
const zoomLevel = ZoomTopLimit +
((altTopLimit - altitude) / (altTopLimit - altBottomLimit)) *
(ZoomBottomLimit - ZoomTopLimit);
return zoomLevel;
}
document.addEventListener("DOMContentLoaded", function() {
const mapContainer = document.getElementById('map');
const chartDom = document.getElementById('chart-container');
const myChart = echarts.init(chartDom);
let option;
let animationInterval;
let currentIndex = 0;
let isAnimating = true;
// Initialize the map
const map = new maplibregl.Map({
container: 'map',
style: 'REDACTED.json',
center: [REDACTED, REDACTED], // starting position [lng, lat]
zoom: 14 // starting zoom
});
// Convert row to minutes and seconds
function convertRowToMinutes(row) {
const minutes = Math.floor(row / 60);
const seconds = row % 60;
return `${minutes}'${seconds}"`;
}
// Describe: which animation? both map and plane that follows eChart path?
function startAnimation(seriesData) {
const mapPlaneIcon = document.getElementById('map-plane-icon'); // Map
Jet
if (!mapPlaneIcon) {
console.error("Error: map-plane-icon element not found.");
return;
}
const echartPlaneIcon = document.getElementById('plane-icon'); // Chart
Jet
if (!echartPlaneIcon) {
console.error("Error: plane-icon element not found.");
return;
}
echartPlaneIcon.style.display = 'block';
// Describe:
animationInterval = setInterval(() => {
if (currentIndex >= seriesData.length) {
clearInterval(animationInterval);
document.getElementById('control-button').style.display = 'none';
document.getElementById('restart-button').style.display = 'block';
return;
}
const dataPoint = seriesData[currentIndex];
const coords = myChart.convertToPixel('grid', dataPoint.value);
echartPlaneIcon.style.left = `${coords[0] - echartPlaneIcon.width /
2}px`;
echartPlaneIcon.style.top = `${coords[1] }px`; // Adjust as necessary
// Update map center and zoom based on altitude
map.setCenter([dataPoint.longitude, dataPoint.latitude]);
const altitude = dataPoint.altitude;
const zoomLevel = calculateZoomLevel(altitude);
//console.log(zoomLevel);
map.setZoom(zoomLevel);
currentIndex++;
}, animationSpeed);
}
// Function to halt animation
function haltAnimation() {
clearInterval(animationInterval);
isAnimating = false;
document.getElementById('control-button').innerText = "Resume Animation";
}
// Function to resume animation
function resumeAnimation(seriesData) {
isAnimating = true;
document.getElementById('control-button').innerText = "Halt Animation";
startAnimation(seriesData);
}
// Function to restart animation
function restartAnimation(seriesData) {
currentIndex = 0;
isAnimating = true;
document.getElementById('control-button').style.display = 'block';
document.getElementById('restart-button').style.display = 'none';
startAnimation(seriesData);
}
// Load and process data
tsv('REDACTEDjet_tracks.csv').then(data => {
const processedData = data.map((d, index) => {
return {
...d,
Altitude: +d.Altitude,
spaceFlag: +d.spaceFlag,
rownumber: +d.rownumber,
Latitude: +d.Latitude,
Longitude: +d.Longitude
};
});
const seriesData = processedData.map(d => ({
value: [d.rownumber, d.Altitude],
longitude: d.Longitude,
latitude: d.Latitude,
altitude: d.Altitude,
itemStyle: {
color: d.spaceFlag === 1 ? 'red' : (d.Altitude < 1000 ? 'orange' :
'green')
},
tooltip: {
formatter: `
Latitude: ${d.Latitude}<br>
Longitude: ${d.Longitude}<br>
Altitude: ${d.Altitude} feet<br>
Relative Time: ${convertRowToMinutes(d.rownumber)}<br>
Real Time: ${d.Time} Zulu
`
}
}));
option = {
tooltip: {
trigger: 'item',
formatter: function(params) {
return params.data.tooltip.formatter;
}
},
xAxis: {
type: 'category',
data: processedData.map(d => convertRowToMinutes(d.rownumber)),
name: 'Time (Minutes and Seconds)'
},
yAxis: {
type: 'value',
name: 'Altitude (Feet)',
min: 0,
max: 4000
},
series: [{
type: 'scatter',
data: seriesData
}]
};
option && myChart.setOption(option);
// Start animation by default
startAnimation(seriesData);
// Control button event listener
document.getElementById('control-button').addEventListener('click', ()
=> {
if (isAnimating) {
haltAnimation();
} else {
resumeAnimation(seriesData);
}
});
// Restart button event listener
document.getElementById('restart-button').addEventListener('click', ()
=> {
restartAnimation(seriesData);
});
}).catch(error => {
console.error("Error loading or processing data: ", error);
});
});
```
Sample data set (tsv expects header row):
```
rownumber spaceFlag Date Time Epoch Altitude
Longitude Latitude
1 0 2024/04/24 19:42:53.824 1713987773 2300
-123.106973 45.037628
2 0 2024/04/24 19:42:54.355 1713987774 2300
-123.106697 45.037242
```
And here is a screenshot of the current implementation:

--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]