Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import (
)

func main() {
// Set FUNCTION_TARGET if not already set
if os.Getenv("FUNCTION_TARGET") == "" {
os.Setenv("FUNCTION_TARGET", "Progress")
}

// Use PORT environment variable, or default to 8080.
port := "8080"
if envPort := os.Getenv("PORT"); envPort != "" {
Expand Down
142 changes: 109 additions & 33 deletions progress.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ import (
"github.com/GoogleCloudPlatform/functions-framework-go/functions"
)

// Data ... is the collection of inputs we need to fill our template
type Data struct {
BackgroundColor string
Percentage int
Progress int
Percentage float64
Progress float64
PickedColor string
Label string
ShowLabel bool
BarWidth float64
}

var grey = "#555"
Expand All @@ -35,19 +37,20 @@ func fixDir() {
}
}

func pickColor(percentage int, successColor string, warningColor string, dangerColor string) string {
func pickColor(percentage float64, successColor, warningColor, dangerColor string) string {
pickedColor := green
if successColor != "" {
pickedColor = "#" + successColor
}

if percentage >= 0 && percentage < 33 {
switch {
case percentage >= 0 && percentage < 33:
if dangerColor != "" {
pickedColor = "#" + dangerColor
} else {
pickedColor = red
}
} else if percentage >= 33 && percentage < 70 {
case percentage >= 33 && percentage < 70:
if warningColor != "" {
pickedColor = "#" + warningColor
} else {
Expand All @@ -63,39 +66,112 @@ func init() {
functions.HTTP("Progress", Progress)
}

// Progress ... Entrypoint of our Cloud Function
func Progress(w http.ResponseWriter, r *http.Request) {
var id = fmt.Sprintf(path.Base(r.URL.Path))

if percentage, err := strconv.Atoi(id); err == nil {
// Template helper to check if a float is an integer
func isInt(f float64) bool {
return f == float64(int(f))
}

// Read (with the intention to overwrite) success, warning, and danger colors if provided
successColor := r.URL.Query().Get("successColor")
warningColor := r.URL.Query().Get("warningColor")
dangerColor := r.URL.Query().Get("dangerColor")
// Template helper for division
func div(a, b float64) float64 {
if b == 0 {
return 0
}
return a / b
}

data := Data{
BackgroundColor: grey,
Percentage: percentage,
Progress: percentage - (percentage / 10),
PickedColor: pickColor(percentage, successColor, warningColor, dangerColor),
}
func Progress(w http.ResponseWriter, r *http.Request) {
id := path.Base(r.URL.Path)

tpl, err := template.ParseFiles("progress.html")
value, err := strconv.ParseFloat(id, 64)
if err != nil {
http.Error(w, "Invalid value", http.StatusBadRequest)
return
}

if err != nil {
log.Fatalln(err)
successColor := r.URL.Query().Get("successColor")
warningColor := r.URL.Query().Get("warningColor")
dangerColor := r.URL.Query().Get("dangerColor")
barColor := r.URL.Query().Get("barColor")
customLabel := r.URL.Query().Get("label")
minStr := r.URL.Query().Get("min")
maxStr := r.URL.Query().Get("max")

// Determine if we're using custom label mode (data bar mode)
showLabel := customLabel != ""

// Calculate percentage and bar width
var percentage float64
var barWidth float64
const defaultWidth = 90.0

if showLabel && minStr != "" && maxStr != "" {
// Data bar mode: scale proportionally based on min/max
min, errMin := strconv.ParseFloat(minStr, 64)
max, errMax := strconv.ParseFloat(maxStr, 64)

if errMin != nil || errMax != nil || min >= max {
http.Error(w, "Invalid min/max values", http.StatusBadRequest)
return
}

// Calculate percentage for color picking (0-100)
if max > min {
percentage = ((value - min) / (max - min)) * 100
} else {
percentage = 0
}

// Calculate bar width proportionally (leave some padding)
if max > min {
barWidth = ((value - min) / (max - min)) * (defaultWidth * 0.95)
} else {
barWidth = 0
}
} else {
// Original percentage mode
percentage = value
if percentage > 100 {
percentage = 100
}
barWidth = percentage - (percentage / 10)
}

buf := new(bytes.Buffer)
// Determine bar color
var pickedColor string
if barColor != "" {
// Use custom bar color if provided (for data bars)
pickedColor = "#" + barColor
} else {
// Use percentage-based color logic
pickedColor = pickColor(percentage, successColor, warningColor, dangerColor)
}

err = tpl.Execute(buf, data)
if err != nil {
log.Fatalln(err)
}
data := Data{
BackgroundColor: grey,
Percentage: percentage,
Progress: barWidth,
BarWidth: defaultWidth,
PickedColor: pickedColor,
Label: customLabel,
ShowLabel: showLabel,
}

fmt.Printf("The percentage is: %d\n", percentage)
w.Header().Add("Content-Type", "image/svg+xml")
fmt.Fprintf(w, buf.String())
// Parse template with custom functions
tpl := template.New("progress.html").Funcs(template.FuncMap{
"isInt": isInt,
"div": div,
})
tpl, err = tpl.ParseFiles("progress.html")
if err != nil {
log.Fatalln("Error parsing template:", err)
}
}

buf := new(bytes.Buffer)
if err := tpl.Execute(buf, data); err != nil {
log.Fatalln("Error executing template:", err)
}

fmt.Printf("The percentage is: %v\n", percentage)
w.Header().Set("Content-Type", "image/svg+xml")
_, _ = w.Write(buf.Bytes())
}
22 changes: 15 additions & 7 deletions progress.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
<svg width="90.0" height="20" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="a" x2="0" y2="100%%">
<svg width="{{.BarWidth}}" height="20" xmlns="http://www.w3.org/2000/svg">
<linearGradient id="a" x2="0" y2="100%">
<stop offset="0" stop-color="#bbb" stop-opacity=".2"/>
<stop offset="1" stop-opacity=".1"/>
</linearGradient>
<rect rx="4" x="0" width="90.0" height="20" fill="{{.BackgroundColor}}"/>
<rect rx="4" x="0" width="{{.BarWidth}}" height="20" fill="{{.BackgroundColor}}"/>
<rect rx="4" x="0" width="{{.Progress}}" height="20" fill="{{.PickedColor}}"/>
<rect rx="4" width="90.0" height="20" fill="url(#a)"/>
<rect rx="4" width="{{.BarWidth}}" height="20" fill="url(#a)"/>
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
<text x="45.0" y="14">
{{.Percentage}}%%
<text x="{{div .BarWidth 2}}" y="14">
{{if .ShowLabel}}
{{.Label}}
{{else}}
{{if isInt .Percentage}}
{{printf "%.0f%%" .Percentage}}
{{else}}
{{printf "%.2f%%" .Percentage}}
{{end}}
{{end}}
</text>
</g>
</svg>
</svg>