Eine Beschreibung der Funktionen findet man vorerst nur im Quelltext Modul:Benutzer:Gadacz/Coltab


--[[ Coltab Version 2a BETA, 2020-05-17
	müsste  noch gründlich "geputzt"  und optimiert werden. Wegen eines 
	laufenden Löschantrags wird die Entwicklung der deutschen Version abgebrochen!
	Ggf. werden irgendwann die Ergänzungen der anderssprachigen Versionen übernommen.
--]]

--[[ siehe https://github.com/telegnom/esp_tools/blob/master/hsv2rgb.lua   func hsv2rgb
  * Konvertiert einen HSV-Farbwert in RGB. Umrechnungsformel angepasst von https://de.wikipedia.org/wiki/HSV-Farbraum
  * Angenommen, h, s und v sind in der Menge [0, 1] und enthalten
  * gibt r, g und b [jeweils 0, 255] hexadezimal zurück
  * @param Nummer Farbwert h 0 - 359° (hue)
  * @param Nummer Sättigung s 0-100 % (saturation)
  * @param Nummer Helligkeit  v oder l (luminance) 0-100 %
  * @return Array: RGB-Darstellung hexadezimal, optional Hintergrund, wenn zu dunkel für Schrift
  * Assumes h, s, and v are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
-- ]]

local p = {} -- Übergabearray
local r2g = 120 -- das entspricht rot (0) zu grün (120) siehe  [[HSV-Farbraum]]
local b2r = 360-- das entspricht blau (240) zu rot (360)
local tblmax = r2g -- Vorgabe hsv-Höchstwert
local gb = 'G' -- Grünskala oder 'b'lau -> rot

local function tu(a,z) -- wandelt in Versalien und extrahiert erstes Zeichen oder Zeichenanzahl z
	return string.sub(string.upper(a), 1, z or 1)
end

--[=[ function tonum separiert einen Zahlenanteil aus einem String wie
    'ca. 55,4 °C', 'Temperatur 44.9', '123,7', '≈99%' usw.
    Punkt und Komma werden generell als (Dezimal-)Punkt ausgewertet; 
    beliebige Tausendertrenner erlaubt, der Letzte (Komma oder Punkt) ist der Dezimaltrenner
    gibt es nur Tausendertrenner, muß hinten ein Punkt oder komma stehen
    Negative Werte werden vorzeichenlos übergeben
    Rückgabe: Der Zahlenwert (erg) und er Eingabestring (ein)
  --]=]
local function tonum(ein)
	local erg, stat = '',0
	erg, stat = string.gsub(ein, "(%D*)([%s%-%d,%.%']+)(%D*)", "%1|%2|%3") 
	if stat > 0 then
		nix, erg ,nix = string.match(erg, "(.*)|(.*)|(.*)")
		erg=string.gsub(string.reverse(erg), "[%.,]+", "QIX",1)
		erg=string.gsub(erg, "[%.,%s%']+", "")
		erg=string.reverse(string.gsub(erg, "QIX", "."))*1
	end -- if stat
	return erg, ein
end

function tu(a,z) -- wandelt in Versalien und extrahiert erstes Zeichen oder Anzahl z
	return string.sub(string.upper(a), 1, z or 1)
end

local function emph(was) -- Emphasis, Schriftauszeichnung für den Text gem. Vorlagen-Parameter 'd= ...' (Dekoration)
	local css = ''
	-- if not was or #was < 1 then return 'NIX' end -- undekorierte Rückgabe
    if #was <= 6 then -- was größer ist, wird eine direkt eingegebene css-Anweisung sein
        was = tu(was,6)
        for e in string.gmatch(was, ".") do -- teilen falls mehrere Parameter
            if e == 'F' or e == 'B' then css = css .. " font-weight:bold;"
              elseif e == 'K' or e == 'I' then css = css .. " font-style:italic;"
              elseif e == 'U' then css = css .. " text-decoration:underline;"
              elseif e == 'V' then css = css .. " text-transform:uppercase;"
              elseif e == 'C' then css = css .. " font-variant:small-caps;"
              elseif e == 'G' then css = css .. " letter-spacing:0.3em;"
            end -- if e
        end -- for e
      else -- if #was
        was = string.gsub(was,"['%\"]+",'')  -- evtl. Anführungszeichen rasieren
        css = string.gsub(was,"[%w]+%s*=%s*",'') -- falls versehentlich mit 'string=' eingeleitet wurde
    end  -- if #was
   return css
