JSFiddle - React, Tailwind, and code Playground

HTML

<canvas></canvas>

CSS

body { background:#eee; margin:1em; text-align:center; }
		canvas { display:block; margin:1em auto; background:#fff; border:1px solid #ccc }

JavaScript

var canvas = document.getElementsByTagName('canvas')[0];
	canvas.width = 800;
canvas.height = 600;

	var gkhead = new Image();
  
  function sleep(ms) 
  {
  return new Promise(resolve => setTimeout(resolve, ms));
  }

	window.onload = function(){		
    
		    var ctx = canvas.getContext('2d');
		    trackTransforms(ctx);
		  
    function redraw(){

          // Clear the entire canvas
          var p1 = ctx.transformedPoint(0,0);
          var p2 = ctx.transformedPoint(canvas.width,canvas.height);
          ctx.clearRect(p1.x,p1.y,p2.x-p1.x,p2.y-p1.y);

          ctx.save();
          ctx.setTransform(1,0,0,1,0,0);
          ctx.clearRect(0,0,canvas.width,canvas.height);
          ctx.restore();

          ctx.drawImage(gkhead,0,0);

        }
        redraw();

      var lastX=canvas.width/2, lastY=canvas.height/2;

      var dragStart,dragged;

      canvas.addEventListener('mousedown',function(evt){
          document.body.style.mozUserSelect = document.body.style.webkitUserSelect = document.body.style.userSelect = 'none';
          lastX = evt.offsetX || (evt.pageX - canvas.offsetLeft);
          lastY = evt.offsetY || (evt.pageY - canvas.offsetTop);
          dragStart = ctx.transformedPoint(lastX,lastY);
          dragged = false;
      },false);

      canvas.addEventListener('mousemove',function(evt){
          lastX = evt.offsetX || (evt.pageX - canvas.offsetLeft);
          lastY = evt.offsetY || (evt.pageY - canvas.offsetTop);
          dragged = true;
          if (dragStart){
            var pt = ctx.transformedPoint(lastX,lastY);
            ctx.translate(pt.x-dragStart.x,pt.y-dragStart.y);
            redraw();
                }
      },false);

      canvas.addEventListener('mouseup', async function(evt)
      {
          dragStart = null;
          var i = 0;
          if (!dragged)
          {
          	while (i < 10)
            {
							//alert(i);
          		zoom(evt.shiftKey ? -1 : 1 );
              i++;
              await sleep(50);
 ...