Skip to content

Commit 8fd7171

Browse files
committed
Add dynamic time axis labels with zoom-adaptive grid intervals
- Grid vertical lines now scale based on zoom level using human-friendly intervals (10ms to 15min) - Time labels displayed at bottom showing elapsed time from log start - Labels format adapts to zoom level with appropriate decimal precision - Grid and labels aligned to log start time for consistent reference
1 parent 8557b7d commit 8fd7171

File tree

1 file changed

+89
-12
lines changed

1 file changed

+89
-12
lines changed

js/grapher.js

Lines changed: 89 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,58 @@ function FlightLogGrapher(flightLog, graphConfig, canvas, craftCanvas, analyserC
615615
canvasContext.fillRect(0,-plotHeight/2,canvas.width, plotHeight);
616616
}
617617

618+
// Human-friendly time intervals in microseconds
619+
var FRIENDLY_INTERVALS_MICROS = [
620+
10000, // 10ms
621+
25000, // 25ms
622+
50000, // 50ms
623+
100000, // 100ms
624+
250000, // 250ms
625+
500000, // 500ms
626+
1000000, // 1 second
627+
2000000, // 2 seconds
628+
5000000, // 5 seconds
629+
10000000, // 10 seconds
630+
30000000, // 30 seconds
631+
60000000, // 1 minute
632+
300000000, // 5 minutes
633+
900000000, // 15 minutes
634+
];
635+
636+
function calculateGridInterval(windowWidth) {
637+
var idealInterval = windowWidth / 8;
638+
return FRIENDLY_INTERVALS_MICROS.reduce(function(prev, curr) {
639+
return Math.abs(curr - idealInterval) < Math.abs(prev - idealInterval) ? curr : prev;
640+
});
641+
}
642+
643+
function formatTimeLabel(timeMicros, intervalMicros) {
644+
var timeSec = timeMicros / 1000000;
645+
var timeMin = timeSec / 60;
646+
var mins = Math.floor(timeMin);
647+
var secs = timeSec % 60;
648+
649+
// Determine decimal places needed based on interval
650+
var decimalPlaces = 0;
651+
if (intervalMicros < 100000) {
652+
decimalPlaces = 2; // 10ms, 25ms, 50ms intervals
653+
} else if (intervalMicros < 1000000) {
654+
decimalPlaces = 1; // 100ms-500ms intervals
655+
}
656+
657+
if (timeSec < 60) {
658+
// Under 1 minute: show as seconds
659+
return timeSec.toFixed(decimalPlaces) + "s";
660+
} else {
661+
// Over 1 minute: show as min:sec
662+
var secsStr = secs.toFixed(decimalPlaces);
663+
if (secs < 10) {
664+
secsStr = "0" + secsStr;
665+
}
666+
return mins + ":" + secsStr;
667+
}
668+
}
669+
618670
//Draw a grid
619671
function drawGrid(curve, plotHeight) {
620672
var settings = curve.getCurve(),
@@ -625,7 +677,7 @@ function FlightLogGrapher(flightLog, graphConfig, canvas, craftCanvas, analyserC
625677
yScale = -plotHeight/2;
626678

627679
canvasContext.strokeStyle = "rgba(255,255,255,0.5)"; // Grid Color
628-
canvasContext.setLineDash([1,10]); // Make the grid line a dash
680+
canvasContext.setLineDash([1,10]); // Make the grid line a dash
629681
canvasContext.lineWidth = 1;
630682
canvasContext.beginPath();
631683

@@ -637,21 +689,44 @@ function FlightLogGrapher(flightLog, graphConfig, canvas, craftCanvas, analyserC
637689
canvasContext.lineTo(canvas.width, yValue);
638690
}
639691
}
640-
// vertical lines
641-
for(var i=(windowStartTime / 100000).toFixed(0) * 100000; i<windowEndTime; i+=100000) {
642-
var x = timeToCanvasX(i);
692+
693+
// vertical lines with scaled intervals, aligned to log start time
694+
var timeInterval = calculateGridInterval(windowWidthMicros);
695+
var logMinTime = flightLog.getMinTime();
696+
var startTime = logMinTime + Math.floor((windowStartTime - logMinTime) / timeInterval) * timeInterval;
697+
698+
for (var t = startTime; t < windowEndTime; t += timeInterval) {
699+
var x = timeToCanvasX(t);
643700
canvasContext.moveTo(x, yScale);
644701
canvasContext.lineTo(x, -yScale);
645-
}
702+
}
646703

647704
canvasContext.stroke();
648705
canvasContext.setLineDash([]); // clear the dash
706+
}
649707

650-
// range values,
651-
//drawAxisLabel(max.toFixed(0), yScale + 12);
652-
//drawAxisLabel(min.toFixed(0), -yScale - 8);
653-
708+
// Draw time labels at the bottom of the canvas
709+
function drawTimeAxisLabels() {
710+
var timeInterval = calculateGridInterval(windowWidthMicros);
711+
var logMinTime = flightLog.getMinTime();
712+
// Align grid to log start time so labels show time from beginning of log
713+
var startTime = logMinTime + Math.floor((windowStartTime - logMinTime) / timeInterval) * timeInterval;
714+
// Leave margin on right for frame label
715+
var rightMargin = 120;
654716

717+
canvasContext.font = drawingParams.fontSizeAxisLabel + "pt " + DEFAULT_FONT_FACE;
718+
canvasContext.fillStyle = "rgba(255,255,255,0.7)";
719+
canvasContext.textAlign = 'center';
720+
721+
for (var t = startTime; t < windowEndTime; t += timeInterval) {
722+
var x = timeToCanvasX(t);
723+
// Only draw if within visible canvas area, with right margin for frame label
724+
if (x >= 0 && x <= canvas.width - rightMargin) {
725+
var relativeTime = t - logMinTime;
726+
var label = formatTimeLabel(relativeTime, timeInterval);
727+
canvasContext.fillText(label, x, canvas.height - 4);
728+
}
729+
}
655730
}
656731

657732
function drawAxisLabel(axisLabel, y) {
@@ -993,7 +1068,7 @@ function FlightLogGrapher(flightLog, graphConfig, canvas, craftCanvas, analyserC
9931068

9941069
//Draw a bar highlighting the current time if we are drawing any graphs
9951070
if (graphs.length) {
996-
var
1071+
var
9971072
centerX = canvas.width / 2;
9981073

9991074
canvasContext.strokeStyle = 'rgba(255, 64, 64, 0.2)';
@@ -1010,9 +1085,11 @@ function FlightLogGrapher(flightLog, graphConfig, canvas, craftCanvas, analyserC
10101085
canvasContext.moveTo(centerX, 0);
10111086
canvasContext.lineTo(centerX, canvas.height);
10121087
canvasContext.stroke();
1013-
1088+
1089+
// Draw time axis labels at bottom
1090+
drawTimeAxisLabels();
10141091
}
1015-
1092+
10161093
// Draw events - if option set or even if option is not set but there are graphs
10171094
// the option is for video export; if you export the video without any graphs set,
10181095
// then the events are not shown either (to keep the video clean. but

0 commit comments

Comments
 (0)