2023年政策修订增补工作正在进行中,欢迎参与!
  • Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:Sandbox/Nzh21/sandbox

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [创建] [刷新]
local p = {}

local getArgs = require('Module:Arguments').getArgs

--           a
--   ---------------
--   \ alpha      /
--    \         /
--    b\      /
--      \   /
--       \/
local function CreateTriangle(a, b, alpha, color)
    if (alpha > 90) then error() end
    local ALPHA = alpha * math.pi / 180
    local A, B;
    if (a > math.cos(ALPHA) * b) then 
        A, B = a, b
    else 
        A, B = b, a
    end
    local outer = mw.html.create('div')
                    :css('position', 'relative')
    local inner = mw.html.create('div')
                    :css('position', 'absolute')
                    :css('border-left', tostring(math.cos(ALPHA) * B)..'px solid transparent')
                    :css('border-right', tostring(A - math.cos(ALPHA) * B)..'px solid transparent')
    mw.log(A, B, A - math.cos(ALPHA) * B)
    if (a > math.cos(ALPHA) * b) then
        inner
            :css('border-top', tostring(math.sin(ALPHA) * B)..'px solid '..color)
    else
        inner
            :css('border-bottom', tostring(math.sin(ALPHA) * B)..'px solid '..color)
            :css('transform', 'rotate('..tostring(alpha)..'deg)')
            :css('transform-origin', '0 100%')
            :css('top', tostring(-math.sin(ALPHA) * B)..'px')
    end
    outer:node(inner)
    return outer
end

