Module:Datastaven
Uiterlijk
![]() | Deze module maakt gebruik van TemplateStyles: |
Deze module kan gebruikt worden voor het in een staafdiagram weergeven van klasseringen / aantallen / rangen / posities / standen / eindstanden of iets in die trant. Of iets anders.
Deze module wordt toegepast in Sjabloon:Datastaven. Zie voor een overzicht van parameters de documentatie aldaar.
Gebruik
Standaard:
{{#invoke:Datastaven|main}}
Speciaal voor eindstanden kan ook gebruik worden gemaakt van:
{{#invoke:Datastaven|main|type=eindstanden}}
Kleuren
De kleuren van de staven kunnen zowel ingesteld worden op de groepen als op individuele staven. Als er geen kleur is opgegeven wordt er een uit het standaardkleurenpalet gehaald:
(Bewerk)
(Bewerk)
Zie ook
- Module:Datastaven/Groepen - Een verzameling met voorgedefinieerde groepen die gebruikt kunnen worden met deze module.
require('Module:No globals')
local p = {}
local getArgs = require('Module:Arguments').getArgs
local unpackItem = require('Module:Item').unpack
local _delink = require('Module:Delink')._delink
local _yesno = require('Module:Yesno')
local templatestyles = 'Module:Datastaven/styles.css'
local data = {}
local chartHeight = 180 -- In px
local extraHeight = 20 -- Extra height per extra tier, in px
local barWidth = 3 -- In em
local truncateX = false
local invertY = false
local ySuffix = ''
local colors = {
'#002a62', '#2c699a', '#db0c23', '#e36271',
'#e99fa8', '#618b25', '#6bd425', '#eee8aa',
'#eca72c', '#fff943', '#ffe4e1', '#dda0dd',
'#0b6b61', '#3ec9a6', '#edf669', '#aabc1e',
'#95291d', '#ee2b08', '#999999', '#ffffff'
}
-- Translations for parameter names
local w = {
type = 'type',
rankings = 'eindstanden',
chartHeight = 'grafiekhoogte',
barWidth = 'staafbreedte',
groups = 'groepen',
truncateX = 'xAfkappen',
invertY = 'yOmkeren',
x = 'x',
y = 'y',
yMax = 'yMax',
ySuffix = 'ySuffix',
group = 'groep',
subgroup = 'subgroep',
label = 'label',
color = 'kleur',
tier = 'niveau',
}
local function isItem(arg)
-- An arg is considered an item if it starts with a pipe character.
return string.find(mw.text.trim(arg), '|', 1, true) == 1
end
local function formatItem(item)
item[w.y] = tonumber(item[w.y])
item[w.yMax] = tonumber(item[w.yMax])
item[w.tier] = tonumber(item[w.tier])
end
local function yesno(value, default)
if _yesno(value) ~= nil then return _yesno(value) else return default end
end
local function pick(param, bar)
-- Picks a parameter from bar or else from it's group or else from data.
return bar[w[param]]
or bar[w.group] and data.groups[bar[w.group]][w[param]]
or data[param]
end
local function minn(table)
-- Returns the lowest positive numerical index of the given table, or zero
-- if the table has no numerical indices.
local minn, k = nil, nil
repeat
k = next(table, k)
if type(k) == 'number' then
if k == 1 then return 1 end
if minn == nil or k < minn then minn = k end
end
until not k
return minn or 0
end
local function countTiers(tiers)
-- Gives the number of tiers, empty inbetweens included.
return table.maxn(tiers) - minn(tiers) + 1
end
local function rankTiers(tiers)
-- Ranks the tiers bottom up for convenience, since heights will be calculated
-- from the bottom up. Example:
-- [2] = true, [2] = 4,
-- [3] = true, --> [3] = 3,
-- [5] = true, [5] = 1,
local highestTierNumber = table.maxn(tiers)
for n, _ in pairs(tiers) do
tiers[n] = highestTierNumber - n + 1
end
return tiers
end
local function mergeTables(t1, t2)
if t1 and t2 then for k, v in pairs(t2) do t1[k] = v end end
return t1
end
local function importGroups(basename)
if basename == nil or basename == '' then return {} end
return require('Module:Datastaven/Groepen/' .. basename)
end
local function extractData(args)
-- Extract all the data we need from the args.
data = {
barWidth = args[w.barWidth] or barWidth,
truncateX = yesno(args[w.truncateX], truncateX),
invertY = yesno(args[w.invertY], invertY),
yMax = args[w.yMax] or 0,
ySuffix = args[w.ySuffix] or ySuffix,
bars = {},
groups = {},
tiers = {},
}
-- Import preset groups.
local presetGroups = importGroups(args[w.groups])
-- Extract from inline groups.
for i = 1, 20 do
local arg = args[w.group .. i]
if arg and isItem(arg) then
local group = unpackItem(arg)
if group[w.group] then
group = mergeTables(presetGroups[group[w.group]] or {}, group)
data.groups[group[w.group]] = group -- Add to our groups
group[w.label] = group[w.label] or group[w.group]
group[w.group] = nil
formatItem(group)
end
end
end
-- Extract from items.
for _, arg in ipairs(args) do
if isItem(arg) then
local bar = unpackItem(arg)
formatItem(bar)
table.insert(data.bars, bar)
if bar[w.y] then
data.yMax = math.max(data.yMax, bar[w.y])
end
if bar[w.group] and data.groups[bar[w.group]] == nil then
data.groups[bar[w.group]] = presetGroups[bar[w.group]]
or { [w.label] = bar[w.group] }
end
local tier = tonumber(pick('tier', bar))
if tier then data.tiers[tier] = true end
end
end
data.tiers = rankTiers(data.tiers)
data.tiersCount = countTiers(data.tiers)
data.chartHeight = args[w.chartHeight] or chartHeight + extraHeight * (data.tiersCount - 1)
return data
end
local function calculateBarHeight(bar)
local y = bar[w.y]
local yMax = pick('yMax', bar)
local tierRank = data.tiers[pick('tier', bar)] or 1
local h
if data.invertY then
h = y and (1 - ((y - 1) / yMax)) * 100 -- Height % (within it's tier)
if y > yMax then h = 0 end
else
h = y and y / yMax * 100
if y > yMax then h = 100 end
end
h = (h + tierRank * 100 - 100) / data.tiersCount -- Add heights of lower tiers
h = math.floor(h * 1000) / 1000 -- Truncate number
return h
end
local function pickColor(bar)
local color = pick('color', bar)
if color then return color end
-- Else, pick a color from the colors table.
color = table.remove(colors) or '#fff'
if bar[w.group] then
-- Add color to group.
data.groups[bar[w.group]][w.color] = color
end
return color
end
local function delink(text)
-- Removes (wiki)links from a text.
if not type(text) == 'string' then return text end
return _delink({ text, urls = 'no', comments = 'no', whitespace = 'no' })
end
local function drawTooltip(bar)
local text = mw.html.create()
if bar[w.x] and bar[w.x] ~= '' then text:tag('b'):wikitext(bar[w.x]) end
if bar[w.x] and bar[w.y] then text:wikitext(' ') end
if bar[w.y] then text:wikitext(bar[w.y] .. pick('ySuffix', bar)) end
if bar[w.group] then
if tostring(text) ~= '' then text:tag('br') end
text:wikitext(delink(pick('label', bar)))
if bar[w.subgroup] then text:wikitext(' ' .. bar[w.subgroup]) end
end
return mw.html.create()
:newline()
:tag('div')
:addClass('es-tip')
:node(text)
:done()
end
local function drawBars()
local bars = mw.html.create()
for _, bar in ipairs(data.bars) do
local x = bar[w.x]
local y = bar[w.y]
local h = y and calculateBarHeight(bar) .. '%'
local c = pickColor(bar)
if x and data.truncateX then x = string.sub(x, -2) end -- Show only the last two digits of the year
bars
:newline()
:tag('li')
:addClass('es-bar')
:attr('data-x', x)
:attr('data-y', y)
:css('height', h)
:css('background-color', c)
:node(drawTooltip(bar))
:newline()
end
return bars
end
local function drawLegend()
local legend = mw.html.create('div')
:addClass('es-legend')
:tag('ul')
for _, group in pairs(data.groups) do
legend
:newline()
:tag('li')
:tag('span')
:css('background-color', group[w.color] or '#fff')
:done()
:wikitext(group[w.label])
end
return legend:done()
end
local function drawChart(args)
data = extractData(args)
-- return mw.dumpObject(data)
if #data.bars == 0 then
return "''Geen data om weer te geven.''"
end
local chart = mw.html.create()
:tag('div')
:addClass('es-chart')
:css('overflow-y', 'auto')
:tag('ul')
:addClass('es-grid')
:css('width', data.barWidth * #data.bars .. 'em')
:css('height', data.chartHeight .. 'px')
:css('background', 'repeating-linear-gradient(#ccc, white 1px, white ' .. 100 / data.tiersCount .. '%)')
:node(drawBars())
:allDone()
:node(drawLegend())
return tostring(chart)
end
function p.main(frame)
local args = getArgs(frame)
-- Settings for rankings.
if args[w.type] == w.rankings then
invertY = true
barWidth = 1.5
truncateX = true
ySuffix = 'e'
end
return frame:extensionTag{ name = 'templatestyles', args = { src = templatestyles } } .. drawChart(args)
end
return p