打开/关闭搜索
搜索
打开/关闭菜单
1.1K
4.5K
75
18.1K
Cookie☆Wiki
导航
首页
最近更改
随机页面
帮助
沙盒
特殊页面
上传文件
常用
曲奇简介
用语列表
人物一览
曲奇团体
曲奇年表
本篇列表
榜单列表
专辑列表
创作
音MAD
曲奇静画
曲奇实况
曲奇素材
BB剧场
漫画
同人游戏
曲奇实况
中华曲奇
本篇列表
人物列表
搬运者列表
汉化组列表
友情链接
Cookie☆贴吧
真夏夜的银梦贴吧
中文音MAD维基
潮学维基
银饼视频搜索站
中文曲奇维基Fandom站[已弃用]
通知
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。
user-interface-preferences
个人工具
创建账号
登录
查看“模块:Chart”的源代码
来自Cookie☆Wiki
查看
阅读
查看源代码
查看历史
associated-pages
模块
讨论
更多操作
←
模块:Chart
因为以下原因,您没有权限编辑该页面:
您请求的操作仅限属于该用户组的用户执行:
用户
您可以查看和复制此页面的源代码。
--<source lang=lua> -- 来自:https://en.wikipedia.org/wiki/Module:Chart --[[ keywords are used for languages: they are the names of the actual parameters of the template keywords 是外部调用时实际的参数名称 ]] local keywords = { -- 不做翻译,使用方法见文档 barChart = 'bar chart', pieChart = 'pie chart', width = 'width', height = 'height', stack = 'stack', colors = 'colors', group = 'group', xlegend = 'x legends', tooltip = 'tooltip', accumulateTooltip = 'tooltip value accumulation', links = 'links', defcolor = 'default color', scalePerGroup = 'scale per group', unitsPrefix = 'units prefix', unitsSuffix = 'units suffix', groupNames = 'group names', hideGroupLegends = 'hide group legends', slices = 'slices', slice = 'slice', radius = 'radius', percent = 'percent', } -- here is what you want to translate local defColors = require "Module:Chart/DefaultColors" -- 原先为 "Module:Plotter/DefaultColors" local hideGroupLegends 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 table.insert( tab, mw.text.tag( 'div' ) ) local list = {} local spanStyle = "padding:0 1em;background-color:%s;border:1px solid %s;margin-right:1em;-webkit-print-color-adjust:exact;" for gi = 1, #legends do local span = mw.text.tag( 'span', { style = string.format( spanStyle, cols[gi], cols[gi] ) }, ' ' ) .. ' '.. legends[gi] table.insert( list, mw.text.tag( 'li', {}, span ) ) end table.insert( tab, mw.text.tag( 'ul', {style="width:100%;list-style:none;-webkit-column-width:12em;-moz-column-width:12em;column-width:12em;"}, 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 = {}, {}, {}, {}, {} local delimiter = args.delimiter or ':' local lang = mw.getContentLanguage() 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%%)', 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 = 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 = 'left' w1, w2, w3, w4 = 0, 0, wsin, wcos s1, s2 = 'bottom', 'left' elseif q == 2 then border = 'bottom' w1, w2, w3, w4 = 0, wcos, wsin, 0 s1, s2 = 'bottom', 'right' elseif q == 3 then border = 'right' w1, w2, w3, w4 = wsin, wcos, 0, 0 s1, s2 = 'top', 'right' else border = 'top' 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 = 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 = startC * 2 * math.pi, endC * 2 * math.pi, 0.02 do table.insert( poly, coordsOfAngle( angle ) ) end table.insert( poly, coordsOfAngle( endC * 2 * math.pi ) .. ' 100 100 ' .. links[i] ) table.insert( imslices, table.concat( poly, ' ' ) ) start = start + values[i] end end analyzeParams() if #values == 0 then error( "no slices found - can't draw pie chart" ) end addRes( mw.text.tag( 'div', { class = 'chart noresize', style = string.format( 'margin-top:0.5em;max-width:%spx;', radius * 2 ) } ) ) addRes( mw.text.tag( 'div', { style = string.format( 'position:relative;min-width:%spx;min-height:%spx;max-width:%spx;overflow:hidden;', 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 return frame:preprocess( table.concat( res, '\n' ) ) end function barChart( frame ) local res = {} local args = frame.args -- can be changed to frame:getParent().args local values, xlegends, colors, tooltips, yscales = {}, {}, {}, {} ,{}, {}, {} local groupNames, unitsSuffix, unitsPrefix, links = {}, {}, {}, {} local width, height, stack, delimiter = 500, 350, false, args.delimiter or ':' local chartWidth, chartHeight, defcolor, scalePerGroup, accumulateTooltip local numGroups, numValues local scaleWidth function validate() function asGroups( name, tab, toDuplicate, emptyOK ) if #tab == 0 and not emptyOK then error( "must supply values for " .. keywords[name] ) end if #tab == 1 and toDuplicate then for i = 2, numGroups do tab[i] = tab[1] end end if #tab > 0 and #tab ~= numGroups then error ( keywords[name] .. ' must contain the same number of items as the number of groups, but it contains ' .. #tab .. ' items and there are ' .. numGroups .. ' groups') end end -- do all sorts of validation here, so we can assume all params are good from now on. -- among other things, replace numerical values with mw.language:parseFormattedNumber() result chartHeight = height - 80 numGroups = #values numValues = #values[1] defcolor = defcolor or 'blue' colors[1] = colors[1] or defcolor scaleWidth = scalePerGroup and 80 * numGroups or 100 chartWidth = width -scaleWidth asGroups( 'unitsPrefix', unitsPrefix, true, true ) asGroups( 'unitsSuffix', unitsSuffix, true, true ) asGroups( 'colors', colors, true, true ) asGroups( 'groupNames', groupNames, false, false ) if stack and scalePerGroup then error( string.format( 'Illegal settings: %s and %s are incompatible.', keyword.stack, keyword.scalePerGroup ) ) end for gi = 2, numGroups do if #values[gi] ~= numValues then error( keywords.group .. " " .. gi .. " does not have same number of values as " .. keywords.group .. " 1" ) end end if #xlegends ~= numValues then error( 'Illegal number of ' .. keywords.xlegend .. '. Should be exactly ' .. numValues ) end end function extractParams() function testone( keyword, key, val, tab ) i = keyword == key and 0 or key:match( keyword .. "%s+(%d+)" ) if not i then return end i = tonumber( i ) or error("Expect numerical index for key " .. keyword .. " instead of '" .. key .. "'") if i > 0 then tab[i] = {} end for s in mw.text.gsplit( val, '%s*' .. delimiter .. '%s*' ) do table.insert( i == 0 and tab or tab[i], s ) end return true end for k, v in pairs( args ) do if k == keywords.width then width = tonumber( v ) if not width or width < 200 then error( 'Illegal width value (must be a number, and at least 200): ' .. v ) end elseif k == keywords.height then height = tonumber( v ) if not height or height < 200 then error( 'Illegal height value (must be a number, and at least 200): ' .. v ) end elseif k == keywords.stack then stack = true elseif k == keywords.scalePerGroup then scalePerGroup = true elseif k == keywords.defcolor then defcolor = v elseif k == keywords.accumulateTooltip then accumulateTooltip = not nulOrWhitespace( v ) elseif k == keywords.hideGroupLegends then hideGroupLegends = not nulOrWhitespace( v ) else for keyword, tab in pairs( { group = values, xlegend = xlegends, colors = colors, tooltip = tooltips, unitsPrefix = unitsPrefix, unitsSuffix = unitsSuffix, groupNames = groupNames, links = links, } ) do if testone( keywords[keyword], k, v, tab ) then break end end end end end function roundup( x ) -- returns the next round number: eg., for 30 to 39.999 will return 40, for 3000 to 3999.99 wil return 4000. for 10 - 14.999 will return 15. local ordermag = 10 ^ math.floor( math.log10( x ) ) local normalized = x / ordermag local top = normalized >= 1.5 and ( math.floor( normalized + 1 ) ) or 1.5 return ordermag * top, top, ordermag end function calcHeightLimits() -- if limits were passed by user, use them, otherwise calculate. for "stack" there's only one limet. if stack then local sums = {} for _, group in pairs( values ) do for i, val in ipairs( group ) do sums[i] = ( sums[i] or 0 ) + val end end local sum = math.max( unpack( sums ) ) for i = 1, #values do yscales[i] = sum end else for i, group in ipairs( values ) do yscales[i] = math.max( unpack( group ) ) end end for i, scale in ipairs( yscales ) do yscales[i] = roundup( scale * 0.9999 ) end if not scalePerGroup then for i = 1, #values do yscales[i] = math.max( unpack( yscales ) ) end end end function tooltip( gi, i, val ) if tooltips and tooltips[gi] and not nulOrWhitespace( tooltips[gi][i] ) then return tooltips[gi][i], true end local groupName = not nulOrWhitespace( groupNames[gi] ) and groupNames[gi] .. ': ' or '' local prefix = unitsPrefix[gi] or unitsPrefix[1] or '' local suffix = unitsSuffix[gi] or unitsSuffix[1] or '' return mw.ustring.gsub(groupName .. prefix .. mw.getContentLanguage():formatNum( tonumber( val ) or 0 ) .. suffix, '_', ' '), false end function calcHeights( gi, i, val ) local barHeight = math.floor( val / yscales[gi] * chartHeight + 0.5 ) -- add half to make it "round" instead of "trunc" local top, base = chartHeight - barHeight, 0 if stack then local rawbase = 0 for j = 1, gi - 1 do rawbase = rawbase + values[j][i] end -- sum the "i" value of all the groups below our group, gi. base = math.floor( chartHeight * rawbase / yscales[gi] ) -- normally, and especially if it's "stack", all the yscales must be equal. end return barHeight, top - base end function groupBounds( i ) local setWidth = math.floor( chartWidth / numValues ) local setOffset = ( i - 1 ) * setWidth return setOffset, setWidth end function calcx( gi, i ) local setOffset, setWidth = groupBounds( i ) if stack or numGroups == 1 then local barWidth = math.min( 38, math.floor( 0.8 * setWidth ) ) return setOffset + (setWidth - barWidth) / 2, barWidth end setWidth = 0.85 * setWidth local barWidth = math.floor( 0.75 * setWidth / numGroups ) local left = setOffset + math.floor( ( gi - 1 ) / numGroups * setWidth ) return left, barWidth end function drawbar( gi, i, val, ttval ) if val == '0' then return end -- do not show single line (borders....) if value is 0, or rather, '0'. see talkpage local color, tooltip, custom = colors[gi] or defcolor or 'blue', tooltip( gi, i, ttval or val ) local left, barWidth = calcx( gi, i ) local barHeight, top = calcHeights( gi, i, val ) -- borders so it shows up when printing local style = string.format("position:absolute;left:%spx;top:%spx;height:%spx;min-width:%spx;max-width:%spx;background-color:%s;-webkit-print-color-adjust:exact;border:1px solid %s;border-bottom:none;overflow:hidden;", left, top, barHeight-1, barWidth-2, barWidth-2, color, color) local link = links[gi] and links[gi][i] or '' local img = not nulOrWhitespace( link ) and mw.ustring.format( '[[File:Transparent.png|1000px|link=%s|%s]]', link, custom and tooltip or '' ) or '' table.insert( res, mw.text.tag( 'div', { style = style, title = tooltip, }, img ) ) end function drawYScale() function drawSingle( gi, color, width, single ) local yscale = yscales[gi] local _, top, ordermag = roundup( yscale * 0.999 ) local numnotches = top <= 1.5 and top * 4 or top < 4 and top * 2 or top local valStyleStr = single and 'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;padding:0 2px' or 'position:absolute;height=20px;text-align:right;vertical-align:middle;width:%spx;top:%spx;left:3px;background-color:%s;color:white;font-weight:bold;text-shadow:-1px -1px 0 #000,1px -1px 0 #000,-1px 1px 0 #000,1px 1px 0 #000;padding:0 2px' local notchStyleStr = 'position:absolute;height=1px;min-width:5px;top:%spx;left:%spx;border:1px solid %s;' for i = 1, numnotches do local val = i / numnotches * yscale local y = chartHeight - calcHeights( gi, 1, val ) local div = mw.text.tag( 'div', { style = string.format( valStyleStr, width - 10, y - 10, color ) }, mw.getContentLanguage():formatNum( tonumber( val ) or 0 ) ) table.insert( res, div ) div = mw.text.tag( 'div', { style = string.format( notchStyleStr, y, width - 4, color ) }, '' ) table.insert( res, div ) end end if scalePerGroup then local colWidth = 80 local colStyle = "position:absolute;height:%spx;min-width:%spx;left:%spx;border-right:1px solid %s;color:%s" for gi = 1, numGroups do local left = ( gi - 1 ) * colWidth local color = colors[gi] or defcolor table.insert( res, mw.text.tag( 'div', { style = string.format( colStyle, chartHeight, colWidth, left, color, color ) } ) ) drawSingle( gi, color, colWidth ) table.insert( res, '</div>' ) end else drawSingle( 1, 'black', scaleWidth, true ) end end function drawXlegends() local setOffset, setWidth local legendDivStyleFormat = "position:absolute;left:%spx;top:10px;min-width:%spx;max-width:%spx;text-align:center;vertical-align:top;" local tickDivstyleFormat = "position:absolute;left:%spx;height:10px;width:1px;border-left:1px solid black;" for i = 1, numValues do if not nulOrWhitespace( xlegends[i] ) then setOffset, setWidth = groupBounds( i ) -- setWidth = 0.85 * setWidth table.insert( res, mw.text.tag( 'div', { style = string.format( legendDivStyleFormat, setOffset + 5, setWidth - 10, setWidth - 10 ) }, xlegends[i] or '' ) ) table.insert( res, mw.text.tag( 'div', { style = string.format( tickDivstyleFormat, setOffset + setWidth / 2 ) }, '' ) ) end end end function drawChart() table.insert( res, mw.text.tag( 'div', { class = 'chart noresize', style = string.format( 'margin-top:1em;max-width:%spx;', width ) } ) ) table.insert( res, mw.text.tag( 'div', { style = string.format("position:relative;min-height:%spx;min-width:%spx;max-width:%spx;", height, width, width ) } ) ) table.insert( res, mw.text.tag( 'div', { style = string.format("float:right;position:relative;min-height:%spx;min-width:%spx;max-width:%spx;border-left:1px black solid;border-bottom:1px black solid;", chartHeight, chartWidth, chartWidth ) } ) ) local acum = stack and accumulateTooltip and {} for gi, group in pairs( values ) do for i, val in ipairs( group ) do if acum then acum[i] = ( acum[i] or 0 ) + val end drawbar( gi, i, val, acum and acum[i] ) end end table.insert( res, '</div>' ) table.insert( res, mw.text.tag( 'div', { style = string.format("position:absolute;height:%spx;min-width:%spx;max-width:%spx;", chartHeight, scaleWidth, scaleWidth, scaleWidth ) } ) ) drawYScale() table.insert( res, '</div>' ) table.insert( res, mw.text.tag( 'div', { style = string.format( "position:absolute;top:%spx;left:%spx;width:%spx;", chartHeight, scaleWidth, chartWidth ) } ) ) drawXlegends() table.insert( res, '</div>' ) table.insert( res, '</div>' ) createGroupList( res, groupNames, colors ) table.insert( res, '</div>' ) end extractParams() validate() calcHeightLimits() drawChart() return table.concat( res, "\n" ) end return { ['bar-chart'] = barChart, [keywords.barChart] = barChart, [keywords.pieChart] = pieChart, } --</source>
该页面使用的模板:
模块:Chart/doc
(
查看源代码
)
返回
模块:Chart
。