codeberg.org/go-pdf/fpdf@v0.11.1/label.go (about)

     1  // Copyright ©2023 The go-pdf Authors. All rights reserved.
     2  // Use of this source code is governed by a MIT-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fpdf
     6  
     7  // Adapted from Nice Numbers for Graph Labels by Paul Heckbert from "Graphics
     8  // Gems", Academic Press, 1990
     9  
    10  // Paul Heckbert	2 Dec 88
    11  
    12  // https://github.com/erich666/GraphicsGems
    13  
    14  // LICENSE
    15  
    16  // This code repository predates the concept of Open Source, and predates most
    17  // licenses along such lines. As such, the official license truly is:
    18  
    19  // EULA: The Graphics Gems code is copyright-protected. In other words, you
    20  // cannot claim the text of the code as your own and resell it. Using the code
    21  // is permitted in any program, product, or library, non-commercial or
    22  // commercial. Giving credit is not required, though is a nice gesture. The
    23  // code comes as-is, and if there are any flaws or problems with any Gems code,
    24  // nobody involved with Gems - authors, editors, publishers, or webmasters -
    25  // are to be held responsible. Basically, don't be a jerk, and remember that
    26  // anything free comes with no guarantee.
    27  
    28  import (
    29  	"math"
    30  )
    31  
    32  // niceNum returns a "nice" number approximately equal to x. The number is
    33  // rounded if round is true, converted to its ceiling otherwise.
    34  func niceNum(val float64, round bool) float64 {
    35  	var nf float64
    36  
    37  	exp := int(math.Floor(math.Log10(val)))
    38  	f := val / math.Pow10(exp)
    39  	if round {
    40  		switch {
    41  		case f < 1.5:
    42  			nf = 1
    43  		case f < 3.0:
    44  			nf = 2
    45  		case f < 7.0:
    46  			nf = 5
    47  		default:
    48  			nf = 10
    49  		}
    50  	} else {
    51  		switch {
    52  		case f <= 1:
    53  			nf = 1
    54  		case f <= 2.0:
    55  			nf = 2
    56  		case f <= 5.0:
    57  			nf = 5
    58  		default:
    59  			nf = 10
    60  		}
    61  	}
    62  	return nf * math.Pow10(exp)
    63  }
    64  
    65  // TickmarkPrecision returns an appropriate precision value for label
    66  // formatting.
    67  func TickmarkPrecision(div float64) int {
    68  	return int(math.Max(-math.Floor(math.Log10(div)), 0))
    69  }
    70  
    71  // Tickmarks returns a slice of tickmarks appropriate for a chart axis and an
    72  // appropriate precision for formatting purposes. The values min and max will
    73  // be contained within the tickmark range.
    74  func Tickmarks(min, max float64) (list []float64, precision int) {
    75  	if max > min {
    76  		spread := niceNum(max-min, false)
    77  		d := niceNum((spread / 4), true)
    78  		graphMin := math.Floor(min/d) * d
    79  		graphMax := math.Ceil(max/d) * d
    80  		precision = TickmarkPrecision(d)
    81  		for x := graphMin; x < graphMax+0.5*d; x += d {
    82  			list = append(list, x)
    83  		}
    84  	}
    85  	return
    86  }