0

I am entirely new to Javascript, usually working just as a designer in CSS / HTML (And the occasional cut/paste piece of pre-written JS) but couldn't see anyway other than JS to achieve what I am after so had a go.... but failed!

What I want to achieve is a parent that contains a much larger child whereby moving the mouse to the edge of the parent will scroll it in that direction (Think first person video games type effect) with the ultimate goal being to give the effect of being stood in the middle of a room and looking around. (Currently child is just gradient filled to test and keep code short until I get it working)

After days of googling every combination of words I could think of to find this and not finding exactly what I want, I have found the closest answers I could on stackoverflow and pieced it together as best as I could.... but (with grim predictability) it doesn't work!

So what I am looking for is anything ranging from somebody giving me the code I need to hints or pointers towards what I have done wrong. My code as it stands in all below along with a link to Codepen showing it not working :(

Bonus Question: Once I have got this working my next goal was to make it so if you scrolled all the way either left or right it jumped to the opposite end of the (Eg scroll right > 100% takes you to very left of div) so once related back to being in the room you can turn 360^o and then keep going... Haven't even started looking at this yet, but thought I'd through it out now in case a) it would be bound up in the script for the first part, or b) it simply isn't possible and you could save me a lot of time trying to look up how to do it.


Codepen


<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8" />

<title>TEST</title>
<style media="screen" type="text/css">

html{
position:relative;
font-size:62.5%;
margin:0;
padding:0;
width:100%;
}

body{
position:relative;
margin:0;
padding:0;
height:100%;
width:100%;
overflow:hidden;
background:blue;
}

#container{
position:relative;
box-sizing:border-box;
width:calc(100vw - 4rem);
height:calc(100vh - 4rem);
overflow: hidden;
margin-left:2rem;
margin-top:2rem;
}

#content{
width:200vw;
height:200vh;
background: #ff0000;
background: -moz-linear-gradient(-45deg, #ff0000 0%, #00ff00 50%, #0000ff 100%);
background: -webkit-linear-gradient(-45deg, #ff0000 0%,#00ff00 50%,#0000ff 100%);
background: linear-gradient(135deg, #ff0000 0%,#00ff00 50%,#0000ff 100%);
}

#hoverleft{
position:absolute;
cursor:pointer;
left:0;
top:0;
width:5rem;
height:100%;
background:rgba(0,0,0,0.5);
-webkit-clip-path: polygon(0 0, 100% 5rem, 100% calc(100% - 5rem), 0% 100%);
clip-path: polygon(0 0, 100% 5rem, 100% calc(100% - 5rem), 0% 100%);
}

#hoverright{
position:absolute;
cursor:pointer;
right:0;
top:0;
width:5rem;
height:100%;
background:rgba(0,0,0,0.5);
-webkit-clip-path: polygon(0 5rem, 100% 0, 100% 100%, 0 calc(100% - 5rem));
clip-path: polygon(0 5rem, 100% 0, 100% 100%, 0 calc(100% - 5rem));
}

#hoverup{
position:absolute;
cursor:pointer;
left:0;
top:0;
width:100%;
height:5rem;
background:rgba(250,250,250,0.5);
-webkit-clip-path: polygon(0 0, 100% 0, calc(100% - 5rem) 100%, 5rem 100%);
clip-path: polygon(0 0, 100% 0, calc(100% - 5rem) 100%, 5rem 100%);
}

#hoverdown{
position:absolute;
cursor:pointer;
left:0;
bottom:0;
width:100%;
height:5rem;
background:rgba(250,250,250,0.5);
-webkit-clip-path: polygon(5rem 0, calc(100% - 5rem) 0, 100% 100%, 0 100%);
clip-path: polygon(5rem 0, calc(100% - 5rem) 0, 100% 100%, 0 100%);
}

</style>
<script type="text/javascript">

var amount = '';

function scroll() {
    $('#container').animate({
        scrollTop: amount
    }, 100, 'linear',function() {
        if (amount != '') {
        scroll();
        }
    });
}
$('#hoverup').hover(function() {
    amount = '+=10';
   scroll();
}, function() {
   amount = '';
});
$('#hoverdown').hover(function() {
    amount = '-=10';
    scroll();
}, function() {
    amount = '';
});


var amount = '';

function scroll() {
    $('#container').animate({
        scrollLeft: amount
    }, 100, 'linear',function() {
        if (amount != '') {
            scroll();
        }
    });
}
$('#hoverleft').hover(function() {
    amount = '+=10';
    scroll();
}, function() {
    amount = '';
});
$('#hoverright').hover(function() {
    amount = '-=10';
    scroll();
}, function() {
    amount = '';
});

</script>


</head>
<body>

<div id="container">

  <div id="content">
  </div>

  <div id="hoverleft"></div>
  <div id="hoverright"></div>
  <div id="hoverup"></div>
  <div id="hoverdown"></div>

</div>

</body>  

