richmake
richmake

Reputation: 29

HTML - Resize multiple divs and their content

I am looking to create a bottom pannel with a resizable height. The top pannel consists of 2 divs with a resizable width. I was able to follow this https://htmldom.dev/create-resizable-split-views/ , but the vertical resizing is not resizing the contents of the two top divs. How can I fill the contents of the top container with the contents of the two Divs, to ensure that they resize when the bottom pannel is dragged up?

In other words, I'm looking for two top horizontally resizable pannels and one bottom pannel vertically resizable from them, while shrinking/expanding the contents during resize.

Edit: The bottom container needs to be set on all tabs and show up under all tab content on the page.

<div class="container">
  <div class = "container__top">
      <div class="tab-content" >
          <body class="noscroll">
              <div class="Tab1">
                  <div class="main-body">
                      <div class="page-wrapper">
                          <div class="row">
                              <div class="col-sm-12">
                                      <div class="container__left">
                                               STUFF</div>
                                       <div class="resizer" data-direction="horizontal"></div>
                                      <div class="container__right">
                                               STUFF</div> 
                              </div>
                        </div>
                    </div>
                </div>
             <div class="Tab2"></div>
         </body>
       </div>
   </div>
       <div class="resizer" data-direction="vertical"></div>
     <div class = "container__bottom">
      STUFF</div>

Upvotes: 0

Views: 1261

Answers (1)

red cloud
red cloud

Reputation: 48

You could try something like this. You'll have to be explicit for a few things, like parent height and the min/max heights for top and bottom sections, but this could be a decent start. It's ugly, sorry.

edit: it's still ugly, and you'll have to fix up the tab/hide function for more tabs, but this works as intended as far as I can tell.

document.addEventListener('DOMContentLoaded', function() {
  const resizable = function(resizer) {
    const direction = resizer.getAttribute('data-direction') || 'horizontal';
    const prevSibling = resizer.previousElementSibling;
    const nextSibling = resizer.nextElementSibling;

    // The current position of mouse
    let x = 0;
    let y = 0;
    let prevSiblingHeight = 0;
    let prevSiblingWidth = 0;

    // Handle the mousedown event
    // that's triggered when user drags the resizer
    const mouseDownHandler = function(e) {
      // Get the current mouse position
      x = e.clientX;
      y = e.clientY;
      const rect = prevSibling.getBoundingClientRect();
      prevSiblingHeight = rect.height;

      // Attach the listeners to `document`
      document.addEventListener('mousemove', mouseMoveHandler);
      document.addEventListener('mouseup', mouseUpHandler);
    };

    const mouseMoveHandler = function(e) {
      // How far the mouse has been moved
      const dx = e.clientX - x;
      const dy = e.clientY - y;
      const parentHeight = resizer.parentNode.getBoundingClientRect().height;

      const h = (prevSiblingHeight + dy)
      prevSibling.style.height = `${h}px`;
      nextSibling.style.height = `${parentHeight - h}px`;

      const cursor = 'row-resize';
      resizer.style.cursor = cursor;
      document.body.style.cursor = cursor;

      prevSibling.style.userSelect = 'none';
      prevSibling.style.pointerEvents = 'none';

      nextSibling.style.userSelect = 'none';
      nextSibling.style.pointerEvents = 'none';
    };

    const mouseUpHandler = function() {
      resizer.style.removeProperty('cursor');
      document.body.style.removeProperty('cursor');

      prevSibling.style.removeProperty('user-select');
      prevSibling.style.removeProperty('pointer-events');

      nextSibling.style.removeProperty('user-select');
      nextSibling.style.removeProperty('pointer-events');

      // Remove the handlers of `mousemove` and `mouseup`
      document.removeEventListener('mousemove', mouseMoveHandler);
      document.removeEventListener('mouseup', mouseUpHandler);
    };

    // Attach the handler
    resizer.addEventListener('mousedown', mouseDownHandler);
  };

  // Query all resizers
  document.querySelectorAll('.resizer').forEach(function(ele) {
    resizable(ele);
  });

  // Query the element
  const horizontalResizer = document.getElementById('dragMeHorizontal');
  const leftSide = horizontalResizer.previousElementSibling;
  const rightSide = horizontalResizer.nextElementSibling;

  // The current position of mouse
  let x = 0;
  let y = 0;
  let leftWidth = 0;

  // Handle the mousedown event
  // that's triggered when user drags the resizer
  const mouseDownHandler = function(e) {
    // Get the current mouse position
    x = e.clientX;
    y = e.clientY;
    leftWidth = leftSide.getBoundingClientRect().width;

    // Attach the listeners to `document`
    document.addEventListener('mousemove', mouseMoveHandler);
    document.addEventListener('mouseup', mouseUpHandler);
  };

  const mouseMoveHandler = function(e) {
    // How far the mouse has been moved
    const dx = e.clientX - x;
    const dy = e.clientY - y;

    const newLeftWidth = ((leftWidth + dx) * 100) / horizontalResizer.parentNode.getBoundingClientRect().width;
    leftSide.style.width = `${newLeftWidth}%`;

    horizontalResizer.style.cursor = 'col-resize';
    document.body.style.cursor = 'col-resize';

    leftSide.style.userSelect = 'none';
    leftSide.style.pointerEvents = 'none';

    rightSide.style.userSelect = 'none';
    rightSide.style.pointerEvents = 'none';
  };

  const mouseUpHandler = function() {
    horizontalResizer.style.removeProperty('cursor');
    document.body.style.removeProperty('cursor');

    leftSide.style.removeProperty('user-select');
    leftSide.style.removeProperty('pointer-events');

    rightSide.style.removeProperty('user-select');
    rightSide.style.removeProperty('pointer-events');

    // Remove the handlers of `mousemove` and `mouseup`
    document.removeEventListener('mousemove', mouseMoveHandler);
    document.removeEventListener('mouseup', mouseUpHandler);
  };

  // Attach the handler
  horizontalResizer.addEventListener('mousedown', mouseDownHandler);
});

