Make canvas multi-canvased; add zoom and cursor
parent
963294ceaa
commit
9e07913210
|
@ -13,34 +13,72 @@
|
|||
|
||||
let offsetX: number
|
||||
let offsetY: number
|
||||
let zoom: number = 1.0
|
||||
|
||||
$: ((animation, frame, layer, img, refresh) => {
|
||||
setTimeout(() => {
|
||||
redraw()
|
||||
}, 0)
|
||||
})(animation, frame, layer, img, refresh)
|
||||
|
||||
let canvas: HTMLCanvasElement
|
||||
function redraw() {
|
||||
if (!canvas) return
|
||||
let ctx = canvas.getContext('2d')
|
||||
let mouseX: number = 0
|
||||
let mouseY: number = 0
|
||||
let mousePixelX: number = 0
|
||||
let mousePixelY: number = 0
|
||||
|
||||
let rootCanvas: HTMLCanvasElement
|
||||
let overlayCanvas: HTMLCanvasElement = document.createElement('canvas')
|
||||
let canvas: HTMLCanvasElement = document.createElement('canvas')
|
||||
|
||||
let overlayDirty: boolean = true
|
||||
let canvasDirty: boolean = true
|
||||
|
||||
// check resizes canvases, etc.
|
||||
function check() {
|
||||
let ctx = rootCanvas.getContext('2d')
|
||||
if (!ctx) return
|
||||
let computedSize = getComputedStyle(canvas)
|
||||
if (canvas.width !== parseInt(computedSize.width) || canvas.height !== parseInt(computedSize.height)) {
|
||||
canvas.width = parseInt(computedSize.width)
|
||||
canvas.height = parseInt(computedSize.height)
|
||||
let computedSize = getComputedStyle(rootCanvas)
|
||||
if (rootCanvas.width !== parseInt(computedSize.width) || rootCanvas.height !== parseInt(computedSize.height)) {
|
||||
rootCanvas.width = parseInt(computedSize.width)
|
||||
rootCanvas.height = parseInt(computedSize.height)
|
||||
canvas.width = rootCanvas.width
|
||||
canvas.height = rootCanvas.height
|
||||
overlayCanvas.width = rootCanvas.width
|
||||
overlayCanvas.height = rootCanvas.height
|
||||
overlayDirty = true
|
||||
canvasDirty = true
|
||||
}
|
||||
|
||||
if (offsetX === undefined || offsetY === undefined) {
|
||||
// Adjust offset to center image on first LOAD.
|
||||
offsetX = canvas.width/2 - img.width/2
|
||||
offsetY = canvas.height/2 - img.height/2
|
||||
offsetX = rootCanvas.width/2 - img.width/2
|
||||
offsetY = rootCanvas.height/2 - img.height/2
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
if (!rootCanvas) return
|
||||
check()
|
||||
if (canvasDirty) {
|
||||
drawCanvas()
|
||||
canvasDirty = false
|
||||
}
|
||||
if (overlayDirty) {
|
||||
drawOverlay()
|
||||
overlayDirty = false
|
||||
}
|
||||
let ctx = rootCanvas.getContext('2d')
|
||||
if (!ctx) return
|
||||
ctx.clearRect(0, 0, rootCanvas.width, rootCanvas.height)
|
||||
ctx.drawImage(canvas, 0, 0)
|
||||
ctx.drawImage(overlayCanvas, 0, 0)
|
||||
}
|
||||
|
||||
function drawCanvas() {
|
||||
let ctx = canvas.getContext('2d')
|
||||
if (!ctx) return
|
||||
|
||||
ctx.fillStyle = '#111111'
|
||||
ctx.fillRect(0, 0, canvas.width, canvas.height)
|
||||
|
||||
// Draw checkboard.
|
||||
ctx.save()
|
||||
ctx.imageSmoothingEnabled = false
|
||||
ctx.scale(zoom, zoom)
|
||||
//ctx.transform(1, 0, 0, 1, -img.width/2, -img.height/2)
|
||||
{
|
||||
ctx.beginPath()
|
||||
ctx.fillStyle = '#888888'
|
||||
|
@ -68,6 +106,28 @@
|
|||
|
||||
// TODO: Draw the current layer of the current frame.
|
||||
ctx.drawImage(img, offsetX, offsetY)
|
||||
ctx.restore()
|
||||
}
|
||||
|
||||
function drawOverlay() {
|
||||
if (!overlayCanvas) return
|
||||
let ctx = overlayCanvas.getContext('2d')
|
||||
if (!ctx) return
|
||||
ctx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height)
|
||||
ctx.save()
|
||||
ctx.translate(0.5, 0.5)
|
||||
// Draw a cursor.
|
||||
{
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = '#ff0000'
|
||||
ctx.lineWidth = 1
|
||||
|
||||
ctx.rect(offsetX*zoom+mousePixelX*zoom, offsetY*zoom+mousePixelY*zoom, 1*zoom, 1*zoom)
|
||||
|
||||
ctx.rect(mouseX, mouseY, 1, 1)
|
||||
ctx.stroke()
|
||||
}
|
||||
ctx.restore()
|
||||
}
|
||||
|
||||
function capOffset() {
|
||||
|
@ -88,6 +148,15 @@
|
|||
let x: number = 0
|
||||
let y: number = 0
|
||||
|
||||
node.addEventListener('mouseenter', (e: MouseEvent) => {
|
||||
// hide cursor
|
||||
document.body.style.cursor = 'none'
|
||||
})
|
||||
node.addEventListener('mouseleave', (e: MouseEvent) => {
|
||||
// show cursor
|
||||
document.body.style.cursor = 'default'
|
||||
})
|
||||
|
||||
node.addEventListener('mousedown', (e: MouseEvent) => {
|
||||
buttons.add(e.button)
|
||||
x = e.clientX
|
||||
|
@ -95,6 +164,21 @@
|
|||
})
|
||||
|
||||
node.addEventListener('wheel', (e: WheelEvent) => {
|
||||
if (e.ctrlKey) {
|
||||
if (e.deltaY < 0) {
|
||||
zoom *= 2
|
||||
} else if (e.deltaY > 0) {
|
||||
zoom /= 2
|
||||
}
|
||||
if (zoom > 1) {
|
||||
zoom = Math.round(zoom)
|
||||
}
|
||||
|
||||
capOffset()
|
||||
canvasDirty = true
|
||||
overlayDirty = true
|
||||
return
|
||||
}
|
||||
if (e.deltaY < 0) {
|
||||
if (e.shiftKey) {
|
||||
offsetX--
|
||||
|
@ -109,10 +193,22 @@
|
|||
}
|
||||
}
|
||||
capOffset()
|
||||
redraw()
|
||||
canvasDirty = true
|
||||
overlayDirty = true
|
||||
})
|
||||
|
||||
window.addEventListener('mousemove', (e: MouseEvent) => {
|
||||
if (!canvas) return
|
||||
// Get mouse position relative to canvas.
|
||||
{
|
||||
let rect = canvas.getBoundingClientRect()
|
||||
mouseX = e.offsetX - rect.left
|
||||
mouseY = e.offsetY - rect.top
|
||||
mousePixelX = Math.floor(mouseX / zoom - offsetX)
|
||||
mousePixelY = Math.floor(mouseY / zoom - offsetY)
|
||||
overlayDirty = true
|
||||
}
|
||||
|
||||
if (buttons.size === 0) return
|
||||
let dx = e.clientX - x
|
||||
let dy = e.clientY - y
|
||||
|
@ -123,14 +219,15 @@
|
|||
console.log('0')
|
||||
}
|
||||
if (buttons.has(1)) {
|
||||
offsetX += dx
|
||||
offsetY += dy
|
||||
offsetX += dx / zoom
|
||||
offsetY += dy / zoom
|
||||
capOffset()
|
||||
canvasDirty = true
|
||||
overlayDirty = true
|
||||
}
|
||||
if (buttons.has(2)) {
|
||||
console.log('2')
|
||||
}
|
||||
redraw()
|
||||
})
|
||||
|
||||
window.addEventListener('mouseup', (e: MouseEvent) => {
|
||||
|
@ -139,12 +236,20 @@
|
|||
}
|
||||
|
||||
onMount(() => {
|
||||
redraw()
|
||||
let frameID: number = 0
|
||||
let frameDraw = () => {
|
||||
draw()
|
||||
frameID = window.requestAnimationFrame(frameDraw)
|
||||
}
|
||||
frameID = window.requestAnimationFrame(frameDraw)
|
||||
return () => {
|
||||
window.cancelAnimationFrame(frameID)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<main>
|
||||
<canvas bind:this={canvas} use:canvasMousedown on:contextmenu={(e)=>e.preventDefault()}></canvas>
|
||||
<canvas bind:this={rootCanvas} use:canvasMousedown on:contextmenu={(e)=>e.preventDefault()}></canvas>
|
||||
</main>
|
||||
|
||||
<style>
|
||||
|
@ -156,5 +261,6 @@
|
|||
canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue