Last active
September 22, 2022 15:11
-
-
Save runezero/38ee97e1d3fa1c4fe26b741bfafa3a1a to your computer and use it in GitHub Desktop.
[Zoomable image canvas] a zoomable map for displaying image maps #tools
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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