Just started to work with IA and have a simple question. I have an irregular shaped component that is representing multiple level lift station. I'm wanting to animate the fill color to show water level based on the value in the PLC. Is there a way to do this for 0-100%
I looked at the level indication but didn't see a way to edit its shape.
The quick and dirty solution would be to place background-colored, borderless empty objects in front of the level indicator to obscure it where the irregular steps are. The precision solution would be to draw exactly what you need with the paintable canvas.
Thanks for the reply.
I’m trying to avoid the down and dirty method. I have my object drawn but not sure how to control the fill height based on the value [0-100] in the PLC.
Thanks for pointing out the paintable canvas for this, @pturmel. Using it to draw a shape and then fill to a certain level is easy using the clip method. Definitely beats my previous method of creating shapes to fill the area and dynamically calculating their size and position to make it all work!
Below is a basic example, in case it’s helpful to others. It expects the paintable canvas to have a custom property fillPercent used to set the fill level 0-100%:
from java.awt import Color
from java.awt.geom import GeneralPath
from java.awt.geom import Rectangle2D
g = event.graphics
#### Create shapes assuming 250x350 size, then scale the graphics
#### to proper size later
# Silo
silo = GeneralPath()
silo.moveTo(0,0)
silo.lineTo(0,250)
silo.lineTo(75,350)
silo.lineTo(150,250)
silo.lineTo(150,0)
silo.closePath()
# Shape to be clipped to actual empty area
empty = GeneralPath()
empty.moveTo(0.5,0.5)
empty.lineTo(0.5,250)
empty.lineTo(75,350)
empty.lineTo(150,250)
empty.lineTo(150,0.5)
empty.closePath()
# Empty area based on fillPercent property
emptyPercent = 100 - event.source.fillPercent
emptyArea = Rectangle2D.Float(0, 0, 150, 350 * emptyPercent/100)
#### Scale graphics to actual component size
dX = (event.width-1)/151.0
dY = (event.height-1)/351.0
g.scale(dX,dY)
# Paint silo (includes fill for filled area)
g.setPaint(Color.YELLOW)
g.fill(silo)
g.setColor(Color.GRAY)
g.draw(silo)
# Clip empty area to exclude filled area
g.setClip(emptyArea)
g.clip(empty)
# Paint empty area
g.setPaint(Color.DARK_GRAY)
g.fill(empty)
Along with the example the paintable canvas comes prefilled with, the information in the Java 2D Graphics tutorial here filled in the rest needed to accomplish this (and much more).
HI Witman
If have a complex pre-created svg shape this method doesn’t work and also draw complex shape with code is really hard.
So I’d like to know is there any other solution for that?
My Batik SVG Canvas Module provides an SVG rendering component, but you’ll have to modify that SVG on the fly to include the fill level animation (empty complete shape with clipped fill shape on top). The component does expose the graphics object tree for runtime manipulation, if you wish to experiment with dynamically modifying that instead.
Thank you for taking the time to come back and post this, 6 years later this post is super useful
Plus my contribution (modified version of the original) for science
from java.awt import Color, BasicStroke
from java.awt.geom import GeneralPath, Rectangle2D
g = event.graphics
#### Create shapes assuming 250x350 size, then scale the graphics
#### to proper size later
# Silo with a flat section at the bottom
silo = GeneralPath()
silo.moveTo(0, 0) # Top-left
silo.lineTo(0, 250) # Vertical left edge
silo.lineTo(50, 350) # Taper to the bottom-left flat edge
silo.lineTo(100, 350) # Flat bottom edge
silo.lineTo(150, 250) # Taper back up to the right
silo.lineTo(150, 0) # Vertical right edge
silo.closePath()
# Shape to be clipped to actual empty area
empty = GeneralPath()
empty.moveTo(0.5, 0.5) # Start slightly inset for clipping
empty.lineTo(0.5, 250) # Vertical left edge
empty.lineTo(50, 350) # Taper to the bottom-left flat edge
empty.lineTo(100, 350) # Flat bottom edge
empty.lineTo(150, 250) # Taper back up to the right
empty.lineTo(150, 0.5) # Vertical right edge
empty.closePath()
# Empty area based on fillPercent property
emptyPercent = 100 - event.source.fillPercent
emptyArea = Rectangle2D.Float(0, 0, 150, 350 * emptyPercent / 100)
#### Scale graphics to actual component size
dX = (event.width - 1) / 151.0
dY = (event.height - 1) / 351.0
g.scale(dX, dY)
# Set line thickness
stroke = BasicStroke(2)
g.setStroke(stroke)
# Paint filled area
g.setPaint(Color.WHITE)
g.fill(silo)
# Paint silo outline
g.setColor(Color.decode("#4C4C4C"))
g.draw(silo)
# Clip empty area to exclude filled area
g.setClip(emptyArea)
g.clip(empty)
# Set stroke again (ensures consistent line thickness)
g.setStroke(stroke)
# Paint empty area
g.setPaint(Color.decode("#C0C0C0"))
g.fill(empty)
# Draw outline for the empty area
g.setColor(Color.decode("#4C4C4C"))
g.draw(empty)