end


--[[ function hsv2rgb
		übernimmt hsv Werte und wandelt sie in rgb (hex) um.
		Sofern der Hintergrund zu dunkel ist: 
			Schrift weiß ('color:#ffffff;') als 2. Rückgabewert
--]]
local function hsv2rgb(h,s,v)
	h = tonumber(h)
  -- Lokale
    local k, c = 'color:#ffffff;', '' -- Schrift weiß, falls Hintergrund zu dunkel
    local wert = h -- vorerst  nur Kontrolle 
    local iR, iG, iB, r, g, b, diff
     -- Position im Farbkreis (hue)
    if h < 61                       then r = 255;                             g = (425 * h) / 100;  b = 0
        elseif  h >= 61 and h < 121 then r = 255 - ((425 * (h - 60)) / 100);  g = 255;              b = 0
        elseif h >= 121 and h < 181 then r = 0;                               g = 255;              b = (425 * (h-120)) / 100
        elseif h >= 181 and h < 241 then r = 0;                               g = 255 - ((425 * (h-180))/100);  b = 255
        elseif h >= 241 and h < 301 then r = (425 * (h-240))/100;             g = 0;                b = 255
        elseif h >= 301 and h < 360 then r = 255;                             g = 0;                b = 255 - ((425 * (h-300))/100)
    end
  -- Farbsättigung
    s = 100 - s; diff = ((255 - r) * s) / 100
    r = r + diff; diff = ((255 - g) * s) / 100
    g = g + diff; diff = ((255 - b) * s) / 100
    b = b + diff
  -- Helligkeit
    r = (r * v) / 100;  g = (g * v) / 100;   b = (b * v) / 100
  -- Rückgabewerte runden
    iR= math.floor(r); iG= math.floor(g); iB= math.floor(b)
  -- Schriftfarbe festlegen bei dunklem Hintergrund
    if iG <=120  then c = k end
  -- Ausgabe
    --return string.format('#%02x%02x%02x', iR, iG, iB), c, string.format('rgb(%d,%d,%d)',iR, iG, iB)
    return string.format('#%02x%02x%02x', iR, iG, iB), c --, string.format('rgb(%d,%d,%d)',iR, iG, iB)
end

--[[ function val2hsv
	Setzt eine Zahl (val) <= max in einen größenabhängigen Farbwert um.
	Hier wird nur der Farbraum von grün nach rot (vv) verarbeitet
	Parameter max ist der Höchstwert des darzustellenden Werteraums. Der mUss in Relation stehen
	zum vorhandenen Werteraum, also 0 (rot) bis 120 (grün). Daraus ergibt sich ein Teiler (d) für den Wert
	bei max = 50; Teiler 120/max (120/50) = skal (3)
	bei max = 700; Teiler 120/max (tblmax) = skal (0.171428571)
	Ist der Farbwert > max, wird eine Fehlermeldung ausgegeben
	
	HIER muss drastisch eingegriffen werden, um die Logik einem Minimalwert anzupassen
	evtl. auch alternatibe Farbskala bearbeiten rot->>blau für Temperaturen
  --]]
