Skip to content

Commit aed1893

Browse files
Merge pull request #2518 from sensei-hacker/fix/terrain-elevation-chart-esm
Fix: Re-enable terrain elevation chart with Chart.js ESM support
2 parents 73df5e7 + bef73fc commit aed1893

File tree

3 files changed

+769
-335
lines changed

3 files changed

+769
-335
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"acorn": "^8.14.0",
2323
"@electron/remote": "^2.1.3",
2424
"browserify-fs": "^1.0.0",
25+
"chart.js": "^4.4.1",
2526
"d3": "^7.9.0",
2627
"electron-squirrel-startup": "^1.0.1",
2728
"electron-store": "^10.1.0",

tabs/mission_control.js

Lines changed: 183 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
'use strict';
22

33
import xml2js from 'xml2js';
4+
import { Chart, registerables } from 'chart.js';
5+
6+
// Register Chart.js components
7+
Chart.register(...registerables);
8+
9+
// Make Chart available globally for plotElevation function
10+
window.Chart = Chart;
411

512
import Map from 'ol/Map.js';
613
import XYZ from 'ol/source/XYZ.js';
@@ -2333,6 +2340,9 @@ function iconKey(filename) {
23332340

23342341
plotElevation();
23352342
})()
2343+
} else {
2344+
// Update elevation chart even for non-selected waypoints
2345+
plotElevation();
23362346
}
23372347
}
23382348
else if (tempMarker.kind == "home" ) {
@@ -4221,131 +4231,197 @@ function iconKey(filename) {
42214231
return altitude;
42224232
}
42234233

4234+
// Track elevation chart update sequence to prevent race conditions
4235+
let elevationUpdateSequence = 0;
4236+
42244237
function plotElevation() {
4225-
/*
42264238
if ($('#missionPlannerElevation').is(":visible") && !disableMarkerEdit) {
42274239
if (mission.isEmpty()) {
4228-
var data = [[0], [0]];
4229-
var layout = {showlegend: true,
4230-
legend: {
4231-
"orientation": "h",
4232-
xanchor: "center",
4233-
y: 1.3,
4234-
x: 0.5
4235-
},
4236-
title: 'Mission Elevation Profile',
4237-
xaxis: {
4238-
title: 'Distance (m)'
4239-
},
4240-
yaxis: {
4241-
title: 'Elevation (m)',
4242-
},
4243-
height: 300,
4244-
}
4245-
//Plotly.newPlot('elevationDiv', data, layout);
4246-
4247-
var ctx = $("#elevationChart").get(0);
4248-
4249-
new Chart(ctx, {
4240+
const ctx = $("#elevationChart").get(0);
4241+
4242+
if (!ctx || ctx.tagName !== 'CANVAS') {
4243+
console.error('elevationChart canvas element not found');
4244+
return;
4245+
}
4246+
4247+
// Destroy existing chart if it exists
4248+
if (window.elevationChartInstance) {
4249+
window.elevationChartInstance.destroy();
4250+
window.elevationChartInstance = null;
4251+
}
4252+
4253+
// Create empty chart with message
4254+
window.elevationChartInstance = new Chart(ctx, {
42504255
type: 'line',
42514256
data: {
4252-
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
4253-
datasets: [
4254-
{
4255-
label: 'One',
4256-
data: [12, 19, 3, 5, 2, 3],
4257-
borderWidth: 1,
4258-
fill: 'start',
4259-
},
4260-
{
4261-
label: 'Two',
4262-
data: [13, 21, 7, 7, 3, 6],
4263-
borderWidth: 2,
4264-
radius: 0
4265-
}
4266-
]
4257+
labels: [0],
4258+
datasets: [
4259+
{
4260+
label: 'WGS84 elevation',
4261+
data: [{x: 0, y: 0}],
4262+
borderColor: '#ff7f0e',
4263+
backgroundColor: 'rgba(255, 127, 14, 0.2)',
4264+
borderWidth: 2,
4265+
fill: true,
4266+
pointRadius: 0,
4267+
},
4268+
{
4269+
label: 'Mission altitude',
4270+
data: [{x: 0, y: 0}],
4271+
borderColor: '#1497f1',
4272+
backgroundColor: 'rgba(20, 151, 241, 0)',
4273+
borderWidth: 2,
4274+
pointRadius: 5,
4275+
pointBackgroundColor: '#1f77b4',
4276+
}
4277+
]
42674278
},
42684279
options: {
4280+
responsive: true,
42694281
maintainAspectRatio: false,
4282+
plugins: {
4283+
title: {
4284+
display: true,
4285+
text: 'Mission Elevation Profile'
4286+
},
4287+
legend: {
4288+
display: true,
4289+
position: 'top',
4290+
}
4291+
},
42704292
scales: {
4271-
y: {
4272-
beginAtZero: true
4293+
x: {
4294+
type: 'linear',
4295+
title: {
4296+
display: true,
4297+
text: 'Distance (m)'
4298+
}
4299+
},
4300+
y: {
4301+
title: {
4302+
display: true,
4303+
text: 'Elevation (m)'
4304+
},
4305+
beginAtZero: true
4306+
}
42734307
}
4274-
}
42754308
}
4276-
});
4309+
});
42774310
}
42784311
else {
42794312
(async () => {
4280-
const [lengthMission, totalMissionDistance, samples, elevation, altPoint2measure, namePoint2measure, refPoint2measure] = await mission.getElevation(globalSettings);
4281-
let x_elevation = Array.from(Array(samples+1), (_,i)=> i*totalMissionDistance/samples);
4282-
var trace_WGS84 = {
4283-
x: x_elevation,
4284-
y: elevation,
4285-
type: 'scatter',
4286-
name: 'WGS84 elevation',
4287-
hovertemplate: '<b>Elevation</b>: %{y} m',
4288-
fill: 'tozeroy',
4289-
line: {
4290-
color: '#ff7f0e',
4291-
},
4292-
};
4293-
let y_missionElevation = altPoint2measure.map((x,i) => x / 100 + HOME.getAlt()*(1-refPoint2measure[i]));
4294-
let y_elevationReference = refPoint2measure.map((x,i) => (x == 1 ? "WGS84" : "Take-off Home"));
4295-
var trace_missionHeight = {
4296-
x: lengthMission,
4297-
y: y_missionElevation ,
4298-
type: 'scatter',
4299-
mode: 'lines+markers+text',
4300-
name: 'Mission altitude',
4301-
text: namePoint2measure,
4302-
textposition: 'top center',
4303-
textfont: {
4304-
family: 'Raleway, sans-serif'
4305-
},
4306-
customdata: y_elevationReference,
4307-
hovertemplate: '<b>WP</b>: %{text}' +
4308-
'<br><b>Elevation</b>: %{y} m<br>' +
4309-
'<b>Reference</b>: %{customdata}',
4310-
line: {
4311-
color: '#1497f1',
4312-
},
4313-
marker: {
4314-
color: '#1f77b4',
4315-
},
4316-
};
4317-
Show multi mission number in plot title when single mission displayed
4318-
* Not updated when ALL multi missions displayed since plot disabled
4319-
4320-
let missionNumber = '';
4321-
if (multimissionCount) {
4322-
missionNumber = ' ' + ($('#multimissionOptionList').val());
4313+
// Capture current sequence number to detect stale updates
4314+
const currentSequence = ++elevationUpdateSequence;
4315+
4316+
try {
4317+
const [lengthMission, totalMissionDistance, samples, elevation, altPoint2measure, namePoint2measure, refPoint2measure] = await mission.getElevation(globalSettings);
4318+
4319+
// Check if a newer update has been triggered while we were fetching data
4320+
if (currentSequence !== elevationUpdateSequence) {
4321+
console.log('Ignoring stale elevation data');
4322+
return;
4323+
}
4324+
const x_elevation = Array.from(Array(samples+1), (_,i)=> i*totalMissionDistance/samples);
4325+
const y_missionElevation = altPoint2measure.map((x,i) => x / 100 + HOME.getAlt()*(1-refPoint2measure[i]));
4326+
4327+
/* Show multi mission number in plot title when single mission displayed
4328+
* Not updated when ALL multi missions displayed since plot disabled
4329+
*/
4330+
let missionNumber = '';
4331+
if (multimissionCount) {
4332+
missionNumber = ' ' + ($('#multimissionOptionList').val());
4333+
}
4334+
const chartTitle = 'Mission' + missionNumber + ' Elevation Profile';
4335+
4336+
// Calculate Y-axis range safely
4337+
const minElevation = elevation.length > 0 ? Math.min(...elevation) : 0;
4338+
const minMission = y_missionElevation.length > 0 ? Math.min(...y_missionElevation) : 0;
4339+
const maxElevation = elevation.length > 0 ? Math.max(...elevation) : 100;
4340+
const maxMission = y_missionElevation.length > 0 ? Math.max(...y_missionElevation) : 100;
4341+
4342+
const ctx = $("#elevationChart").get(0);
4343+
if (!ctx || ctx.tagName !== 'CANVAS') {
4344+
console.error('elevationChart canvas element not found');
4345+
return;
4346+
}
4347+
4348+
const newData = {
4349+
labels: x_elevation,
4350+
datasets: [
4351+
{
4352+
label: 'WGS84 elevation',
4353+
data: elevation.map((y, i) => ({x: x_elevation[i], y: y})),
4354+
borderColor: '#ff7f0e',
4355+
backgroundColor: 'rgba(255, 127, 14, 0.2)',
4356+
borderWidth: 2,
4357+
fill: true,
4358+
pointRadius: 0,
4359+
},
4360+
{
4361+
label: 'Mission altitude',
4362+
data: lengthMission.map((x, i) => ({x: x, y: y_missionElevation[i]})),
4363+
borderColor: '#1497f1',
4364+
backgroundColor: 'rgba(20, 151, 241, 0)',
4365+
borderWidth: 2,
4366+
pointRadius: 5,
4367+
pointBackgroundColor: '#1f77b4',
4368+
}
4369+
]
4370+
};
4371+
4372+
// Update existing chart if it exists, otherwise create new one
4373+
if (window.elevationChartInstance) {
4374+
// Update data
4375+
window.elevationChartInstance.data = newData;
4376+
window.elevationChartInstance.options.plugins.title.text = chartTitle;
4377+
window.elevationChartInstance.options.scales.y.min = Math.floor(-10 + Math.min(minMission, minElevation));
4378+
window.elevationChartInstance.options.scales.y.max = Math.ceil(10 + Math.max(maxMission, maxElevation));
4379+
// Trigger re-render without animation for better performance during drag operations
4380+
window.elevationChartInstance.update('none');
4381+
} else {
4382+
// Create new chart
4383+
window.elevationChartInstance = new Chart(ctx, {
4384+
type: 'line',
4385+
data: newData,
4386+
options: {
4387+
responsive: true,
4388+
maintainAspectRatio: false,
4389+
plugins: {
4390+
title: {
4391+
display: true,
4392+
text: chartTitle
4393+
},
4394+
legend: {
4395+
display: true,
4396+
position: 'top',
4397+
}
4398+
},
4399+
scales: {
4400+
x: {
4401+
type: 'linear',
4402+
title: {
4403+
display: true,
4404+
text: 'Distance (m)'
4405+
}
4406+
},
4407+
y: {
4408+
title: {
4409+
display: true,
4410+
text: 'Elevation (m)'
4411+
},
4412+
min: Math.floor(-10 + Math.min(minMission, minElevation)),
4413+
max: Math.ceil(10 + Math.max(maxMission, maxElevation))
4414+
}
4415+
}
4416+
}
4417+
});
4418+
}
4419+
} catch (error) {
4420+
console.error('Failed to plot elevation:', error);
43234421
}
4324-
var layout = {showlegend: true,
4325-
legend: {
4326-
"orientation": "h",
4327-
xanchor: "center",
4328-
y: 1.3,
4329-
x: 0.5
4330-
},
4331-
title: 'Mission' + missionNumber + ' Elevation Profile',
4332-
xaxis: {
4333-
title: 'Distance (m)'
4334-
},
4335-
yaxis: {
4336-
title: 'Elevation (m)',
4337-
range: [-10 + Math.min(Math.min(...y_missionElevation), Math.min(...elevation)), 10 + Math.max(Math.max(...y_missionElevation), Math.max(...elevation))],
4338-
},
4339-
height: 300,
4340-
}
4341-
4342-
var data = [trace_WGS84, trace_missionHeight];
4343-
4344-
//Plotly.newPlot('elevationDiv', data, layout);
43454422
})()
43464423
}
43474424
}
4348-
*/
43494425
}
43504426

43514427
function parseBooleans (str) {

0 commit comments

Comments
 (0)