יחידה:גרפים: הבדלים בין גרסאות בדף
אין תקציר עריכה |
עדכון הקוד מהעדכונים שנעשו בויקיפדיה האנגלית |
||
| שורה 59: | שורה 59: | ||
'#FF5005', | '#FF5005', | ||
} | } | ||
local hideGroupLegends | |||
local function nulOrWhitespace( s ) | local function nulOrWhitespace( s ) | ||
| שורה 65: | שורה 67: | ||
local function createGroupList( tab, legends, cols ) | local function createGroupList( tab, legends, cols ) | ||
if #legends > 1 then | if #legends > 1 and not hideGroupLegends then | ||
table.insert( tab, mw.text.tag( 'div' ) ) | table.insert( tab, mw.text.tag( 'div' ) ) | ||
local list = {} | local list = {} | ||
local spanStyle = "padding:0 1em;background-color:%s; | 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 | for gi = 1, #legends do | ||
local span = mw.text.tag( 'span', { style = string.format( spanStyle, cols[gi] ) }, ' ' ) .. ' '.. legends[gi] | local span = mw.text.tag( 'span', { style = string.format( spanStyle, cols[gi], cols[gi] ) }, ' ' ) .. ' '.. legends[gi] | ||
table.insert( list, mw.text.tag( 'li', {}, span ) ) | table.insert( list, mw.text.tag( 'li', {}, span ) ) | ||
end | end | ||
table.insert( tab, | table.insert( tab, | ||
mw.text.tag( 'ul', | 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.concat( list, '\n' ) | ||
) | ) | ||
| שורה 88: | שורה 89: | ||
local radius | local radius | ||
local values, colors, names, legends, links = {}, {}, {}, {}, {} | local values, colors, names, legends, links = {}, {}, {}, {}, {} | ||
local delimiter = args | local delimiter = args.delimiter or ':' | ||
local lang = mw.getContentLanguage() | local lang = mw.getContentLanguage() | ||
| שורה 101: | שורה 102: | ||
local value, name, color, link = unpack( mw.text.split( slice, '%s*' .. delimiter .. '%s*' ) ) | local value, name, color, link = unpack( mw.text.split( slice, '%s*' .. delimiter .. '%s*' ) ) | ||
values[i] = tonumber( lang:parseFormattedNumber( value ) ) | values[i] = tonumber( lang:parseFormattedNumber( value ) ) | ||
or error( string.format( 'Slice %d: | 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] | colors[i] = not nulOrWhitespace( color ) and color or defColors[i * 2] | ||
names[i] = name or '' | names[i] = name or '' | ||
links[i] = link | links[i] = link | ||
| שורה 108: | שורה 109: | ||
radius = getArg( 'radius', 150 ) | radius = getArg( 'radius', 150 ) | ||
hideGroupLegends = not nulOrWhitespace( args[keywords.hideGroupLegends] ) | |||
local slicesStr = getArg( 'slices' ) | local slicesStr = getArg( 'slices' ) | ||
local prefix = getArg( 'unitsPrefix', '', '_', ' ' ) | local prefix = getArg( 'unitsPrefix', '', '_', ' ' ) | ||
| שורה 128: | שורה 130: | ||
local addprec = percent and string.format( ' (%0.1f%%)', value / sum * 100 ) or '' | 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 ) | 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]]', | links[i] = mw.text.trim( links[i] or mw.ustring.format( '[[#noSuchAnchor|%s]]', legends[i] ) ) | ||
end | end | ||
end | end | ||
| שורה 201: | שורה 203: | ||
analyzeParams() | analyzeParams() | ||
if #values == 0 then error( "no slices found - can't draw pie chart" ) end | if #values == 0 then error( "no slices found - can't draw pie chart" ) end | ||
addRes( mw.text.tag( 'div', { style = string.format( | addRes( mw.text.tag( 'div', { class = 'chart', 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 ) } ) ) | 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() | createSlices() | ||
| שורה 219: | שורה 221: | ||
local values, xlegends, colors, tooltips, yscales = {}, {}, {}, {} ,{}, {}, {} | local values, xlegends, colors, tooltips, yscales = {}, {}, {}, {} ,{}, {}, {} | ||
local groupNames, unitsSuffix, unitsPrefix, links = {}, {}, {}, {} | local groupNames, unitsSuffix, unitsPrefix, links = {}, {}, {}, {} | ||
local width, height, stack, delimiter | local width, height, stack, delimiter = 500, 350, false, args.delimiter or ':' | ||
local chartWidth, chartHeight, defcolor, scalePerGroup | local chartWidth, chartHeight, defcolor, scalePerGroup, accumulateTooltip | ||
| שורה 228: | שורה 229: | ||
function validate() | function validate() | ||
function asGroups( name, tab, toDuplicate, emptyOK | function asGroups( name, tab, toDuplicate, emptyOK ) | ||
if #tab == 0 and not emptyOK then | if #tab == 0 and not emptyOK then | ||
error( "must supply values for " .. keywords[name] ) | error( "must supply values for " .. keywords[name] ) | ||
| שורה 235: | שורה 236: | ||
for i = 2, numGroups do tab[i] = tab[1] end | for i = 2, numGroups do tab[i] = tab[1] end | ||
end | end | ||
if #tab > 0 and #tab ~= numGroups then | if #tab > 0 and #tab ~= numGroups then | ||
error ( keywords[name] .. ' | 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 | ||
end | end | ||
| שורה 249: | שורה 249: | ||
numValues = #values[1] | numValues = #values[1] | ||
defcolor = defcolor or 'blue' | defcolor = defcolor or 'blue' | ||
colors[1] = colors[1] or | colors[1] = colors[1] or defcolor | ||
scaleWidth = scalePerGroup and 80 * numGroups or 100 | scaleWidth = scalePerGroup and 80 * numGroups or 100 | ||
chartWidth = width -scaleWidth | chartWidth = width -scaleWidth | ||
asGroups( 'unitsPrefix', unitsPrefix, true, true ) | asGroups( 'unitsPrefix', unitsPrefix, true, true ) | ||
asGroups( 'unitsSuffix', unitsSuffix, true, true ) | asGroups( 'unitsSuffix', unitsSuffix, true, true ) | ||
asGroups( 'colors', colors, | asGroups( 'colors', colors, true, true ) | ||
asGroups( 'groupNames', groupNames, false, false ) | asGroups( 'groupNames', groupNames, false, false ) | ||
if stack and scalePerGroup then | if stack and scalePerGroup then | ||
| שורה 262: | שורה 262: | ||
if #values[gi] ~= numValues then error( keywords.group .. " " .. gi .. " does not have same number of values as " .. keywords.group .. " 1" ) end | if #values[gi] ~= numValues then error( keywords.group .. " " .. gi .. " does not have same number of values as " .. keywords.group .. " 1" ) end | ||
end | end | ||
if #xlegends ~= numValues then error( 'Illegal number of ' .. keywords.xlegend .. '. Should be exactly ' .. numValues | if #xlegends ~= numValues then error( 'Illegal number of ' .. keywords.xlegend .. '. Should be exactly ' .. numValues ) end | ||
end | end | ||
| שורה 292: | שורה 291: | ||
elseif k == keywords.scalePerGroup then scalePerGroup = true | elseif k == keywords.scalePerGroup then scalePerGroup = true | ||
elseif k == keywords.defcolor then defcolor = v | elseif k == keywords.defcolor then defcolor = v | ||
elseif k == keywords. | elseif k == keywords.accumulateTooltip then accumulateTooltip = not nulOrWhitespace( v ) | ||
elseif k == keywords.hideGroupLegends then hideGroupLegends = not nulOrWhitespace( v ) | |||
else | else | ||
for keyword, tab in pairs( { | for keyword, tab in pairs( { | ||
| שורה 315: | שורה 315: | ||
local ordermag = 10 ^ math.floor( math.log10( x ) ) | local ordermag = 10 ^ math.floor( math.log10( x ) ) | ||
local normalized = x / ordermag | local normalized = x / ordermag | ||
local top = normalized >= | local top = normalized >= 1.5 and ( math.floor( normalized + 1 ) ) or 1.5 | ||
return ordermag * top, top, ordermag | return ordermag * top, top, ordermag | ||
end | end | ||
function calcHeightLimits() -- if limits were passed by user, use | function calcHeightLimits() -- if limits were passed by user, use them, otherwise calculate. for "stack" there's only one limet. | ||
if stack then | if stack then | ||
local sums = {} | local sums = {} | ||
| שורה 333: | שורה 330: | ||
for i, group in ipairs( values ) do yscales[i] = math.max( unpack( group ) ) end | for i, group in ipairs( values ) do yscales[i] = math.max( unpack( group ) ) end | ||
end | end | ||
for i, scale in ipairs( yscales ) do yscales[i] = roundup( scale ) 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 | if not scalePerGroup then for i = 1, #values do yscales[i] = math.max( unpack( yscales ) ) end end | ||
end | end | ||
| שורה 346: | שורה 343: | ||
function calcHeights( gi, i, val ) | function calcHeights( gi, i, val ) | ||
local barHeight = math.floor( val / yscales[gi] * chartHeight + 0.5 ) -- add half to make it "round" | 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 | local top, base = chartHeight - barHeight, 0 | ||
if stack then | if stack then | ||
| שורה 364: | שורה 361: | ||
function calcx( gi, i ) | function calcx( gi, i ) | ||
local setOffset, setWidth = groupBounds( i ) | local setOffset, setWidth = groupBounds( i ) | ||
if stack then | if stack or numGroups == 1 then | ||
local barWidth = math.min( 38, math.floor( 0.8 * setWidth ) ) | local barWidth = math.min( 38, math.floor( 0.8 * setWidth ) ) | ||
return setOffset + (setWidth - barWidth) / 2, barWidth | return setOffset + (setWidth - barWidth) / 2, barWidth | ||
| שורה 374: | שורה 371: | ||
end | end | ||
function drawbar( gi, i, val ) | function drawbar( gi, i, val, ttval ) | ||
local color, tooltip, custom = colors[gi] or defcolor or 'blue', tooltip( gi, i, val ) | local color, tooltip, custom = colors[gi] or defcolor or 'blue', tooltip( gi, i, ttval or val ) | ||
local left, barWidth = calcx( gi, i ) | local left, barWidth = calcx( gi, i ) | ||
local barHeight, top = calcHeights( gi, i, val ) | local barHeight, top = calcHeights( gi, i, val ) | ||
local style = string.format("position:absolute;left:%spx;top:%spx;height:%spx;min-width:%spx;max-width:%spx;background-color:%s; | -- borders so it shows up when printing | ||
left, top, barHeight, barWidth, barWidth, color, | 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 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 '' | 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 | table.insert( res, mw.text.tag( 'div', { style = style, title = tooltip, }, img ) ) | ||
end | end | ||
| שורה 391: | שורה 389: | ||
local _, top, ordermag = roundup( yscale * 0.999 ) | local _, top, ordermag = roundup( yscale * 0.999 ) | ||
local numnotches = top <= 1.5 and top * 4 | local numnotches = top <= 1.5 and top * 4 | ||
or top < 4 and top * 2 | |||
or top < | |||
or top | or top | ||
local valStyleStr = | local valStyleStr = | ||
| שורה 425: | שורה 422: | ||
function drawXlegends() | function drawXlegends() | ||
local setOffset, setWidth | local setOffset, setWidth | ||
local legendDivStyleFormat = "position:absolute;left:%spx;top: | 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;" | local tickDivstyleFormat = "position:absolute;left:%spx;height:10px;width:1px;border-left:1px solid black;" | ||
for i = 1, numValues do | for i = 1, numValues do | ||
if not nulOrWhitespace( xlegends[i] ) then | if not nulOrWhitespace( xlegends[i] ) then | ||
setOffset, setWidth = groupBounds( i ) | setOffset, setWidth = groupBounds( i ) | ||
table.insert( res, mw.text.tag( 'div', | -- 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 ) }, '' ) ) | table.insert( res, mw.text.tag( 'div', { style = string.format( tickDivstyleFormat, setOffset + setWidth / 2 ) }, '' ) ) | ||
end | end | ||
| שורה 442: | שורה 435: | ||
function drawChart() | function drawChart() | ||
table.insert( res, mw.text.tag( 'div', { style = string.format( 'max-width:%spx;', width ) } ) ) | table.insert( res, mw.text.tag( 'div', { class = 'chart', 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("position:relative;min-height:%spx;min-width:%spx;max-width:%spx;", height, width, width ) } ) ) | ||
table.insert( res, mw.text.tag( 'div', { style = string.format("position:relative | 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 gi, group in pairs( values ) do | ||
for i, val in ipairs( group ) do | for i, val in ipairs( group ) do | ||
drawbar( gi, i, val ) | if acum then acum[i] = ( acum[i] or 0 ) + val end | ||
drawbar( gi, i, val, acum and acum[i] ) | |||
end | end | ||
end | end | ||
table.insert( res, '</div>' ) | 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 ) } ) ) | |||
table.insert( res, mw.text.tag( 'div', { style = string.format("position:absolute | |||
drawYScale() | drawYScale() | ||
table.insert( res, '</div>' ) | 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 ) } ) ) | table.insert( res, mw.text.tag( 'div', { style = string.format( "position:absolute;top:%spx;left:%spx;width:%spx;", chartHeight, scaleWidth, chartWidth ) } ) ) | ||
drawXlegends() | drawXlegends() | ||
| שורה 477: | שורה 470: | ||
[keywords.pieChart] = pieChart, | [keywords.pieChart] = pieChart, | ||
} | } | ||
--</ | --</source> | ||