PathrockNetwork Gno Explorer
HomeBlocksTransactionsRealmsPackagesValidatorsAnalytics

PathrockNetwork Gno Explorer — an independent explorer for Gno.land Mainnet (gnoland-1), operated by PathrockNetwork. Not an official Gno.land service.

gnowebarchive RPC

gno.land/p/moul/x/daily/sparkline/v0

Package
Open in gnoweb ↗

Overview

Kind
Pure package
Name
v0
Namespace
moul / x / daily / sparkline
Files
3 (README)(gnomod.toml)
Exported functions
n/a — not supported for pure packages by the node (vm/qfuncs)
Module
gno.land/p/moul/x/daily/sparkline/v0
gno
0.9

Files (3)

  • README.mdmarkdown
  • gnomod.tomltoml
  • sparkline.gnogno
sparkline.gnogno
1// Package sparkline renders a numeric series as one line of Unicode block2// characters — ▁▂▃▄▅▆▇█ — so a realm's Render can show a trend inline, with no3// image, no chart library and no client-side code.4//5// Everything is integer math, deliberately. A realm's Render must produce6// byte-identical output on every validating node, and floating point is the7// usual way that quietly stops being true. Scaling here is integer division8// with the rounding rule stated below, so a given series always yields exactly9// the same runes.10//11// Rendering is O(len(values)) and allocates one builder; a realm should bound12// what it feeds in (slice to a window) rather than sparking an unbounded,13// user-grown slice.14//15// A live demo of this package is at16// [r/moul/x/daily/sparklinedemo](/r/moul/x/daily/sparklinedemo/v0).17package sparkline1819import "strings"2021// Levels is the ramp, lowest to highest. A string constant rather than a22// []rune so callers cannot mutate the ramp out from under other realms.23const Levels = "▁▂▃▄▅▆▇█"2425// Steps is how many levels the ramp has.26const Steps = 82728// maxInt is the largest int, used to keep the scaling multiply from wrapping.29const maxInt = int(^uint(0) >> 1)3031// Ints renders values scaled between their own smallest and largest element.32// An empty series renders as the empty string.33func Ints(values []int) string {34	lo, hi, ok := Bounds(values)35	if !ok {36		return ""37	}38	return Scaled(values, lo, hi)39}4041// Scaled renders values against an explicit [lo, hi] window. Values outside it42// clamp to the ends rather than erroring: a window is chosen for readability43// (0..100 for a percentage, say), and one outlier should not be able to break a44// realm's Render.45//46// A window with hi <= lo is treated as flat; see Level.47func Scaled(values []int, lo, hi int) string {48	if len(values) == 0 {49		return ""50	}51	ramp := []rune(Levels)52	var b strings.Builder53	for _, v := range values {54		b.WriteRune(ramp[Level(v, lo, hi)])55	}56	return b.String()57}5859// Level maps v within [lo, hi] to a ramp index in [0, Steps-1].60//61// Rounding is floor, so only a value at hi itself reaches the top of the ramp;62// everything below it rounds down. That makes the maximum visually distinct,63// which is what a reader is looking for in a sparkline.64//65// A flat window (hi <= lo) maps everything to the MIDDLE of the ramp, not the66// bottom: a series that sits unchanged at 1000 carries no shape, but drawing it67// along the floor would read as "zero", which is a different and wrong claim.68func Level(v, lo, hi int) int {69	if hi <= lo {70		return Steps / 271	}72	if v <= lo {73		return 074	}75	if v >= hi {76		return Steps - 177	}7879	span, d, top := hi-lo, v-lo, Steps-180	if span <= 0 {81		// hi-lo wrapped: the window is wider than an int can express, so there82		// is no usable ramp. Split at the midpoint, computed without overflowing.83		if v < lo/2+hi/2 {84			return 085		}86		return Steps - 187	}88	// d*top would wrap on an extreme span; halve both until it cannot. The89	// chosen bucket is unchanged for any realistic series, and off by at most90	// one level for the pathological ones this protects against.91	for span > maxInt/top {92		span >>= 193		d >>= 194	}95	return d * top / span96}9798// Bounds returns the smallest and largest value in values. ok is false when99// values is empty, in which case lo and hi are zero.100func Bounds(values []int) (lo, hi int, ok bool) {101	if len(values) == 0 {102		return 0, 0, false103	}104	lo, hi = values[0], values[0]105	for _, v := range values[1:] {106		if v < lo {107			lo = v108		}109		if v > hi {110			hi = v111		}112	}113	return lo, hi, true114}115

Functions

not supported for pure packages by the node (vm/qfuncs)

Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.