// Tab Changer
function changeActiveTab(tabNumber) {
  const allOtherTabs = document.getElementsByClassName("tab")
  const hideElements = [...allOtherTabs].filter((element, index) => index !== tabNumber)
  const selectedTab = document.getElementsByClassName("tab")[tabNumber]
  hideElements.forEach(element => element.classList.add("hidden"));
  selectedTab.classList.remove("hidden");
}
// handle tab 1 select
document.getElementById("tab1").addEventListener('mousedown', () => {
  changeActiveTab(0)
})
// handle tab 2 select
document.getElementById("tab2").addEventListener('mousedown', () => {
  changeActiveTab(1)
})
// handle tab 3 select
document.getElementById("tab3").addEventListener('mousedown', () => {
  changeActiveTab(2)
})
.resizer[data-direction='vertical'] {
  background-color: #cbd5e0;
  cursor: ns-resize;
  height: 10px;
  width: 100%;
}

.button__container {
  margin: 6px 12px;
  display: flex;
  flex-direction: row;
}

.tab__internal {
  max-height: 18%;
}

button {
  background-color: orange;
  border: none;
  padding: 8px;
  min-width: 150px;
  margin: 1px;
  border: 1px solid teal;
}

.main__container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  border: 1px solid blue;
}

.sub__container {
  height: 250px;
  /* Misc */
}

#tab__2 {
  background-color: green;
}

#tab__3 {
  background-color: teal;
}

.container__top {
  /* Initial height */
  height: 100%;
  /* Misc */
  display: flex;
  flex-direction: row;
  background-color: green;
}

.hidden {
  display: none;
}

.tabs__container {
  background-color: blue;
  height: 100px;
  max-height: calc(100% - 100px);
  min-height: 50px;
}

.tab__contents {
  height: 100%;
}

.container__bottom {
  /* Take the remaining height */
  width: 100%;
  height: 150px;
  min-height: 100px;
  max-height: calc(100% - 50px);
  /* Misc */
  display: flex;
  flex-direction: column;
  background-color: red;
}

.container__left {
  width: 50%;
  height: 100%;
  /* Misc */
  display: flex;
  background-color: goldenrod;
}

.resizer__horizontal {
  background-color: #cbd5e0;
  cursor: ew-resize;
  height: 100%;
  width: 5px;
}

.container__right {
  /* Take the remaining width */
  flex: 1;
  height: 100%;
  /* Misc */
  display: flex;
  background-color: purple;
}
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>HTML DOM - Create resizable split views</title>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <link rel="stylesheet" href="/css/demo.css" />
  <link rel="preconnect" href="https://fonts.gstatic.com" />
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter&family=Source+Code+Pro&display=swap" />

</head>

<body>
  <div class="main__container">
    <h3>Main Container</h3>
    <div class="button__container">
      <button class="tab_selector" id="tab1">Tab 1</button>
      <button class="tab_selector" id="tab2">Tab 2</button>
      <button class="tab_selector" id="tab3">Tab 3</button>
    </div>
  </div>
  <div class="sub__container">
    <div class="tabs__container">

      <div class="container__top tab" id="tab__1">
        <div class="container__left">
          <div class="tab__contents">
            <div class="tab__internal">stuff</div>
            <div class="tab__internal">stuff</div>
            <div class="tab__internal">stuff</div>
            <div class="tab__internal">stuff</div>
          </div>
        </div>
        <div class="resizer__horizontal" id="dragMeHorizontal"></div>
        <div class="container__right tab__contents">Right</div>
      </div>

      <div class="container__top tab hidden" id="tab__2">
        <div class="tab-contents">Tab 2</div>
      </div>

      <div class="container__top tab hidden" id="tab__3">
        <div class="tab-contents">Tab </div>
      </div>

    </div>
    <div class="resizer" data-direction="vertical"></div>
    <div class="container__bottom">
      <h4>Bottom</h4>
      <p>Stuff up in here.</p>
    </div>
  </div>
</body>

</html>

Upvotes: 2

Related Questions