Positioning <tr> elements with absolute precision within a intricate layout

I am faced with the challenge of developing a complex UI control. The structure consists of a left-side TreeTable component, implemented using a <table> element, and a right-side SVG component that displays data corresponding to each row of the left TreeTable. While both sides need to function independently as per requirements, they also need to synchronize scrolling behaviors.

The overall layout is structured as follows:

<div>
   <div id="leftComponent">
      <table>...</table
   </div>
   <div id="rightComponent">
      <svg>...</svg>
   </div>
</div>

To optimize performance for large datasets with over 1 million rows, I have implemented a feature where only the rows within the viewport on either side are rendered in the DOM.

However, this approach presents the following challenges:

  1. When scrolling on the right side, due to absolute positioning of elements, achieving synchronization between the two components poses difficulties. For example, part of a row may be visible at the top of the viewport, then all other rows, followed by another partial row at the bottom. How can I offset the content of the leftComponent table to match the rows displayed on the right side? Absolute positioning on the <tr> elements is ineffective. Although rasterized scrolling was considered, it was not deemed viable. Attempting to offset the entire <table> element using something like
    <table style="margin-top:1337px">
    affects the sticky header functionality. Are there alternative solutions?
  2. As both components operate relatively independently, having separate vertical scrollbars for each side disrupts the UI experience. Hiding the y-axis scrollbar by setting overflow-y: hidden disables scrolling on the left side. One potential solution could involve intercepting WheelEvents to simulate ScrollEvents for the rightComponent. Previous attempts to hide the y-axis scrollbar using CSS properties like scrollbar-width: none; affected both scrollbars. Keeping the x-axis scrollbar intact visually and functionally while hiding the y-axis scrollbar remains a challenge. Experimenting with techniques such as margin-right: -20px successfully hides the y-axis scrollbar but seems cumbersome.

In summary:

  1. Both components must maintain relative independence while exhibiting synchronized behavior.
  2. Visual removal of the y-axis scrollbar between components without compromising scrolling ability on the left side is necessary.
  3. Ability to offset the left <table> section based on arbitrary pixel values to align with the freely scrollable right side is essential.
  4. Avoidance of a complete overhaul of the left-side structure by converting the <table> into a <div> structure is preferred due to complexity.
  5. Preservation of performance enhancements for rendering only visible rows while ensuring correct alignment with the right side is crucial.

Seeking innovative solutions for these issues. Your insights and suggestions are appreciated.

EDIT: Added screenshots for clarity. https://i.sstatic.net/mXSO5.png https://i.sstatic.net/3l8nN.png

Description: The first image illustrates perfect alignment when scrolled to the top. Both sets of rows are perfectly matched. In contrast, the second image showcases partially scrolled rows, where the topmost row is barely visible. Aiming to achieve consistent alignment similar to the first image proves challenging due to restrictions of the <table> structure on the leftComponent. Additionally, eliminating the middle scrollbar, as specified earlier, while retaining horizontal scrolling functionality on both components remains a priority.

For further details, feel free to inquire.

Answer №1

This JS implementation features a scrollTop technique in combination with relative positioning on the rows, as suggested earlier.

The logic should be fairly self-explanatory. Feel free to ask any questions if needed.

const leftComponent = document.getElementById("leftComponent");
const rightComponent = document.getElementById("rightComponent");
const svg = rightComponent.querySelector("svg");

const theadHeight = leftComponent.querySelector("thead").offsetHeight;
const tbodyRowHeight = leftComponent.querySelector("tbody tr").offsetHeight;

const numRows = 100;    // Number of rows in th table
document.documentElement.style.setProperty('--table-height', (theadHeight + numRows * tbodyRowHeight) + 'px');


