Friday, January 11, 2019

scrolling minimaps with css and javascript

Remember the old arcade game Defender? And how they had a little minimap scanner at the top, that could show you where aliens were abducting your humanoids even as the screen was scrolling horizontally? For my timelines project, with a big vertical scroll, I wanted something similar - I want a generous amount of space to include images, but I wasn't liking losing the sense of "a whole life", so a small map seemed like the right idea, with a little frame on the map saying "you are here" (Kind of like a modern disappearing relative scrollbar, except it can hold a mini-me version of the whole thing.)

I might have cheated a little bit - I decided everything above the main content will be in a single block with an id of "header". The minimap and the frame moving in it then look like this:
<div id="minimap">
    <div id="frame"></div>
</div>

The CSS (fixed to one edge, and using opacity to let you see the real world beneath it)

#minimap {
    position:fixed;
    width:80px;
    border:1px black solid;
    height:400px;
    left:0px;
    top: 40px;
    background-color:rgba(255,255,255,.8);
    z-index: 100;
    overflow: hidden;
}
#frame {
    position: absolute;
    top:20px;
    border:3px red solid;
    height:80px;
    width:100%;
}

Then I just call setupMinimap. The code is a little wonky for IE support:

function setupMinimap(){
    if(window.addEventListener) {
        window.addEventListener('scroll', onScrollEventHandler, false);   
        window.addEventListener('resize', onScrollEventHandler, false);   
    }
    else if (window.attachEvent) {
        window.attachEvent('onscroll', onScrollEventHandler); 
        window.attachEvent('onresize', onScrollEventHandler); 
    }
}

function onScrollEventHandler() { 
    const main = document.getElementById('main');
    const frame = document.getElementById('frame');
    const header = document.getElementById('header');
    
    frame.style.height = (window.innerHeight / main.offsetHeight) * 100.0 +"%";
    let frameTopPercent = (100*((window.scrollY - header.offsetHeight) / (main.offsetHeight)));
    frame.style.top = frameTopPercent+"%";

    // DON'T NEED THIS CODE, NOW USING OVERFLOW:HIDDEN
    /*if(frameTopPercent < 0) {
        frame.style.display = 'none';    
    } else {
        frame.style.display = 'block';    
    }*/
}


FOLLOWUP: you can see the end result on my timelines page

No comments:

Post a Comment