Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Pinch Zoom

I wanted to figure out a way to implement pinch zoom, and the easiest way was to build off of the multi-touch example.

function setup()
    print("This example tracks multiple touches and colors them based on their ID")
    -- keep track of our touches in this table
    touches = {}
    a = nil
    b = nil
    av = vec2(0,0)
    bv = vec2(0,0)
    initialDistance = 0
    ratio = 1    
end

function countTouches()
    i = 0
    for k,v in pairs(touches) do
        i = i+1
    end
    return i
end

function gatherTouches()
    a = {}
    for k,t in pairs(touches) do
        table.insert(a,t)
    end
    return a[1],a[2]
end

function between( val, low, high )
    return (low <= val and val <= high)
end

function touched(touch)
    if touch.state == ENDED then
        -- When any touch ends, remove it from
        --  our table
        touches[touch.id] = nil
        if( twoFingerTouch == true ) then
            twoFingerTouch = false 
            initialDistance = 0
            ratio = 1
        end
    else
        -- If the touch is in any other state 
        --  (such as BEGAN) we add it to our
        --  table
        touches[touch.id] = touch
    end
    --print( "num touches", countTouches())
    if( countTouches() == 2 ) then
        --calc distance between the touches
        a,b = gatherTouches()
        av = vec2(a.x, a.y)
        bv = vec2(b.x, b.y)
        dist = av:dist(bv)
        --print("distance between touches", dist)
        if( touch.state == BEGAN ) then
            --we started a 2-finger touch so mark the distance
            initialDistance = dist
            --when we stop touching with two fingers, we need to reset ratio and initialDistance
            twoFingerTouch = true
        elseif( touch.state == MOVING and dist ~= initialDistance ) then
            --figure out how much it's changed
            if( between(dist, initialDistance*0.5, initialDistance * 2) ) then
                ratio = dist / initialDistance
            end
        end
    else
        a,b = nil,nil 
        initialDistance = 0
        ratio = 1
    end
end

function draw()
    background(0, 0, 0, 255)
    spriteMode(CENTER)
    w,h = spriteSize("SpaceCute:Background")
    sprite("SpaceCute:Background",WIDTH/2, HEIGHT/2, w*0.5*ratio, h*0.5*ratio)

    for k,touch in pairs(touches) do
        -- Use the touch id as the random seed
        math.randomseed(touch.id)
        -- This ensures the same fill color is used for the same id
        fill(math.random(255),math.random(255),math.random(255))
        -- Draw ellipse at touch position
        ellipse(touch.x, touch.y, 100 * ratio, 100 * ratio)
    end
    if( a ~= nil and b ~= nil ) then
        fill(255,0,0,255)
        strokeWidth(1)
        line(av.x,av.y, bv.x, bv.y)
    end
end

Can anyone see any means of improving this such that the gatherTouches() and countTouches() methods aren't needed?

Comments

  • Posts: 2,020

    Have you tried a forum search, there are a couple of implementations of pinch to zoom on here. One of them I thought worked pretty well. If you add a touch of velocity to it, it can smooth out the motion.

  • dave1707dave1707 Mod
    Posts: 9,601

    @matkatmusic Here's a version I had that doesn't use a table.

    function setup()
        t1,t2=vec3(0,0,0),vec3(0,0,0)
        img=readImage("Planet Cute:Character Horn Girl")
        scale=img.width
    end
    
    function draw()
        background(40, 40, 50)
        sprite(img,WIDTH/2,HEIGHT/2,scale)
    end
    
    function touched(t)
        if t.state==BEGAN then
            hdist=0
            if t1.z==0 then
                t1=vec3(t.x,t.y,t.id)
            elseif t2.z==0 then
                t2=vec3(t.x,t.y,t.id)
            end
        end
        if t.state==MOVING then
            if t1.z==t.id then
                t1=vec3(t.x,t.y,t.id)
            elseif t2.z==t.id then
                t2=vec3(t.x,t.y,t.id)
            end
            if t1.z~=0 and t2.z~=0 then
                dist=vec2(t1.x,t1.y):dist(vec2(t2.x,t2.y))
                if dist-hdist>0 then
                    scale=scale*1.02
                else
                    scale=scale*.98
                end
                hdist=dist
            end
        end
        if t.state==ENDED then
            if t1.z==t.id then
                t1=vec3(0,0,0)
            elseif t2.z==t.id then
                t2=vec3(0,0,0)
            end
        end
    end
    
  • Posts: 212

    I saw @Herwig's version after following your suggestion and searching for it. I'm at least on the right track, as we both did the same thing (gather the touches, see if there are 2, calc the distance between the two, monitor the change in distance)

  • Based on the version above I coded my own version which supports pinch to zoom and moving at the same time: https://gist.github.com/dmitrii-eremin/3bfe12835cc4b8a7c6041dde0b654e24

  • dave1707dave1707 Mod
    Posts: 9,601

    @NeonMercury Works great. Need to add background(0) to the draw function in your example or else you’ll get multiple images as you zoom in/out.

  • Posts: 2,430

    @matkatmusic - neat demo, having a play with it to see where I might apply it. Thanks.

Sign In or Register to comment.