Custom progress bars for FileMaker

At the Spanish developer conference an attendee asked me about whether we have something to show a nice colored progress bar in a portal, preferable possible for Web Direct, too.

After a bit of research, I found an easy way to do this with MBS FileMaker Plugin and without using web viewers and JavaScript. We simply use GraphicsMagick functions to generate a nice picture on demand and show it as a container field. This can either be a script to generate the picture on the fly using a trigger. Or it can be a calculated field to generate it when needed. In both cases you can trigger the recreation of the image by changing a field with the percent value.

First let us show you the sample script. It creates a 300x30 Pixel big image with white background. Then we take the color from a field and if the color is "auto", we calculate the color based on a formula based on the percent value. Once we got a color, we draw a 20 pixel wide line with round caps with the background color. That background color for the bar is dynamically calculated to be lighter than the actual bar color. After the background bar line we draw the normal color bar on top. And save it to the container field, so FileMaker shows it. Don't forget to free the image on the end and avoid the memory get filled with images.

# Creates an image, sets settings for the line, paints it with a special size in the environment and writes the image into the container 
# 
# create environment
Set Variable [ $img ; Value: MBS( "GMImage.New"; "300x30"; "RGB 1 1 1") ]
Set Variable [ $color ; Value: PortalRecords::Color ]
# 
If [ $color = "auto" ]
	# color based on percent
	Set Variable [ $red ; Value: 65535 * (1 - PortalRecords::Percent / 100) ]
	Set Variable [ $green ; Value: 0 ]
	Set Variable [ $blue ; Value: 65535 * PortalRecords::Percent / 100 ]
	Set Variable [ $color ; Value: "COLOR " & Round ( $red; 0 ) & " " & Round ( $green; 0 ) & " " & Round ( $blue; 0 ) ]
End If
# 
# Define the settings for the line
Set Variable [ $r ; Value: MBS("GMImage.SetStrokeColor"; $img; $color) ]
Set Variable [ $actualColor ; Value: MBS("GMImage.GetStrokeColor"; $img) // this will give COLOR, even if color was set with RGB or name ]
Set Variable [ $actualColorRed ; Value: GetAsNumber(MiddleWords ( $actualColor ; 2 ; 1 )) ]
Set Variable [ $actualColorGreen ; Value: GetAsNumber(MiddleWords ( $actualColor ; 3 ; 1 )) ]
Set Variable [ $actualColorBlue ; Value: GetAsNumber(MiddleWords ( $actualColor ; 4 ; 1 )) ]
Set Variable [ $r ; Value: MBS( "GMImage.SetStrokeColor"; $img; "COLOR " & Round($actualColorRed/2 + 32767;0) & " " & Round($actualColorGreen/2 + 32767;0) & " " & Round($actualColorBlue/2 + 32767;0)) ]
Set Variable [ $r ; Value: MBS( "GMImage.SetLineWidth"; $img; 20) ]
Set Variable [ $r ; Value: MBS( "GMImage.SetStrokeLineCap"; $img; 2 ) // round cap ]
# draw the background
Set Variable [ $r ; Value: MBS( "GMImage.DrawLine"; $img; 15; 15; 300-15; 15) ]
# setup foreground
Set Variable [ $r ; Value: MBS( "GMImage.SetStrokeColor"; $img; $actualColor) ]
Set Variable [ $r ; Value: MBS( "GMImage.SetLineWidth"; $img; 20) ]
Set Variable [ $r ; Value: MBS( "GMImage.SetStrokeLineCap"; $img; 2 ) // round cap ]
# draw the smaller part
Set Variable [ $r ; Value: MBS( "GMImage.DrawLine"; $img; 15; 15; 15 + (300-30) * PortalRecords::Percent/100 ; 15) ]
# write image to container
Set Variable [ $png ; Value: MBS( "GMImage.WriteToPNGContainer"; $img; "bar.png") ]
# Release environment
Set Variable [ $r ; Value: MBS("GMImage.Free"; $img) ]
Set Field [ PortalRecords::Bar Script ; $png ]

The script can be triggered with a field change or whenever you need the progress bar to update. This could also be done with Perform Script on Server from FileMaker Go. Or in Web Direct, where you may like to update the record. Especially if you use Perform Script on Server to do this in background on demand and pass layout and record ID to do the image creation without user waiting for it.

We translated this script line by line into a calculation using Let statements to group multiple commands together. Technically the same, but all variables are local ones without dollar.

Let([
img = MBS( "GMImage.New"; "300x30"; "RGB 1 1 1");
color = PortalRecords::Color;
 
color = If(color = "auto"; 
	Let([
		// color based on percent
		red = 65535 * (1 - PortalRecords::Percent / 100);
		green = 0;
		blue = 65535 * PortalRecords::Percent / 100;
		color = "COLOR " & Round ( red; 0 ) & " " & Round ( green; 0 ) & " " & Round ( blue; 0 ) 
	]; color); color);
 
// Define the settings for the line
r = MBS("GMImage.SetStrokeColor"; img; color); 
actualColor = MBS("GMImage.GetStrokeColor"; img);
// this will give COLOR, even if color was set with RGB or name 
actualColorRed   = GetAsNumber(MiddleWords ( actualColor ; 2 ; 1 ));
actualColorGreen = GetAsNumber(MiddleWords ( actualColor ; 3 ; 1 ));
actualColorBlue  = GetAsNumber(MiddleWords ( actualColor ; 4 ; 1 ));
r = MBS( "GMImage.SetStrokeColor"; img; "COLOR " & Round(actualColorRed/2 + 32767;0) & " " & Round(actualColorGreen/2 + 32767;0) & " " & Round(actualColorBlue/2 + 32767;0));
r = MBS( "GMImage.SetLineWidth"; img; 20);
r = MBS( "GMImage.SetStrokeLineCap"; img; 2 ); // round cap 
// draw the background
r = MBS( "GMImage.DrawLine"; img; 15; 15; 300-15; 15);
// setup foreground
r = MBS( "GMImage.SetStrokeColor"; img; actualColor);
r = MBS( "GMImage.SetLineWidth"; img; 20);
r = MBS( "GMImage.SetStrokeLineCap"; img; 2 ); // round cap 
// draw the smaller part
r = MBS( "GMImage.DrawLine"; img; 15; 15; 15 + (300-30) * PortalRecords::Percent/100 ; 15); 
// write image to container
bar = MBS( "GMImage.WriteToPNGContainer"; img; "bar.png");
r = MBS("GMImage.Free"; img)
]; bar)

Please try the example file included with 14.2 plugin (now in beta) and play with it. Maybe you can use it in one of your solutions? Let us know if you have questions.