Skip to content

Instantly share code, notes, and snippets.

@runezero
Last active September 22, 2022 15:11
Show Gist options
  • Save runezero/38ee97e1d3fa1c4fe26b741bfafa3a1a to your computer and use it in GitHub Desktop.
Save runezero/38ee97e1d3fa1c4fe26b741bfafa3a1a to your computer and use it in GitHub Desktop.
[Zoomable image canvas] a zoomable map for displaying image maps #tools
<!-- This is a very basic canvas example which allows for panning and zooming using a mouse (Click & drag & scrollwheel) or touchscreen (tap and drag to pan, pinch to zoom). -->
<body>
<canvas id="canvas"></canvas>
</body>
//https://codepen.io/chengarda/pen/wRxoyB
let canvas = document.getElementById("canvas")
let ctx = canvas.getContext('2d')
let cameraOffset = { x: window.innerWidth/2, y: window.innerHeight/2 }
let cameraZoom = 1
let MAX_ZOOM = 2 //zoomin amount
let MIN_ZOOM = 0.5 //zoomout amount
let SCROLL_SENSITIVITY = 0.0005
function draw()
{
canvas.width = window.innerWidth
canvas.height = window.innerHeight
// Translate to the canvas centre before zooming - so you'll always zoom on what you're looking directly at
//ctx.translate( window.innerWidth / 2, window.innerHeight / 2 )
ctx.scale(cameraZoom, cameraZoom)
ctx.translate( -window.innerWidth / 2 + cameraOffset.x, -window.innerHeight / 2 + cameraOffset.y )
var img = document.createElement("IMG");
img.src = "https://billybird.nl/wp-content/uploads/2022/09/plattegrond-herfst.jpg";
ctx.drawImage(img, -500, -400);
requestAnimationFrame( draw )
}
// Gets the relevant location from a mouse or single touch event
function getEventLocation(e)
{
if (e.touches && e.touches.length == 1)
{
return { x:e.touches[0].clientX, y: e.touches[0].clientY }
}
else if (e.clientX && e.clientY)
{
return { x: e.clientX, y: e.clientY }
}
}
function drawRect(x, y, width, height)
{
ctx.fillRect( x, y, width, height )
}
function drawText(text, x, y, size, font)
{
ctx.font = `${size}px ${font}`
ctx.fillText(text, x, y)
}
let isDragging = false
let dragStart = { x: 0, y: 0 }
function onPointerDown(e)
{
isDragging = true
dragStart.x = getEventLocation(e).x/cameraZoom - cameraOffset.x
dragStart.y = getEventLocation(e).y/cameraZoom - cameraOffset.y
}
function onPointerUp(e)
{
isDragging = false
initialPinchDistance = null
lastZoom = cameraZoom
}
function onPointerMove(e)
{
if (isDragging)
{
cameraOffset.x = getEventLocation(e).x/cameraZoom - dragStart.x
cameraOffset.y = getEventLocation(e).y/cameraZoom - dragStart.y
}
}
function handleTouch(e, singleTouchHandler)
{
if ( e.touches.length == 1 )
{
singleTouchHandler(e)
}
else if (e.type == "touchmove" && e.touches.length == 2)
{
isDragging = false
handlePinch(e)
}
}
let initialPinchDistance = null
let lastZoom = cameraZoom
function handlePinch(e)
{
e.preventDefault()
let touch1 = { x: e.touches[0].clientX, y: e.touches[0].clientY }
let touch2 = { x: e.touches[1].clientX, y: e.touches[1].clientY }
// This is distance squared, but no need for an expensive sqrt as it's only used in ratio
let currentDistance = (touch1.x - touch2.x)**2 + (touch1.y - touch2.y)**2
if (initialPinchDistance == null)
{
initialPinchDistance = currentDistance
}
else
{
adjustZoom( null, currentDistance/initialPinchDistance )
}
}
function adjustZoom(zoomAmount, zoomFactor)
{
if (!isDragging)
{
if (zoomAmount)
{
cameraZoom += zoomAmount
}
else if (zoomFactor)
{
console.log(zoomFactor)
cameraZoom = zoomFactor*lastZoom
}
cameraZoom = Math.min( cameraZoom, MAX_ZOOM )
cameraZoom = Math.max( cameraZoom, MIN_ZOOM )
console.log(zoomAmount)
}
}
canvas.addEventListener('mousedown', onPointerDown)
canvas.addEventListener('touchstart', (e) => handleTouch(e, onPointerDown))
canvas.addEventListener('mouseup', onPointerUp)
canvas.addEventListener('touchend', (e) => handleTouch(e, onPointerUp))
canvas.addEventListener('mousemove', onPointerMove)
canvas.addEventListener('touchmove', (e) => handleTouch(e, onPointerMove))
canvas.addEventListener( 'wheel', (e) => adjustZoom(e.deltaY*SCROLL_SENSITIVITY))
// Ready, set, go
draw()
html, body
{
height: 500px;
width: 400px;
margin: 0;
padding: 0px;
overflow: hidden;
}
#canvas
{
width: auto;
height: auto;
background: #555;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment