require('strict')
local p = {}
local getArgs = require('Module:Arguments').getArgs
local errorCategory = '[[Categoria:Errori di compilazione del template Diagramma parlamentare]]'
local colore = require('Module:Partiti').colore
local dimx = 175
local dimr = 50
local dimc = 40
local limite = 2000
-- Arrotonda
local function tondo(a)
return (math.floor(10*(a+0.5))/10);
end
-- Error handler per xpcall, formatta l'errore.
local function errhandler(msg)
local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or ''
return string.format('<span class="error">%s</span>%s', msg, cat)
end
-- crea unico array per stringa
local function agg(a,...)
local args = {...}
for _, s in ipairs(args) do
table.insert(a, s)
end
end
-- recupera colore del partito da Modulo:Partiti
-- a = partito; b = colore opzionale
local function colora(a,b)
local c = '#CCC'
if (b) then
c = b
else
c = colore({a,(c)})
end
if string.sub(c,1,5) == '#' then c = "#" .. string.sub(c, 6, 11) end
return c
end
-- crea punti
local function valori(n)
local totali= {4, 17, 36, 65, 100, 144, 196, 255, 322, 398, 480, 571, 670, 776, 891, 1013, 1143, 1281, 1427, 1580, 1743, 1911, 2089}
local punti = 0
local righe = 1
local jj,rr,aa
-- cerca numero di righe che permettano di mostrare tutti i punti
while (n > totali[righe]) do
righe = righe + 1
end
local dd = dimr/righe -- distanza tra gli archi
dimc = 0.7*dimr/righe -- dimensione dei cerchi
local lista = {} -- lista dei punti
-- calcola angolo e raggio di ogni punto
for rg=0,righe-2 do
rr = dimx - dd*(2*rg+1) -- raggio
jj = math.floor((n/totali[righe])*math.pi/(2*math.asin(dd/rr)))+1 --numero punti
if (jj==1) then
punti = punti + 1
lista[punti] = {0.5, rr}
else
for ps=0,jj-1 do
aa = ps/(jj-1)
punti = punti + 1
lista[punti] = {aa,rr}
end
end
end
-- punti rimasti da porre su arco più interno
jj=n-punti
rr= dimx - dd*(2*righe-1) -- raggio
if (jj==1) then
punti = punti + 1
lista[punti] = {1/2, rr}
else
for ps=0,jj-1 do
aa=ps/(jj-1)
punti = punti + 1
lista[punti] = {aa,rr}
end
end
-- ordina punti per angolo crescente partendo dal centro
table.sort(lista, function(a,b) return ((a[1]<b[1]) or (a[1]==b[1] and a[2]<b[2])) end)
return lista
end
-- crea arco parlamentare
function p._parlamento(args)
local ss = {}
local ss2 = {}
local dati = {}
local num = 1
local totalepunti = 0
local dida = args.didascalia or ''
local mostra = tonumber(args.mostra) or 0
while (args['n'..num]) do
if (tonumber(args['n'..num])) then
dati[num] = {
n = args['n'..num] and tonumber(args['n'..num]),
c = colora(args['p'..num] or '', args['c'..num]),
b = args['b'..num] or '-',
p = args['p'..num] or 'Serie '..num
}
totalepunti = totalepunti + dati[num].n
num = num+1
else
error(string.format('Valore per n%d non valido', num),2)
end
end
num = num - 1
if (totalepunti>limite) then
error('Numero di punti superiore al limite')
elseif (totalepunti<1) then
error('Non sono stati indicati punti')
end
local punti = valori(totalepunti)
local larghezza = 2*dimx
local altezza = dimx+dimc
local scala = 1.0
if (args['larghezza'] and tonumber(args['larghezza'])) then
larghezza = tonumber(args['larghezza'])
scala = larghezza/(2*dimx)
altezza = (dimx+dimc)*scala
elseif (args['altezza'] and tonumber(args['altezza'])) then
altezza = tonumber(args['altezza'])
scala = altezza/(dimx+dimc)
larghezza = 2*dimx*scala
elseif (totalepunti<29) then
larghezza = 200
scala = larghezza/(2*dimx)
altezza = (dimx+dimc)*scala
elseif (totalepunti<101) then
larghezza = 250
scala = larghezza/(2*dimx)
altezza = (dimx+dimc)*scala
elseif (totalepunti<281) then
larghezza = 300
scala = larghezza/(2*dimx)
altezza = (dimx+dimc)*scala
end
local graph = {
width = tondo(larghezza), height = tondo(altezza), padding = "no",
data = { },
scales = {
{ name = "x", type = "linear", range = "width", zero = true, domain = {0, tondo(2*dimx) } },
{ name = "y", type = "linear", range = "height", zero = true, domain = {0, tondo(dimx + dimc) } }
},
marks = { }
}
local ee = 0
local valori
for i=1,num do
valori = {}
for j=1,dati[i].n do
ee = ee + 1
valori[j] = {
px = tondo(dimx-punti[ee][2]*math.cos(math.pi*punti[ee][1])),
py = tondo(dimc+punti[ee][2]*math.sin(math.pi*punti[ee][1])),
}
end
graph['data'][i] = { name = "tab"..i, values = valori }
graph['marks'][i] = { type = "symbol", from = {data = "tab"..i },
encode = {
enter = {
x = {scale = "x",field = "px"},
y = {scale = "y",field = "py"},
fill = {value = dati[i].c},
size = {value = tondo((2*dimc*scala)^2)}
}
}
}
if (dati[i].b ~= "-") then
graph['marks'][i]['encode']['enter']['stroke'] = {value = dati[i].b}
graph['marks'][i]['encode']['enter']['strokeWidth'] = {value = 1}
end
end
graph['marks'][num+1] = {
type = "text",
encode = {
enter = {
x = {scale = "x",value=tondo(dimx)},
y = {scale = "y",value=tondo(dimc+8)},
align = {value = "center"},
fill = {value = "#000"},
font = {value = "Helvetica"},
fontSize = { value = tondo(36*scala) },
fontWeight = { value = "bold" },
text = {value = totalepunti }
}
}
}
agg(ss, mw.getCurrentFrame():extensionTag('graph', mw.text.jsonEncode(graph)))
if (dida ~= '') then
agg(ss,string.format('<p style="font-size:90%%; margin-left:10px">%s</p>',dida))
end
if mostra == 1 then
for i=1,num do
agg(ss2,string.format('<span style="display:inline-block;border:solid grey 1px;background:%s;width:1em;height:1em"> </span> %s', dati[i].c, dati[i].n))
end
agg(ss,'<p style="font-size:90%; margin-left:10px">')
agg(ss,table.concat(ss2," · "))
agg(ss,'</p>')
elseif mostra ==2 then
for i=1,num do
agg(ss2,string.format('<span style="display:inline-block;border:solid grey 1px;background:%s;width:1em;height:1em"> </span> %s %s', dati[i].c, dati[i].p, dati[i].n))
end
agg(ss,'<p style="font-size:90%; margin-left:10px">')
agg(ss,table.concat(ss2,"<br/>"))
agg(ss,'</p>')
end
if args['debug'] then
return mw.text.jsonEncode(graph)
else
return table.concat(ss)
end
end
function p.parlamento(frame)
return select(2, xpcall(function()
return p._parlamento(getArgs(frame, { parentOnly = true }))
end, errhandler))
end
return p