-
-
Notifications
You must be signed in to change notification settings - Fork 226
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/johnfercher/maroto/v2" | ||
"github.com/johnfercher/maroto/v2/pkg/components/chart" | ||
"github.com/johnfercher/maroto/v2/pkg/components/text" | ||
"github.com/johnfercher/maroto/v2/pkg/config" | ||
"github.com/johnfercher/maroto/v2/pkg/props" | ||
"log" | ||
) | ||
|
||
func main() { | ||
cfg := config.NewBuilder(). | ||
WithPageNumber(). | ||
WithDebug(true). | ||
Build() | ||
|
||
mrt := maroto.New(cfg) | ||
m := maroto.NewMetricsDecorator(mrt) | ||
|
||
xMax := 620 | ||
yMax := 200 | ||
max := 620 + 200 | ||
heat := buildHeat(xMax, yMax, max) | ||
|
||
m.AddRows(text.NewRow(10, "HeatMap")) | ||
m.AddRows(chart.NewHeatMapRow(100, "map", heat, props.HeatMap{ | ||
TransparentValues: []int{0}, | ||
InvertScale: true, | ||
})) | ||
|
||
/*m.AddRow(100, | ||
chart.NewHeatMapCol(6, "map", heat, props.HeatMap{ | ||
TransparentValues: []int{0}, | ||
Chart: &props.Chart{ | ||
Axis: true, | ||
}, | ||
}), | ||
chart.NewHeatMapCol(6, "map", heat, props.HeatMap{ | ||
TransparentValues: []int{0}, | ||
Chart: &props.Chart{ | ||
Axis: true, | ||
}, | ||
}), | ||
)*/ | ||
|
||
document, err := m.Generate() | ||
if err != nil { | ||
log.Fatal(err.Error()) | ||
} | ||
|
||
err = document.Save("docs/assets/pdf/heatmap.pdf") | ||
if err != nil { | ||
log.Fatal(err.Error()) | ||
} | ||
|
||
err = document.GetReport().Save("docs/assets/text/heatmap.txt") | ||
if err != nil { | ||
log.Fatal(err.Error()) | ||
} | ||
} | ||
|
||
func buildHeat(x, y, max int) [][]int { | ||
var heat [][]int | ||
for i := 0; i < x; i++ { | ||
var line []int | ||
for j := 0; j < y; j++ { | ||
line = append(line, i+j) | ||
} | ||
heat = append(heat, line) | ||
} | ||
return heat | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
generate -> avg: 120.35ms, executions: [120.35ms] | ||
add_rows -> avg: 6520.50ns, executions: [12.88μs, 0.17μs] | ||
file_size -> 6.41Mb |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
generate -> avg: 18.06ms, executions: [18.06ms] | ||
header -> avg: 356.00ns, executions: [356.00ns] | ||
footer -> avg: 71.00ns, executions: [71.00ns] | ||
add_row -> avg: 112.55ns, executions: [0.11μs, 0.15μs, 0.05μs, 0.08μs, 0.02μs, 0.02μs, 0.53μs, 0.06μs, 0.02μs, 0.07μs, 0.02μs, 0.02μs, 0.02μs, 0.06μs, 0.02μs, 0.02μs, 0.03μs, 1.41μs, 0.06μs, 0.02μs, 0.06μs, 0.02μs, 0.02μs, 0.01μs, 0.07μs, 0.02μs, 0.02μs, 0.03μs, 0.29μs, 1.74μs, 0.02μs, 0.07μs, 0.02μs, 0.02μs, 0.02μs, 0.06μs, 0.02μs, 0.02μs, 0.02μs, 0.24μs, 0.05μs, 0.02μs, 0.07μs, 0.02μs, 0.01μs, 0.02μs, 0.06μs, 0.03μs, 0.01μs, 0.01μs, 0.24μs, 0.05μs, 0.01μs, 0.05μs, 0.02μs] | ||
file_size -> 267.93Kb | ||
generate -> avg: 26.67ms, executions: [26.67ms] | ||
header -> avg: 21.00μs, executions: [21.00μs] | ||
footer -> avg: 333.00ns, executions: [333.00ns] | ||
add_rows -> avg: 157.56ns, executions: [0.29μs, 0.50μs, 0.29μs, 0.50μs, 0.08μs, 0.12μs, 1.21μs, 0.17μs, 0.04μs, 0.08μs, 0.04μs, 0.04μs, 0.04μs, 0.21μs, 0.04μs, 0.04μs, 0.04μs, 0.67μs, 0.17μs, 0.04μs, 0.12μs, 0.04μs, 0.04μs, 0.04μs, 0.17μs, 0.04μs, 0.04μs, 0.04μs, 0.50μs, 0.12μs, 0.04μs, 0.12μs, 0.04μs, 0.21μs, 0.04μs, 0.12μs, 0.04μs, 0.04μs, 0.08μs, 0.50μs, 0.17μs, 0.04μs, 0.08μs, 0.04μs, 0.04μs, 0.04μs, 0.33μs, 0.04μs, 0.04μs, 0.04μs, 0.46μs, 0.08μs, 0.04μs, 0.12μs, 0.04μs] | ||
file_size -> 282.23Kb |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package gofpdf | ||
|
||
import ( | ||
"github.com/johnfercher/maroto/v2/internal/providers/gofpdf/gofpdfwrapper" | ||
"github.com/johnfercher/maroto/v2/pkg/consts/linestyle" | ||
"github.com/johnfercher/maroto/v2/pkg/consts/orientation" | ||
"github.com/johnfercher/maroto/v2/pkg/core" | ||
"github.com/johnfercher/maroto/v2/pkg/core/entity" | ||
"github.com/johnfercher/maroto/v2/pkg/props" | ||
) | ||
|
||
type chart struct { | ||
pdf gofpdfwrapper.Fpdf | ||
line core.Line | ||
text core.Text | ||
} | ||
|
||
func NewChart(pdf gofpdfwrapper.Fpdf, line core.Line, text core.Text) *chart { | ||
return &chart{ | ||
pdf: pdf, | ||
line: line, | ||
text: text, | ||
} | ||
} | ||
|
||
func (c *chart) Add(cell *entity.Cell, margins *entity.Margins, prop *props.Chart) { | ||
// X | ||
c.line.Add(cell, &props.Line{ | ||
Orientation: orientation.Horizontal, | ||
SizePercent: 88, | ||
OffsetPercent: 94, | ||
Style: linestyle.Solid, | ||
Thickness: 0.5, | ||
}) | ||
|
||
// Y | ||
c.line.Add(cell, &props.Line{ | ||
Orientation: orientation.Vertical, | ||
SizePercent: 88, | ||
OffsetPercent: 6, | ||
Style: linestyle.Solid, | ||
Thickness: 0.5, | ||
}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
package gofpdf | ||
|
||
import ( | ||
"errors" | ||
"math" | ||
|
||
"github.com/johnfercher/maroto/v2/pkg/props" | ||
|
||
"github.com/johnfercher/maroto/v2/internal/providers/gofpdf/gofpdfwrapper" | ||
"github.com/johnfercher/maroto/v2/pkg/core" | ||
"github.com/johnfercher/maroto/v2/pkg/core/entity" | ||
) | ||
|
||
var ErrOutOfRange = errors.New("out of range") | ||
|
||
type heatMap struct { | ||
pdf gofpdfwrapper.Fpdf | ||
defaultFillColor *props.Color | ||
chart core.Chart | ||
padding float64 | ||
} | ||
|
||
func NewHeatMap(pdf gofpdfwrapper.Fpdf, chart core.Chart) *heatMap { | ||
return &heatMap{ | ||
pdf: pdf, | ||
chart: chart, | ||
defaultFillColor: &props.WhiteColor, | ||
padding: 0, | ||
} | ||
} | ||
|
||
func (s heatMap) Add(heatMap [][]int, cell *entity.Cell, margins *entity.Margins, prop *props.HeatMap) { | ||
if heatMap == nil || len(heatMap) == 0 || len(heatMap[0]) == 0 { | ||
Check failure on line 33 in internal/providers/gofpdf/heatmap.go
|
||
return | ||
} | ||
|
||
max := s.getMax(heatMap) | ||
transparent := s.getTransparent(prop) | ||
stepX, stepY := s.getSteps(heatMap, cell, prop) | ||
|
||
for i := 0; i < len(heatMap)-1; i++ { | ||
for j := 0; j < len(heatMap[i])-1; j++ { | ||
if !transparent[heatMap[i][j]] { | ||
r, g, b := s.GetHeatColor(heatMap[i][j], max, prop.InvertScale, prop.HalfColor) | ||
|
||
x := float64(i)*stepX + cell.X + margins.Left | ||
y := float64(j) * stepY | ||
|
||
// Invert to draw from bottom to up | ||
y = cell.Height + margins.Top + cell.Y - y - stepY | ||
|
||
s.pdf.SetFillColor(r, g, b) | ||
s.pdf.Rect(x, y, stepX, stepY, "F") | ||
s.pdf.SetFillColor(s.defaultFillColor.Red, s.defaultFillColor.Green, s.defaultFillColor.Blue) | ||
} | ||
} | ||
} | ||
|
||
if prop.Chart != nil { | ||
s.chart.Add(cell, margins, prop.Chart) | ||
} | ||
} | ||
|
||
func (s heatMap) getSteps(heatMap [][]int, cell *entity.Cell, prop *props.HeatMap) (float64, float64) { | ||
Check failure on line 64 in internal/providers/gofpdf/heatmap.go
|
||
xSize := len(heatMap) | ||
stepX := (cell.Width) / float64(xSize-1) | ||
|
||
ySize := len(heatMap[0]) | ||
stepY := (cell.Height) / float64(ySize-1) | ||
|
||
return stepX, stepY | ||
} | ||
|
||
func (s heatMap) GetHeatColor(i int, total int, invertScale bool, halfColor bool) (int, int, int) { | ||
hueMax := 360.0 | ||
if halfColor { | ||
hueMax /= 2.0 | ||
} | ||
|
||
offset := +60 | ||
if total+offset < 0 { | ||
total = 360 + offset | ||
} else { | ||
total = total + offset | ||
Check failure on line 84 in internal/providers/gofpdf/heatmap.go
|
||
} | ||
|
||
step := hueMax / float64(total) | ||
iStep := step * float64(i) | ||
|
||
if invertScale { | ||
iStep = 160 - iStep | ||
} | ||
|
||
r, g, b, _ := HSVToRGB(iStep, 1.0, 1.0) | ||
return int(r), int(g), int(b) | ||
} | ||
|
||
func (s heatMap) getMax(matrix [][]int) int { | ||
var max = 0 | ||
Check failure on line 99 in internal/providers/gofpdf/heatmap.go
|
||
for _, row := range matrix { | ||
for _, cell := range row { | ||
if cell > max { | ||
max = cell | ||
} | ||
} | ||
} | ||
|
||
return max | ||
} | ||
|
||
func (s heatMap) getTransparent(p *props.HeatMap) map[int]bool { | ||
m := make(map[int]bool) | ||
for _, t := range p.TransparentValues { | ||
m[t] = true | ||
} | ||
return m | ||
} | ||
|
||
// HSVToRGB converts an HSV triple to an RGB triple. | ||
// Source: https://github.com/Crazy3lf/colorconv/blob/master/colorconv.go | ||
func HSVToRGB(h, s, v float64) (r, g, b uint8, err error) { | ||
if h < 0 || h >= 360 || | ||
s < 0 || s > 1 || | ||
v < 0 || v > 1 { | ||
return 0, 0, 0, ErrOutOfRange | ||
} | ||
// When 0 ≤ h < 360, 0 ≤ s ≤ 1 and 0 ≤ v ≤ 1: | ||
C := v * s | ||
X := C * (1 - math.Abs(math.Mod(h/60, 2)-1)) | ||
m := v - C | ||
var Rnot, Gnot, Bnot float64 | ||
switch { | ||
case 0 <= h && h < 60: | ||
Rnot, Gnot, Bnot = C, X, 0 | ||
case 60 <= h && h < 120: | ||
Rnot, Gnot, Bnot = X, C, 0 | ||
case 120 <= h && h < 180: | ||
Rnot, Gnot, Bnot = 0, C, X | ||
case 180 <= h && h < 240: | ||
Rnot, Gnot, Bnot = 0, X, C | ||
case 240 <= h && h < 300: | ||
Rnot, Gnot, Bnot = X, 0, C | ||
case 300 <= h && h < 360: | ||
Rnot, Gnot, Bnot = C, 0, X | ||
} | ||
r = uint8(math.Round((Rnot + m) * 255)) | ||
g = uint8(math.Round((Gnot + m) * 255)) | ||
b = uint8(math.Round((Bnot + m) * 255)) | ||
return r, g, b, nil | ||
} |