lharby
lharby

Reputation: 3265

Bind vertical scrolling in one element to horizontal scrolling in another and map the height of one to the width of the other

I have built a very simple jsfiddle which takes the vertical scrolling from one container, and uses it to scroll left and right in a second container.

Currently as the height of container A has no correlation to the width of container B, the scrolling will end sooner or later depending on heights, margins and so on if the elements inside each container.

I need some formula to make the scrolling relative between the two elements if this is possible.

JS:

const multiElementScroll = ( elem1, elem2 ) => {
  elem1.onscroll = function() {
    elem2.scrollLeft = this.scrollTop;
  };
}

multiElementScroll( div1, div2 );

Basic HTML:

<div class="scroll-box" id="div1"> 
    <h1>A</h1>
    <h2>B</h2>
    <h2>C</h2>
    <h2>D</h2>
    <h2>E</h2>
    <h2>F</h2>
    <h2>G</h2>
    <h2>H</h2>
</div>

<div class="scroll-box scroll-box-h" id="div2"> 
    <h1>1</h1>
    <h2>2</h2>
    <h2>3</h2>
    <h2>4</h2>
    <h2>5</h2>
</div>

And SCSS:

.scroll-box {
    width: 200px;
    height: 200px;
    overflow-y: scroll;
    border: 1px solid #d99;
    
    &-h {
        display: flex;
        height: 100px;
        width: 1000px;
        overflow-x: overlay;
        overflow-y: hidden;
        
        h1, h2 {
            display: inline;
            margin: 0 200px 0 0 !important;
        }
    }
}

.scroll-box h2 { margin-top: 50px; }

Probably makes more sense in the fiddle.

Is there some formula to pass in the height and width and calculate the scrollLeft px offset? Apologies if this is badly worded.

Upvotes: 0

Views: 467

Answers (3)

Jaime Bl&#225;zquez
Jaime Bl&#225;zquez

Reputation: 328

Use the heights and widths removing the full (scrollable) size from the visible one, as the value that you read or set is the lower one (top and left). Calculate the percentage and multiply the width:

const multiElementScroll = ( elem1, elem2 ) => {
  elem1.onscroll = function() {
    var percent = this.scrollTop / (this.scrollHeight - this.clientHeight);
    elem2.scrollLeft = (elem2.scrollWidth - elem2.clientWidth) * percent;
  };
}

multiElementScroll( div1, div2 );

The intermediate variable percent is only added for readability, you can inline it if you prefer so. Use

Upvotes: 1

vanowm
vanowm

Reputation: 10201

All you need is calculate percentage of vertical scroll and use that percentage to calculate width scroll:

const multiElementScroll = ( elem1, elem2 ) => {
  elem1.onscroll = function() {
    const scrollTop = this.scrollTop;
    const height = this.scrollHeight - this.offsetHeight;
    const width = elem2.scrollWidth - elem2.offsetWidth;
    elem2.scrollLeft = (scrollTop * 100 / height) * width / 100;
  };
}

multiElementScroll( div1, div2 );
.scroll-box {
  width:200px;
  height:100px;
  overflow-y:scroll;
  border:1px solid #d99
}
.scroll-box-h {
  display:flex;
  height:100px;
  width:100%;
  overflow-x:overlay;
  overflow-y:hidden
}
.scroll-box-h h1,
.scroll-box-h h2 {
  display:inline;
  margin:0 200px 0 0 !important
}
.scroll-box h2 {
  margin-top:50px
}
  
<div class="scroll-box" id="div1"> 
    <h1>A</h1>
    <h2>B</h2>
    <h2>C</h2>
    <h2>D</h2>
    <h2>E</h2>
    <h2>F</h2>
    <h2>G</h2>
    <h2>H</h2>
</div>

<div class="scroll-box scroll-box-h" id="div2"> 
    <h1>1</h1>
    <h2>2</h2>
    <h2>3</h2>
    <h2>4</h2>
    <h2>5</h2>
</div>

Upvotes: 1

Jan Pfeifer
Jan Pfeifer

Reputation: 2861

So you need to calculate and set relative scroll position:

const multiElementScroll = ( elem1, elem2 ) => {
    elem1.onscroll = function() {            
        const m = elem1.scrollHeight - elem1.offsetHeight;
        const c = elem1.scrollTop / m;

        const m2 = elem2.scrollWidth - elem2.offsetWidth;
        elem2.scrollLeft = m2 * c;
    };
}

Upvotes: 1

Related Questions