JSFiddle - React, Tailwind, and code Playground

by Tomasz Janiszewski

HTML

<div id="wrapper">
  <div id="tourWrapper"></div>
  <div id="canvasWrapper">
    <svg id="canvas">
      <rect x="0" y="0" width="210" height="210" />
    </svg>
  </div>
</div>

CSS

html,
body {
  margin: 0;
  padding: 0;
}

#wrapper {
  box-sizing: border-box;
  width: 100%;
  height: 100vh;
}

#tourWrapper,
#canvasWrapper {
  box-sizing: border-box;
  width: 50%;
  height: 100vh;
  min-width: 15%;
  max-width: 85%;
}

#tourWrapper {
  background: white;
  background-size: contain;
  float: left;
}

#canvasWrapper {
  position: relative;
  overflow: hidden;
  background: #eee;
  border-left: 5px solid slategray;
  float: right;
}

#canvas {
  position: absolute;
  top: 50%;
  left: 50%;
  background-size: cover;
}

rect {
  fill: rgba(255, 0, 0, 0.5);
}

rect:hover {
  fill: rgba(255, 0, 0, 0.2);
}

JavaScript

"use strict";

if (!canvasW) {
  var canvasW = document.getElementById('canvasWrapper')
}
if (!tourW) {
  var tourW = document.getElementById('tourWrapper')
}

function Canvas(src, width, height, cnvsWrapper) {

  this.canvas = document.getElementById('canvas');
  this.scaleFactor = 1;
  this.cnvsWrapper = cnvsWrapper;

  this.initiateCanvas = function(src, width, height) {
    this.background = src;
    this.baseWidth = width;
    this.baseHeight = height;
    this.width = this.baseWidth;
    this.height = this.baseHeight;
    this.translateX = -this.width / 2;
    this.translateY = -this.height / 2;
    this.setBaseTranslateXY();
    this.setMinAndMaxScale();
    this.scale = this.minScale;
    this.setCanvasCSS();
  };

  this.setCanvasCSS = function() {
    this.canvas.style.backgroundImage = 'url(\'' + this.background + '\')';
    this.canvas.style.backgroundSize = this.baseWidth + 'px ' + this.baseHeight + 'px';
    this.canvas.style.width = this.baseWidth + 'px';
    this.canvas.style.height = this.baseHeight + 'px';
    this.canvas.style.transform = 'translate(' + this.translateX + 'px, ' + this.translateY + 'px) scale(' + this.scale + ') translateZ(0)';

    this.updateRectData();
  };

  this.setMinAndMaxScale = function() {
    this.maxScale = 1;
    this.minScale = this.cnvsWrapper.getBoundingClientRect().width / this.baseWidth;
  };

  this.setScale = function(scaleFactor, e) {
    if (e) {

      this.setMinAndMaxScale();

      if (this.scale + scaleFactor / 50 < this.minScale) {
        this.scale = this.minScale;
      } else if (this.scale + scaleFactor / 50 > this.maxScale) {
        this.scale = this.maxScale;
      } else {
        this.scale = this.scale + scaleFactor / 50;
      }
    } else {
      this.scale = this.minScale;
    }
    this.setCanvasCSS();
  };

  this.zoom = function(e) {
    if (e.deltaY > 0) {
      this.setScale(-(this.scaleFactor), e);
    } else {
      this.setScale(this.scaleFactor, e);
    }
  };

  this.move =...