Module:Overlay
-- this module implements [[Template:Overlay]]
 local p = {}
 
 local mArguments = require('Module:Arguments')
 
 -- used to cache the calculated font color to avoid repeat calculations
 local previous_backgroundcolor = ''
 local fontcolor = ''
 
 local function buildicon(n, form, lk, c, t)
 	local res
 	if form == 'text' then
 		return tostring(
 				mw.html.create('span')
 					:css('font-weight', 'bold')
 					:css('color', c)
 					:wikitext(n)
 				)
 	elseif form == 'color' or form == 'colour' then
 		return tostring(
 				mw.html.create('span')
 					:css('background-color', c)
 					:wikitext('&amp;#160;&amp;#160;')
 				)
 	else
 		-- check if the color is difference from the previous color
 		if c ~= previous_backgroundcolor then
 			-- color changed, so look up the best font color
 			local greatercontrast = require('Module:Color contrast')._greatercontrast
 			fontcolor = greatercontrast{c, 'white', 'black', bias = 1.3}
 			-- update the previous value for the next check
 			previous_backgroundcolor = c
 		end
 		-- build the inner span for the icon
 		local span = mw.html.create('span')
 			:css('color', fontcolor)
 			:css('font-size', '88%')
 			:css('font-weight', 'bold')
 			:attr('title', t)
 			:wikitext(n)
 		-- build the outer div
 		local div = mw.html.create('div')
 			:css('display', 'inline-block')
 			:css('width', 'auto')
 			:css('height', 'auto')
 			:css('text-align', 'center')
 			:css('padding', ((tonumber(n) or 0) &lt; 10) and '0px 4px' or '0px 2px')
 			:css('vertical-align', 'middle')
 			:css('border-radius', '3px')
 			:css('background-color', c)
 
 		-- link the inner span if requested and insert in the div
 		if lk ~= '' then
 			div:wikitext('[[:' .. lk .. '|' .. tostring(span) .. ']]')
 		else
 			div:wikitext(tostring(span))
 		end
 		-- convert to a string
 		return tostring(div)
 	end
 end
 
 local function buildlegend(data, cols, border, caption)
 	-- create the outer table to hold the columns
 	local root = mw.html.create('table')
 		:css('width', '100%')
 		:css('border', (border ~= 'no') and '1px #ccc solid' or '')
 	-- create the outer row which will contain the columns
 	local outerrow = root:tag('tr')
 	local percol = math.ceil((#data) / cols)
 	local k = 0
 	for j=1,cols do
 		-- create the outer cell to hold this column
 		local colcell = outerrow:tag('td')
 			:css('width', (math.floor(10/cols)/10) .. '%')
 			:css('vertical-align', 'top')
 		-- create the inner table to hold the entries in the column
 		local coltable = colcell:tag('table')
 			:css('width', '100%')
 			:css('font-size', '85%')
 			:css('line-height', '95%')
 		-- add the entries to the column
 		for l = 1,percol do
 			k = k + 1
 			if k &lt;= #data then
 				local rdata = data[k]
 				local tr = coltable:tag('tr'):css('vertical-align','top')
 				tr:tag('td')
 					:css('width', '12px')
 					:css('text-align', 'right')
 					:css('padding-bottom', '2px')
 					:wikitext(rdata[1] or '')
 				tr:tag('td')
 					:css('padding-bottom', '2px')
 					:wikitext(rdata[2] or '')
 			end
 		end
 	end
 	return caption .. tostring(root)
 end
 
 local function buildlegenditem(im, lk, t)
 	local res = {im, ''}
 	if t ~= '' then
 		if lk ~= '' then
 			res[2] = '[[:' .. lk .. '|' .. t .. ']]'
 		else
 			res[2] = t
 		end
 	else
 		res[2] = '[[:' .. lk .. '|' .. lk .. ']]'
 	end
 	return res 
 end
 
 function p.icon(frame)
 	local args = mArguments.getArgs(frame)
 	return tostring(
 		mw.html.create('div')
 			:css('display', 'inline-block')
 			:css('line-height', '95%')
 			:wikitext(buildicon(args['1'] or '', 
 								args['form'] or 'icon',
 								args['link'] or '', 
 								args['2'] or 'red',
 								args['tip'] or ''))
 	)
 end
 
 function p.main(frame)
 	local args = mArguments.getArgs(frame)
 	
 	local image = args['image'] or ''
 	local width = tonumber(args['width'] or '500') or 500
 	local height = tonumber(args['height'] or '500') or 500
 	local columns = tonumber(args['columns'] or '3') or 3
 	local grid = ((args['grid'] or ''):lower() == 'yes') and 'yes' or 'no'
 	local legendbox = ((args['legendbox'] or ''):lower() == 'no') and 'no' or 'yes'
 	local overlay = (image == '') and 'no' or ( ((args['overlay'] or ''):lower() == 'no') and 'no' or 'yes' )
 	local float = args['float'] or 'center'
 	local border = ((args['border'] or ''):lower() == 'no') and 'no' or 'yes'
 	local padding = args['padding'] or ''
 
 	-- create the root table
 	local root = mw.html.create('table')
 	if float == 'center' or float == 'centre' then
 		root:css('margin-left', 'auto')
 			:css('margin-right', 'auto')
 	elseif float == 'right' then
 		root:css('float', 'right')
 			:css('clear', 'right')
 			:css('margin-left', '1em')
 	elseif float == 'left' then
 		root:css('float', 'left')
 			:css('clear', 'left')
 			:css('margin-right', '1em')
 	else
 		root:css('float', float)
 	end
 	if border == 'yes' then
 		root:css('border', '1px #ccc solid')
 	end
 
 	-- create a list of all the overlay numbers
 	local itemnums = {}
 	for k, v in pairs( args ) do
 		local i = tonumber(tostring(k):match( '^%s*overlay([%d]+)%s*$' ) or '-1')
 		if i &gt; -1 then
 			table.insert(itemnums, i)
 		else
 			i = tonumber(tostring(k):match( '^%s*overlay([%d]+)tip%s*$' ) or '-1')
 			if i &gt; -1 then
 				table.insert(itemnums, i)
 			end
 		end
 	end
 	-- sort to process in order
 	table.sort( itemnums )
 	
 	-- remove duplicates
 	for k = 2,#itemnums do
 		if itemnums[k] == itemnums[k-1] then
 			table.remove(itemnums, k)
 		end
 	end
 
 	-- build the overlay markers and text
 	itemdata = {}
 	local colori = args['color'] or args['colour'] or 'red'
 	local formi = ''	
 	for k = 1,#itemnums do
 		local i = itemnums[k]
 		formi = args['overlay' .. i .. 'form'] or formi
 		colori = args['overlay' .. i .. 'color'] or args['overlay' .. i .. 'colour'] or colori
 		local linki = args['overlay' .. i .. 'link'] or ''
 		local tipi = args['overlay' .. i .. 'tip'] or args['overlay' .. i] or ''
 		local overlayi = args['overlay' .. i] or args['overlay' .. i .. 'tip'] or ''
 		if (overlayi ~= '' or tipi ~= '') then
 			local imagei = buildicon(i, formi, linki, colori, tipi)
 			itemdata[k] = buildlegenditem(imagei, args['overlay' .. i .. 'link'] or '', overlayi)
 		end
 	end
 
 	-- create the overlay image
 	if image ~= '' then
 		local cell = root:tag('tr'):tag('td')
 		cell:attr('align', 'center')
 		if( padding ~= '' ) then
 			cell:css('padding', padding)
 		end
 		if( columns &gt; 1 and legendbox == 'yes' ) then
 			cell:attr('colspan', columns)
 		end
 		local imagediv = cell:tag('div')
 		imagediv:css('position','relative')
 			:css('left', '0px')
 			:css('top', '0px')
 			:css('width', ((grid == 'yes') and 940 or width) .. 'px')
 			:css('height', ((grid == 'yes') and 940 or height) .. 'px')
 		if grid == 'yes' then
 			imagediv:tag('span')
 				:css('position', 'absolute')
 				:css('left', '0px')
 				:css('top', '0px')
 				:css('z-index', '2')
 				:wikitext('[[File:Grid 99, 100 int red 50 int yellow (940).svg|940px]]')
 		end
 		imagediv:tag('span')
 			:css('position', 'absolute')
 			:css('left', '0px')
 			:css('top', '0px')
 			:css('z-index', '0')
 			:css('width', width .. 'px')
 			:css('height', height .. 'px')
 			:wikitext('[[File:' .. image .. '|' .. width .. 'x' .. height .. 'px]]')
 		if overlay == 'yes' then
 			for k = 1,#itemnums do
 				local i = itemnums[k]
 				local imagei = (itemdata[k])[1]
 				for j =0,3 do
 					local overlayileftj = args['overlay' .. i .. 'left' .. ((j == 0) and '' or j)] or ''
 					local overlayitopj = args['overlay' .. i .. 'top' .. ((j == 0) and '' or j)] or ''
 					if overlayileftj ~= '' then
 						imagediv:tag('div')
 							:css('position', 'absolute')
 							:css('left', overlayileftj .. 'px')
 							:css('top', overlayitopj .. 'px')
 							:css('line-height', '95%')
 							:css('z-index', '1')
 							:wikitext(imagei)
 					end
 				end
 			end
 		end
 	end
 
 	-- Split the legend items into sub-legends
 	legend = {{}, {}, {}, {}, {}}
 	local jmax = itemnums[#itemnums]
 	for i=1,5 do
 		if args['legend' .. i .. 'start'] then
 			-- default is all items
 			j1 = 0
 			j2 = jmax
 			-- set start item number to (legendistart) or (legend(i-1)end + 1)
 			if args['legend' .. i .. 'start'] then
 				j1 = tonumber(args['legend' .. i .. 'start']) or j1
 			elseif args['legend' .. (i-1) .. 'end'] then
 				j1 = (tonumber(args['legend' .. (i-1) .. 'end']) or j1) + 1
 			end
 			-- set end item number to (legendiend) or (legend(i+1)start - 1)
 			if args['legend' .. i .. 'end'] then
 				j2 = tonumber(args['legend' .. i .. 'end']) or j2
 			elseif args['legend' .. (i+1) .. 'start'] then
 				j2 = (tonumber(args['legend' .. (i+1) .. 'start']) or j2) - 1
 			end
 			-- get the items within the range, marking them as they are used
 			for k=1,#itemnums do
 				j = itemnums[k]
 				if (j &gt;= 0 and j &gt;= j1 and j &lt;= j2) then
 					table.insert(legend[i], itemdata[k])
 					itemnums[k] = -1
 				end
 			end
 		end
 	end
 
 	-- Add any left over items to the first legend
 	for k = 1,#itemnums do
 		if itemnums[k] &gt;= 0 then
 			table.insert(legend[1], itemdata[k])
 		end
 	end
 
 	-- Build the legend
 	if columns &gt; 0 then
 		for i = 1,5 do
 			local locallegend = legend[i]
 			if (locallegend and #locallegend &gt; 0) then
 				local cell = root:tag('tr'):tag('td')
 				cell:wikitext(buildlegend(locallegend, columns, border, args['legend' .. i .. 'title'] or ''))
 			end
 		end
 	end
 
 	return tostring(root)
 end