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:
   
![tvnviewer_2024-08-05_21-15-24](https://github.com/user-attachments/assets/c94f3b29-5426-4b12-8c14-50d8ed641f05)
   
   


-- 
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]

Reply via email to