#### Howdy, Stranger!

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

# Ellipse Progress Bar

Posts: 7

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.

• Posts: 1,898
@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?
• Posts: 571

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

• Mod
edited December 2020 Posts: 8,723

@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
``````
• Mod
Posts: 8,723

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
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
``````
• Mod
edited December 2020 Posts: 8,723

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

``````Removed code, see updated class version below
``````
• Posts: 7

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?

• Mod
edited December 2020 Posts: 8,723

@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
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
``````
• Posts: 7

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

• Mod
Posts: 8,723

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: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

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
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
``````
• Posts: 7

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

• Mod
edited December 2020 Posts: 8,723

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