模块:议会
来自Novark
更多操作
此模块的文档可以在模块:议会/doc创建
local p = {}
function p.render(frame)
local args = frame:getParent().args
local groups, total = {}, 0
for line in mw.text.gsplit(args['席位'] or '', '\n') do
line = mw.text.trim(line)
if line ~= '' then
local name, count = line:match('^(.-)%s*=%s*(%d+)%s*$')
if not name or mw.text.trim(name) == '' then
return '<strong class="error">议会席位:每行请填写“名称=席数”。</strong>'
end
count = tonumber(count)
groups[#groups + 1] = { name = mw.text.trim(name), count = count }
total = total + count
end
end
if total == 0 then return '<strong class="error">议会席位:请填写席位数据。</strong>' end
local capacity = tonumber(args['总席位']) or total
if capacity ~= total then
return '<strong class="error">议会席位:分组合计' .. total .. '席,与总席位' .. capacity .. '席不一致。</strong>'
end
local root = mw.html.create('div'):addClass('nv-parliament')
root:tag('div'):addClass('nv-parliament__title'):wikitext(args['名称'] or '议会席位')
root:tag('p'):addClass('nv-parliament__session'):wikitext((args['届次'] or '') .. ' · 共' .. total .. '席')
local chamber = root:tag('div'):addClass('nv-parliament__chamber'):attr('aria-hidden', 'true')
local positions, allocated = {}, 0
local radii = total < 30 and { 46 } or (total < 80 and { 46, 32, 18 } or { 46, 39, 32, 25, 18 })
local radiusSum = 0
for _, radius in ipairs(radii) do radiusSum = radiusSum + radius end
for ring, radius in ipairs(radii) do
local count = ring == #radii and total - allocated or math.floor(total * radius / radiusSum + 0.5)
allocated = allocated + count
for seat = 1, count do
local angle = count == 1 and math.pi / 2 or (seat - 1) * math.pi / (count - 1)
positions[#positions + 1] = { angle = angle, radius = radius }
end
end
table.sort(positions, function(a, b)
if a.angle == b.angle then return a.radius > b.radius end
return a.angle > b.angle
end)
local seat = 1
for index, group in ipairs(groups) do
local class = 'nv-parliament__party--' .. ((index - 1) % 12 + 1)
group.class = class
for _ = 1, group.count do
local point = positions[seat]
local x = 50 + math.cos(point.angle) * point.radius
local y = 98 - math.sin(point.angle) * point.radius * 2
chamber:tag('span'):addClass('nv-parliament__seat'):addClass(class)
:css('left', string.format('%.3f%%', x)):css('top', string.format('%.3f%%', y))
seat = seat + 1
end
end
local legend = root:tag('table'):addClass('wikitable'):addClass('nv-parliament__legend')
legend:tag('caption'):wikitext('席位构成')
local header = legend:tag('tr')
header:tag('th'):attr('scope', 'col'):wikitext('组别')
header:tag('th'):attr('scope', 'col'):wikitext('席位')
header:tag('th'):attr('scope', 'col'):wikitext('占比')
for _, group in ipairs(groups) do
local row = legend:tag('tr')
local label = row:tag('th'):attr('scope', 'row')
label:tag('span'):addClass('nv-parliament__key'):addClass(group.class):attr('aria-hidden', 'true')
label:wikitext(mw.text.nowiki(group.name))
row:tag('td'):wikitext(tostring(group.count))
row:tag('td'):wikitext(string.format('%.1f%%', group.count / total * 100))
end
root:tag('p'):addClass('nv-parliament__note'):wikitext('按表中顺序排布,不表示政治光谱。')
return tostring(root)
end
return p