<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>http://steuerlein-reimbibel.de/index.php?action=history&amp;feed=atom&amp;title=Module%3Apiechart</id>
	<title>Module:piechart - Versionsgeschichte</title>
	<link rel="self" type="application/atom+xml" href="http://steuerlein-reimbibel.de/index.php?action=history&amp;feed=atom&amp;title=Module%3Apiechart"/>
	<link rel="alternate" type="text/html" href="http://steuerlein-reimbibel.de/index.php?title=Module:piechart&amp;action=history"/>
	<updated>2026-04-15T12:39:17Z</updated>
	<subtitle>Versionsgeschichte dieser Seite in Johann Steuerleins Reimbibel</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>http://steuerlein-reimbibel.de/index.php?title=Module:piechart&amp;diff=1084&amp;oldid=prev</id>
		<title>Walknud: Die Seite wurde neu angelegt: „local p = {} -- 	Smooth piechart module.  	Draws charts in HTML with an accessible legend (optional). 	A list of all features is in the &quot;TODO&quot; section of the main `p.pie` function.  	Use with a helper template that adds required CSS.  	{{{1}}}: 	[ 		{ &quot;label&quot;: &quot;pie: $v&quot;, &quot;color&quot;: &quot;wheat&quot;, &quot;value&quot;: 40 }, 		{ &quot;label&quot;: &quot;cheese pizza $v&quot;, &quot;color&quot;: &quot;#fc0&quot;, &quot;value&quot;: 20 }, 		{ &quot;label&quot;: &quot;mixed pizza: $v&quot;, &quot;color&quot;: &quot;#f60&quot;, &quot;value&quot;: 20 }, 		{ &quot;label&quot;: &quot;raw pizza…“</title>
		<link rel="alternate" type="text/html" href="http://steuerlein-reimbibel.de/index.php?title=Module:piechart&amp;diff=1084&amp;oldid=prev"/>
		<updated>2024-01-18T16:15:21Z</updated>

		<summary type="html">&lt;p&gt;Die Seite wurde neu angelegt: „local p = {} -- 	Smooth piechart module.  	Draws charts in HTML with an accessible legend (optional). 	A list of all features is in the &amp;quot;TODO&amp;quot; section of the main `p.pie` function.  	Use with a helper template that adds required CSS.  	{{{1}}}: 	[ 		{ &amp;quot;label&amp;quot;: &amp;quot;pie: $v&amp;quot;, &amp;quot;color&amp;quot;: &amp;quot;wheat&amp;quot;, &amp;quot;value&amp;quot;: 40 }, 		{ &amp;quot;label&amp;quot;: &amp;quot;cheese pizza $v&amp;quot;, &amp;quot;color&amp;quot;: &amp;quot;#fc0&amp;quot;, &amp;quot;value&amp;quot;: 20 }, 		{ &amp;quot;label&amp;quot;: &amp;quot;mixed pizza: $v&amp;quot;, &amp;quot;color&amp;quot;: &amp;quot;#f60&amp;quot;, &amp;quot;value&amp;quot;: 20 }, 		{ &amp;quot;label&amp;quot;: &amp;quot;raw pizza…“&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Neue Seite&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local p = {}&lt;br /&gt;
--[[&lt;br /&gt;
	Smooth piechart module.&lt;br /&gt;
&lt;br /&gt;
	Draws charts in HTML with an accessible legend (optional).&lt;br /&gt;
	A list of all features is in the &amp;quot;TODO&amp;quot; section of the main `p.pie` function.&lt;br /&gt;
&lt;br /&gt;
	Use with a helper template that adds required CSS.&lt;br /&gt;
&lt;br /&gt;
	{{{1}}}:&lt;br /&gt;
	[&lt;br /&gt;
		{ &amp;quot;label&amp;quot;: &amp;quot;pie: $v&amp;quot;, &amp;quot;color&amp;quot;: &amp;quot;wheat&amp;quot;, &amp;quot;value&amp;quot;: 40 },&lt;br /&gt;
		{ &amp;quot;label&amp;quot;: &amp;quot;cheese pizza $v&amp;quot;, &amp;quot;color&amp;quot;: &amp;quot;#fc0&amp;quot;, &amp;quot;value&amp;quot;: 20 },&lt;br /&gt;
		{ &amp;quot;label&amp;quot;: &amp;quot;mixed pizza: $v&amp;quot;, &amp;quot;color&amp;quot;: &amp;quot;#f60&amp;quot;, &amp;quot;value&amp;quot;: 20 },&lt;br /&gt;
		{ &amp;quot;label&amp;quot;: &amp;quot;raw pizza $v&amp;quot;, &amp;quot;color&amp;quot;: &amp;quot;#f30&amp;quot; }&lt;br /&gt;
	]&lt;br /&gt;
    Where $v is a formatted number (see `function prepareLabel`).&lt;br /&gt;
&lt;br /&gt;
	{{{meta}}}:&lt;br /&gt;
		{&amp;quot;size&amp;quot;:200, &amp;quot;autoscale&amp;quot;:false, &amp;quot;legend&amp;quot;:true}&lt;br /&gt;
	All meta options are optional (see `function p.setupOptions`).&lt;br /&gt;
]]&lt;br /&gt;
-- Author: [[User:Nux|Maciej Nux]] (pl.wikipedia.org).&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Debug:&lt;br /&gt;
	&lt;br /&gt;
	-- labels and auto-value&lt;br /&gt;
	local json_data = &amp;#039;[{&amp;quot;label&amp;quot;: &amp;quot;k: $v&amp;quot;, &amp;quot;value&amp;quot;: 33.1}, {&amp;quot;label&amp;quot;: &amp;quot;m: $v&amp;quot;, &amp;quot;value&amp;quot;: -1}]&amp;#039;&lt;br /&gt;
	local html = p.renderPie(json_data)&lt;br /&gt;
	mw.logObject(html)&lt;br /&gt;
	&lt;br /&gt;
	-- autoscale values&lt;br /&gt;
	local json_data = &amp;#039;[{&amp;quot;value&amp;quot;: 700}, {&amp;quot;value&amp;quot;: 300}]&amp;#039;&lt;br /&gt;
	local html = p.renderPie(json_data, options)&lt;br /&gt;
	mw.logObject(html)	&lt;br /&gt;
	&lt;br /&gt;
	-- size option&lt;br /&gt;
	local json_data = &amp;#039;[{&amp;quot;label&amp;quot;: &amp;quot;k: $v&amp;quot;, &amp;quot;value&amp;quot;: 33.1}, {&amp;quot;label&amp;quot;: &amp;quot;m: $v&amp;quot;, &amp;quot;value&amp;quot;: -1}]&amp;#039;&lt;br /&gt;
	local options = &amp;#039;{&amp;quot;size&amp;quot;:200}&amp;#039;&lt;br /&gt;
	local html = p.renderPie(json_data, options)&lt;br /&gt;
	mw.logObject(html)	&lt;br /&gt;
&lt;br /&gt;
	-- custom colors&lt;br /&gt;
	local json_data = &amp;#039;[{&amp;quot;label&amp;quot;: &amp;quot;k: $v&amp;quot;, &amp;quot;value&amp;quot;: 33.1, &amp;quot;color&amp;quot;:&amp;quot;black&amp;quot;}, {&amp;quot;label&amp;quot;: &amp;quot;m: $v&amp;quot;, &amp;quot;value&amp;quot;: -1, &amp;quot;color&amp;quot;:&amp;quot;green&amp;quot;}]&amp;#039;&lt;br /&gt;
	local html = p.renderPie(json_data)&lt;br /&gt;
	mw.logObject(html)&lt;br /&gt;
	&lt;br /&gt;
	-- 4-cuts&lt;br /&gt;
	local entries = {&lt;br /&gt;
	    &amp;#039;{&amp;quot;label&amp;quot;: &amp;quot;ciastka: $v&amp;quot;, &amp;quot;value&amp;quot;: 2, &amp;quot;color&amp;quot;:&amp;quot;goldenrod&amp;quot;}&amp;#039;,&lt;br /&gt;
	    &amp;#039;{&amp;quot;label&amp;quot;: &amp;quot;słodycze: $v&amp;quot;, &amp;quot;value&amp;quot;: 4, &amp;quot;color&amp;quot;:&amp;quot;darkred&amp;quot;}&amp;#039;,&lt;br /&gt;
	    &amp;#039;{&amp;quot;label&amp;quot;: &amp;quot;napoje: $v&amp;quot;, &amp;quot;value&amp;quot;: 1, &amp;quot;color&amp;quot;:&amp;quot;lightblue&amp;quot;}&amp;#039;,&lt;br /&gt;
	    &amp;#039;{&amp;quot;label&amp;quot;: &amp;quot;kanapki: $v&amp;quot;, &amp;quot;value&amp;quot;: 3, &amp;quot;color&amp;quot;:&amp;quot;wheat&amp;quot;}&amp;#039;&lt;br /&gt;
	}&lt;br /&gt;
	local json_data = &amp;#039;[&amp;#039;..table.concat(entries, &amp;#039;,&amp;#039;)..&amp;#039;]&amp;#039;&lt;br /&gt;
	local html = p.renderPie(json_data, &amp;#039;{&amp;quot;autoscale&amp;quot;:true}&amp;#039;)&lt;br /&gt;
	mw.logObject(html)&lt;br /&gt;
&lt;br /&gt;
	-- colors&lt;br /&gt;
	local fr = { args = { &amp;quot; 123 &amp;quot; } }&lt;br /&gt;
	local ret = p.color(fr)&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Color for a slice (defaults).&lt;br /&gt;
&lt;br /&gt;
	{{{1}}}: slice number&lt;br /&gt;
]]&lt;br /&gt;
function p.color(frame)&lt;br /&gt;
	local index = tonumber(trim(frame.args[1]))&lt;br /&gt;
	return &amp;#039; &amp;#039; .. defaultColor(index)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Piechart.&lt;br /&gt;
	&lt;br /&gt;
    TODO:&lt;br /&gt;
    - [x] basic 2-element pie chart&lt;br /&gt;
        - read json&lt;br /&gt;
        - calculate value with -1&lt;br /&gt;
        - generate html&lt;br /&gt;
        - new css + tests&lt;br /&gt;
        - provide dumb labels (just v%)&lt;br /&gt;
    - [x] colors in json&lt;br /&gt;
    - [x] 1st value &amp;gt;= 50%&lt;br /&gt;
    - [x] custom labels support&lt;br /&gt;
    - [x] pie size from &amp;#039;meta&amp;#039; param (options json)&lt;br /&gt;
    - [x] pl formatting for numbers?&lt;br /&gt;
    - [x] support undefined value (instead of -1)&lt;br /&gt;
    - [x] undefined in any order&lt;br /&gt;
    - [x] scale values to 100% (autoscale)&lt;br /&gt;
    - [x] order values clockwise (not left/right)&lt;br /&gt;
    - [x] multi-cut pie&lt;br /&gt;
    - [x] sanitize user values&lt;br /&gt;
    - [x] auto colors&lt;br /&gt;
    - [x] function to get color by number (for custom legend)&lt;br /&gt;
	- [x] remember and show autoscaled data&lt;br /&gt;
    - [x] generate a legend&lt;br /&gt;
	- [x] simple legend positioning by (flex-)direction&lt;br /&gt;
    - legend2: customization&lt;br /&gt;
		- (?) itemTpl support&lt;br /&gt;
			- replace default item with tpl&lt;br /&gt;
			- can I / should I sanitize it?&lt;br /&gt;
			- support for $v, $d, $p&lt;br /&gt;
		- (?) custom head&lt;br /&gt;
    - (?) validation of input&lt;br /&gt;
		- check if required values are present&lt;br /&gt;
		- message showing whole entry, when entry is invalid&lt;br /&gt;
		- pre-sanitize values?&lt;br /&gt;
		- sane info when JSON fails? Maybe dump JSON and show example with quotes-n-all...&lt;br /&gt;
    - (?) option to sort entries by value&lt;br /&gt;
]] &lt;br /&gt;
function p.pie(frame)&lt;br /&gt;
	local json_data = trim(frame.args[1])&lt;br /&gt;
	local options = nil&lt;br /&gt;
	if (frame.args.meta) then&lt;br /&gt;
		options = trim(frame.args.meta)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local html = p.renderPie(json_data, options)&lt;br /&gt;
	return trim(html)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Setup chart options.&lt;br /&gt;
function p.setupOptions(json_options)&lt;br /&gt;
	local options = {&lt;br /&gt;
		-- circle size in [px]&lt;br /&gt;
		size = 100,&lt;br /&gt;
		-- autoscale values (otherwise assume they sum up to 100)&lt;br /&gt;
		autoscale = false,&lt;br /&gt;
		-- hide chart for screen readers (when you have a table, forced for legend)&lt;br /&gt;
		ariahidechart = false,&lt;br /&gt;
		-- show legend (defaults to the left side)&lt;br /&gt;
		legend = false,&lt;br /&gt;
		-- direction of legend-chart flexbox (flex-direction)&lt;br /&gt;
		direction = &amp;quot;&amp;quot;,&lt;br /&gt;
	}   &lt;br /&gt;
	if json_options then&lt;br /&gt;
		local rawOptions = mw.text.jsonDecode(json_options)&lt;br /&gt;
		if rawOptions then&lt;br /&gt;
			if type(rawOptions.size) == &amp;quot;number&amp;quot; then&lt;br /&gt;
				options.size = math.floor(rawOptions.size)&lt;br /&gt;
			end&lt;br /&gt;
			options.autoscale = rawOptions.autoscale or false &lt;br /&gt;
			if rawOptions.legend then&lt;br /&gt;
				options.legend = true&lt;br /&gt;
			end&lt;br /&gt;
			if rawOptions.ariahidechart then&lt;br /&gt;
				options.ariahidechart = true&lt;br /&gt;
			end&lt;br /&gt;
			if (type(rawOptions.direction) == &amp;quot;string&amp;quot;) then&lt;br /&gt;
				-- Remove unsafe/invalid characters&lt;br /&gt;
				local sanitized = rawOptions.direction:gsub(&amp;quot;[^a-z0-9%-]&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
				-- also adjust width so that row-reverse won&amp;#039;t push things to the right&lt;br /&gt;
				options.direction = &amp;#039;width: max-content; flex-direction: &amp;#039; .. sanitized&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	if (options.legend) then&lt;br /&gt;
		options.ariahidechart = true&lt;br /&gt;
	end&lt;br /&gt;
	return options&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Render piechart.&lt;br /&gt;
	&lt;br /&gt;
	@param json_data JSON string with pie data.&lt;br /&gt;
]]&lt;br /&gt;
function p.renderPie(json_data, json_options)&lt;br /&gt;
	local data = mw.text.jsonDecode(json_data)&lt;br /&gt;
	local options = p.setupOptions(json_options)&lt;br /&gt;
&lt;br /&gt;
	-- prepare&lt;br /&gt;
	local ok, total = p.prepareEntries(data, options)&lt;br /&gt;
&lt;br /&gt;
	-- init render&lt;br /&gt;
	local html = &amp;quot;&amp;lt;div class=&amp;#039;smooth-pie-container&amp;#039; style=&amp;#039;&amp;quot;..options.direction..&amp;quot;&amp;#039;&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	-- error info&lt;br /&gt;
	if not ok then&lt;br /&gt;
		html = html .. renderErrors(data)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- render legend&lt;br /&gt;
	if options.legend then&lt;br /&gt;
		html = html .. p.renderLegend(data, options)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- render items&lt;br /&gt;
	local header, items, footer = p.renderEntries(ok, total, data, options)&lt;br /&gt;
	html = html .. header .. items .. footer&lt;br /&gt;
&lt;br /&gt;
	-- end .smooth-pie-container&lt;br /&gt;
	html = html .. &amp;quot;\n&amp;lt;/div&amp;gt;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Prepare data (slices etc)&lt;br /&gt;
function p.prepareEntries(data, options)&lt;br /&gt;
	local sum = sumValues(data);&lt;br /&gt;
	-- force autoscale when over 100&lt;br /&gt;
	if (sum &amp;gt; 100) then&lt;br /&gt;
		options.autoscale = true&lt;br /&gt;
	end&lt;br /&gt;
	-- pre-format entries&lt;br /&gt;
	local ok = true&lt;br /&gt;
	local no = 0&lt;br /&gt;
	local total = #data&lt;br /&gt;
	for index, entry in ipairs(data) do&lt;br /&gt;
		no = no + 1&lt;br /&gt;
		if not prepareSlice(entry, no, sum, total, options) then&lt;br /&gt;
			no = no - 1&lt;br /&gt;
			ok = false&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	total = no -- total valid&lt;br /&gt;
&lt;br /&gt;
	return ok, total&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function sumValues(data)&lt;br /&gt;
	local sum = 0;&lt;br /&gt;
	for _, entry in ipairs(data) do&lt;br /&gt;
		local value = entry.value&lt;br /&gt;
		if not (type(value) ~= &amp;quot;number&amp;quot; or value &amp;lt; 0) then&lt;br /&gt;
		    sum = sum + value&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return sum&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- render error info&lt;br /&gt;
function renderErrors(data)&lt;br /&gt;
	local html = &amp;quot;\n&amp;lt;ol class=&amp;#039;chart-errors&amp;#039; style=&amp;#039;display:none&amp;#039;&amp;gt;&amp;quot;&lt;br /&gt;
	for _, entry in ipairs(data) do&lt;br /&gt;
		if entry.error then&lt;br /&gt;
			entryJson = mw.text.jsonEncode(entry)&lt;br /&gt;
			html = html .. &amp;quot;\n&amp;lt;li&amp;gt;&amp;quot;.. entryJson ..&amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return html .. &amp;quot;\n&amp;lt;/ol&amp;gt;\n&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Prepare single slice data (modifies entry).&lt;br /&gt;
function prepareSlice(entry, no, sum, total, options)&lt;br /&gt;
	local autoscale = options.autoscale&lt;br /&gt;
	local value = entry.value&lt;br /&gt;
	if (type(value) ~= &amp;quot;number&amp;quot; or value &amp;lt; 0) then&lt;br /&gt;
		if autoscale then&lt;br /&gt;
			entry.error = &amp;quot;cannot autoscale unknown value&amp;quot;&lt;br /&gt;
			return false&lt;br /&gt;
		end&lt;br /&gt;
		value = 100 - sum&lt;br /&gt;
	end&lt;br /&gt;
	-- entry.raw only when scaled&lt;br /&gt;
	if autoscale then&lt;br /&gt;
		entry.raw = value&lt;br /&gt;
		value = (value / sum) * 100&lt;br /&gt;
	end&lt;br /&gt;
	entry.value = value&lt;br /&gt;
&lt;br /&gt;
	-- prepare final label&lt;br /&gt;
	entry.label = prepareLabel(entry.label, entry)&lt;br /&gt;
	-- prepare final slice bg color&lt;br /&gt;
	local index = no&lt;br /&gt;
	if no == total then&lt;br /&gt;
		index = -1&lt;br /&gt;
	end&lt;br /&gt;
	entry.bcolor = backColor(entry, index)&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- render legend for pre-processed entries&lt;br /&gt;
function p.renderLegend(data, options)&lt;br /&gt;
	local html = &amp;quot;\n&amp;lt;ol class=&amp;#039;smooth-pie-legend&amp;#039;&amp;gt;&amp;quot;&lt;br /&gt;
	for _, entry in ipairs(data) do&lt;br /&gt;
		if not entry.error then&lt;br /&gt;
			html = html .. renderLegendItem(entry, options)&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	return html .. &amp;quot;\n&amp;lt;/ol&amp;gt;\n&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
-- render legend item&lt;br /&gt;
function renderLegendItem(entry, options)&lt;br /&gt;
	local label = entry.label&lt;br /&gt;
	local bcolor = entry.bcolor&lt;br /&gt;
	local html = &amp;quot;\n&amp;lt;li&amp;gt;&amp;quot;&lt;br /&gt;
	html = html .. &amp;#039;&amp;lt;span class=&amp;quot;l-color&amp;quot; style=&amp;quot;&amp;#039;..bcolor..&amp;#039;&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	html = html .. &amp;#039;&amp;lt;span class=&amp;quot;l-label&amp;quot;&amp;gt;&amp;#039;..label..&amp;#039;&amp;lt;/span&amp;gt;&amp;#039;&lt;br /&gt;
	return html .. &amp;quot;&amp;lt;/li&amp;gt;&amp;quot;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Prepare data (slices etc)&lt;br /&gt;
function p.renderEntries(ok, total, data, options)&lt;br /&gt;
	-- cache for some items (small slices)&lt;br /&gt;
	p.cuts = mw.loadJsonData(&amp;#039;Module:Piechart/cuts.json&amp;#039;)&lt;br /&gt;
&lt;br /&gt;
	local first = true&lt;br /&gt;
	local previous = 0&lt;br /&gt;
	local no = 0&lt;br /&gt;
	local items = &amp;quot;&amp;quot;&lt;br /&gt;
	local header = &amp;quot;&amp;quot;&lt;br /&gt;
	for index, entry in ipairs(data) do&lt;br /&gt;
		if not entry.error then&lt;br /&gt;
			no = no + 1&lt;br /&gt;
			if no == total then&lt;br /&gt;
				header = renderFinal(entry, options)&lt;br /&gt;
			else&lt;br /&gt;
				items = items .. renderOther(previous, entry, options)&lt;br /&gt;
			end&lt;br /&gt;
			previous = previous + entry.value&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	local footer = &amp;#039;\n&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
	return header, items, footer&lt;br /&gt;
end&lt;br /&gt;
-- final, but header...&lt;br /&gt;
function renderFinal(entry, options)&lt;br /&gt;
	local label = entry.label&lt;br /&gt;
	local bcolor = entry.bcolor&lt;br /&gt;
	local size = options.size&lt;br /&gt;
&lt;br /&gt;
	-- hide chart for readers, especially when legend is there&lt;br /&gt;
	local aria = &amp;quot;&amp;quot;&lt;br /&gt;
	if (options.ariahidechart) then&lt;br /&gt;
		aria = &amp;#039;aria-hidden=&amp;quot;true&amp;quot;&amp;#039;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- slices container and last slice&lt;br /&gt;
	local style = &amp;#039;width:&amp;#039;..size..&amp;#039;px; height:&amp;#039;..size..&amp;#039;px;&amp;#039;..bcolor&lt;br /&gt;
	local html = [[&lt;br /&gt;
&amp;lt;div class=&amp;quot;smooth-pie&amp;quot;&lt;br /&gt;
	style=&amp;quot;]]..style..[[&amp;quot;&lt;br /&gt;
	title=&amp;quot;]]..label..[[&amp;quot;&lt;br /&gt;
	]]..aria..[[&lt;br /&gt;
&amp;gt;]]&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
-- any other then final&lt;br /&gt;
function renderOther(previous, entry, options)&lt;br /&gt;
	local value = entry.value&lt;br /&gt;
	local label = entry.label&lt;br /&gt;
	local bcolor = entry.bcolor&lt;br /&gt;
&lt;br /&gt;
	-- value too small to see&lt;br /&gt;
	if (value &amp;lt; 0.03) then&lt;br /&gt;
		mw.log(&amp;#039;value too small&amp;#039;, value, label)&lt;br /&gt;
		return &amp;quot;&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local html =  &amp;quot;&amp;quot;&lt;br /&gt;
	&lt;br /&gt;
	local size = &amp;#039;&amp;#039;&lt;br /&gt;
	-- mw.logObject({&amp;#039;v,p,l&amp;#039;, value, previous, label})&lt;br /&gt;
	if (value &amp;gt;= 50) then&lt;br /&gt;
		html = sliceWithClass(&amp;#039;pie50&amp;#039;, 50, value, previous, bcolor, label)&lt;br /&gt;
	elseif (value &amp;gt;= 25) then&lt;br /&gt;
		html = sliceWithClass(&amp;#039;pie25&amp;#039;, 25, value, previous, bcolor, label)&lt;br /&gt;
	elseif (value &amp;gt;= 12.5) then&lt;br /&gt;
		html = sliceWithClass(&amp;#039;pie12-5&amp;#039;, 12.5, value, previous, bcolor, label)&lt;br /&gt;
	elseif (value &amp;gt;= 7) then&lt;br /&gt;
		html = sliceWithClass(&amp;#039;pie7&amp;#039;, 7, value, previous, bcolor, label)&lt;br /&gt;
	elseif (value &amp;gt;= 5) then&lt;br /&gt;
		html = sliceWithClass(&amp;#039;pie5&amp;#039;, 5, value, previous, bcolor, label)&lt;br /&gt;
	else&lt;br /&gt;
		-- 0-5%&lt;br /&gt;
		local cutIndex = round(value*10)&lt;br /&gt;
		if cutIndex &amp;lt; 1 then&lt;br /&gt;
		    cutIndex = 1&lt;br /&gt;
		end&lt;br /&gt;
		local cut = p.cuts[cutIndex]&lt;br /&gt;
		local transform = rotation(previous)&lt;br /&gt;
		html = sliceX(cut, transform, bcolor, label)&lt;br /&gt;
	end	&lt;br /&gt;
	-- mw.log(html)&lt;br /&gt;
&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- round to int&lt;br /&gt;
function round(number)&lt;br /&gt;
    return math.floor(number + 0.5)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- render full slice with specific class&lt;br /&gt;
function sliceWithClass(sizeClass, sizeStep, value, previous, bcolor, label)&lt;br /&gt;
	local transform = rotation(previous)&lt;br /&gt;
	local html =  &amp;quot;&amp;quot;&lt;br /&gt;
	html = html .. sliceBase(sizeClass, transform, bcolor, label)&lt;br /&gt;
	-- mw.logObject({&amp;#039;sliceWithClass:&amp;#039;, sizeClass, sizeStep, value, previous, bcolor, label})&lt;br /&gt;
	if (value &amp;gt; sizeStep) then&lt;br /&gt;
		local extra = value - sizeStep&lt;br /&gt;
		transform = rotation(previous + extra)&lt;br /&gt;
		-- mw.logObject({&amp;#039;sliceWithClass; extra, transform&amp;#039;, extra, transform})&lt;br /&gt;
		html = html .. sliceBase(sizeClass, transform, bcolor, label)&lt;br /&gt;
	end&lt;br /&gt;
	return html&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- render single slice&lt;br /&gt;
function sliceBase(sizeClass, transform, bcolor, label)&lt;br /&gt;
	local style = bcolor&lt;br /&gt;
	if transform ~= &amp;quot;&amp;quot; then&lt;br /&gt;
        style = style .. &amp;#039;; &amp;#039; .. transform&lt;br /&gt;
    end&lt;br /&gt;
	return &amp;#039;\n\t&amp;lt;div class=&amp;quot;&amp;#039;..sizeClass..&amp;#039;&amp;quot; style=&amp;quot;&amp;#039;..style..&amp;#039;&amp;quot; title=&amp;quot;&amp;#039;..label..&amp;#039;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- small slice cut to fluid size.&lt;br /&gt;
-- range in theory: 0 to 24.(9)% reaching 24.(9)% for cut = +inf&lt;br /&gt;
-- range in practice: 0 to 5%&lt;br /&gt;
function sliceX(cut, transform, bcolor, label)&lt;br /&gt;
	local path = &amp;#039;clip-path: polygon(0% 0%, &amp;#039;..cut..&amp;#039;% 0%, 0 100%)&amp;#039;&lt;br /&gt;
	return &amp;#039;\n\t&amp;lt;div style=&amp;quot;&amp;#039;..transform..&amp;#039;; &amp;#039;..bcolor..&amp;#039;; &amp;#039;..path..&amp;#039;&amp;quot; title=&amp;quot;&amp;#039;..label..&amp;#039;&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- translate value to turn rotation&lt;br /&gt;
function rotation(value)&lt;br /&gt;
	if (value &amp;gt; 0) then&lt;br /&gt;
		return string.format(&amp;quot;transform: rotate(%.3fturn)&amp;quot;, value/100)&lt;br /&gt;
	end&lt;br /&gt;
	return &amp;#039;&amp;#039;&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Language sensitive float.&lt;br /&gt;
function formatNum(value)&lt;br /&gt;
	local lang = mw.language.getContentLanguage()&lt;br /&gt;
	&lt;br /&gt;
	-- doesn&amp;#039;t do precision :(&lt;br /&gt;
	-- local v = lang:formatNum(value)&lt;br /&gt;
	&lt;br /&gt;
	local v = string.format(&amp;quot;%.1f&amp;quot;, value)&lt;br /&gt;
	if (lang:getCode() == &amp;#039;pl&amp;#039;) then&lt;br /&gt;
		v = v:gsub(&amp;quot;%.&amp;quot;, &amp;quot;,&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	return v&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	Prepare final label.&lt;br /&gt;
&lt;br /&gt;
	Typical tpl:&lt;br /&gt;
		&amp;quot;Abc: $v&amp;quot;&lt;br /&gt;
	will result in:&lt;br /&gt;
		&amp;quot;Abc: 23%&amp;quot; -- when values are percentages&lt;br /&gt;
		&amp;quot;Abc: 1234 (23%)&amp;quot; -- when values are autoscaled&lt;br /&gt;
	&lt;br /&gt;
	Advanced tpl:&lt;br /&gt;
		&amp;quot;Abc: $d ($p)&amp;quot; -- only works with autoscale&lt;br /&gt;
]]&lt;br /&gt;
function prepareLabel(tpl, entry)&lt;br /&gt;
	-- static tpl&lt;br /&gt;
	if tpl and not string.find(tpl, &amp;#039;$&amp;#039;) then&lt;br /&gt;
		return tpl&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- format % value without %&lt;br /&gt;
	local p = formatNum(entry.value)&lt;br /&gt;
&lt;br /&gt;
	-- default template&lt;br /&gt;
	if not tpl then&lt;br /&gt;
		tpl = &amp;quot;$v&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local label = &amp;quot;&amp;quot; &lt;br /&gt;
	if entry.raw then&lt;br /&gt;
		label = tpl:gsub(&amp;quot;%$p&amp;quot;, p .. &amp;quot;%%&amp;quot;):gsub(&amp;quot;%$d&amp;quot;, entry.raw):gsub(&amp;quot;%$v&amp;quot;, entry.raw .. &amp;quot; (&amp;quot; .. p .. &amp;quot;%%)&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		label = tpl:gsub(&amp;quot;%$v&amp;quot;, p .. &amp;quot;%%&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	return label&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- default colors&lt;br /&gt;
local colorPalette = {&lt;br /&gt;
    &amp;#039;#005744&amp;#039;,&lt;br /&gt;
    &amp;#039;#006c52&amp;#039;,&lt;br /&gt;
    &amp;#039;#00814e&amp;#039;,&lt;br /&gt;
    &amp;#039;#009649&amp;#039;,&lt;br /&gt;
    &amp;#039;#00ab45&amp;#039;,&lt;br /&gt;
    &amp;#039;#00c140&amp;#039;,&lt;br /&gt;
    &amp;#039;#00d93b&amp;#039;,&lt;br /&gt;
    &amp;#039;#00f038&amp;#039;,&lt;br /&gt;
}&lt;br /&gt;
local lastColor = &amp;#039;#cdf099&amp;#039;&lt;br /&gt;
-- background color from entry or the default colors&lt;br /&gt;
function backColor(entry, no)&lt;br /&gt;
    if (type(entry.color) == &amp;quot;string&amp;quot;) then&lt;br /&gt;
    	-- Remove unsafe characters from entry.color&lt;br /&gt;
    	local sanitizedColor = entry.color:gsub(&amp;quot;[^a-zA-Z0-9#%-]&amp;quot;, &amp;quot;&amp;quot;)&lt;br /&gt;
        return &amp;#039;background-color: &amp;#039; .. sanitizedColor&lt;br /&gt;
    else&lt;br /&gt;
    	local color = defaultColor(no)&lt;br /&gt;
        return &amp;#039;background-color: &amp;#039; .. color&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
-- color from the default colors&lt;br /&gt;
-- last entry color for 0 or -1&lt;br /&gt;
function defaultColor(no)&lt;br /&gt;
	local color = lastColor&lt;br /&gt;
	if (no &amp;gt; 0) then &lt;br /&gt;
		local cIndex = (no - 1) % #colorPalette + 1&lt;br /&gt;
		color = colorPalette[cIndex]&lt;br /&gt;
	end&lt;br /&gt;
	return color&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	trim string&lt;br /&gt;
	&lt;br /&gt;
	note:&lt;br /&gt;
	`(s:gsub(...))` returns only a string&lt;br /&gt;
	`s:gsub(...)` returns a string and a number&lt;br /&gt;
]]&lt;br /&gt;
function trim(s)&lt;br /&gt;
	return (s:gsub(&amp;quot;^%s+&amp;quot;, &amp;quot;&amp;quot;):gsub(&amp;quot;%s+$&amp;quot;, &amp;quot;&amp;quot;))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>Walknud</name></author>
	</entry>
</feed>