local function val2hsvOLD(val, max, min)
	local r1,r2, erg, revert, tmpmax, diff
	val = tonumber(val)
	max, r1 = string.gsub(max,'#', ""); max = tonumber(max)
	min, r2 = string.gsub(min,'#', ""); min = tonumber(min)
	if max < min then -- Werte austauschen, da falsche Reihenfolge
		tmpmax = max; max = min; min = tmpmax
	end 
	diff= math.abs(max - min) -- 'Länge' der Skala
	revert = r1 + r2
	if val then
		--- local tblmax = 120 -- das entspricht grün
		-- Ist max negativ, ergibt das einen Farbverlauf von grün nach rot
		-- DAS MUSS anders geregelt werden, via # revert
		if  val >  math.abs(max) then return nil end -- Error größer als Tabelle
		erg = val * tblmax / max
		-- hier ggf auf '#' abfragen statt Negativwert
		--if max < 0 then erg = tblmax + erg end -- wird ersetzt durch ... revert
		if revert > 0 then erg = tblmax + erg end
	end
	return erg
end

local function val2hsv(val, max, min, gb)
	local r1, r2, erg, diff, err
	local revert, ergb = 0,0
	
	if val then
	    max, r1 = string.gsub(max,'#', "") -- falls '#' enthalten wird Farbskala umgekehrt
	    min, r2 = string.gsub(min,'#', "")
	    val = tonumber(val) -- vorsorglich
	    max = tonumber(max); min = tonumber(min)
	    if (max < min) then -- wurden versehentlich max/min vertauschr, korrigieren
			tmpmax = max
			max = min
			min = tmpmax
	    end -- if max<min
		diff = math.abs(max - min) -- 'Länge' der Skala
		revert = r1 + r2 -- falls '#' auftauchte, > 0
		-- nur sinnvol, wenn bei 'b' die Skala gedreht werden muss, sonst ausschaten
		if gb == 'B' then 
			ergb = b2r
				if revert ==  0 then revert = 1 
				else revert = 0
			end -- if revert
		end -- if gb==b
		if val then erg = val * tblmax / diff else val =  max + 1 end
		if  (val >  max) or (val < min) then -- Error: Wert außerhalb Skala
			err = 'Wert außerhalb der Skala'
			erg = nil
		else
			erg = math.abs(math.floor(erg+0.5))
		end -- end if val>max
		if revert > 0 then
			if erg then erg = tblmax - erg end
		end -- if revert
		if erg then erg = erg + ergb end -- falls 'b', hat ergb +240
    -- erg = erg + ergb
	else
		erg = nil
		err = 'kein berechenbarer Wert'
	end -- 	if val
	return erg, err
end  

