Módulo:Graph 2

Fonte: Wikinotícias
Documentação Documentação de módulo
Essa é uma versão alternativa de Módulo:Graph. Ele cria gráficos ({{gráfico}}) usando apenas CSS. Algumas funções adicionais estão disponíveis. Verifique Wikinotícias:Redação/Gráficos quebrados (05/06/2023) para mais detalhes.
Esta documentação se encontra na subpágina Módulo:Graph 2/doc (editar | histórico)
Por favor inclua as categorias à subpágina /doc. Subpáginas deste módulo.

local p = {}
--gráfico de barras
function p.rect(frame)
    local width = frame.args.width or ''
    local height = frame.args.height or ''
    local y = frame.args.y or ''
    local colors = frame.args.colors or ''
    local fontcolor = frame.args.fontcolor or ''

    local html = mw.html.create()
    local container = html:tag('div')
    container:css('width', width .. 'px')
    container:css('height', height .. 'px')
    container:css('display', 'flex')
    container:css('justify-content', 'space-between')
    container:css('align-items', 'flex-end')
    container:css('color', fontcolor)

    local yValues = mw.text.split(y, ',')
    local dataSize = #yValues
    local maxY = 0
    for i = 1, dataSize do
        local yValue = tonumber(yValues[i]) or 0
        maxY = math.max(maxY, yValue)
    end

    for i = 1, dataSize do
        local bar = container:tag('div')
        bar:css('min-width', '30px')
        bar:css('margin', '.1em')
        bar:css('height', (yValues[i] * 100 / maxY) .. '%')
        bar:css('background', colors)
        local text = mw.html.create('span')
        text:wikitext(yValues[i])
        bar:wikitext(tostring(text))
    end

    return tostring(html)
end
--gráfico de área
function p.area(frame)
    local args = frame.args
    local width = args.width or ''
    local height = args.height or ''
    local opacity = args.opacity or ''
    local colors = args.colors or ''
    local wValues = args.w and mw.text.split(args.w, ',') or {}
    local yValues = args.y and mw.text.split(args.y, ',') or {}

    local maxW = math.max(unpack(wValues))
    local scale = 100 / maxW
    local html = mw.html.create()
    local table = html:tag('table')
    table:attr('style', 'border-collapse: collapse;')
    local row = table:tag('tr')
    local numValues = #yValues

    if numValues > 1 then
        for i = 1, numValues - 1 do
            local y = yValues[i]
            local w = wValues[i]
            local invertedY = tostring(100 - tonumber(y) * scale)
            local invertedY2 = tostring(100 - tonumber(yValues[i + 1]) * scale)
            row:tag('td')
                :css('min-width', width .. 'px')
                :css('height', height .. 'px')
                :css('opacity', opacity)
                :css('background', colors)
                :css('clip-path', 'polygon(0% ' .. invertedY .. '%, 100% ' .. invertedY2 .. '%, 100% 100%, 0% 100%)')
        end
    end

    return tostring(html)
end
--gráfico circular
function p.pie(frame)
    local width = frame.args.width or ''
    local height = frame.args.height or ''
    local y = frame.args.y or ''
    local colors = frame.args.colors or ''

    local html = mw.html.create()
    local container = html:tag('div')
    container:css('width', width .. 'px')
    container:css('height', height .. 'px')
    container:css('border-radius', '50%')
    container:css('background', 'conic-gradient(' .. generateConicGradient(y, colors) .. ')')
    container:css('display', 'block')

    return tostring(html)
end

function generateConicGradient(y, colors)
    local yValues = mw.text.split(y, ',')
    local colorValues = mw.text.split(colors, ',')
    local dataSize = math.min(#yValues, #colorValues)

    local total = 0
    for i = 1, dataSize do
        total = total + (tonumber(yValues[i]) or 0)
    end
    local anglePerUnit = 360 / total
    local conicGradient = ''
    local accumulatedAngle = 0
    for i = 1, dataSize do
        local angle = (tonumber(yValues[i]) or 0) * anglePerUnit
        local endAngle = accumulatedAngle + angle
        conicGradient = conicGradient .. colorValues[i] .. ' ' .. accumulatedAngle .. 'deg ' .. endAngle .. 'deg, '
        accumulatedAngle = endAngle
    end

    conicGradient = conicGradient:sub(1, -3)

    return conicGradient
end
--gráfico de linha
function p.line(frame)
    local args = frame.args
    local width = args.width or ''
    local height = args.height or ''
    local opacity = args.opacity or ''
    local colors = args.colors or ''
    local wValues = args.w and mw.text.split(args.w, ',') or {}
    local yValues = args.y and mw.text.split(args.y, ',') or {}

    local maxW = math.max(unpack(wValues))
    local scale = 100 / maxW
    local html = mw.html.create()
    local table = html:tag('table')
    table:attr('style', 'border-collapse: collapse;')
    local row = table:tag('tr')
    local numValues = #yValues

    if numValues > 1 then
        for i = 1, numValues - 1 do
            local y = yValues[i]
            local w = wValues[i]
            local invertedY = tostring(100 - tonumber(y) * scale)
            local invertedY2 = tostring(100 - tonumber(yValues[i + 1]) * scale)
            local inverted3 = tostring(tonumber(invertedY) + 1)
            local inverted4 = tostring(tonumber(invertedY2) + 1)
            row:tag('td')
                :css('min-width', width .. 'px')
                :css('height', height .. 'px')
                :css('opacity', opacity)
                :css('background', colors)
                :css('clip-path', 'polygon(0% ' .. invertedY .. '%, 100% ' .. invertedY2 .. '%, 100% ' .. inverted4 .. '%, 0% ' .. inverted3 .. '%)')
        end
    end

    return tostring(html)
end
--legendas
function p.legenda(frame)
    local args = frame.args
    local xValues = args.x and mw.text.split(args.x, ",") or {}
    local colors = args.colors and mw.text.split(args.colors, ",") or {}
    local output = mw.html.create('table')

    for i, x in ipairs(xValues) do
        local color = colors[i] or ""
        local row = output:tag('tr')
        local th1 = row:tag('th')
        th1:wikitext('<div style="width: 8px; height: 8px; background: ' .. color .. '; border-radius: 50%;"></div>')
        row:tag('th'):css('white-space', 'nowrap'):wikitext(x)
    end

    return tostring(output)
end
--legendas com porcentagem
function p.conta(frame)
    local args = frame.args
    local xValues = args.x and mw.text.split(args.x, ",") or {}
    local yValues = args.y and mw.text.split(args.y, ",") or {}
    local colors = args.colors and mw.text.split(args.colors, ",") or {}
    local total = 0
    local output = mw.html.create('table')

    for i, y in ipairs(yValues) do
        total = total + tonumber(y)
    end

    for i, x in ipairs(xValues) do
        local color = colors[i] or ""
        local y = tonumber(yValues[i]) or 0
        local percentage = total > 0 and y / total * 100 or 0
        local row = output:tag('tr')
        local th1 = row:tag('th')
        th1:wikitext('<div style="width: 8px; height: 8px; background: ' .. color .. '; border-radius: 50%;"></div>')
        row:tag('th'):css('white-space', 'nowrap')
            :wikitext(x .. ' (' .. string.format("%.2f", percentage) .. '%)')
    end

    return tostring(output)
end
--quantos números
function p.quantos(frame)
    local y = frame.args.y or ''
    local yValues = mw.text.split(y, ',')
    local dataSize = #yValues
    return dataSize
end
--valores para coluna
function p.x(frame)
    local width = frame.args.width or ''
    local x = frame.args.x or ''

    local html = mw.html.create()
    local container = html:tag('div')
    container:css('width', width .. 'px')
    container:css('display', 'flex')
    container:css('justify-content', 'space-between')
    container:css('align-items', 'flex-end')

    local xValues = mw.text.split(x, ',')
    local dataSize = #xValues

    for i = 1, dataSize do
        local bar = container:tag('div')
        bar:wikitext(xValues[i])
        if i == 1 then
        end
    end

    return tostring(html)
end
--números para lateral
function p.val(frame)
    local x = frame.args.x or ''
    local height = frame.args.height or ''
    local values = mw.text.split(x, ',')
    local formattedValues = {}

    if #values >= 3 then
        local min = math.min(unpack(values))
        local max = math.max(unpack(values))
        local middleIndex = math.ceil(#values / 2)
        local middleValue = max / 2
        local formattedMaxValue = '<div style="justify-content: flex-start; display: flex; flex-direction: column; height: ' .. tonumber(height) / 3 .. 'px">' .. max .. '</div>'
        local formattedMiddleValue = '<div style="justify-content: center; display: flex; flex-direction: column; height: ' .. tonumber(height) / 3 .. 'px">' .. middleValue .. '</div>'
        local formattedMinValue = '<div style="justify-content: flex-end; display: flex; flex-direction: column; height: ' .. tonumber(height) / 3 .. 'px">' .. min .. '</div>'
        table.insert(formattedValues, formattedMaxValue)
        table.insert(formattedValues, formattedMiddleValue)
        table.insert(formattedValues, formattedMinValue)
    end

    local result = table.concat(formattedValues, ' ')
    local finalResult = result
    return finalResult
end
--valores inferiores
function p.vai(frame)
    local x = frame.args.x or ''
    local values = mw.text.split(x, ',')
    local formattedValues = {}

    if #values >= 3 then
        local firstValue = values[1]
        local middleValue = values[math.ceil(#values / 2)]
        local lastValue = values[#values]
        local formattedFirstValue = '<div style="text-align: left; width: 33%">' .. firstValue .. '</div>'
        local formattedMiddleValue = '<div style="text-align: center; width: 33%">' .. middleValue .. '</div>'
        local formattedLastValue = '<div style="text-align: right; width: 33%">' .. lastValue .. '</div>'
        table.insert(formattedValues, formattedFirstValue)
        table.insert(formattedValues, formattedMiddleValue)
        table.insert(formattedValues, formattedLastValue)
    end

    local result = table.concat(formattedValues, ' ')
    local finalResult = '<div style="display: flex;">' .. result .. '</div>'
    return finalResult
end

return p