Skip to content

Change sample time line to vertical layout - #531

Open
pengbins wants to merge 4 commits into
gpac:mainfrom
pengbins:sample_time_line_vertical_layout
Open

pengbins wants to merge 4 commits into
gpac:mainfrom
pengbins:sample_time_line_vertical_layout

Conversation

@pengbins

@pengbins pengbins commented Dec 7, 2025 •

Copy link
Copy Markdown

Description

This PR try to imporve the readability of sample timeline in filereader demo. The horizontal layout for displaying Decoding and Composition mapping was too compact and difficult to interpret. The changes introduce a vertical layout and add hover highlighting to clearly visualize the correspondence between Decoding and Composition sample mappings.

Changes Made

  1. Layout Restructuring
  • Changed from a compact horizontal arrangement to a clear vertical stacked layout

  • Improved visual separation and alignment between Decoding and Composition timelines

  1. Interactive Enhancement
  • Added mouse hover highlighting that visually links corresponding Decoding and Composition pair.

Benefits

✅ Enhanced Readability: Vertical layout provides more space and reduces visual clutter

✅ Better Mapping Visualization: Hover highlighting instantly shows Decoding ↔ Composition relationships

✅ Improved User Experience: Intuitive interaction helps users understand sample mappings without guesswork

✅ Maintains All Functionality: All existing features remain fully functional

Visual Comparison

  • Before: Compact horizontal layout making it hard to trace mappings
image
  • After: Clean vertical layout with hover highlighting for clear relationship visualization
image

@rbouqueau

Copy link
Copy Markdown
Member

Looks better, thanks for your contribution. I'll let @DenizUgur validate the technical side and merge.

@changeset-bot

changeset-bot Bot commented May 24, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: cf45a9a

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@rbouqueau

Copy link
Copy Markdown
Member

Didn't get any feedback so I submitted it roughly to my LLM:

I’d keep the vertical layout and hover approach, but fix the SVG sizing before merging. I reviewed [PR #531](#531) at 89fb972.

The main problem is that [the SVG viewport still uses the browser’s dimensions](

mp4box.js/demo/filereader.js

Lines 1077 to 1093 in 89fb972

function SampleTimeline() {
var margin = { top: 10, right: 10, bottom: 80, left: 20 };
var width = (this.width = document.body.clientWidth - margin.left - margin.right);
var height = (this.height = window.innerHeight - margin.top - margin.bottom);
var div = d3.select('#sampletimeline');
div.html('');
this.svg = div
.append('svg')
.attr('width', '100%')
.attr('height', '100%')
.attr(
'viewBox',
'0 0 ' + (width + margin.left + margin.right) + ' ' + (height + margin.top + margin.bottom),
)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
), while the vertical content grows with sample timestamps.

Using the actual D3 code, I reproduced two regressions:

  • 1280×600, 20 equal-duration samples: the old layout fits everything; the PR places the final two sample pairs outside the viewport.
  • 320-pixel width, two samples: the old layout fits; the PR’s composition column extends to x=380 and is partially clipped.

Two inherited issues also remain: negative composition timestamps can fall outside the viewport, and updating with an empty selection leaves the previous samples displayed.

I prepared a refinement patch, applicable on top of the PR. It:

  • Sizes the SVG to the full timestamp range, allowing normal page scrolling.
  • Uses a content-sized width that scales down on narrow screens.
  • Includes both DTS and CTS when choosing the timeline origin.
  • Clears old samples when the selection becomes empty.

Validation: ten targeted DOM/SVG scenarios passed, including reordered timestamps, variable durations, and repeated updates. JavaScript syntax checking passed. Browser visual and hover verification remain untested because browser access was unavailable.

Your checkout is unchanged.


The LLM suggested the following update:

--- a/demo/filereader.js
+++ b/demo/filereader.js
@@ -1006,18 +1006,23 @@
   }
 }
 
