Module:Bar box

From MOASSpedia
Jump to navigation Jump to search

This 'Bar box' template documentation is transcluded for all Bar box/doc including templates [edit].Masterpage

 

{{Bar box}}, {{bar percent}}, {{bar pixel}}, {{bar stacked}} and {{bar gap}} are a family of templates for construction of horizontal bar charts.

Usage

{{Bar box
|width   =  width of the graph         (optional)
|barwidth=  width of the bar area      (optional, defaults to 100px)
|float   =  (left|right|none)          (optional, defaults to none)
|title   =  title of the chart         (optional)
|titlebar=  title bar colour           (optional, defaults to none)
|left1   =  first left column header   (optional)
|left2   =  second left column header  (optional)
|right1  =  first right column header  (optional)
|right2  =  second right column header (optional)
|bars    =  chart contents             (see below)
|caption =  caption under the chart    (optional)
}}

Chart contents

The chart can contain any number of bars. There are four types:

Percentage bar

{{bar percent|row label|colour|value (width in percents)|optional value label}}

If value label is not provided, it is constructed from the percentage and "%". This bar type also has the {{bar percent 2}} and {{bar percent 3}} variations which display more bars for the same row label.

Pixel bar

{{bar pixel|row label|colour|value (width in pixels)|value suffix|optional value label}}

If value label is provided, value suffix is ignored. Otherwise, the value label is constructed from the value and the value suffix. This is used as shorthand. Both following examples give identical results:

{{bar pixel|foo|red|12||12,345}}
{{bar pixel|foo|red|12|,345}}

This bar type also has the {{bar pixel 2}} variation which displays two bars for the same row label.

Stacked bars

{{bar stacked|1st left label|1st right label|color 1|width 1 (in pixels)|...|color 5|width 5 (in pixels)|note1=2nd left label|note2=2nd right label|title1="tooltip" 1|...|title5="tooltip" 5|align=xxxx(l|c|r|d)|collapsed=(yes|y|1)|id=collapsible id}}

titlex sets the "tooltip" of the respective bar and is viewed when hovered over. align sets the text-alignment (left, center, right or default) for each column based on the respective initials. All parameters are optional, but if id is not supplied, collapsed has no effect. Use a custom toggle as the default toggle will distort the chart (see the last example).

Gap bar

{{bar gap|optional separator|height=any valid length (omitting unit defaults to px, default is 10px)}}

Omitting the separator generates a blank row. Another useful separator is <hr> which produces a horizontal line.

Examples

Using {{bar percent}}:

{{Bar box
|float=right
|caption=distribution of stuff
|barwidth=200px
|bars=
{{bar percent|foo|red|30}}
{{bar percent|bar|green|40}}
{{bar percent|baz|blue|20}}
{{bar percent|bla|orange|8}}
{{bar percent|bla1|teal|2|1/50}}
}}
foo
30%
bar
40%
baz
20%
bla
8%
bla1
1/50
distribution of stuff

Using {{bar pixel}}:

{{Bar box
|title=Quantity of stuff
|titlebar=#DDD
|left1=kinds of stuff
|right2=pcs.
|width=400px
|bars=
{{bar pixel|Foobar|red|33|,213}}
{{bar pixel|Barfoo|green|123|,123}}
{{bar pixel|Bazbar|blue|210|,121}}
{{bar pixel|Barfoobaz|orange|13||12,854}}
|caption=Some stuff displayed by quantity.
}}
Quantity of stuff
kinds of stuff pcs.
Foobar
33,213
Barfoo
123,123
Bazbar
210,121
Barfoobaz
12,854
Some stuff displayed by quantity.

Using {{bar percent 2}}:

{{Bar box
|float=right
|title=Election results
|titlebar=#AAF
|left1=party
|left2=year
|right1=votes
|right2=change
|width=300px
|bars=
{{bar percent 2|Left|1898|silver|33|1902|red|42|+9%}}
{{bar percent 2|Right|1898|silver|40|1902|black|35|-5%}}
{{bar percent 2|Middle|1898|silver|17|1902|blue|10|-7%}}
{{bar percent 2|Other|1898|silver|10|1902|gray|13|+3%}}
|caption=1902 and 1898 election results in Freedonia compared.
}}
Election results
party year votes change
Left 1898
  
33% +9%
1902
  
42%
Right 1898
  
40% -5%
1902
  
35%
Middle 1898
  
17% -7%
1902
  
10%
Other 1898
  
10% +3%
1902
  
13%
1902 and 1898 election results in Freedonia compared.

Using {{bar stacked}}:

{{Bar box
|width=300px
|title=
<div class="mw-customtoggle-a mw-customtoggle-b">Toggle all</div>
<div class="mw-customtoggle-b">Toggle last item</div>
|bars=
{{bar stacked|January|(---)|red|3|blue|22|align=ddcd|id=a}}
{{bar stacked|February|+60.3%|red|8|blue|26|green|6|id=a}}
{{bar stacked|March|99|red|11|blue|18|green|8|orange|11|magenta|20|note2=+25%|align=cdrl|id=a}}
{{bar stacked|April|142|red|15|blue|24|green|8|orange|13|magenta|26|note1=foo|note2=+11%|collapsed=yes|id=b}}
}}
Toggle all
Toggle last item
January
(---)
February
+60.3%
March
99 +25%
April foo
142 +11%

Tracking category

See also


require('Module:Lua class')
require('Module:No globals')

local BarBox = class('BarBox', {
	_css = 'Module:Bar box/styles.css',

	__init = function (self, args)
		self.css			 = args[1]  or args.css
		self.float			 = args[2]  or args.float or 'none'
		self.backgroundcolor = args[3]  or args.backgroundcolor or 'white'
		self.borderwidth	 = args[4]  or args.borderwidth or '1'
		self.style			 = args[5]  or args.style
		self.width			 = args[6]  or args.width-- or 'auto'
		self.barwidth		 = args[7]  or args.barwidth or '100px'
		self.lineheight		 = args[8]  or args.lineheight-- or '1.6'
		self.title			 = args[9]  or args.title
		self.titlebar		 = args[10] or args.titlebar-- or 'none'
		self.left1			 = args[11] or args.left1
		self.left2			 = args[12] or args.left2
		self.right1			 = args[13] or args.right1
		self.right2			 = args[14] or args.right2
		self.bars			 = args[15] or args.bars
		self.caption		 = args[16] or args.caption -- deprecated
		self.footer			 = args[17] or args.footer or args[16] or args.caption
	end,

	create = function (cls, args)
		args = mw.clone(args)
		args.float	  = args.float and args.float:lower()
		args.width	  = tonumber(args.width) and args.width .. 'px' or args.width and args.width:lower()
		args.barwidth = tonumber(args.barwidth) and args.barwidth .. 'px' or args.barwidth and args.barwidth:lower()
		return cls(args)
	end,

	_sDefaultAlign = 'lrlr',
	_tDefaultAlign = {false, 'r', false, 'r'},

	_setAlign = function (obj, align)
		obj._alignClasses = {}
		for i, d in ipairs(obj._tDefaultAlign) do
			local a = align:sub(i,i)
			if a == 'l' then
				a = false
			elseif a == 'd' then
				a = d
			elseif a ~= 'c' and a ~= 'r' then
				error('unrecognized align[' .. i .. ']')
			end
			obj._alignClasses[i] = a and 'class=bb-' .. a
		end
	end,

	html = function (self)
		local output = {}

		local frame = mw.getCurrentFrame()
		output[1] = frame:extensionTag('templatestyles', '', {src=self._css}) .. '\n'
		output[2] = self.css and frame:extensionTag('templatestyles', '', {src=self.css}) .. '\n' or ''

		local class = 'barbox'
		if self.float == 'left' or self.float == 'right' then
			class = class .. ' t' .. self.float
		end

		output[3] =
			'<div class="' .. class .. '" style="background:' .. self.backgroundcolor ..
			'; border:' .. self.borderwidth .. 'px solid silver' ..
			(self.float == 'center' and '; margin:0 auto' or '') ..
			(self.width and '; width:' .. self.width or '') ..
			(self.style and '; ' .. self.style or '') .. '">\n' ..
				'{|' .. (self.lineheight and ' style="line-height:' .. self.lineheight .. '"' or '') .. '\n'

			output[4] = self.title and
				'|+ class=bb-default' .. (self.titlebar and ' style="background:' .. self.titlebar .. '"' or '') .. ' |\n' ..
				self.title .. '\n'
			or ''

			output[5] = '|- class=bb-default style="font-size:88%; min-height:4px"\n'
				if self._alignClasses then -- same as self.__class._alignClasses
					self._alignClasses = self._alignClasses
					self.__class._alignClasses = nil
				else
					self._setAlign(self, self._sDefaultAlign)
				end

				local attributes =
					not self.left2 and 'colspan=2' .. (self._alignClasses[1] and ' ' .. self._alignClasses[1] or '') or self._alignClasses[1]
				output[6] = '!' .. (attributes and attributes .. '|' or '') .. (self.left1 or ' ')
				output[7] = self.left2 and '!!' .. (self._alignClasses[2] and self._alignClasses[2] .. '|' or '') .. self.left2 or ''
				output[8] = '!!style="width:' .. self.barwidth .. '"| '
				attributes =
					not self.right2 and 'colspan=2' .. (self._alignClasses[4] and ' ' .. self._alignClasses[4] or '') or self._alignClasses[3]
				output[9] = '!!' .. (attributes and attributes .. '|' or '') .. (self.right1 or self.right2 and ' ' or '')
				output[10] = self.right2 and '!!' .. (self._alignClasses[4] and self._alignClasses[4] .. '|' or '') .. self.right2 or ''
			output[11] = '\n'

			output[12] = self.bars and self.bars .. '\n' or ''

			if self.caption then
				output[15] = '\n[[Category:Pages using bar box with deprecated caption parameter]]'
			else
				output[15] = ''
			end
			output[13] = self.footer and
				'|- class=bb-default\n| colspan=5 style="padding:5px 0" | ' .. -- <p> is created if \n precedes the footer
				self.footer .. '\n'
			or ''
		output[14] = '|}\n</div>'

		return table.concat(output)
	end,

	__tostring = function (self)
		return self.html()
	end,

	percent = function (args)
		local output = {}
		local percentage = (args[3] or '0') .. '%'

		output[1] = '|-' .. (args.bg and 'style="background:' .. args.bg .. '"' or '') .. '\n'
			output[2] = '|colspan=2 class=bb-min8|' .. (args[1] or ' ')
			output[3] = '||class=bb-b|'
				output[4] = '<div style="background:' .. (args[2] or 'gray') .. '; width:' .. percentage .. '">&#8203;</div>'
			output[5] = '||' .. (args.note and '' or 'colspan=2 class=bb-r|') .. (args[4] or percentage)
			output[6] = args.note and '||class=bb-r|' .. args.note or ''

		return table.concat(output)
	end,

	pixel = function (args)
		local output = {}
		local pixels = args[3] or '0'

		output[1] = '|-' .. (args.bg and 'style="background:' .. args.bg .. '"' or '') .. '\n'
			output[2] = '|colspan=2|' .. (args[1] or ' ')
			output[3] = '||class=bb-b|'
				output[4] = '<div style="background:' .. (args[2] or 'gray') .. '; width:' .. pixels .. 'px">&#8203;</div>'
			output[5] = '||class="bb-min3' .. (args.note and '"' or ' bb-r" colspan=2') .. '|' .. (args[5] or pixels .. (args[4] or ''))
			output[6] = args.note and '||class=bb-r|' .. args.note or ''

		return table.concat(output)
	end,

	stacked = function (cls, args)
		local output = {}

		output[1] = args.id and
			'|-class="mw-collapsible' .. (args.collapsed and ' mw-collapsed' or '') .. '" id=mw-customcollapsible-' .. args.id .. '\n'
		or '|-\n'
			if not cls._alignClasses then
				cls._setAlign(cls, args.align and args.align:lower() or cls._sDefaultAlign)
			end

			local attributes =
				not args.note1 and 'colspan=2' .. (cls._alignClasses[1] and ' ' .. cls._alignClasses[1] or '') or cls._alignClasses[1]
			output[2] = '|' .. (attributes and attributes .. '|' or '') .. (args[1] or ' ')
			output[3] = args.note1 and '||' .. (cls._alignClasses[2] and cls._alignClasses[2] .. '|' or '') .. args.note1 or ''
			output[4] = '||class=bb-b|'

				local len = 0 -- can't use #args because of [[Module:Arguments#Known limitations]]
				for k in pairs(args) do
					local idx = tonumber(k) or 0
					if idx > len then len = idx end
				end

				if args.bkgclasses then -- used when wikitext minimization is essential
					for i = 1, len-2 do
						local width, delim, title --is delim reset every cycle?
						width = args[i+2] or 0
						width = tonumber(('%.2f'):format(width))
						if width > 0 then
							if not delim then -- assuming title types are consistent
								delim = tonumber(args['title' .. i]) and '' or '"'
							end
							title = args['title' .. i] and ' title=' .. delim .. args['title' .. i] .. delim or ''
							output[#output+1] =
								'<div' .. title .. ' class=' .. args.bkgclasses[i] .. ' style=width:' .. width .. 'px>&#8203;</div>'
						end
					end
				else
					for i = 1, (len-2) / 2 do
						local width, title, background
						width = args[2*i + 2] or 0
						width = tonumber(('%.2f'):format(width))
						if width > 0 then
							title = args['title' .. i] and ' title="' .. args['title' .. i] .. '"' or ''
							background = args[2*i + 1] or 'gray'
							output[#output+1] =
								'<div' .. title .. ' style="background:' .. background .. '; width:' .. width .. 'px">&#8203;</div>'
						end
					end
				end

				if #output == 4 then
					output[5] = ' '
				end

			attributes =
				not args.note2 and 'colspan=2' .. (cls._alignClasses[4] and ' ' .. cls._alignClasses[4] or '') or cls._alignClasses[3]
			output[#output+1] = '||' .. (attributes and attributes .. '|' or '') .. (args[2] or args.note2 and ' ' or '')
			output[#output+1] = args.note2 and '||' .. (cls._alignClasses[4] and cls._alignClasses[4] .. '|' or '') .. args.note2 or ''

		return table.concat(output)
	end,

	gap = function (args)
		local output = {}
		local height = tonumber(args.height) and args.height .. 'px' or args.height and args.height:lower() or '10px'

		output[1] = '|-\n'
			output[2] = '|colspan=5 style="height:' .. height .. '"|' .. (args[1] or '')

		return table.concat(output)
	end,

	__classmethods = {'create', 'stacked'},
	__staticmethods = {'_setAlign', 'percent', 'pixel', 'gap'},
	__slots = {'_alignClasses'}
})


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

local p = {BarBox}

function p.box(frame)
	local args = getArgs(frame)
	local box = BarBox.create(args)
	return tostring(box)
end

function p.percent(frame)
	local args = getArgs(frame)
	return BarBox.percent(args)
end

function p.pixel(frame)
	local args = getArgs(frame)
	return BarBox.pixel(args)
end

function p.stacked(frame)
	local yesno = require('Module:Yesno')
	local args = getArgs(frame, {
		valueFunc = function (key, value)
			if value then
				if key == 'collapsed' then
					return yesno(value)
				elseif key == 'bkgclasses' then
					return mw.text.jsonDecode(value) -- string to table
				end
				value = mw.text.trim(value)
				if value ~= '' then
					return value
				end
			end
			return nil
		end
	})
	return BarBox.stacked(args)
end

function p.gap(frame)
	local args = getArgs(frame)
	return BarBox.gap(args)
end

return p