Module:Sandbox/Izno/Pie chart

local p = {} local compress_sparse_array = require('Module:TableTools').compressSparseArray

local function arg_or_default(arg, default) if arg and mw.text.trim(arg) ~= '' then return arg else return default end end

local incoming_args = { ['other-color'] = 'other_color_default', style = nil, thumb = nil, labeln = nil, valuen = nil, colorn = 'get_graph_color(n)', caption = nil, other = nil, footer = nil }

local graph_colors = { '#1F78B4', '#33A02C', '#FF7F00', '#6A3D9A', '#B15928', '#A6CEE3', '#B2DF8A', '#FB9A99', '#FDBF6F', '#CAB2D6', '#FFFF99', '#FEEBE2', '#A9A9A9' } local function get_graph_color(nth_item) return graph_colors[math.max(math.min(nth_item, #graph_colors), 1)] end

local function get_css_for_slices(args) local slices = {} local degree_ratio = 360/100

for k, v in pairs(args) do		if k:match('value%d+') then local number = k:find('(%d+)') slices[number] = { value = tonumber(v) * degree_ratio } end end -- second loop because we need to guarantee that we've found all the potential slices -- before attempting to add their labels and colors for k, v in pairs(args) do		if k:match('label%d+') then local number = k:find('(%d)') if slices[number] then -- if we don't have a value, then no label set slices[number]['label'] = v			end end if k:match('color%d+') then local number = k:find('(%d)') if slices[number] then -- if we don't have a value, then no color set slices[number]['color'] = v			end end end compress_sparse_array(slices) local conical_css_for_slices = {} local accumulated_value = 0 for i, slice in ipairs(slices) do		local value = slice.value local color = slice.color or get_graph_color(i) local next_accumulated_value = accumulated_value + value if i == 1 then -- we only need the end degree for the first table.insert(conical_css_for_slices, color .. ' ' .. value .. 'deg,') elseif i > 1 and i < #slices then -- need both start and end for the first, start is the previous end table.insert(conical_css_for_slices, color .. ' ' .. accumulated_value .. 'deg ' .. next_accumulated_value .. 'deg,') elseif i == #slices then -- we only need the start degree for the last table.insert(conical_css_for_slices, color .. ' ' .. accumulated_value .. 'deg') end accumulated_value = next_accumulated_value end return 'background: conic-gradient(' .. table.concat(conical_css_for_slices) .. ')' end

function p._main(args) local root = mw.html.create('div') root:addClass('pie-chart thumb') :cssText(arg_or_default(args.style, nil)) local thumb = arg_or_default(args.thumb, nil) local thumb_class = 'tright' if thumb and (thumb == 'center' or thumb == 'none') then thumb_class = 'tnone' elseif thumb and thumb == 'left' then thumb_class = 'tleft' end root:addClass(thumb_class) local radius = tonumber(arg_or_default(args.radius, 100)) local diameter = radius * 2 root:tag('div') :addClass('pie-chart-inner thumbinner') :css('width', (diameter + 2) .. 'px') local chart = mw.html.create('div') chart:addClass('pie-chart-chart mw-no-invert') chart:css('border-radius', '50%') -- can be in pie chart/styles.css if we have one chart:css('width', diameter .. 'px') chart:css('height', diameter .. 'px') local conic_css = get_css_for_slices(args) chart:cssText(conic_css)

if thumb and thumb == 'center' then local root_container = mw.html.create('div') root_container:addClass('pie-chart-container center') :node(root) return root_container end

return root end

function p.main(frame) return p._main(frame:getParent.args) end

return p