JSFiddle - React, Tailwind, and code Playground

HTML

<canvas id=canvas width=300 height=300></canvas>

CSS

canvas {
    position: absolute;
    left: 0;
    top: 0;
}

CoffeeScript

canvas = document.getElementById 'canvas'
ctx = canvas.getContext '2d'
offset = x: 0, y: 0
scale = 1

draw = ->
    ctx.clearRect 0, 0, canvas.width, canvas.height
    ctx.save()
    ctx.translate offset.x, offset.y
    ctx.scale scale, scale
    for i in [0..5]
        for j in [0..5]
        	ctx.fillRect i * 50, j * 50, 40, 40
    ctx.restore()

clicked = (e) ->
    # clientX/Y will *only* work if the canvas is positioned at (0, 0)
    # in most cases, this will not be the case
    # but here, it is
    mousePos = x: e.clientX, y: e.clientY
    untransformed =
        x: (mousePos.x - offset.x) / scale
        y: (mousePos.y - offset.y) / scale
    step = 1.5
    newScale = scale * step
    offset.x += untransformed.x * (scale - newScale)
    offset.y += untransformed.y * (scale - newScale)
    scale = newScale
    draw()

draw()

canvas.addEventListener 'click', clicked, false