</html>
Neil Schulz
  • 21
  • 1
  • 1
  • 7
  • 1
    The $() functions depend on a third party JS library called jQuery. Your codepen was missing this library. I added it for you, and things seem to mostly be working: https://codepen.io/hyrumwhite/pen/dRdEVO – SethWhite Jun 30 '17 at 16:41
  • Thanks, and sorry for being a simpleton but where / how do I add that to my code? Is it just a case of downloading and adding to the ? – Neil Schulz Jun 30 '17 at 16:50
  • 1
    That'll work, or you could pull straight from google cdn: `` in your index.html. For codepen, go to settings > Javascript, and paste this into one of the fields: https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js – SethWhite Jun 30 '17 at 16:58
  • Great - Thank-you very much – Neil Schulz Jun 30 '17 at 17:09

2 Answers2

1

Got it working for ya: example here (I'm sure you can fix the css part of it to line up the borders) https://codepen.io/anon/pen/vZdwyg

Basically what needed to change was you needed to only declare the scroll function once, and then have it being called on interval, not just once.

Below is how the new scroll function works and how to apply it to your hover up, then instead of using the hover method i did mouseenter and mouseleave to combine the mouseleave events for all the directions

var scrolling;
var $container = $('#container');

function scroll(isLeft, neg) {
  var oldScroll = isLeft ? $container.scrollLeft() : $container.scrollTop()
  var newScroll = neg ? oldScroll -= 100 : oldScroll += 100;

  if(isLeft) {
    $container.animate({
      scrollLeft: newScroll
    }, 100, 'linear');
  } else {
    $container.animate({
      scrollTop: newScroll
    }, 100, 'linear');
  }
}

$('#hoverup').on('mouseenter', function() {
  scrolling = setInterval(function() {
    scroll(false, true)
  }, 100);
});

// similar thing for each of the directions, changing true/false around

$('#hoverup, #hoverdown, #hoverleft, #hoverright').on('mouseleave', function() {
    clearInterval(scrolling);
});
Joe Lissner
  • 2,181
  • 1
  • 15
  • 21
1

Very basically

As the mouse is moved around inside the .outer <div>, the mousemove event triggers and its event argument provides (amongst other values) the pageX and pageY positions of the cursor.

Using getComputedStyle we can get the width and height of both .inner and .outer, and calculate the width and height ratios of .inner to .outer.
Although we already know this, because we set the values in our CSS, calculating the values on-the-fly might prove useful in a practical application.

We can set the scrollLeft and scrollTop values of the .outer <div> to the normalized evt.x and evt.y values, multiplied by the relevant ratio, to scroll the child's left and top edges closer to or farther away from the parent's top and left.

i.e. if the cursor is moving at the far right near the bottom, the x and y values of the mousemove event will be closer to the actual width and height of the .outer <div>, so the scroll* values (multiplied by the previously established ratios) will be closer to their maximums, and thus closer to the end of the respective scrolls.

This simple demo does not take layout offsets into account, and how to get/calculate those will depend on the practical application.

const divs = document.querySelectorAll( "div" ),
      outer_div = divs[ 0 ],
      outer_div_styles = window.getComputedStyle( outer_div ),
      inner_div_styles = window.getComputedStyle( divs[ 1 ] ),
      outer_div_width = parseInt( outer_div_styles.width ),
      outer_div_height = parseInt( outer_div_styles.height ),
      dimention_ratio = {
        x: ( parseInt( inner_div_styles.width ) - outer_div_width ) / outer_div_width,
        y: ( parseInt( inner_div_styles.height ) - outer_div_height ) / outer_div_height
      },
      half_odw = outer_div_width / 2,
      half_odh = outer_div_height / 2,
      expandCoords = function( e ) { // zero to width/height
        var X = e.pageX,
            Y = e.pageY;
        if ( X < half_odw ) {
          X -= 1;
        } else if ( X > half_odw ) {
          X += 1;
        }
        if ( Y < half_odh ) {
          Y -= 1;
        } else if ( Y > half_odh ) {
          Y += 1;
        }
        return { x: X, y: Y };
      };
outer_div.addEventListener( "mousemove", function( evt ) {
  evt = expandCoords( evt );
  outer_div.scrollLeft = evt.x * dimention_ratio.x;
  outer_div.scrollTop = evt.y * dimention_ratio.y;
}, false );
body {
  overflow: hidden;
  margin: 0;
}
.outer {
  width: 100vw; /* the width of the viewport */
  height: 100vh; /* the height of the viewport */
  overflow: hidden; /* overflow mustn't be visible */
}
.inner {
  width: 1000vw; /* 10 times the width of its parent */
  height: 500vh; /* 5 times the height of its parent */
  box-shadow: inset 0 0 20px 20px green;
  background: radial-gradient( white, black );
}
<div class="outer"><div class="inner"></div></div>
Fred Gandt
  • 4,217
  • 2
  • 33
  • 41