Ellipse Progress Bar

Hi everyone. I’m trying to create a progress bar but instead of using a rectangle, I want to use an ellipse. So 0% would be an ellipse unfilled, 50% the ellipse would be half filled like a semi circle. At 25% the ellipse would look like the pic below. Would appreciate any help.

Thanks

Will.

Hi Dave. That’s great. Using this code allows me to put 3 progress bars at the same time. Thanks heaps!

@WilliamHouten With the class code, you can have 1 or 100 timers or just about any amount at the same time.

@WilliamHouten - thought about your problem and I think there is a way to do this but it would depend on the interval you need for rotation - or the displacement round the circle for each update.
My idea was to create an image which you update in memory and display as a Sprite. You could use a line() with a fixed stroke drawn from the centre and if necessary use blend mode with a circle to ensure the circular effect is intact.
Have you tried anything yet?

@WilliamHouten i think you could probably use the ARC shader in the shaderlab to do that.

@WilliamHouten Here’s an example of a timer. It needs some work, but I’ll let you change it for your needs. This is set for 20 seconds. Change sec for what you need.

Updated code below

Here’s a class version of the above code with some additions.

Removed code, see updated class version below

Made changes to my code so changing the radius changes the circle size also.

viewer.mode=STANDARD

function setup()
    e=0
    sec=20 -- number of seconds to fill circle
    m=mesh()
end

function draw()
    background(0)
    timer()
    m.vertices=mtab
    m:setColors(0,200,255)
    m.draw(m)
    fill(255)
    text("tap screen to start timer for  "..sec.."  seconds",WIDTH/2,HEIGHT-50)
end

function touched(t)
    if t.state==BEGAN then
        startTimer=true
    end
end

function timer()
    if startTimer then
        e=e+6/sec
    end
    circ(WIDTH/2,HEIGHT/2,100,0,e)
end

-- x, y, radius, starting angle, number of degrees
function circ(x,y,r,s,e)
    stroke(0,200,255)
    strokeWidth(2)
    noFill()
    ellipse(x,y,r*2+2)
    if not startTimer then
        return
    end
    mtab={}
    ctab={}
    table.insert(ctab,vec2(x,y))
    for z=s,s+e do
        x1=math.cos(math.rad(z))*r+x
        y1=math.sin(math.rad(z))*r+y
        table.insert(ctab,vec2(x1,y1))
    end
    for z=2,#ctab do
        table.insert(mtab,(vec2(ctab[1].x,ctab[1].y)))
        table.insert(mtab,(vec2(ctab[z-1].x,ctab[z-1].y)))
        table.insert(mtab,(vec2(ctab[z].x,ctab[z].y)))
    end
end

Hi Dave. That’s great! Exactly what I was after.
What would I need to change to start the fill from the top and make it fill going clockwise?

@WilliamHouten Here’s the change. I made a minor change to timer() and circ(). The change to timer was just to stop adding to e when it’s over 360. The change to calc() was 90-z .

PS. I also added if e<365 in timer() so it stops calling circ when the circle is complete.

viewer.mode=STANDARD

function setup()
    e=0
    sec=20 -- number of seconds to fill circle
    m=mesh()
end

function draw()
    background(0)
    timer()
    m.vertices=mtab
    m:setColors(0,200,255)
    m.draw(m)
    fill(255)
    text("tap screen to start timer for  "..sec.."  seconds",WIDTH/2,HEIGHT-50)
end

function touched(t)
    if t.state==BEGAN then
        startTimer=true
    end
end

function timer()
    if startTimer and e<360 then
        e=e+6/sec
    end
    if e<365 then
        circ(WIDTH/2,HEIGHT/2,100,0,e)
    end
end

-- x, y, radius, starting angle, number of degrees
function circ(x,y,r,s,e)
    stroke(0,200,255)
    strokeWidth(2)
    noFill()
    ellipse(x,y,r*2+2)
    if not startTimer then
        return
    end
    mtab={}
    ctab={}
    table.insert(ctab,vec2(x,y))
    for z=0,s+e do
        x1=math.cos(math.rad(90-z))*r+x
        y1=math.sin(math.rad(90-z))*r+y
        table.insert(ctab,vec2(x1,y1))
    end
    for z=2,#ctab do
        table.insert(mtab,(vec2(ctab[1].x,ctab[1].y)))
        table.insert(mtab,(vec2(ctab[z-1].x,ctab[z-1].y)))
        table.insert(mtab,(vec2(ctab[z].x,ctab[z].y)))
    end
end

Here’s an updated class version. I allow circles or ellipses for the timers.

viewer.mode=FULLSCREEN

function setup()
    tab={}
    table.insert(tab,timer(200,300,100,100,10))
    table.insert(tab,timer(300,500,150,50,20))
    table.insert(tab,timer(600,500,80,150,30))
end

function draw()
    background(0)
    for a,b in pairs(tab) do
        b:draw()
        if b.done then
            fill(255)
            text("Done",b.x,b.y)
        end
    end
    text("Tap inside each ellipse to start timer",WIDTH/2,HEIGHT-50)
end

function touched(t)
    if t.state==BEGAN then
        for a,b in pairs(tab) do
            b:touched(t)
        end
    end
end

timer=class()

function timer:init(x,y,a,b,t)
    self.x=x
    self.y=y
    self.a=a
    self.b=b
    self.e=0
    self.t=t
    self.run=false
    self.done=false
    self.m=mesh()
end

function timer:draw()
    self:addAngle()
    self:calcMesh()
    self:drawMesh()
    self:meshOutline()
    self:countdown()
    self:checkAngle()
end

function timer:touched(t)
    if t.state==BEGAN then
        if (t.x-self.x)^2/self.a^2+(t.y-self.y)^2/self.b^2 <= 1 then
            self.run=true
        end
    end
end

function timer:drawMesh()
    self.m.vertices=self.mtab
    if self.done then
        self.m:setColors(255,0,0)
    else
        self.m:setColors(0,200,255)
    end
    self.m.draw(self.m)
end

function timer:meshOutline()
    stroke(0,200,255)
    strokeWidth(2)
    noFill()
    ellipse(self.x,self.y,self.a*2+2,self.b*2+2)
end

function timer:countdown()
    fill(255)
    if not self.done then
        text(string.format("%.1f",self.t-(self.t/(360/self.e))),self.x,self.y)
    end
end

function timer:addAngle()
    if self.run then
        self.e=self.e+6/self.t
    end
end

function timer:checkAngle()
    if self.e>360 then
        self.run=false
        self.done=true
    end
end

function timer:calcMesh()
    if self.run then
        self.mtab={}
        self.ctab={}
        table.insert(self.ctab,vec2(self.x,self.y))
        for z=0,self.e do
            x1=self.a*math.cos(math.rad(90-z))+self.x
            y1=self.b*math.sin(math.rad(90-z))+self.y
            table.insert(self.ctab,vec2(x1,y1))
        end
        for z=2,#self.ctab do
            table.insert(self.mtab,(vec2(self.ctab[1].x,self.ctab[1].y)))
            table.insert(self.mtab,(vec2(self.ctab[z-1].x,self.ctab[z-1].y)))
            table.insert(self.mtab,(vec2(self.ctab[z].x,self.ctab[z].y)))
        end
    end
end

Thanks mate! That’s exactly what I was after. Cheers.