local getArgs = require('Modulo:Arguments').getArgs
local yesno = require('Modulo:Yesno')
local p = {}
local function is(v)
return (v or '') ~= ''
end
function p._barColors(n)
if n == 1 then
return 'Black' --morti
elseif n == 2 then
return 'Lightgreen' --guarigioni
elseif n == 3 then
return 'Red' --casi o altlbl1
elseif n == 4 then
return 'Gold' --altlbl2
elseif n == 5 then
return 'OrangeRed' --altlbl3
end
return nil
end
function p._legend0(args)
return '<span style="margin:0px; font-size:90%;">' .. '<span style="' .. 'border:' .. (args.border or 'none') .. '; background-color:' .. (args[1] or 'none') .. '; color:' .. (args[1] or 'none') .. ';">' .. ' ' .. '</span>' .. ' ' .. (args[2] or '') .. '</span>'
end
function p._buildBars(args)
local lines = mw.text.split(args.data, '\n')
local frame = mw.getCurrentFrame()
local lang = mw.getContentLanguage()
local bars, rows, months, prevRow, maxparam = {}, {}, {}, '', 1
for k, line in pairs(lines) do
local barargs, i = {}, 1
for parameter in mw.text.gsplit(line, ';') do
parameter = mw.text.trim(parameter)
if string.find(parameter, '^%a') then
parameter = mw.text.split(parameter, '=')
if parameter[1] == 'alttot1' or parameter[1] == 'alttot2' then
parameter[2] = tonumber(frame:callParserFunction('#expr', parameter[2]))
if is(parameter[2]) then
maxparam = math.max(maxparam, parameter[2])
end
end
barargs[parameter[1]] = parameter[2]
else
if is(parameter) then
if i >= 2 and i <= 6 then
parameter = tonumber(frame:callParserFunction('#expr', frame:callParserFunction('formatnum',parameter,'R')))
maxparam = math.max(maxparam, parameter or 1)
end
barargs[i] = parameter
if i == 7 or i == 9 then
parameter = tonumber(mw.ustring.match(frame:callParserFunction('formatnum',parameter,'R'), '^%d*'))
maxparam = math.max(maxparam, parameter or 1)
end
end
i = i + 1
end
end
function format_thousand(v)
local s = string.format("%d", math.floor(v))
local pos = string.len(s) % 3
if pos == 0 then pos = 3 end
return string.sub(s, 1, pos)
.. string.gsub(string.sub(s, pos+1), "(...)", ".%1")
end
local function fillCols(col, change)
local data
local changetype
local value, num, prevnum
if col == 1 then
data = args.right1data or 3
changetype = args.changetype1 or 'p'
num = tonumber(barargs[tonumber(data) + 1])
prevnum = tonumber(prevRow[tonumber(data) + 1])
else
data = args.right2data or 1
changetype = args.changetype2 or 'p'
num = tonumber(barargs[tonumber(data) + 1])
prevnum = tonumber(prevRow[tonumber(data) + 1])
end
if num then -- nothing in column, source found, and data exists
value = num
if not change and yesno(barargs['firstright' .. col] ~= true) then
if prevnum and prevnum ~= 0 then -- data on previous row
if num - prevnum ~= 0 then --data has changed since previous row
change = num-prevnum
if changetype == 'a' then -- change type is "absolute"
if change > 0 then
change = '+' .. lang:formatNum(change)
end
else -- change type is "percent", "only percent" or undefined
local percent = 100 * change / prevnum -- calculate percent
local rounding = math.abs(percent) >= 10 and "%.0f" or math.abs(percent) >= 1 and "%.1f" or "%.2f"
percent = tonumber(mw.ustring.format(rounding, percent)) -- round to two sigfigs
if percent > 0 then
change = '+' .. lang:formatNum(percent) .. '%'
elseif percent < 0 then
change = lang:formatNum(percent) .. '%'
else
change = '='
end
end
else -- data has not changed since previous row
change = '='
end
else -- no data on previous row
barargs['firstright' .. col] = true -- set to (n.a.)
end
end
value = format_thousand(value)
end
return value, change
end
if not is(barargs[7]) then
barargs[7], barargs[8] = fillCols(1, barargs[8])
end
if not is(barargs[9]) then
barargs[9], barargs[10] = fillCols(2, barargs[10])
end
if is(barargs[1]) then
local e,f = pcall(function () return mw.getContentLanguage('it'):formatDate('M',barargs[1]) end)
if e then
months[#months+1] = f
end
end
barargs.prevDate = prevRow[1]
rows[#rows + 1] = barargs
prevRow = barargs
end
for i=1,#rows do -- build rows
rows[i].divisor = tonumber(args.divisor) and tonumber(args.divisor) or maxparam / (0.95 * args.barwidth)
rows[i].numwidth = args.numwidth
rows[i].collapsible = args.collapsible
rows[i].rowsToEnd = #rows - i
rows[i].rowheight = args.rowheight
rows[i].duration = args.duration
bars[i] = p._row(rows[i])
end
monthsOut = {}
for i=1,#months do -- deduplicate months
if months[i] ~= monthsOut[#monthsOut] then
monthsOut[#monthsOut+1] = months[i]
end
end
return table.concat(bars), monthsOut
end
function p._row(args)
local barargs = {}
local rowDate = args.prevDate or ''
frame = mw.getCurrentFrame()
lang=mw.language.getContentLanguage()
if args[1] then
if pcall(function () lang:formatDate('', args[1]) end) then
barargs[1] = args[1]
rowDate = args[1]
else
barargs[1] = '<strong class="error">Error: Invalid time.</strong>'
end
else
barargs[1] = '⋮'
end
local two = args[2] or 0
barargs[2] = frame:callParserFunction('#expr', two)
local three = args[3] or 0
barargs[3] = frame:callParserFunction('#expr', three)
if args['alttot1'] then
barargs[4] = frame:callParserFunction('#expr', args['alttot1'])
elseif args[4] then
barargs[4] = frame:callParserFunction('#expr', (args[4] .. '-' .. two .. '-' .. three) )
else
barargs[4] = 0
end
local five = args[5] or 0
barargs[5] = frame:callParserFunction('#expr', five)
if args['alttot2'] then
barargs[6] = frame:callParserFunction('#expr', args['alttot2'])
elseif args[6] then
barargs[6] = frame:callParserFunction('#expr', (args[6] .. '-' .. two .. '-' .. three) )
else
barargs[6] = 0
end
if args[7] then
barargs[7] = string.gsub(args[7],",",".") or ''
else
barargs[7] = ''
end
local function changeArg(firstright, valuecol, changecol)
local change = ''
if yesno(args['firstright' .. firstright]) == true then
change = '(n.a.)'
elseif yesno(args['firstright' .. firstright]) == false or not is(args['firstright' .. firstright]) then
if not is(args[1]) and is(args[valuecol]) then
change = '(=)'
else
change = is(args[changecol]) and '(' .. args[changecol] .. ')' or ''
change = string.gsub(change,"%.",",")
end
end
return change
end
barargs[8] = changeArg(1,7,8)
if args[9] then
barargs[9] = string.gsub(args[9],",",".") or ''
else
barargs[9] = ''
end
barargs[10] = changeArg(2,9,10)
barargs.divisor = args.divisor or 1
barargs.numwidth = args.numwidth
local elapsedDays = (lang:formatDate('\U') - lang:formatDate('\U',args[1])) / 86400
if yesno(args.collapsible) == true then
if args.collapsed then
barargs.collapsed = args.collapsed
elseif ( elapsedDays > 15 ) then
barargs.collapsed = 'y'
else
barargs.collapsed = ''
end
if args.id then
barargs.id = args.id
else
barargs.id = mw.ustring.lower(lang:formatDate('\M',args[1]))
if elapsedDays <= 15 then
barargs.id = barargs.id .. '-l15'
end
end
else
barargs.collapsed = ''
barargs.id = ''
end
return p._customBarStacked(barargs)
end
function p._customBarStacked(args)
barargs = {}
barargs[1] = args[1]
local function _numwidth(n)
if n == 'n' then
return 0
elseif n == 't' then
return 2.45
elseif n == 'm' then
return 3.5
elseif n == 'w' then
return 4.55
elseif n == d then
return 3.5
end
return 3.5
end
width1 = 3.5
width2 = 3.5
if args.numwidth and args.numwidth ~= '' then
width1 = _numwidth( mw.ustring.sub(args.numwidth,1,1) )
width2 = _numwidth( mw.ustring.sub(args.numwidth,2,2) )
width3 = _numwidth( mw.ustring.sub(args.numwidth,3,3) )
width4 = _numwidth( mw.ustring.sub(args.numwidth,4,4) )
end
barargs[2] =
'<span class="nowrap">' ..
'<span style="width:' .. width1 .. 'em; padding:0 0.3em 0 0; text-align:right; display:inline-block">' .. (args[7] or '') .. '</span>' ..
'<span style="width:' .. width2 .. 'em; text-align:left; display:inline-block">' .. (args[8] or '') .. '</span>\n' ..
'</span>'
if mw.ustring.len(args.numwidth) == 4 then
local padding = '0.3em'
if mw.ustring.sub(args.numwidth,3,3) == 'n' then
padding = '0'
end
barargs.note2 =
'<span style="width:' .. width3 .. 'em; padding:0 ' .. padding .. ' 0 0; text-align:right; display:inline-block">'
.. (args[9] or '') ..
'</span>' ..
'<span style="width:' .. width4 .. 'em; text-align:left; display:inline-block">' ..
(args[10] or '') ..
'</span>'
end
for i=1,5,1 do
barargs[(2*i) + 1] = p._barColors(i)
barargs[(2*i) + 2] = tonumber(mw.ustring.format("%.2f", tonumber(args[i+1])/tonumber(args.divisor) ) )
barargs['title' .. i] = args[i+1]
end
barargs.align = 'cdcc'
barargs.collapsed = args.collapsed
barargs.id = args.id
return p._barStacked(barargs)
end
function p._barStacked(args)
local function _align(n, default)
if args.align and args.align ~= '' then
local a = mw.ustring.sub(args.align,n,n)
if a == 'l' then
return 'left'
elseif a == 'c' then
return 'center'
elseif a == 'r' then
return 'right'
elseif a == 'd' then
return default
end
end
return default
end
local output = {}
if args.id and args.id ~= '' then
output[1] = '<tr class="mw-collapsible' .. ( yesno(args.collapsed) and ' mw-collapsed' or '') ..
'" id="mw-customcollapsible-' .. args.id .. '"}}>\n'
else
output[1] = '<tr>\n'
end
if args[1]=='⋮' then
output[2] =
'<td ' .. (args.note1 and '' or 'colspan="2" ') ..
'style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(1,'left') .. '">' ..
'⋮'..
'</td>\n'
else
output[2] =
'<td ' .. (args.note1 and '' or 'colspan="2" ') ..
'style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(1,'left') .. '">' ..
mw.text.trim(lang:formatDate("d-m-Y", args[1]) or '') ..
'</td>\n'
end
if args.note1 and args.note1 ~= '' then
output[3] =
'<td style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(2,'right') .. '">' ..
args.note1 ..
'</td>\n'
else
output[3] = ''
end
output[4] = '<td style="border-left:1px solid silver; border-right:1px solid silver">\n'
for i=1,5,1 do
output[i+4] =
'<div' .. (args['title' .. i] and (' title=' .. args['title' .. i]) or '') ..
' style="background:' .. (args[(2*i) + 1] or 'gray') ..
'; float:left; overflow:hidden; width:' .. mw.text.trim(args[(2*i) + 2] or '0') .. 'px">' ..
'​' ..
'</div>\n'
end
output[10] = '</td>\n'
output[11] =
'<td ' .. (args.note2 and '' or 'colspan="2" ') ..
'style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(3,'left') .. '">' ..
mw.text.trim(args[2] or '') ..
'</td>\n'
if args.note2 and args.note2 ~= '' then
output[12] =
'<td style="padding-left:0.4em; padding-right:0.4em; text-align:' .. _align(4,'right') .. '">' ..
args.note2 ..
'</td>\n'
else
output[12] = ''
end
output[13] = '</tr>\n'
return table.concat(output)
end
function p._chart(args)
local navbar = require('Modulo:Navbox')._navbox
local barargs = {}
local barwidth = 280
if args.barwidth == 'thin' then
barwidth = 120
elseif args.barwidth == 'medium' then
barwidth = 280
elseif args.barwidth == 'wide' then
barwidth = 400
end
local function _numwidth(p)
local n = mw.ustring.sub((args.numwidth or ''),p,p)
if n == 'n' then
return 0
elseif n == 't' then
return 40
elseif n == 'm' then
return 55
elseif n == 'w' then
return 70
elseif n == 'd' then
return 55
end
return 0
end
local numwidth = 120
local right1 = numwidth - 8 -- -8 because of padding
if args.numwidth then
numwidth = _numwidth(1) + 10 + _numwidth(2)
if mw.ustring.len(args.numwidth) == 4 then
numwidth = numwidth + _numwidth(3) + _numwidth(4)
if mw.ustring.sub(args.numwidth,3,3) == 'n' then
numwidth = numwidth + 6
else
numwidth = numwidth + 10
end
end
right1 = _numwidth(1) + 2 + _numwidth(2)
if (not args.destra2) and mw.ustring.len(args.numwidth) == 4 then
right1 = right1 + _numwidth(3) + _numwidth(4)
if mw.ustring.sub(args.numwidth,3,3) == 'n' then
numwidth = numwidth + 6
else
numwidth = numwidth + 10
end
end
end
barargs.width = (85 + barwidth + numwidth) .. 'px'
barargs.barwidth = barwidth .. 'px'
barargs.float = args.float and args.float or 'right'
local ___location = mw.ustring.gsub(args.localita, 'I ', '')
___location = mw.ustring.upper(mw.ustring.sub(___location,1,1)) .. mw.ustring.sub(___location,2)
local navbartitle = args.epidemia .. '/' ..
'grafico dei casi in' .. ((args.localita3) and (args.posttitolo and '/') or '') ..
((args.localita2) and (args.localita2 and '/') or '') ..
___location
local title = {}
title[1] = ((args.pretitolo) and (args.pretitolo .. ' ') or ('')) ..
' casi di ' .. args.malattia .. args.preposizione ..
((args.localita) or '') ..
((args.localita2) and (', ' .. args.localita2) or '') ..
((args.localita3) and (', ' .. args.localita3) or '') ..
((args.posttitolo) and (' ' .. args.posttitolo) or '') .. '<span class="nowrap"> </span>(' ..
navbar({[1] = navbartitle, titleArg = (':' .. mw.getCurrentFrame():getParent():getTitle()), mini = 1, nodiv = 1}) ..
')<br />'
title[2] = p._legend0({[1] = p._barColors(1),[2] = 'Morti'})
if yesno(args.guarigioni) == false then
title[3] = ''
else
title[3] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(2),[2] = (args.reclbl or 'Guarigioni')})
end
title[4] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(3),[2] = (args.altlbl1 or 'Ammalati')})
if args.altlbl2 then
title[5] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(4),[2] = args.altlbl2})
else
title[5] = ''
end
if args.altlbl3 then
title[6] = '<span class="nowrap"> </span>' .. p._legend0({[1] = p._barColors(5),[2] = args.altlbl3}) ..'\n'
else
title[6] = '\n'
end
title[7] = (args.togglesbar or '') -- this feature is WIP
barargs.title = table.concat(title)
barargs.left1 =
'<div class="center" style="margin-left:auto; margin-right:auto;width:77px;">' .. -- 85-8 because of padding
"'''Data'''" ..
'</div>'
barargs.right1 =
'<div class="center" style="margin-left:auto; margin-right:auto;width:' .. right1 .. 'px;">' ..
(args.destra1 or "'''# di casi'''") ..
'</div>'
if args.destra2 then
local right2 = _numwidth(3) + _numwidth(4)
if mw.ustring.sub(args.numwidth,3,3) == 'n' then
right2 = right2 - 2
else
right2 = right2 + 2
end
barargs.right2 =
'<div class="center" style="margin-left:auto; margin-right:auto;width:' ..right2 ..'px;">' ..
"'''" .. args.destra2 .. "'''" ..
'</div>'
end
if args.rows then
barargs.bars = args.rows
elseif args.data then
barargs.bars = p._buildBars({
barwidth = barwidth,
data = args.data,
divisor = args.divisor,
numwidth = args.numwidth,
collapsible = args.collapsible
})
end
barargs.caption = args.caption
return p._barBox(barargs)
end
function p._barBox(args)
local width = args.width or 'auto'
local class = 'barbox'
if args.float == 'left' or args.float == 'right' or args.float == 'none' then
class = 'barbox t' .. args.float
elseif args.float == 'center' then
class = 'barbox tnone'
end
local output = {}
if (args.float == 'left') or (args.float == 'right') then
output[1] = ''
output[11] = ''
else
output[1] = '<table style="margin:' .. ( (args.float == 'center') and '0 auto' or 'auto' ) .. '; border:none;"><tr><td style="border:none; padding:0;">'
output[11] = '</td></tr></table>[[Category:Pages using bar box without float left or float right|' .. ( (width == 'auto') and 'Ω' or '' ) .. mw.title.getCurrentTitle().text .. ']]'
end
output[2] =
'<div class="' .. class .. '" style="overflow-x: auto;' .. (args.style or '') .. '">\n' ..
'<div style="border:' .. (args.border_width or '1') .. 'px solid silver; font-size:88%; padding:0.4em; width:' .. width .. '; background: ' .. (args['background-color'] or 'white') .. ';">\n' ..
'<table style="text-align:left; border-collapse:collapse; width:100%;">\n'
if args.title then
output[3] =
'<tr style="background:' .. (args.titlebar or 'none') .. '">' ..
'<th style="text-align:center;" colspan="5">' .. args.title .. '</th>' ..
'</tr>\n'
else
output[3] = ''
end
output[4] =
'<tr style="font-size:88%; height:4px;">\n' ..
'<td ' .. (args.left2 and '' or 'colspan="2"') .. ' style="padding:0 4px; text-align:left;">' ..
(args.left1 or '') ..
'</td>\n'
if args.left2 then
output[5] = '<td style="padding:0 4px; text-align:right;">' .. args.left2 .. '</td>\n'
else
output[5] = ''
end
output[6] = '<td style="width:' .. (args.barwidth or '100px') .. '; text-align:left;"></td>\n' ..
'<td ' .. (args.destra2 and '' or 'colspan="2"') .. ' style="padding:0 4px; width:1em; text-align:right;">' ..
(args.destra1 or '') ..
'</td>\n'
if args.destra2 then
output[7] = '<td style="padding:0 4px; text-align:right;">' .. args.destra2 .. '</td>\n'
else
output[7] = ''
end
output[8] = '</tr>\n' .. (args.bars or '')
if args.caption then
output[9] = '<tr><td colspan="5" style="padding:5px; text-align:left;">' .. args.caption .. '</td></tr>\n'
else
output[9] = ''
end
output[10] = '</table>\n</div>\n</div>\n'
-- output[11] defined above
return table.concat(output)
end
function p.barBox(frame)
local args = getArgs(frame, {
valueFunc = function (key, value)
if value then
value = mw.text.trim(value)
if (key == 'width') or (key == 'float') then
value = mw.ustring.lower(value)
end
if value ~= '' then
return value
end
end
return nil
end
})
return p._barBox(args)
end
function p.chart(frame)
local args = getArgs(frame, {
valueFunc = function (key, value)
if value then
value = mw.text.trim(value)
if (key == 'numwidth') or (key == 'barwidth') or (key == 'guarigioni') then
value = mw.ustring.lower(value)
end
if value ~= '' then
return value
end
end
return nil
end
})
return p._chart(args)
end
function p.buildBars(frame)
return p._buildBars(frame.args)
end
return p