It looks like you're new here. If you want to get involved, click one of these buttons!
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\nPinch to zoom\nDouble 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
Comments
Wonderful! Thanks! Zooming isn't too easy to do, so it makes everything better!
Thanks!
Many thanks @Herwig! I was already impressed with the zoom in your Spirograph app and now this!
Thanks guys! In the meantime I made a small update to the Zoom library that takes an initial parameter specifying where to put the origin (needed that for my Strandbeest example).
@Zoyt - This is for your competition
Great! Thanks! I was worried no one would enter
Updated version, which also saves the last viewpoint:
Thanks!
@Herwig I finally got around to trying this and it's really brilliant. So easy to use it's almost as if it's not even there. Great work!
@Simeon @Zoyt Thanks guys!
This is great work! Thanks for sharing!
Thanks! Also works well with the new dependency feature...
@Herwig would you mind to add a small piece of code showing the result? When i create a project out of this code and run it, i just have a black screen...? I guess this is a library with no example of usage? I am not an expert of codea, so i can't easily enjoy your development,nor understand how to use it. Thanks anyhow.
@Jmv38 put this in the main of a project called 'Zoom lib', and the code above in a separate tab.
@Herwig thanks! Works very nicely!
Thanks for a great library!
Is there some way we make scrolling bounds in an easy manner?