JSFiddle - React, Tailwind, and code Playground

HTML

<canvas id="c" width="400" height="400"></canvas>
<div id="debug"></div>

CSS

#c {
    outline: 1px solid #ccc;
    width: 400px;
    height: 400px;
    margin: 10px;
}

JavaScript

/* Trying to make a Google Maps-style app.
 * Attempting to allow the following:
 *  -panning (works)
 *  -zooming (works)
 * The problem:
 *  -centering the map on mouse coordinates after zooming
 */
var canvas, ctx, colorOffset;
var c_width, c_height

var globalPan = { startX : 0, startY : 0, currentX : 0, currentY : 0 };
var mouse = { x : 0, y : 0 };
var globalZoom = 1.0;
var isPanning = false;

function draw() {
    ctx.clearRect(0,0,c_width,c_height);
    
    ctx.save();
    
    //Update for panning and zoom
    
    /*THE PROBLEM - no matter what I do, this doesn't have the desired effect. It *sort of* works, but it's just a little... off. */
    ctx.translate(
      (mouse.x*globalZoom) / globalZoom, 
      (mouse.y*globalZoom) / globalZoom
    );
    //ctx.translate(
    //  mouse.x / globalZoom, 
    //  mouse.y / globalZoom
    //);
    ctx.scale(globalZoom, globalZoom);
    ctx.translate(
      -mouse.x / globalZoom, 
      -mouse.y / globalZoom
    );
    /* end of problem */
    
    ctx.translate(
      globalPan.currentX / globalZoom, 
      globalPan.currentY / globalZoom
    );
    
    
    
    
    //Draw shapes
    
    //Bounding box; all drawings are contained herewithin
    ctx.strokeStyle = "#333";
    ctx.strokeRect(0,0,c_width,c_height);
    
    //Circles
    
    //Color is just to show that we are animating
    colorOffset = (new Date()).getSeconds() * 20;
    for (var i = 12; i > 0; i--) {
        ctx.beginPath();
        ctx.strokeStyle = "hsl(" + (30 * i + colorOffset) + ", 100%, 50%)";
        ctx.arc(200,200,10 * i, 0, Math.PI * 2, false);
        ctx.stroke();
    }
    
    //Reset context so it doesn't keep translating and zooming endlessly
    ctx.restore();
    
    //Debugging stuff
    debug.innerHTML = "globalPan.startX: " + globalPan.startX
         + "<br>globalPan.startY: " + globalPan.startY
         + "<br>globalPan.currentX: " + globalPan.currentX
         + "<br>globalPan.currentY: " + globalPan.currentY
       ...