--[=[function p.f(frame)
	* Übernahme der Werte und Parameter aus Artikel via Vorlage:Coltab als Array
	* Auswertung 
	* * Berechnung des Farbwertes via val2hsv und hsv2rgb
	* * Zusammensetzung des Feldinhalts in der Tabelle incl. Formatier- und Färbungsanweisengen.
	* Rückgabe des Ergebnisses ala Attay (Lua-Table)
	!! Anmerkung: Die Bezeichner für die Parameter werden auf den ersten Buchstaben reduziert.
		Klein-Großschreibung ist bedeutungslos, Bezeichner ist beliebig wählbar,
		sofern der 1. Buchstabe eindeutig ist
		Parameter:
		@param 1 oder named-key = 'V'alie  oder  'W'ert
			Zahlenwert. Er kann Zusätze wie Bezeichner °C  $  § ≈ ≠ ± ≤ ≥ ² ³ ½ ⚭ # ‰ € ¢ £ ¥ km³ usw. enthalten, 
			also jeder beliebige Wert, der durchgereicht und angezeigt, aber nie ausgewertet wird.
			Nur der numerische Wert ist für die Färbung entscheidend
		@param 2 oder 'M'ax
			Der Höchstwert der Skala. Alle Werte müssen niedriger sein,
			sonst stimmt der Farbverlauf nicht mehr bzw. Fehlermeldung
       Ist m negativ, geht die Farbskala von grün nach rot, sonst rot -> grün
		@param 'E'rgänzungen (beliebig), wie z.B. <ref ..., Links, Illustrationen
		@param 'S'ortierwert, wenn er vom Wert 1 (V,W) abweicht (generiert data-sort-value)
		@param 'O'rientierung sofern von der allg. Vorgabe der Tabelle abweichend
			O=L -> linksbündig
			O=R -> rechtsbündig
			O=Z oder O=C -> zentriert
			O=D Ausrichtung auf Dezimalkomma/-Punkt (ggf. Anzahl Nachkommastellen)
		@param 'A'ttribut:  Ergänzung zur Farbangabe außerhalb 'style=', wie
			colspan, rowspan, class. 
			data-sort-value wird via 'S', class="hintergrundfarbe .. bringt keinen Sinn
		@param 'K'ontrast, <100 wird blasser
--]=]
function p.f(frame)
	local numval, maximum, kontrast, hell , minimum = 0, 10, 25, 100, 0
	local stringval, orient, anhang, sort, erg , class, css, style = '', '', '', '', '', '','', ''
	local ft

	frame = frame:getParent() -- erst mal die übergebenen Parameter aufrufen
	for key, val in pairs(frame.args) do
			key = tu(key) -- hier Parameter auf einen Großbuchstaben verkürzen
		if key == "1" or key == 'V' or key == 'W' then numval, stringval = tonum(val) -- tonumber, aber Zeichen, wie ~#€$§ ... abfangen. ggf Kleinberechnung
	    elseif key == "2" or key == 'M' then maximum  = val --[[ höchster Wert der Skala
	    			MUSS GEÄNDERT WERDEN, wenn M < 0 erreichen könnte (Negativskala)
	    			ggf. extra Parameter oder Wert z.B 100- bzw. -100- 
	    			oder '#' als Kennzeichen (-100#)? Könnte dann auch bei 'N' stehen. --]]
	    elseif key == "3" or key == 'N' then minimum  = val --[[ niedrigster Wert der Skala
	    			der könnte deutlich über 0 liegen für Skalen die sinnvoll weit oben beginnen
	    			wir z.B. hPa (Mittel 1013,25 hPa), ggf Extremwerte 880 - 1100
	    			oder Temperaturskala -50°C bis +50 °C --]]
	    elseif key == 'E'  then anhang = val -- evtl SPACE falls nicht ref
	    elseif key == 'A' then class = val .. ' ' -- auch rowspan, colspan, ... alles was vor pipe steht
		elseif key == 'O' then val = tu(val)
			    if val == 'L' then orient = 'text-align:left; ' end
			    if val == 'R' then orient = 'text-align:right;' end
			    if val == 'C' or val == 'Z' then orient = 'text-align:center; ' end
		elseif key == 'S' then
			if val == '#' then val = numval end -- nur der Zahlenwert wird sortiert
			sort = ' data-sort-value="' .. val .. '" '
		elseif key == 'K' then if tonumber(val) ~= kontrast then kontrast = val end
		elseif key == 'D' then css =  css .. emph(val) 
	elseif key == 'B' then gb=tu(val) -- 'B' ergibt Rot-blau-Skala
		elseif key == 'T' then stringval = val -- Anzeigetext, aber numerische Farbbestimmung bleibt
		elseif key == 'I' then val = tu(val) -- inline
				if val == 'D' then ft = 'div' else ft = 'span' end
			end -- if key ...
	end -- for key, val in ..
  -- Aufruf der Berechnungen val2hsv hsv2rgb
	numval, err = val2hsv(numval, maximum, minimum, gb) -- Farbwert in Relation zur Skala ermitteln
	if numval then
		hexval, schriftfarbe = hsv2rgb(numval,kontrast,hell) -- Farbwert hsv zu rgb umrechnen
		-- jetzt Ausgabetring zusammenbasteln
		if ft then -- für Fließtext (param T)
			erg = '<' .. ft .. ' style="background:' .. hexval .. '; ' .. schriftfarbe .. css .. '">' .. stringval .. anhang ..'</' .. ft .. '>'
		else  -- für Tabellenfelder
			erg = 'style="background:' .. hexval .. '; ' .. schriftfarbe .. css .. orient .. '" ' .. sort .. class .. '|' .. stringval .. anhang
		end
    else erg = err -- Fehlermeldung fehlt noch class=error
    end
    return erg
end

return p