local function CreateRadarChart(data, max, color, bgcolor, name, number)
    if (#name ~= #number or #data ~= #number or #data ~= #name) then error() end
    local n = #data
    local outer = mw.html.create('div')
                    :css('position', 'relative')
                    :css('width', tostring(max * 2)..'px')
                    :css('height', tostring(max * 2)..'px')
                    :css('margin', '0 auto')
    for i = 1, #data do
        local bg = CreateTriangle(max, max, 360 / n, bgcolor)
        local front = CreateTriangle(data[i], data[i % n + 1], 360 / n, color)
        local inner = mw.html.create('div')
                        :css('position', 'relative')
                        :css('transform', 'rotate('..tostring(-90 + 360 / n * (i - 1))..'deg)')
                        :css('transform-origin', '0 0')
                        :css('top', tostring(max)..'px')
                        :css('left', tostring(max)..'px')
        inner:node(bg)
        inner:node(front)
        outer:node(inner)
    end

    for i = 1, n do
        local name_tag = mw.html.create('div')
                            :css('position', 'absolute')
                            :css('top', tostring(max - math.cos(2 * math.pi / n * (i - 1)) * (max + 8))..'px')
                            :wikitext(name[i] or '')
        local number_tag = mw.html.create('div')
                            :css('position', 'absolute')
                            :css('transform', 'translate(-50%, -50%)')
                            :css('left', tostring(max + math.sin(2 * math.pi / n * (i - 1)) * (max - 10))..'px')
                            :css('top', tostring(max - math.cos(2 * math.pi / n * (i - 1)) * (max - 10))..'px')
                            :wikitext(number[i] or '')
        
        if (i % math.ceil(n / 2) == 1 or (n % 2 == 1 and i == math.ceil(n / 2))) then   -- 顶部/底部标签
            name_tag
                :css('transform', 'translate(-50%, -50%)')
                :css('left', tostring(max + math.sin(2 * math.pi / n * (i - 1)) * (max + 8))..'px')
        elseif i > n / 2 then   -- 左侧标签
            name_tag
                :css('transform', 'translate(-100%, -50%)')
                :css('left', tostring(max + math.sin(2 * math.pi / n * (i - 1)) * (max + 4))..'px')
        else    -- 右侧标签
            name_tag
                :css('transform', 'translate(100%, -50%)')
                :css('right', tostring(max * 2 - (max + math.sin(2 * math.pi / n * (i - 1)) * (max + 4)))..'px')
        end
        outer:node(name_tag)
        outer:node(number_tag)
    end

    return outer
end

local function Color(color, text)
    return '<span style="color:'..color..'">'..text..'</span>'
end

function p.main(frame)
    local args = getArgs(frame)

    local size = tonumber(args.size) or 100
    local color = args.color or '#666'
    local bgcolor = args.bgcolor or '#000'
    local width = tonumber(args.width) or size * 2
    local height = tonumber(args.height) or size * 2 
    local data = {}
    local name = {}
    local number = {}
    i = 1
    while (args['var'..tostring(i)] ~= nil) do 
        data[i] = tonumber(args['var'..tostring(i)])
        name[i] = Color(args.ftcolor or '#000', args['text'..tostring(i)] or '数据')
        if (args.num and args.num =='none') then
            number[i] = ''
        else
            number[i] = Color(args.numcolor or '#fff', args['num'..tostring(i)] or data[i])
        end
        i = i + 1
    end
    local outer = mw.html.create('div')
                    :css('width', tostring(width)..'px')
                    :css('height', tostring(height)..'px')
                    :css('padding', tostring((height - size * 2) / 2 + 30)..'px '..tostring((width - size * 2) / 2 + 30)..'px')
                    :node(CreateRadarChart(data, size, color, bgcolor, name, number))
    return outer
end

local function CreateRadarChartSvg(data, max, color, bgcolor, name, number)
    if (#name ~= #number or #data ~= #number or #data ~= #name) then error() end
    local n = #data
    local outer = mw.html.create('div')
                    :css('position', 'relative')
                    :css('width', tostring(max * 2)..'px')
                    :css('height', tostring(max * 2)..'px')
                    :css('margin', '0 auto')
    val = tostring(data[1])
    for i = 2, n, 1 do
        val = val..','..tostring(data[i])
    end
    path = 'https://api.nzh21.site/RadarChart.php?color='..color:gsub('#', 'sharp')..'&bgcolor='..bgcolor:gsub('#', 'sharp')
                ..'&max='..tostring(max)..'&val='..val
    local svg = mw.html.create('img')
                    :attr('src', path)
                    :css('width', tostring(max * 2)..'px')
                    :css('height', tostring(max * 2)..'px')
    outer:node(svg)

    for i = 1, n do
        local name_tag = mw.html.create('div')
                            :css('position', 'absolute')
                            :css('top', tostring(max - math.cos(2 * math.pi / n * (i - 1)) * (max + 8))..'px')
                            :wikitext(name[i] or '')
        local number_tag = mw.html.create('div')
                            :css('position', 'absolute')
                            :css('transform', 'translate(-50%, -50%)')
                            :css('left', tostring(max + math.sin(2 * math.pi / n * (i - 1)) * (max - 10))..'px')
                            :css('top', tostring(max - math.cos(2 * math.pi / n * (i - 1)) * (max - 10))..'px')
                            :wikitext(number[i] or '')
        
        if (i % math.ceil(n / 2) == 1 or (n % 2 == 1 and i == math.ceil(n / 2))) then   -- 顶部/底部标签
            name_tag
                :css('transform', 'translate(-50%, -50%)')
                :css('left', tostring(max + math.sin(2 * math.pi / n * (i - 1)) * (max + 8))..'px')
        elseif i > n / 2 then   -- 左侧标签
            name_tag
                :css('transform', 'translate(-100%, -50%)')
                :css('left', tostring(max + math.sin(2 * math.pi / n * (i - 1)) * (max + 4))..'px')
        else    -- 右侧标签
            name_tag
                :css('transform', 'translate(100%, -50%)')
                :css('right', tostring(max * 2 - (max + math.sin(2 * math.pi / n * (i - 1)) * (max + 4)))..'px')
        end
        outer:node(name_tag)
        outer:node(number_tag)
    end

    return outer
end

function p.SvgVersion(frame)
    local args = getArgs(frame)

    local size = tonumber(args.size) or 100
    local color = args.color or '#666'
    local bgcolor = args.bgcolor or '#000'
    local width = tonumber(args.width) or size * 2
    local height = tonumber(args.height) or size * 2 
    local data = {}
    local name = {}
    local number = {}
    i = 1
    while (args['var'..tostring(i)] ~= nil) do 
        data[i] = tonumber(args['var'..tostring(i)])
        name[i] = Color(args.ftcolor or '#000', args['text'..tostring(i)] or '数据')
        if (args.num and args.num =='none') then
            number[i] = ''
        else
            number[i] = Color(args.numcolor or '#fff', args['num'..tostring(i)] or data[i])
        end
        i = i + 1
    end
    local outer = mw.html.create('div')
                    :css('width', tostring(width)..'px')
                    :css('height', tostring(height)..'px')
                    :css('padding', tostring((height - size * 2) / 2 + 30)..'px '..tostring((width - size * 2) / 2 + 30)..'px')
                    :node(CreateRadarChartSvg(data, size, color, bgcolor, name, number))
    return outer
end

return p