JSFiddle - React, Tailwind, and code Playground

by levchenko_d

HAML

.content
  .item.item-a
  .item.item-b
  
.navigator

.tools
  button#zoom-in
    | +
  
  button#zoom-out
    | -

CSS

html,
body{
  height: 100%;
  overflow: scroll;
}

.content{
  width: 200vw;
  height: 200vh;
  position: relative;
}

.item{
  position: absolute;
  width: 50px;
  height: 30px;
  background: blue;
}

.item-b{
  width: 120px;
  height: 60px;
  top: 50px;
  left: 300px;
  background: red;
}




.minimap {
  position: fixed;
  top: 20px;
  right: 20px;
  width: 200px;
  background: rgba(0, 0, 0, 0.3);
}

.minimap-item{
  position: absolute;
  background: gray;
}

.minimap-viewbox{
  position: absolute;
  max-width: 99%;
  top: 0;
  left: 0;
  margin: auto;
  background: rgba(255,255,255,0.3);
  z-index: 9;
}



.navigator{
  position: fixed;
  top: 10px;
  right: 10px;
  width: 210px;
}

.navigator .minimap{
  position: relative;
  top: 0;
  right: 0;
}

Babel + JSX

/**
* @class MiniMap
* creates minimap of given viewport
*/
class MiniMap {
	/**
  * Create minimap
  * @param {object} options - minimap options
  * @param {HTMLElement} options.parent - where to append minimiap
  * @param {HTMLElement} options.viewport - viewport (parent with scroll)
  * @param {string} options.itemSelector - children items query selector
  * @param {number} [options.initialZoom=1] - initial zoom [0...1];
  * @param {function} [options.getScrollPosition=] - custom scroll position getter
  * @param {Position} [options.itemShift={top: 0, left: 0}] - adds virtual shift to the items. Original items don't change their position. But mini items do. It will be used like `miniItem.top = miniItem.top + (itemShift.top * factor)`
  * @example
  * {...getScrollPosition: ()=>{return {top: 0, left: 0};}... }
  */
	constructor (options){
	  const {
    	parent,
    	viewport,
      itemSelector,
      initialZoom,
      getScrollPosition,
      itemShift,
    } = options;
    
    this._PROPS = {
    	selectors: {
      	minimap: '.minimap',
      	item: '.minimap-item',
        viewbox: '.minimap-viewbox',
      },
      template: {
        minimap: '<div class="minimap"></div>',
        item: '<div class="minimap-item"></div>',
        viewbox: '<div class="minimap-viewbox"></div>',
      },
      default: {
	      itemShift: {
        	top: 0,
          left: 0,
        },
        zoom: 1,
      }
    };
    
    this.options = options;
  	this.$parent = $(parent);
  	this.$viewport = $(viewport);
  	this.$items = $(itemSelector);
    this.getScrollPosition = getScrollPosition;
    
    this.zoom = initialZoom || this._PROPS.default.zoom;
    this.itemShift = itemShift || this._PROPS.default.itemShift;

		/** It doesn't exist just yet*/
		this.$viewBox = $('EMPTY_SELECTOR');
    
    
    this.eventStore = {
    	scroll: {},
      click: {},
    };
    
    this.init();
  }
  
  /**
  * Calculate map box
  * @param {jQueryElement} $map - original jquery dom...