-function verticalTimeline () {
-  var that = this;
-  var data = this.data;
-  if (!data || data.length === 0) {
-    return;
-  }
-  var scale = data[0].duration ? 30 / data[0].duration : 30;
+function verticalTimeline() {
+  var data = this.data || [];
+  var scale = data.length && data[0].duration ? 30 / data[0].duration : 30;
   const sample_width = 120;
-  const content =   this.svg.select("g.content");
+  const content = this.svg.select('g.content');
   content.html('');
-  var dts_offset = data[0].dts;
+  var dts_offset = d3.min(data, function (d) {
+    return Math.min(d.dts, d.cts);
+  }) || 0;
+  var timeline_end = d3.max(data, function (d) {
+    return Math.max(d.dts, d.cts) + d.duration;
+  }) || 0;
   var ypos = 50;
+  this.height = ypos + (timeline_end - dts_offset) * scale;
+  var width = this.width + this.margin.left + this.margin.right;
+  var height = this.height + this.margin.top + this.margin.bottom;
+  this.viewport.attr('height', height).attr('viewBox', '0 0 ' + width + ' ' + height);
   data.forEach(function (d, i) {
     var sampleg = content.append('g').attr("class","pair");
     const dts_y = (d.dts - dts_offset) * scale + ypos;
@@ -1075,24 +1080,28 @@
 SampleTimeline.prototype.update = verticalTimeline;
 
 function SampleTimeline() {
-  var margin = { top: 10, right: 10, bottom: 80, left: 20 };
-  var width = (this.width = document.body.clientWidth - margin.left - margin.right);
-  var height = (this.height = window.innerHeight - margin.top - margin.bottom);
+  var margin = (this.margin = { top: 10, right: 10, bottom: 20, left: 20 });
+  const sample_height = 30;
+  const sample_width = 120;
+  var width = (this.width = 3 * sample_width);
+  var height = (this.height = 50);
 
   var div = d3.select('#sampletimeline');
   div.html('');
-  this.svg = div
+  this.viewport = div
     .append('svg')
-    .attr('width', '100%')
-    .attr('height', '100%')
+    .attr('width', width + margin.left + margin.right)
+    .attr('height', height + margin.top + margin.bottom)
+    .style('max-width', '100%')
+    .style('height', 'auto')
+    .style('display', 'block')
     .attr(
       'viewBox',
       '0 0 ' + (width + margin.left + margin.right) + ' ' + (height + margin.top + margin.bottom),
-    )
+    );
+  this.svg = this.viewport
     .append('g')
     .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-  const sample_height = 30;
-  const sample_width = 120;
   this.svg
     .append('text')
     .attr('x', sample_width/2)

Do you agree with it?

@pengbins

Copy link
Copy Markdown
Author

Didn't get any feedback so I submitted it roughly to my LLM:

I’d keep the vertical layout and hover approach, but fix the SVG sizing before merging. I reviewed [PR #531](#531) at 89fb972.

The main problem is that [the SVG viewport still uses the browser’s dimensions](

mp4box.js/demo/filereader.js

Lines 1077 to 1093 in 89fb972

function SampleTimeline() {
var margin = { top: 10, right: 10, bottom: 80, left: 20 };
var width = (this.width = document.body.clientWidth - margin.left - margin.right);
var height = (this.height = window.innerHeight - margin.top - margin.bottom);
var div = d3.select('#sampletimeline');
div.html('');
this.svg = div
.append('svg')
.attr('width', '100%')
.attr('height', '100%')
.attr(
'viewBox',
'0 0 ' + (width + margin.left + margin.right) + ' ' + (height + margin.top + margin.bottom),
)
.append('g')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

), while the vertical content grows with sample timestamps.
Using the actual D3 code, I reproduced two regressions:

  • 1280×600, 20 equal-duration samples: the old layout fits everything; the PR places the final two sample pairs outside the viewport.
  • 320-pixel width, two samples: the old layout fits; the PR’s composition column extends to x=380 and is partially clipped.

Two inherited issues also remain: negative composition timestamps can fall outside the viewport, and updating with an empty selection leaves the previous samples displayed.

I prepared a refinement patch, applicable on top of the PR. It:

  • Sizes the SVG to the full timestamp range, allowing normal page scrolling.
  • Uses a content-sized width that scales down on narrow screens.
  • Includes both DTS and CTS when choosing the timeline origin.
  • Clears old samples when the selection becomes empty.

Validation: ten targeted DOM/SVG scenarios passed, including reordered timestamps, variable durations, and repeated updates. JavaScript syntax checking passed. Browser visual and hover verification remain untested because browser access was unavailable.

Your checkout is unchanged.

The LLM suggested the following update:

--- a/demo/filereader.js
+++ b/demo/filereader.js
@@ -1006,18 +1006,23 @@
   }
 }
 
-function verticalTimeline () {
-  var that = this;
-  var data = this.data;
-  if (!data || data.length === 0) {
-    return;
-  }
-  var scale = data[0].duration ? 30 / data[0].duration : 30;
+function verticalTimeline() {
+  var data = this.data || [];
+  var scale = data.length && data[0].duration ? 30 / data[0].duration : 30;
   const sample_width = 120;
-  const content =   this.svg.select("g.content");
+  const content = this.svg.select('g.content');
   content.html('');
-  var dts_offset = data[0].dts;
+  var dts_offset = d3.min(data, function (d) {
+    return Math.min(d.dts, d.cts);
+  }) || 0;
+  var timeline_end = d3.max(data, function (d) {
+    return Math.max(d.dts, d.cts) + d.duration;
+  }) || 0;
   var ypos = 50;
+  this.height = ypos + (timeline_end - dts_offset) * scale;
+  var width = this.width + this.margin.left + this.margin.right;
+  var height = this.height + this.margin.top + this.margin.bottom;
+  this.viewport.attr('height', height).attr('viewBox', '0 0 ' + width + ' ' + height);
   data.forEach(function (d, i) {
     var sampleg = content.append('g').attr("class","pair");
     const dts_y = (d.dts - dts_offset) * scale + ypos;
@@ -1075,24 +1080,28 @@
 SampleTimeline.prototype.update = verticalTimeline;
 
 function SampleTimeline() {
-  var margin = { top: 10, right: 10, bottom: 80, left: 20 };
-  var width = (this.width = document.body.clientWidth - margin.left - margin.right);
-  var height = (this.height = window.innerHeight - margin.top - margin.bottom);
+  var margin = (this.margin = { top: 10, right: 10, bottom: 20, left: 20 });
+  const sample_height = 30;
+  const sample_width = 120;
+  var width = (this.width = 3 * sample_width);
+  var height = (this.height = 50);
 
   var div = d3.select('#sampletimeline');
   div.html('');
-  this.svg = div
+  this.viewport = div
     .append('svg')
-    .attr('width', '100%')
-    .attr('height', '100%')
+    .attr('width', width + margin.left + margin.right)
+    .attr('height', height + margin.top + margin.bottom)
+    .style('max-width', '100%')
+    .style('height', 'auto')
+    .style('display', 'block')
     .attr(
       'viewBox',
       '0 0 ' + (width + margin.left + margin.right) + ' ' + (height + margin.top + margin.bottom),
-    )
+    );
+  this.svg = this.viewport
     .append('g')
     .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
-  const sample_height = 30;
-  const sample_width = 120;
   this.svg
     .append('text')
     .attr('x', sample_width/2)

Do you agree with it?

Thanks a lot. I have applied this update to this PR.

In the original horizontal layout, the SVG also can't include all samples when there are too many samples. There is no horizontal scroll bar. So I didn't try to update the SVG size when more samples are selected.

With your suggestion, it is much better that the selected samples are always visible.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants