Modul:Diagram rozšířený

Z Wikipedie, otevřené encyklopedie

Používá se stejně jako Modul:Diagram, umožňuje však pouze koláčový graf (pozor, musí být stále uvedeno jako parametr při volání modulu) přidává však 2 nové parametry:

  • float legendy = vlevo nebo vpravo; legenda bude napravo nebo nalevo od grafu samotného
  • sirka legendy = šířka legendy v pixelech bez px na konci
--<syntaxhighlight lang="lua">
--[[
    keywords are used for languages: they are the names of the actual
    parameters of the template
]]

local keywords = {
    pieChart = 'kolacovy',
    width = 'sirka',
    height = 'vyska',
    stack = 'na sobe',
    colors = 'barvy',
    group = 'skupina',
    xlegend = 'legenda x',
    tooltip = 'tooltip',
    accumulateTooltip = 'spojeny tooltip',
    links = 'odkazy',
    defcolor = 'default color',
    scalePerGroup = 'oddelene stupnice',
    unitsPrefix = 'jednotky pred',
    unitsSuffix = 'jednotky za',
    groupNames = 'nazvy skupin',
    groupLegendsFloat = 'float legendy',
    groupLegendsWidth = 'sirka legendy',
    hideGroupLegends = 'skryt popis skupin',
    slices = 'sektory',
    slice = 'sektor',
    radius = 'polomer',
    percent = 'procenta',
    float = 'float',
    delimiter = 'oddelovac',
    header = 'zahlavi',
    footer = 'zapati',
    left = 'vlevo',
    right = 'vpravo',
} -- here is what you want to translate

local defColors = require "Modul:Diagram/DefaultColors"
local hideGroupLegends
local groupAlign = 'none'
local groupWidth

local function nulOrWhitespace( s )
    return not s or mw.text.trim( s ) == ''
end

local function createGroupList( tab, legends, cols )
    if #legends > 1 and not hideGroupLegends then
    	local divStyle
    	if groupAlign == 'left' then
    		divStyle = 'margin-right:8px;margin-top:10px;width:'..(groupWidth)..'px;float:left;'
		elseif groupAlign == 'right' then
			divStyle = 'margin-left:8px;margin-top:10px;width:'..(groupWidth)..'px;float:right;'
		else
			divStyle = ''
		end
        table.insert( tab, mw.text.tag( 'div', { style = divStyle } ) )
        local list = {}
        local spanStyle = "padding:0 1em;background-color:%s;box-shadow:2px -1px 4px 0 silver;margin-right:0.5em;"
        for gi = 1, #legends do
            local span = mw.text.tag( 'span', { style = string.format( spanStyle, cols[gi] ) }, '&nbsp;' ) .. ' '..  legends[gi]
            table.insert( list, mw.text.tag( 'li', { style = "padding:0;"}, span ) )
        end
        table.insert( tab,
            mw.text.tag( 'ul',
                {style="width:100%;margin-left:8px;list-style:none;-webkit-column-width:12em;-moz-column-width:12em;column-width:12em;padding:0;"},
                table.concat( list, '\n' )
            )
        )
        table.insert( tab, '</div>' )
    end
end

function pieChart( frame )
    local res, imslices, args = {}, {}, frame.args
    local radius
    local values, colors, names, legends, links = {}, {}, {}, {}, {}
    if args[keywords.groupLegendsFloat] == keywords.left then
    	groupAlign = 'left'
	elseif args[keywords.groupLegendsFloat] == keywords.right then
    	groupAlign = 'right'
	end
    local delimiter = args[keywords.delimiter] or ':'
    local lang = mw.getContentLanguage()
    local float = args[keywords.float] or 'none'
    local header = args[keywords.header]
    local footer = args[keywords.footer]

    function getArg( s, def, subst, with )
        local result = args[keywords[s]] or def or ''
        if subst and with then result = mw.ustring.gsub( result, subst, with ) end
        return result
    end

    function analyzeParams()
        function addSlice( i, slice )
            local value, name, color, link = unpack( mw.text.split( slice, '%s*' .. delimiter .. '%s*' ) )
            values[i] = tonumber( lang:parseFormattedNumber( value ) )
                or error( string.format( 'Slice %d: "%s", first item("%s") could not be parsed as a number', i, value or '', sliceStr ) )
            colors[i] = not nulOrWhitespace( color ) and color or defColors[i * 2]
            names[i] = name or ''
            links[i] = link
        end
        
        radius = getArg( 'radius', 150 )
        hideGroupLegends = not nulOrWhitespace( args[keywords.hideGroupLegends] )
        local slicesStr = getArg( 'slices' )
        local prefix = getArg( 'unitsPrefix', '', '_', ' ' )
        local suffix = getArg( 'unitsSuffix', '', '_', ' ' )
        local percent = args[keywords.percent]
        local sum = 0
        local i, value = 0
        for slice in mw.ustring.gmatch( slicesStr or '', "%b()" ) do
            i = i + 1
            addSlice( i, mw.ustring.match( slice, '^%(%s*(.-)%s*%)$' ) )
        end
        
        for k, v in pairs(args) do
            local ind = mw.ustring.match( k, '^' .. keywords.slice .. '%s+(%d+)$' )
            if ind then addSlice( tonumber( ind ), v ) end
        end
        
        for _, val in ipairs( values ) do sum = sum + val end
        for i, value in ipairs( values ) do
            local addprec = percent and string.format( ' (%0.1f&nbsp;%%)', value / sum * 100 ) or ''
            legends[i] = mw.ustring.format( '%s: %s%s%s%s', names[i], prefix, lang:formatNum( value ), suffix, addprec )
            links[i] = mw.text.trim( links[i] or mw.ustring.format( '[[#noSuchAnchor|%s]]', legends[i] ) )
        end
    end

    function addRes( ... )
        for _, v in pairs( { ... } ) do
            table.insert( res, v )
        end
    end

    function createImageMap()
        addRes( '{{#tag:imagemap|', 'Image:Circle frame.svg{{!}}' .. ( radius * 2 ) .. 'px' )
        addRes( unpack( imslices ) )
        addRes( 'desc none', '}}' )
    end

    function drawSlice( i, q, start )
        local color = colors[i]
        local angle = ( .25 - start ) * 2 * math.pi
        local sin, cos = math.abs( math.sin( angle ) ), math.abs( math.cos( angle ) )
        local wsin, wcos = sin * radius, cos * radius
        local s1, s2, w1, w2, w3, w4, width, border
        local style
        if q == 1 then
            border = 'bottom'
            w1, w2, w3, w4 = 0, 0, wsin, wcos
            s1, s2 = 'bottom', 'left'
        elseif q == 4 then
            border = 'right'
            w1, w2, w3, w4 = 0, wcos, wsin, 0
            s1, s2 = 'bottom', 'right'
        elseif q == 3 then
            border = 'top'
            w1, w2, w3, w4 = wsin, wcos, 0, 0
            s1, s2 = 'top', 'right'
        else
            border = 'left'
            w1, w2, w3, w4 = wsin, 0, 0, wcos
            s1, s2 = 'top', 'left'
        end

        local style = string.format( 'position:absolute;%s:%spx;%s:%spx;width:%spx;height:%spx', s1, radius, s2, radius, radius, radius )
        if start <= ( q - 1 ) * 0.25 then
            style = string.format( '%s;border:0;background-color:%s', style, color )
        else
            style = string.format( '%s;border-width:%spx %spx %spx %spx;border-%s-color:%s', style, w1, w2, w3, w4, border, color )
        end
        addRes( mw.text.tag( 'div', { class = 'transborder', style = 'border: medium solid transparent; ' .. style }, '' ) )
    end

    function createSlices()
        function coordsOfAngle( angle )
            return ( 100 + math.floor( 100 * math.cos( angle ) ) ) .. ' ' .. ( 100 - math.floor( 100 * math.sin( angle ) ) )
        end

        local sum, start = 0, 0
        for _, value in ipairs( values ) do sum = sum + value end
        for i, value in ipairs(values) do
            local poly = { 'poly 100 100' }
            local startC, endC =  start / sum, ( start + value ) / sum
            local startQ, endQ = math.floor( startC * 4 + 1 ), math.floor( endC * 4 + 1 )
            for q = startQ, math.min( endQ, 4 ) do drawSlice( i, q, startC ) end
            for angle = ( .25 - startC ) * 2 * math.pi, ( .25 - endC ) * 2 * math.pi, -0.02 do
                table.insert( poly,  coordsOfAngle( angle ) )
            end
            table.insert( poly, coordsOfAngle( ( .25 - endC ) * 2 * math.pi ) .. ' 100 100 ' .. links[i] )
            table.insert( imslices, table.concat( poly, ' ' ) )
            start = start + values[i]
        end
    end

    analyzeParams()
    local width
    groupWidth = args[keywords.groupLegendsWidth] or (radius * 2)
    if groupAlign == 'none' then width = radius * 2 else width = (radius * 2 + groupWidth + 10) end
    if #values == 0 then error( "no slices found - can't draw pie chart" ) end
    addRes( mw.text.tag( 'div', { style = string.format( "max-width:%spx;float:%s;", width, float ) } ) )
    if header then addRes( '<div style="font-weight:bold;text-align:center;vertical-align:middle;">' .. header .. '</div>' ) end
    addRes( mw.text.tag( 'div', { style = string.format( 'position:relative;min-width:%spx;min-height:%spx;max-width:%spx;overflow:hidden;display:inline-block;', radius * 2, radius * 2, radius * 2 ) } ) )
    createSlices()
    addRes( mw.text.tag( 'div', { style = string.format( 'position:absolute;min-width:%spx;min-height:%spx;overflow:hidden;', radius * 2, radius * 2 ) } ) )
    createImageMap()
    addRes( '</div>' ) -- close "position:relative" div that contains slices and imagemap.
    addRes( '</div>' ) -- close "position:relative" div that contains slices and imagemap.
    createGroupList( res, legends, colors ) -- legends
    addRes( '</div>') -- close containing div
    if footer then addRes( '<div style="text-align:center">' .. footer .. '</div>' ) end
    return frame:preprocess( table.concat( res, '\n' ) )
end

return {
    [keywords.pieChart] = pieChart,
}
--</syntaxhighlight>