Skip to content

Instantly share code, notes, and snippets.

@EngineerSmith
Last active February 21, 2022 14:41
Show Gist options
  • Save EngineerSmith/83528599ed09762fc6c8e3d611b73027 to your computer and use it in GitHub Desktop.
Save EngineerSmith/83528599ed09762fc6c8e3d611b73027 to your computer and use it in GitHub Desktop.
Pinch and zoom + pan in love2d
local lg, lt = love.graphics, love.touch
local insert, remove = table.insert, table.remove
local sqrt = math.sqrt
local x,y, w,h = love.window.getSafeArea()
local textW, textH = x+w,y+h
local a, b = textW/2, textH/2
local texture = lg.newCanvas(textW,textH)
lg.setCanvas(texture)
lg.setColor(.5,.5,.5)
lg.rectangle("fill", 0,0, a,b)
lg.setColor(0,.5,.5)
lg.rectangle("fill", a,0, a,b)
lg.setColor(.5,0,.5)
lg.rectangle("fill", 0,b, a,b)
lg.setColor(.5,.5,0)
lg.rectangle("fill", a,b, a,b)
lg.setCanvas()
local cameraX, cameraY, cameraScale = 0,0, 1
local cameraScaleSpeed = .01
local lastX, lastY
local scaleLimit = {
low = 0.1,
high = 2,
}
local touches = {}
local lastDist = 0
local prevWidth, prevHeight = w,h
love.draw = function()
lg.setColor(1,1,1)
lg.push()
lg.scale(cameraScale)
lg.translate(cameraX, cameraY)
lg.draw(texture)
if FX and FY then
lg.setColor(1,1,0)
lg.circle("fill", FX, FY, 5)
end
lg.pop()
lg.print(("X: %.2f Y: %.2f\nS: %.2f T: %d\nDist: %.2f\nW: %.2f H: %.2f"):format(cameraX, cameraY, cameraScale, #touches, lastDist, prevWidth, prevHeight), 50,50)
end
local updateTouch = function(touch)
local lastX, lastY = touch.x, touch.y
local dx,dy = 0,0
for k, move in ipairs(touch.moved) do
dx = dx + (move.x - lastX) / cameraScale
dy = dy + (move.y - lastY) / cameraScale
lastX, lastY = move.x, move.y
touch.moved[k] = nil
end
touch.x = lastX
touch.y = lastY
return dx, dy
end
love.update = function(dt)
if #touches == 1 then
local dx, dy = updateTouch(touches[1])
cameraX = cameraX + dx
cameraY = cameraY + dy
elseif #touches == 2 then
updateTouch(touches[1])
updateTouch(touches[2])
local A, B = {}, {}
A.x, B.x = touches[1].x, touches[2].x
A.y, B.y = touches[1].y, touches[2].y
-- Scale
local dx,dy = B.x - A.x, B.y - A.y
local dist = sqrt(dx*dx+dy*dy)
cameraScale = cameraScale * (dist/lastDist)
if scaleLimit then
if cameraScale > scaleLimit.high then
cameraScale = scaleLimit.high
elseif cameraScale < scaleLimit.low then
cameraScale = scaleLimit.low
else
lastDist = dist
end
else
lastDist = dist
end
-- Translate
A.x, B.x = A.x / cameraScale, A.y / cameraScale
A.y, B.y = B.x / cameraScale, B.y / cameraScale
local focalX = (A.x + B.x) / 2
local focalY = (A.y + B.y) / 2
local _,_,w,h = love.window.getSafeArea()
local nextWidth = w * cameraScale
local nextHeight = h * cameraScale
cameraX =cameraX+ (-focalX * ((nextWidth - prevWidth) / nextWidth))
cameraY =cameraY+ (-focalY * ((nextHeight - prevHeight) / nextHeight))
prevWidth, prevHeight = nextWidth, nextHeight
end
end
local getTouch = function(id)
for k,v in ipairs(touches) do
if v.id == id then return k,v end
end
end
love.touchpressed = function(id, x, y, dx, dy, pressure)
insert(touches, {id=id, x=x, y=y, moved={}})
if #touches == 2 then
local dx, dy = touches[2].x - touches[1].x, touches[2].y - touches[1].y
lastDist = sqrt(dx*dx+dy*dy)
end
end
love.touchmoved = function(id, x, y, dx, dy, pressure)
local _, touch = getTouch(id)
insert(touch.moved, {x=x, y=y})
end
love.touchreleased = function(id, x, y, dx, dy, pressure)
remove(touches, getTouch(id))
end
@EngineerSmith
Copy link
Author

Taken from my code at https://github.com/EngineerSmith/BrushMap/blob/main/input/touch.lua which includes more features

There is an issue with drifting the further you zoom out

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment