Zoom library allowing you to easily pinch and zoom on a drawing. Also added an alternative ellipse implementation, a rounded rectangle implementation (using a custom clip implementation that takes the transformation matrix into account), and a custom text implementation (that scales when zoomed, and takes into account that textSize should not exceed 2048 pixels). The example below shows the various elements, compared to the standard implementation.
-- Zoom class example with
-- RoundedRectangle support
-- Ellipse support
-- zoomable text support
-- Herwig Van Marck
-- Use this function to perform your initial setup
function setup()
zoom=Zoom()
end
function roundRect(x,y,w,h,r)
pushStyle()
ellipseMode(CORNER)
smooth()
zoom:clip(x,y,r+1,r+1)
Ellipse(x,y,r*2):draw()
zoom:clip(x,y+h-r,r+1,r+1)
Ellipse(x,y+h-2*r,2*r):draw()
zoom:clip(x+w-r-1,y,r+1,r+1)
Ellipse(x+w-2*r,y,2*r):draw()
zoom:clip(x+w-r,y+h-r,r+1,r+1)
Ellipse(x+w-2*r,y+h-2*r,2*r):draw()
clip()
noSmooth()
rect(x,y+r,w,h-2*r)
rect(x+r,y,w-2*r,r)
rect(x+r,y+h-r,w-2*r,r)
popStyle()
end
function touched(touch)
zoom:touched(touch)
end
-- This function gets called once every frame
function draw()
zoom:draw()
-- This sets a dark background color
background(0, 0, 0, 255)
-- This sets the line thickness
strokeWidth(1)
stroke(255, 255, 255, 255)
noSmooth()
noStroke()
fill(255,255,255,255)
RoundRect(WIDTH/2-100,HEIGHT/2-30,200,60,20):draw()
-- compare text implementations
textMode(CENTER)
font("TimesNewRomanPSMT")
fontSize(20)
fill(0, 8, 255, 157)
text("Rounded rectangle",WIDTH/2,HEIGHT/2+15)
zoom:text("Rounded rectangle",WIDTH/2,HEIGHT/2-15)
-- compare ellipse implementations
fill(255, 255, 255, 255)
ellipse(WIDTH/2,HEIGHT/2-60,40)
Ellipse(WIDTH/2,HEIGHT/2-110,40):draw()
end
-- Geometry part
Ellipse = class()
function Ellipse:init(x,y,w,h)
-- you can accept and set parameters here
self.x = x
self.y = y
self.w = w
if (h==nil) then
self.h=w
else
self.h=h
end
end
function Ellipse:draw()
local points={}
local x=self.x
local y=self.y
local w=self.w
local h=self.h
if (ellipseMode()==CENTER) then
x=x - self.w/2
y=y - self.w/2
elseif (ellipseMode()==RADIUS) then
x=x - self.w
y=y - self.w
w=self.w*2
h=self.h*2
elseif (ellipseMode()==CORNERS) then
w=self.w- self.x
h=self.h- self.y
end
for a=0,2*math.pi,0.1 do
table.insert(points,vec2(x+(1+math.cos(a))*w/2,y+(1+math.sin(a))*h/2))
end
local verts={}
local center=vec2(x+w/2,y+h/2)
for i=1,#points do
table.insert(verts,center)
table.insert(verts,vec2(points[(i % #points)+1].x,points[(i % #points)+1].y))
table.insert(verts,vec2(points[i].x,points[i].y))
end
local m=mesh()
m.vertices=verts
m:draw()
end
RoundRect = class()
function RoundRect:init(x,y,w,h,r)
-- you can accept and set parameters here
self.x = x
self.y = y
self.w = w
self.h = h
self.r = r
end
function RoundRect:draw()
local x=self.x
local y=self.y
local w=self.w
local h=self.h
local r=self.r
if (rectMode()==CENTER) then
x=x - self.w/2
y=y - self.w/2
elseif (rectMode()==RADIUS) then
x=x - self.w
y=y - self.w
w=self.w*2
h=self.h*2
elseif (rectMode()==CORNERS) then
w=self.w- self.x
h=self.h- self.y
end
pushStyle()
ellipseMode(CORNER)
smooth()
zoom:clip(x,y,r+1,r+1)
Ellipse(x,y,r*2):draw()
zoom:clip(x,y+h-r,r+1,r+1)
Ellipse(x,y+h-2*r,2*r):draw()
zoom:clip(x+w-r-1,y,r+1,r+1)
Ellipse(x+w-2*r,y,2*r):draw()
zoom:clip(x+w-r,y+h-r,r+1,r+1)
Ellipse(x+w-2*r,y+h-2*r,2*r):draw()
clip()
noSmooth()
rect(x,y+r,w,h-2*r)
rect(x+r,y,w-2*r,r)
rect(x+r,y+h-r,w-2*r,r)
popStyle()
end
-- Zoom library
-- Herwig Van Marck
-- usage:
--[[
function setup()
zoom=Zoom()
end
function touched(touch)
zoom:touched(touch)
end
function draw()
zoom:draw()
end
]]--
Zoom = class()
function Zoom:init()
-- you can accept and set parameters here
self.touches = {}
self:clear()
print("Tap and drag to move\
Pinch to zoom\
Double tap to reset")
end
function Zoom:clear()
self.lastPinchDist = 0
self.pinchDelta = 1.0
self.center = vec2(0,0)
self.offset = vec2(0,0)
self.zoom = 1
self.started = false
self.started2 = false
end
function Zoom:touched(touch)
-- Codea does not automatically call this method
if touch.state == ENDED then
self.touches[touch.id] = nil
else
self.touches[touch.id] = touch
if (touch.tapCount==2) then
self:clear()
end
end
end
function Zoom:processTouches()
local touchArr = {}
for k,touch in pairs(self.touches) do
-- push touches into array
table.insert(touchArr,touch)
end
if #touchArr == 2 then
self.started = false
local t1 = vec2(touchArr[1].x,touchArr[1].y)
local t2 = vec2(touchArr[2].x,touchArr[2].y)
local dist = t1:dist(t2)
if self.started2 then
--if self.lastPinchDist > 0 then
self.pinchDelta = dist/self.lastPinchDist
else
self.offset= self.offset + ((t1 + t2)/2-self.center)/self.zoom
self.started2 = true
end
self.center = (t1 + t2)/2
self.lastPinchDist = dist
elseif (#touchArr == 1) then
self.started2 = false
local t1 = vec2(touchArr[1].x,touchArr[1].y)
self.pinchDelta = 1.0
self.lastPinchDist = 0
if not(self.started) then
self.offset = self.offset + (t1-self.center)/self.zoom
self.started = true
end
self.center=t1
else
self.pinchDelta = 1.0
self.lastPinchDist = 0
self.started = false
self.started2 = false
end
end
function Zoom:clip(x,y,w,h)
clip(x*self.zoom+self.center.x- self.offset.x*self.zoom,
y*self.zoom+self.center.y- self.offset.y*self.zoom,
w*self.zoom+1,h*self.zoom+1)
end
function Zoom:text(str,x,y)
local fSz = fontSize()
local xt=x*self.zoom+self.center.x- self.offset.x*self.zoom
local yt=y*self.zoom+self.center.y- self.offset.y*self.zoom
fontSize(fSz*self.zoom)
local xtsz,ytsz=textSize(str)
tsz=xtsz
if tsz<ytsz then tsz=ytsz end
if (tsz>2048) then
local eZoom= tsz/2048.0
fontSize(fSz*self.zoom/eZoom)
pushMatrix()
resetMatrix()
translate(xt,yt)
scale(eZoom)
text(str,0,0)
popMatrix()
fontSize(fSz)
else
pushMatrix()
resetMatrix()
fontSize(fSz*self.zoom)
text(str,xt,yt)
popMatrix()
fontSize(fSz)
end
end
function Zoom:draw()
-- compute pinch delta
self:processTouches()
-- scale by pinch delta
self.zoom = math.max( self.zoom*self.pinchDelta, 0.2 )
translate(self.center.x- self.offset.x*self.zoom,
self.center.y- self.offset.y*self.zoom)
scale(self.zoom,self.zoom)
self.pinchDelta = 1.0
end