// Capture rightComponent scroll events
rightComponent.addEventListener('scroll', evt => {
  // Calculate top row index number based on scroll offset and row height
  const topRowIndex = Math.floor(rightComponent.scrollTop / tbodyRowHeight);
  // Work out how many pixels into the top row that the scroll position is
  const scrollFractionalAdjustment = - (rightComponent.scrollTop % tbodyRowHeight);
  // Set the position relative top value for the table rows.
  // This will adjust their vertical position on the page based on scroll fractional offset we just calculated.
  document.documentElement.style.setProperty('--scroll-fractional-adjustment', scrollFractionalAdjustment + 'px');
  // Update the table and graph based on out top row index
  populateTableRows(topRowIndex);
  populateGraph(topRowIndex);
});



function populateTableRows(topRowIndex)
{
  let n = topRowIndex;
  const rows = leftComponent.querySelectorAll("tbody tr");
  rows.forEach((row, i) => {
    const cols = row.querySelectorAll("td");
    cols[0].textContent = "row" + n + " with very long text";
    cols[1].textContent = "row" + n;
    n++;
  });
}


function populateGraph(topRowIndex)
{
}


// Initial setup
populateTableRows(0);
populateGraph(0);
:root {
  --scroll-fractional-adjustment: 0px;
  --table-height: 10000px;
}

html, body {
  margin: 0;
}

body {
  font-family: sans-serif;
  font-size: 20px;
}
th, td {
  height: 36px;
  line-height: 36px;
  padding-top: 0;
  padding-bottom: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
th {
  background-color: #aaa;
  color: white;
}

.system {
  display: flex;
  width: 100%;
  height: 100vh;
  overflow: hidden;
}

#leftComponent.
#rightComponent {
  height: var(--table-height);
}

#leftComponent {
  width: 30%;
  height: 100%;
  overflow: scroll hidden;
}
#leftComponent tbody {
  display: block;
  overflow: hidden;
}
#leftComponent tbody td {
  position: relative;
  top: var(--scroll-fractional-adjustment);
}
#leftComponent table th,
#leftComponent table td
{
  max-width: 150px;
}

#rightComponent {
  width: 70%;
  overflow: scroll;
}
#rightComponent .rightContainer {
  width: 100%;
  height: var(--table-height);
}
#rightComponent svg {
  position: fixed;
}
<div class="system">
   <div id="leftComponent">
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>ID Blub</th>
            <th>Foo</th>
            <th>Sort string</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>row0 with very long text</td>
            <td>row0</td>
            <td>Foo something</td>
            <td>r2u58</td>
          <tr>
            <td>row0 with very long text</td>
            <td>row0</td>
            <td>Foo something</td>
            <td>r2u58</td>
          </tr>
          <tr>
            <td>row0 with very long text</td>
            <td>row0</td>
            <td>Foo something</td>
            <td>r2u58</td>
          </tr>
          <tr>
            <td>row0 with very long text</td>
            <td>row0</td>
            <td>Foo something</td>
            <td>r2u58</td>
          </tr>
          <tr>
            <td>row0 with very long text</td>
            <td>row0</td>
            <td>Foo something</td>
            <td>r2u58</td>
          </tr>
        </tbody>
      </table>
   </div>
   <div id="rightComponent">
      <div class="rightContainer">
        <svg>
          <circle cx="50" cy="50" r="50"/>
        </svg>
      </div>
   </div>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The media query in Css3 is not functioning as expected when using max-width

Struggling to hide a specific element when the screen width reaches 980px or less using media queries. Despite my attempts, the element continues to display. Oddly enough, if I use a media query with min-width instead of max-width, the element disappears ...

The div is lacking in height

I have 3 divs that belong to the stackContainer class: .stackContainer { position: relative; } Within these divs, I want multiple elements stacked on top of each other. To achieve this, I use the following code: .stackItem { position: absolute; ...

An adaptive Bootstrap grid that collapses and changes based on screen dimensions

Currently, I am in the process of creating a collapsible grid using Bootstrap to display details for each item: If you would like to see a visual representation of the concept, click here. To assist in my project, I have been referring to a helpful threa ...

Inconsistency in naming of jQuery CSS properties

Can you explain the reason behind the difference in property names: $(elem).css('padding-top') compared to $(elem).css('marginTop') ? Wouldn't it make more sense if we use: $(elem).css('margin-top') instead? ...

Having trouble applying CSS styles to a class using Material UI withStyle? If you're finding that withStyle isn't working as

Check out this code snippet: import { withStyles, MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import classNames from 'classnames'; const styles = theme => ({ myGridStyle:{ '&:.my-row-s ...

Reposition buttons using JavaScript

I attempted to modify the button that appears at the top of an HTML page. <div class='play'> <input id="play" type="button" value="Play" onclick="mode('play');startSlideshow();" /> </div> <div class='pause ...

Keep HTML in sync across browser and server

Is there a way to efficiently update a large unordered list in a web application without sending the entire list over the network or resorting to pagination, while ensuring it stays synchronized with a memoized server-generated copy? ...

Is there a way to manipulate HTML elements on a webpage using Swift and Xcode?

Is it feasible to manipulate HTML elements on a website from an iOS application? For instance, displaying www.google.com using a UIWebView. I am interested in achieving the following, if this idea/concept is doable: Detecting whether the user has input ...

Steps for aligning the upper rectangular text in the center of the larger rectangular border

https://i.stack.imgur.com/7yr5V.png I was aware of a particular element in html that had text positioned in the upper left corner, but my knowledge didn't go beyond that. Should I be adjusting the translation on both the X and Y axes based on the par ...

Can PhoneGap/Cordova's Media class bypass the restrictions of audio in HTML5 on iOS and Android devices?

After researching the limitations of html5 on iOS, I discovered that only one audio file can be played at a time and audio can only be triggered by user interaction. This is discouraging as I am working on creating a high-quality html5 game that requires b ...

Adjust text size based on device orientation changes

I'm struggling to dynamically change the font size based on screen orientation and width. How can I adjust the font size when switching between landscape and portrait mode? I attempted using an event listener, but it's not updating the font size. ...

Using Jquery to input selected dropdown values into a text input field

Currently, I am facing some challenges in achieving this task. My goal is to have the selected option from a dropdown list called programs_dropdown added to a text field named programs_input, with the option values separated by commas. For example: php, j ...

Rotating SVG images with ease at any center point

I attempted to remove the unsupported animateTransform element: <animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20" dur="1.2s" repeatCount="indefinite" /> and replaced it with CS ...

The appearance of my website appears differently depending on the resolution

Just recently, I began exploring the world of HTML/CSS/JS and created a handy tool for my personal use. However, I encountered an issue when viewing it on different resolutions which caused some elements to look distorted. The tool I made allows me to inp ...

Tips for concealing the body description on the homepage of a blogger website

I want to conceal this description This is my blog and I am facing an issue where I need to hide the description on the home page. I have tried using color:white which worked initially, but when I moved the description to the top or left, the black backgro ...

Incorporate text inside the border of a Material UI chip

https://i.stack.imgur.com/VATrD.png I'm looking to replicate this design using a pre-built Chip component from MaterialUI While the solution might involve Some Text using html and css, it still may not achieve an identical result. I've come acr ...

Insert half a million records into a database table using JavaScript seamlessly without causing the webpage to crash

I am facing an issue with my report system where running a single report query results in over 500,000 rows being returned. The process of retrieving the data via AJAX takes some time, but the real problem arises when the browser freezes while adding the H ...

Utilizing the power of Scoped CSS with Bootstrap/Bootstrap-Vue Integration

I'm currently working on a chrome extension and utilizing Bootstrap-Vue in my Vue files. I have imported bootstrap/bootstrap-vue into my js file, but the styling is being applied globally. Is there a way to scope the Bootstrap only onto specific inser ...

Gradually reveal each page as it loads while a spinner rotates in anticipation

I am attempting to create a fade-in effect for the entire page once it has finished loading, This is my current code: <script type="text/javascript"> $(window).bind("load", function() { $('#overlay').fadeOut(function() { ...

Turn off link preview feature on Android messages

As a developer, I am looking for a way to disable or hide link previews on Android devices when someone receives a text message with a link to our website. I still want the URL address to be visible, but I prefer to keep the link previews on IOS devices. I ...