<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
	<id>https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FHike395%2FGraphical_timeline</id>
	<title>Module:Sandbox/Hike395/Graphical timeline - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://stockhub.co/index.php?action=history&amp;feed=atom&amp;title=Module%3ASandbox%2FHike395%2FGraphical_timeline"/>
	<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/Hike395/Graphical_timeline&amp;action=history"/>
	<updated>2026-04-20T22:47:35Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://stockhub.co/index.php?title=Module:Sandbox/Hike395/Graphical_timeline&amp;diff=145524&amp;oldid=prev</id>
		<title>imported&gt;Hike395: use old default annotation width if annotation string has centering</title>
		<link rel="alternate" type="text/html" href="https://stockhub.co/index.php?title=Module:Sandbox/Hike395/Graphical_timeline&amp;diff=145524&amp;oldid=prev"/>
		<updated>2021-05-01T17:19:23Z</updated>

		<summary type="html">&lt;p&gt;use old default annotation width if annotation string has centering&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local getArgs = require(&amp;#039;Module:Arguments&amp;#039;).getArgs&lt;br /&gt;
local compressSparseArray = require(&amp;#039;Module:TableTools&amp;#039;).compressSparseArray&lt;br /&gt;
local p = {}&lt;br /&gt;
&lt;br /&gt;
-- =================&lt;br /&gt;
-- UTILITY FUNCTIONS&lt;br /&gt;
-- =================&lt;br /&gt;
&lt;br /&gt;
-- Default colors for first 28 bars/periods&lt;br /&gt;
local defaultColor = {&amp;quot;#6ca&amp;quot;,&amp;quot;#ff9&amp;quot;,&amp;quot;#6cf&amp;quot;,&amp;quot;#c96&amp;quot;,&amp;quot;#fcc&amp;quot;,&amp;quot;#9f9&amp;quot;,&amp;quot;#96c&amp;quot;,&amp;quot;#cc6&amp;quot;,&amp;quot;#ccc&amp;quot;,&amp;quot;#f66&amp;quot;,&amp;quot;#6c6&amp;quot;,&amp;quot;#99f&amp;quot;,&amp;quot;#c66&amp;quot;,&amp;quot;#f9c&amp;quot;,&lt;br /&gt;
					  &amp;quot;#396&amp;quot;,&amp;quot;#ff3&amp;quot;,&amp;quot;#06c&amp;quot;,&amp;quot;#963&amp;quot;,&amp;quot;#c9c&amp;quot;,&amp;quot;#9c6&amp;quot;,&amp;quot;#c63&amp;quot;,&amp;quot;#c96&amp;quot;,&amp;quot;#999&amp;quot;,&amp;quot;#c03&amp;quot;,&amp;quot;#393&amp;quot;,&amp;quot;#939&amp;quot;,&amp;quot;#996&amp;quot;,&amp;quot;#f69&amp;quot;}&lt;br /&gt;
			&lt;br /&gt;
-- The default width of annotations (in em)		  &lt;br /&gt;
local defaultAW = 8&lt;br /&gt;
-- Previous version default width (in em)&lt;br /&gt;
local oldDefaultAW = 7&lt;br /&gt;
&lt;br /&gt;
-- Function to turn blank arguments back into nil&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--    s = a string argument&lt;br /&gt;
-- Returns&lt;br /&gt;
--    if s is empty, turn back into nil (considered false by Lua)&lt;br /&gt;
local function ignoreBlank(s)&lt;br /&gt;
	if s == &amp;quot;&amp;quot; then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	return s&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Function to suppress incorrect CSS values&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--    val = dimensional value &lt;br /&gt;
--    unit = unit of value&lt;br /&gt;
--    nonneg = [bool] value needs to be non-negative&lt;br /&gt;
--    formatstr = optional format string&lt;br /&gt;
-- Returns:&lt;br /&gt;
--    correct string for html, or nil if val is negative&lt;br /&gt;
local function checkDim(val, unit, nonneg, formatstr)&lt;br /&gt;
	if not val then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	val = tonumber(val)&lt;br /&gt;
	if not val or (nonneg and val &amp;lt; 0) then&lt;br /&gt;
		return nil&lt;br /&gt;
	end&lt;br /&gt;
	if formatstr then&lt;br /&gt;
		return mw.ustring.format(formatstr,val)..unit&lt;br /&gt;
	end&lt;br /&gt;
	return val..unit&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- function to scan argument list for pattern&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   args = an argument dict that will be scanned for one or more patterns&lt;br /&gt;
--   patterns = a list of Lua string patters to scan for&lt;br /&gt;
--   other = a list of other argument specification lists&lt;br /&gt;
--      each element o corresponds to a new argument to produce in the results&lt;br /&gt;
--         o[1] = key in new argument list&lt;br /&gt;
--         o[2] = prefix of old argument&lt;br /&gt;
--         o[3] = suffix of old argument&lt;br /&gt;
-- Returns:&lt;br /&gt;
--   new argument list that matches patterns specified, with new key names&lt;br /&gt;
--&lt;br /&gt;
-- This function makes the Lua module scalable, by specifying a list of string patterns that&lt;br /&gt;
-- contain relevant arguments for a single graphical element, e.g., &amp;quot;period(%d+)&amp;quot;. These&lt;br /&gt;
-- patterns should have exactly one capture that returns a number.&lt;br /&gt;
--&lt;br /&gt;
-- When such a pattern is detected, the number is extracted and then other arguments&lt;br /&gt;
-- with the same number is searched for. Thus, if &amp;quot;period57&amp;quot; is detected, other relevant&lt;br /&gt;
-- arguments like &amp;quot;period57-text&amp;quot; are searched for and, if non-empty, are copied to the&lt;br /&gt;
-- output list with a new argument key. Thus, there is {&amp;quot;text&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-text&amp;quot;}, and&lt;br /&gt;
-- &amp;quot;period(%d+)&amp;quot; detects period57, the code will look for &amp;quot;period57-text&amp;quot; in the input&lt;br /&gt;
-- and copy it&amp;#039;s value to &amp;quot;text&amp;quot; on the output.&lt;br /&gt;
--&lt;br /&gt;
-- This function thus pulls all relevant arguments for a single graphical item out, and&lt;br /&gt;
-- makes an argument list to call a function to produce a single element (such as a bar or note)&lt;br /&gt;
function p._scanArgs(args,patterns,other)&lt;br /&gt;
	local result = {}&lt;br /&gt;
	for _, p in pairs(patterns) do&lt;br /&gt;
		for k, v in pairs(args) do&lt;br /&gt;
			local m = tonumber(mw.ustring.match(k,p))&lt;br /&gt;
			-- if there is a matching argument, and it&amp;#039;s not blank&lt;br /&gt;
			-- and we haven&amp;#039;t handled that match yet, then find other&lt;br /&gt;
			-- arguments and copy them into output arg list. &lt;br /&gt;
			-- We have to handle blank arguments for backward compatibility with the template&lt;br /&gt;
			-- we check for an existing output with item m to save time&lt;br /&gt;
			if m and v ~= &amp;quot;&amp;quot; and not result[m] then&lt;br /&gt;
				local singleResult = {}&lt;br /&gt;
				for _, o in ipairs(other) do&lt;br /&gt;
					local foundVal = args[(o[2] or &amp;quot;&amp;quot;)..m..(o[3] or &amp;quot;&amp;quot;)]&lt;br /&gt;
					if foundVal then&lt;br /&gt;
						singleResult[o[1]] = foundVal&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
				-- A hack: for any argument number m, there is a magic list of default&lt;br /&gt;
				-- colors. We copy that default color for m into the new argument list, in &lt;br /&gt;
				-- case it&amp;#039;s useful. After this, m is discarded&lt;br /&gt;
				singleResult.defaultColor = defaultColor[m]&lt;br /&gt;
				result[m] = singleResult&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- Squeeze out all skipped values. Thus, continguous argument numbers are not&lt;br /&gt;
	-- required: the module can get called with bar3, bar17, bar59 and it will only produce&lt;br /&gt;
	-- three bars, in numerical order that they were called (3, 17, 59)&lt;br /&gt;
	return compressSparseArray(result)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Function to compute the numeric step in the timescale&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   p1, p2 = lower and upper bounds of timescale&lt;br /&gt;
-- Returns:&lt;br /&gt;
--   round step size that produces ~10 steps between p1 and p2&lt;br /&gt;
--&lt;br /&gt;
-- Implements [[Template:Calculate increment]], except with a slight tweak:&lt;br /&gt;
-- The round value (0.1, 0.2, 0.5, 1.0) is selected based on minimum log&lt;br /&gt;
-- distance, so the thresholds are slightly tweaked&lt;br /&gt;
function p._calculateIncrement(p1, p2)&lt;br /&gt;
	local d = math.abs(p1-p2)&lt;br /&gt;
	if d &amp;lt; 1e-10 then&lt;br /&gt;
		return 1e-10&lt;br /&gt;
	end&lt;br /&gt;
	local logd = math.log10(d)&lt;br /&gt;
	local n = math.floor(logd)&lt;br /&gt;
	local frac = logd-n&lt;br /&gt;
	local prevPower = math.pow(10,n-1)&lt;br /&gt;
	if frac &amp;lt; 0.5*math.log10(2) then&lt;br /&gt;
		return prevPower&lt;br /&gt;
	elseif frac &amp;lt; 0.5 then&lt;br /&gt;
		return 2*prevPower&lt;br /&gt;
	elseif frac &amp;lt; 0.5*math.log10(50) then&lt;br /&gt;
		return 5*prevPower&lt;br /&gt;
	else&lt;br /&gt;
		return 10*prevPower&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Utility function to create HTML container for entire graphical timeline&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   container = HTML container for title&lt;br /&gt;
--   args = arguments passed to main&lt;br /&gt;
--      args[&amp;quot;instance-id&amp;quot;] = unique string per Graphical timeline per page&lt;br /&gt;
--      args.embedded = is timeline embedded in another infobox?&lt;br /&gt;
--      args.align = float of timeline (default=right)&lt;br /&gt;
--      args.margin = uniform margin around timeline&lt;br /&gt;
-- Returns;&lt;br /&gt;
--   html div object that is root of DOM for graphical timeline&lt;br /&gt;
--&lt;br /&gt;
--  CSS taken from previous version of [[Template:Grpahical timeline]]&lt;br /&gt;
local function createContainer(args)&lt;br /&gt;
	local container = mw.html.create(&amp;#039;div&amp;#039;)&lt;br /&gt;
	container:attr(&amp;quot;id&amp;quot;,&amp;quot;Container&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	container:addClass(&amp;quot;toccolours&amp;quot;)&lt;br /&gt;
	container:addClass(&amp;quot;searchaux&amp;quot;)&lt;br /&gt;
	container:css(&amp;quot;text-align&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
	container:css(&amp;quot;padding&amp;quot;,&amp;quot;0 0.5em&amp;quot;)&lt;br /&gt;
	container:css(&amp;quot;border-style&amp;quot;,args.embedded and &amp;quot;none&amp;quot; or &amp;quot;solid&amp;quot;)&lt;br /&gt;
	if args.embedded then&lt;br /&gt;
		container:css(&amp;quot;margin&amp;quot;,&amp;quot;auto&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		container:css(&amp;quot;float&amp;quot;,args.align or &amp;quot;right&amp;quot;)&lt;br /&gt;
		container:css(&amp;quot;clear&amp;quot;,args.align or &amp;quot;right&amp;quot;)&lt;br /&gt;
		local margins = {}&lt;br /&gt;
		margins[1] = args.margin or &amp;quot;0.3em&amp;quot;&lt;br /&gt;
		margins[2] = (args.align == &amp;quot;right&amp;quot; and 0) or args.margin or &amp;quot;1.4em&amp;quot;&lt;br /&gt;
		margins[3] = args.margin or &amp;quot;0.8em&amp;quot;&lt;br /&gt;
		margins[4] = (args.align == &amp;quot;right&amp;quot; and (args.margin or &amp;quot;1.4em&amp;quot;)) or 0&lt;br /&gt;
		container:css(&amp;quot;margin&amp;quot;,table.concat(margins,&amp;quot; &amp;quot;))&lt;br /&gt;
	end&lt;br /&gt;
	container:css(&amp;quot;overflow&amp;quot;,&amp;quot;hidden&amp;quot;)&lt;br /&gt;
	return container&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Utility function to create title for graphical timeline&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   args = arguments passed to main&lt;br /&gt;
--      args[&amp;quot;instance-id&amp;quot;] = unique string per Graphical timeline per page&lt;br /&gt;
--      args[&amp;quot;title-color&amp;quot;] = background color for title&lt;br /&gt;
--      args.title = title of timeline&lt;br /&gt;
-- Returns;&lt;br /&gt;
--   html div object that is the title&lt;br /&gt;
--&lt;br /&gt;
--  CSS taken from previous version of [[Template:Grpahical timeline]]&lt;br /&gt;
local function createTitle(container,args)&lt;br /&gt;
	local title = container:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
	title:attr(&amp;quot;id&amp;quot;,&amp;quot;Title&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	title:css(&amp;quot;background-color&amp;quot;,ignoreBlank(args[&amp;quot;title-colour&amp;quot;] or args[&amp;quot;title-color&amp;quot;] or &amp;quot;#77bb77&amp;quot;))&lt;br /&gt;
	title:css(&amp;quot;font-weight&amp;quot;,&amp;quot;bold&amp;quot;)&lt;br /&gt;
	title:css(&amp;quot;padding&amp;quot;,&amp;quot;0.2em&amp;quot;)&lt;br /&gt;
	title:css(&amp;quot;text-align&amp;quot;,&amp;quot;center&amp;quot;)&lt;br /&gt;
	title:css(&amp;quot;margin&amp;quot;,&amp;quot;0.6em 0 1.2em 0&amp;quot;)&lt;br /&gt;
	title:wikitext(args.title)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Utility function to create optional navbox header for timeline&lt;br /&gt;
-- Parameters:&lt;br /&gt;
--   container = container for navbox header&lt;br /&gt;
--   args = arguments passed to main&lt;br /&gt;
--      args.title = title of timeline&lt;br /&gt;
--      args[&amp;quot;link-to&amp;quot;] = name of parent template (without namespace)&lt;br /&gt;
-- Returns;&lt;br /&gt;
--   html div object that is the navbox header&lt;br /&gt;
--&lt;br /&gt;
--  CSS taken from previous version of [[Template:Grpahical timeline]]&lt;br /&gt;
local function navboxHeader(container,args)&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
	local link_to = container:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
	link_to:css(&amp;quot;text-align&amp;quot;,&amp;quot;right&amp;quot;)&lt;br /&gt;
	link_to:css(&amp;quot;position&amp;quot;,&amp;quot;relative&amp;quot;)&lt;br /&gt;
	if args.title then&lt;br /&gt;
		link_to:css(&amp;quot;top&amp;quot;,&amp;quot;-1em&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		link_to:css(&amp;quot;top&amp;quot;,&amp;quot;0em&amp;quot;)&lt;br /&gt;
		link_to:css(&amp;quot;right&amp;quot;,&amp;quot;0em&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	link_to:wikitext(frame:expandTemplate{title=&amp;quot;Navbar&amp;quot;,args={&amp;quot;Template:&amp;quot;..args[&amp;quot;link-to&amp;quot;]}})&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ==================&lt;br /&gt;
-- TIME AXIS AND BARS&lt;br /&gt;
-- ==================&lt;br /&gt;
&lt;br /&gt;
--Function to create HTML time axis on left side of timeline&lt;br /&gt;
--Arguments:&lt;br /&gt;
--  container = HTML parent object&lt;br /&gt;
--  args = arguments passed to main&lt;br /&gt;
--    args.from = beginning (earliest) time of timeline&lt;br /&gt;
--    args.to = ending (latest) time of timeline&lt;br /&gt;
--    args.height = height of timeline&lt;br /&gt;
--    args[&amp;quot;height-unit&amp;quot;] = unit of height (default args.unit)&lt;br /&gt;
--    args.unit = unit of measurement (default em)&lt;br /&gt;
--    args[&amp;quot;instance-id&amp;quot;] = unique string per Graphical timeline per page&lt;br /&gt;
--    args[&amp;quot;scale-increment&amp;quot;] = gap between time ticks (default=automatically computed)&lt;br /&gt;
-- Returns;&lt;br /&gt;
--   html div object for the time axis&lt;br /&gt;
--&lt;br /&gt;
--  CSS taken from previous version of [[Template:Grpahical timeline]]&lt;br /&gt;
function p._scalemarkers(container,args)&lt;br /&gt;
	local height = tonumber(args.height) or 36&lt;br /&gt;
	local unit = args[&amp;quot;height-unit&amp;quot;] or args.unit or &amp;quot;em&amp;quot;&lt;br /&gt;
	local scaleDiv = container:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
	scaleDiv:attr(&amp;quot;id&amp;quot;,&amp;quot;Scale&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	scaleDiv:css(&amp;quot;width&amp;quot;,&amp;quot;3.1em&amp;quot;)&lt;br /&gt;
	scaleDiv:css(&amp;quot;position&amp;quot;,&amp;quot;relative&amp;quot;)&lt;br /&gt;
	scaleDiv:css(&amp;quot;top&amp;quot;,&amp;quot;-0.82em&amp;quot;)&lt;br /&gt;
	scaleDiv:css(&amp;quot;float&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
	scaleDiv:css(&amp;quot;height&amp;quot;,checkDim(height,unit,true))&lt;br /&gt;
	scaleDiv:css(&amp;quot;padding&amp;quot;,&amp;quot;0px&amp;quot;)&lt;br /&gt;
	local incr = args[&amp;quot;scale-increment&amp;quot;] or p._calculateIncrement(args.from,args.to)&lt;br /&gt;
	-- step through by half the desired increment, alternating labels and ticks&lt;br /&gt;
	local halfIncr = incr/2&lt;br /&gt;
	local tIndex = math.ceil(args.from/incr)*2 -- always start on a label&lt;br /&gt;
	local toIndex = math.floor(args.to/halfIncr)&lt;br /&gt;
	local showNum = true&lt;br /&gt;
	while tIndex &amp;lt;= toIndex do&lt;br /&gt;
		local t = tIndex*halfIncr&lt;br /&gt;
		local div = scaleDiv:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
		div:css(&amp;quot;float&amp;quot;,&amp;quot;right&amp;quot;)&lt;br /&gt;
		div:css(&amp;quot;position&amp;quot;,&amp;quot;absolute&amp;quot;)&lt;br /&gt;
		div:css(&amp;quot;right&amp;quot;,&amp;quot;-1px&amp;quot;)&lt;br /&gt;
		div:css(&amp;quot;top&amp;quot;,checkDim(height*(args.to-t)/(args.to-args.from),unit,nil,&amp;quot;%.2f&amp;quot;))&lt;br /&gt;
		local span = div:tag(&amp;quot;span&amp;quot;)&lt;br /&gt;
		span:attr(&amp;quot;name&amp;quot;,showNum and &amp;quot;Number&amp;quot; or &amp;quot;Tick&amp;quot;)&lt;br /&gt;
		span:css(&amp;quot;font-size&amp;quot;,&amp;quot;90%&amp;quot;)&lt;br /&gt;
		span:css(&amp;quot;white-space:nowrap&amp;quot;)&lt;br /&gt;
		if showNum then&lt;br /&gt;
			span:wikitext(string.format(&amp;quot;%d&amp;amp;nbsp;&amp;amp;mdash;&amp;quot;,t))&lt;br /&gt;
		else&lt;br /&gt;
			span:wikitext(&amp;quot;&amp;amp;ndash;&amp;quot;)&lt;br /&gt;
		end&lt;br /&gt;
		tIndex = tIndex + 1&lt;br /&gt;
		showNum = not showNum&lt;br /&gt;
	end&lt;br /&gt;
	local scaleBar = container:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
	scaleBar:attr(&amp;quot;id&amp;quot;,&amp;quot;ScaleBar&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	scaleBar:css(&amp;quot;width&amp;quot;,&amp;quot;1px&amp;quot;)&lt;br /&gt;
	scaleBar:css(&amp;quot;float&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
	scaleBar:css(&amp;quot;height&amp;quot;,checkDim(height,unit,true))&lt;br /&gt;
	scaleBar:css(&amp;quot;padding&amp;quot;,&amp;quot;0&amp;quot;)&lt;br /&gt;
	scaleBar:css(&amp;quot;background-color&amp;quot;,&amp;quot;#242020&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Function to create timeline container div&lt;br /&gt;
-- Arguments:&lt;br /&gt;
--   container = HTML parent object&lt;br /&gt;
--   args = arguments passed to main&lt;br /&gt;
--     args[&amp;quot;plot-colour&amp;quot;] = background color for timeline&lt;br /&gt;
--     args[&amp;quot;instance-id&amp;quot;] = unique string per graphical timeline per page&lt;br /&gt;
--     args.height = height of timeline (36 by default)&lt;br /&gt;
--     args.width = width of timeline (10 by default)&lt;br /&gt;
--     args[&amp;quot;height-unit&amp;quot;] = unit of height measurement (args.unit by default)&lt;br /&gt;
--     args[&amp;quot;width-unit&amp;quot;] = unit of width measurement (args.unit by default)&lt;br /&gt;
--     args.unit = unit of measurement (em by default)&lt;br /&gt;
-- Returns:&lt;br /&gt;
--   timeline HTML object created&lt;br /&gt;
local function createTimeline(container,args)&lt;br /&gt;
	local color = ignoreBlank(args[&amp;quot;plot-colour&amp;quot;] or args[&amp;quot;plot-color&amp;quot;])&lt;br /&gt;
	local timeline = container:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
	timeline:attr(&amp;quot;id&amp;quot;,&amp;quot;Timeline&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	timeline:addClass(&amp;quot;toccolours&amp;quot;)&lt;br /&gt;
	timeline:css(&amp;quot;font-size&amp;quot;,&amp;quot;100%&amp;quot;)&lt;br /&gt;
	timeline:css(&amp;quot;width&amp;quot;,&amp;quot;100%&amp;quot;)&lt;br /&gt;
	timeline:css(&amp;quot;height&amp;quot;,checkDim(args.height or 36,args[&amp;quot;height-unit&amp;quot;] or args.unit or &amp;quot;em&amp;quot;,true))&lt;br /&gt;
	timeline:css(&amp;quot;padding&amp;quot;,&amp;quot;0px&amp;quot;)&lt;br /&gt;
	timeline:css(&amp;quot;float&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
	timeline:css(&amp;quot;width&amp;quot;,checkDim(args.width or 10,args[&amp;quot;width-unit&amp;quot;] or args.unit or &amp;quot;em&amp;quot;,true))&lt;br /&gt;
	timeline:css(&amp;quot;border&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	timeline:css(&amp;quot;background-color&amp;quot;,color)&lt;br /&gt;
	return timeline&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Function to draw single bar (or box)&lt;br /&gt;
-- Arguments:&lt;br /&gt;
--   container = parent HTML object for bar&lt;br /&gt;
--   args = arguments for this box&lt;br /&gt;
--     args.text = text to display&lt;br /&gt;
--     args.nudgedown = distance to nudge text down (in em)&lt;br /&gt;
--     args.nudgeup = distance to nudge text up (in em)&lt;br /&gt;
--     args.nudgeright = distance to nudge text right (in em)&lt;br /&gt;
--     args.nudgeleft = distance to nudge text left (in em)&lt;br /&gt;
--     args.colour = color of bar (default to color assigned to bar number)&lt;br /&gt;
--     args.left = fraction of timeline width for left edge of bar (default 0)&lt;br /&gt;
--     args.right = fraction of timeline width for right edge of bar (default 1)&lt;br /&gt;
--     args.to = beginning (bottom) of bar, in time units (default timeline begin)&lt;br /&gt;
--     args.from = end (top) of bar, in time units (default timeline end)&lt;br /&gt;
--     args.height = timeline height&lt;br /&gt;
--     args.width = timeline width&lt;br /&gt;
--     args[&amp;quot;height-unit&amp;quot;] = units of timeline height (default args.unit)&lt;br /&gt;
--     args[&amp;quot;width-unit&amp;quot;] = units of timeline width (default args.unit)&lt;br /&gt;
--     args.unit = units for timeline dimensions (default em)&lt;br /&gt;
--     args.border-style = CSS style for top/bottom of border (default &amp;quot;solid&amp;quot; if args.border)&lt;br /&gt;
function p._singleBar(container,args)&lt;br /&gt;
	args.text = args.text or &amp;quot;&amp;amp;nbsp;&amp;quot;&lt;br /&gt;
	args.nudgedown = (tonumber(args.nudgedown) or 0) - (tonumber(args.nudgeup) or 0)&lt;br /&gt;
	args.nudgeright = (tonumber(args.nudgeright) or 0) - (tonumber(args.nudgeleft) or 0)&lt;br /&gt;
	args.colour = args.colour or args.defaultColor&lt;br /&gt;
	args.left = tonumber(args.left) or 0&lt;br /&gt;
	args.right = tonumber(args.right) or 1&lt;br /&gt;
	args.to = tonumber(args.to) or args[&amp;quot;tl-to&amp;quot;]&lt;br /&gt;
	args.from = tonumber(args.from) or args[&amp;quot;tl-from&amp;quot;]&lt;br /&gt;
	args.height = tonumber(args.height) or 36&lt;br /&gt;
	args.width = tonumber(args.width) or 10&lt;br /&gt;
	args[&amp;quot;height-unit&amp;quot;] = args[&amp;quot;height-unit&amp;quot;] or args.unit or &amp;quot;em&amp;quot;&lt;br /&gt;
	args[&amp;quot;width-unit&amp;quot;] = args[&amp;quot;width-unit&amp;quot;] or args.unit or &amp;quot;em&amp;quot;&lt;br /&gt;
	args.border = tonumber(args.border)&lt;br /&gt;
	args[&amp;quot;border-style&amp;quot;] = args[&amp;quot;border-style&amp;quot;] or ((args.border or args[&amp;quot;border-colour&amp;quot;]) and &amp;quot;solid&amp;quot;) or &amp;quot;none&amp;quot;&lt;br /&gt;
	-- the HTML element for the box/bar itself&lt;br /&gt;
	local bar = container:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	bar:css(&amp;quot;font-size&amp;quot;,&amp;quot;100%&amp;quot;)&lt;br /&gt;
	bar:css(&amp;quot;background-color&amp;quot;,ignoreBlank(args.colour or &amp;quot;#aaccff&amp;quot;))&lt;br /&gt;
	bar:css(&amp;quot;border-width&amp;quot;,checkDim(args.border,args[&amp;quot;height-unit&amp;quot;],true))&lt;br /&gt;
	bar:css(&amp;quot;border-color&amp;quot;,ignoreBlank(args[&amp;quot;border-colour&amp;quot;]))&lt;br /&gt;
	bar:css(&amp;quot;border-style&amp;quot;,args[&amp;quot;border-style&amp;quot;]..&amp;quot; none&amp;quot;)&lt;br /&gt;
	bar:css(&amp;quot;position&amp;quot;,&amp;quot;absolute&amp;quot;)&lt;br /&gt;
	bar:css(&amp;quot;text-align&amp;quot;,&amp;quot;center&amp;quot;)&lt;br /&gt;
	local bar_top = args.height*(args[&amp;quot;tl-to&amp;quot;]-args.to)/(args[&amp;quot;tl-to&amp;quot;]-args[&amp;quot;tl-from&amp;quot;])&lt;br /&gt;
	bar:css(&amp;quot;margin-top&amp;quot;,checkDim(bar_top,args[&amp;quot;height-unit&amp;quot;],nil,&amp;quot;%.3f&amp;quot;))&lt;br /&gt;
	local bar_height = args.height*(args.to-args.from)/(args[&amp;quot;tl-to&amp;quot;]-args[&amp;quot;tl-from&amp;quot;])&lt;br /&gt;
	if args[&amp;quot;border-style&amp;quot;] ~= &amp;quot;none&amp;quot; and args.border then&lt;br /&gt;
		bar_height = bar_height-2*args.border&lt;br /&gt;
	end&lt;br /&gt;
	bar:css(&amp;quot;height&amp;quot;,checkDim(bar_height,args[&amp;quot;height-unit&amp;quot;],true,&amp;quot;%.3f&amp;quot;))&lt;br /&gt;
	bar:css(&amp;quot;margin-left&amp;quot;,checkDim(args.left*args.width,args[&amp;quot;width-unit&amp;quot;],nil,&amp;quot;%.3f&amp;quot;))&lt;br /&gt;
	bar:css(&amp;quot;width&amp;quot;,checkDim((args.right-args.left)*args.width,args[&amp;quot;width-unit&amp;quot;],true,&amp;quot;%.3f&amp;quot;))&lt;br /&gt;
	-- within the bar, use a div to nudge text away from center&lt;br /&gt;
	local nudge = bar:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	nudge:css(&amp;quot;font-size&amp;quot;,&amp;quot;100%&amp;quot;)&lt;br /&gt;
	nudge:css(&amp;quot;position&amp;quot;,&amp;quot;relative&amp;quot;)&lt;br /&gt;
	nudge:css(&amp;quot;top&amp;quot;,checkDim(args.nudgedown-0.86,&amp;quot;em&amp;quot;,nil))&lt;br /&gt;
	nudge:css(&amp;quot;left&amp;quot;,checkDim(args.nudgeright,&amp;quot;em&amp;quot;,nil))&lt;br /&gt;
	-- put text div as child of nudge div&lt;br /&gt;
	local text = nudge:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	text:css(&amp;quot;position&amp;quot;,&amp;quot;relative&amp;quot;)&lt;br /&gt;
	text:css(&amp;quot;text-align&amp;quot;,&amp;quot;center&amp;quot;)&lt;br /&gt;
	text:css(&amp;quot;font-size&amp;quot;,ignoreBlank(args.textsize))&lt;br /&gt;
	text:css(&amp;quot;vertical-align&amp;quot;,&amp;quot;middle&amp;quot;)&lt;br /&gt;
	local text_bottom = -0.5*args.height*(args.to-args.from)/(args[&amp;quot;tl-to&amp;quot;]-args[&amp;quot;tl-from&amp;quot;])&lt;br /&gt;
	text:css(&amp;quot;display&amp;quot;,&amp;quot;block&amp;quot;)&lt;br /&gt;
	text:css(&amp;quot;bottom&amp;quot;,checkDim(text_bottom,args[&amp;quot;height-unit&amp;quot;],nil,&amp;quot;%.3f&amp;quot;))&lt;br /&gt;
	text:wikitext(ignoreBlank(args.text))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Function to render all bars/boxes in timeline&lt;br /&gt;
-- Arguments:&lt;br /&gt;
--   container = parent HTML object&lt;br /&gt;
--   args = arguments to main function&lt;br /&gt;
--&lt;br /&gt;
--  Global (main) arguments are parsed, individual box arguments are picked out&lt;br /&gt;
--  and passed to p._singleBar() above&lt;br /&gt;
--&lt;br /&gt;
--  The function looks for bar*-left, bar*-right, bar*-from, or bar*-to,&lt;br /&gt;
--     where * is a string of digits. That string of digits is then used to&lt;br /&gt;
--     find corresponding parameters of the individual bar.&lt;br /&gt;
--  For example, if bar23-left is found, then bar23-colour turns into local colour,&lt;br /&gt;
--     bar23-left turns into local left, bar23-from turns into local from, etc.&lt;br /&gt;
function p._bars(container,args)&lt;br /&gt;
	local barArgs = p._scanArgs(args,{&amp;quot;^bar(%d+)-left$&amp;quot;,&amp;quot;^bar(%d+)-right$&amp;quot;,&amp;quot;^bar(%d)-from&amp;quot;,&amp;quot;^bar(%d)-to&amp;quot;},&lt;br /&gt;
		{{&amp;quot;text&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-text&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgedown&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-nudge-down&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgeup&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-nudge-up&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgeright&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-nudge-right&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgeleft&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-nudge-left&amp;quot;},&lt;br /&gt;
		 {&amp;quot;colour&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-colour&amp;quot;},&lt;br /&gt;
		 {&amp;quot;border&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-border-width&amp;quot;},&lt;br /&gt;
		 {&amp;quot;border-color&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-border-colour&amp;quot;},&lt;br /&gt;
		 {&amp;quot;border-style&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-border-style&amp;quot;},&lt;br /&gt;
		 {&amp;quot;left&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-left&amp;quot;},&lt;br /&gt;
		 {&amp;quot;right&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-right&amp;quot;},&lt;br /&gt;
		 {&amp;quot;from&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-from&amp;quot;},&lt;br /&gt;
		 {&amp;quot;to&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-to&amp;quot;}})&lt;br /&gt;
    -- The individual bar arguments are placed into the barArgs table&lt;br /&gt;
    -- Iterating through barArgs picks out the &lt;br /&gt;
	for _, barg in ipairs(barArgs) do&lt;br /&gt;
		-- barg is a table with the local arguments for one bar.&lt;br /&gt;
		-- barg needs to have some global arguments copied into it:&lt;br /&gt;
		barg[&amp;quot;tl-from&amp;quot;] = args.from&lt;br /&gt;
		barg[&amp;quot;tl-to&amp;quot;] = args.to&lt;br /&gt;
		barg.height = args.height&lt;br /&gt;
		barg.width = args.width&lt;br /&gt;
		barg[&amp;quot;height-unit&amp;quot;] = args[&amp;quot;height-unit&amp;quot;]&lt;br /&gt;
		barg[&amp;quot;width-unit&amp;quot;] = args[&amp;quot;width-unit&amp;quot;]&lt;br /&gt;
		barg.unit = args.unit&lt;br /&gt;
		-- call _singleBar with the local arguments for one bar&lt;br /&gt;
		p._singleBar(container,barg)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Function to draw a bar corresponding to a geological period&lt;br /&gt;
-- Arguments:&lt;br /&gt;
--   container = parent HTML object&lt;br /&gt;
--   args = global arguments passed to main&lt;br /&gt;
--&lt;br /&gt;
-- This function is just like _bars(), above, except with defaults for periods:&lt;br /&gt;
--    a period bar is triggered by period* (* = string of digits)&lt;br /&gt;
--    all other parameters start with &amp;quot;period&amp;quot;, not &amp;quot;bar&amp;quot;&lt;br /&gt;
--    colour, from, and to parameters default to data from named period&lt;br /&gt;
--    text is a wikilink to period article&lt;br /&gt;
function p._periods(container,args)&lt;br /&gt;
	local frame = mw.getCurrentFrame()&lt;br /&gt;
	local periodArgs = p._scanArgs(args,{&amp;quot;^period(%d+)$&amp;quot;},&lt;br /&gt;
		{{&amp;quot;text&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-text&amp;quot;},&lt;br /&gt;
		 {&amp;quot;period&amp;quot;,&amp;quot;period&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgedown&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-nudge-down&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgeup&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-nudge-up&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgeright&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-nudge-right&amp;quot;},&lt;br /&gt;
		 {&amp;quot;nudgeleft&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-nudge-left&amp;quot;},&lt;br /&gt;
		 {&amp;quot;colour&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-colour&amp;quot;},&lt;br /&gt;
		 {&amp;quot;border-width&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-border-width&amp;quot;},&lt;br /&gt;
		 {&amp;quot;border-colour&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-border-colour&amp;quot;},&lt;br /&gt;
		 {&amp;quot;border-style&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-border-style&amp;quot;},&lt;br /&gt;
		 {&amp;quot;left&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-left&amp;quot;},&lt;br /&gt;
		 {&amp;quot;right&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-right&amp;quot;},&lt;br /&gt;
		 {&amp;quot;from&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-from&amp;quot;},&lt;br /&gt;
		 {&amp;quot;to&amp;quot;,&amp;quot;period&amp;quot;,&amp;quot;-to&amp;quot;}})&lt;br /&gt;
	-- Iterate through period* arguments, translating much like bar* arguments&lt;br /&gt;
	-- Supply period defaults to local arguments, also&lt;br /&gt;
	for _, parg in ipairs(periodArgs) do&lt;br /&gt;
		parg.text = parg.text or (&amp;quot;[[&amp;quot;..parg.period..&amp;quot;]]&amp;quot;)&lt;br /&gt;
		parg.textsize = &amp;quot;90%&amp;quot;&lt;br /&gt;
		parg.colour = parg.colour or frame:expandTemplate{title=&amp;quot;period color&amp;quot;,args={parg.period}}&lt;br /&gt;
		parg.from = parg.from or tonumber(&amp;quot;-&amp;quot;..frame:expandTemplate{title=&amp;quot;period start&amp;quot;,args={parg.period}})&lt;br /&gt;
		parg.to = parg.to or tonumber(&amp;quot;-&amp;quot;..frame:expandTemplate{title=&amp;quot;period end&amp;quot;,args={parg.period}})&lt;br /&gt;
		parg[&amp;quot;tl-from&amp;quot;] = args.from&lt;br /&gt;
		parg[&amp;quot;tl-to&amp;quot;] = args.to&lt;br /&gt;
		parg.height = args.height&lt;br /&gt;
		parg.width = args.width&lt;br /&gt;
		parg[&amp;quot;height-unit&amp;quot;] = args[&amp;quot;height-unit&amp;quot;]&lt;br /&gt;
		parg[&amp;quot;width-unit&amp;quot;] = args[&amp;quot;width-unit&amp;quot;]&lt;br /&gt;
		parg.unit = args.unit&lt;br /&gt;
		p._singleBar(container,parg)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- ===========&lt;br /&gt;
-- ANNOTATIONS&lt;br /&gt;
-- ===========&lt;br /&gt;
&lt;br /&gt;
-- Function to render a single note (annotation)&lt;br /&gt;
-- Arguments:&lt;br /&gt;
--    container = parent HTML object&lt;br /&gt;
--    args = arguments for this single note&lt;br /&gt;
--       args.text = text to display in note&lt;br /&gt;
--       args.noarr = bool, true if no arrow should be used&lt;br /&gt;
--       args.height = height of timeline&lt;br /&gt;
--       args.unit = height units&lt;br /&gt;
--       args.at = position of annotation (in time units)&lt;br /&gt;
--       args.colour = color of text in note&lt;br /&gt;
--       args.textsize = size of text (default 90%)&lt;br /&gt;
--       Following parameters are only applicable to &amp;quot;no arrow&amp;quot; case&lt;br /&gt;
--         args.nudgeright = nudge text to right (in em)&lt;br /&gt;
--         args.nudgeleft = nudge text to left (in em)&lt;br /&gt;
--         args.nudgedown = nudge text down (in em)&lt;br /&gt;
--         args.nudgeup = nudge text up (in em)&lt;br /&gt;
--         args.aw = annotation width (in em)&lt;br /&gt;
&lt;br /&gt;
function p._singleNote(container,args)&lt;br /&gt;
	-- Ensure some parameters default to sensible values&lt;br /&gt;
	args.height = tonumber(args.height) or 36&lt;br /&gt;
	args.at = tonumber(args.at) or 0.5*(args.to+args.from)&lt;br /&gt;
	args.colour = args.colour or &amp;quot;black&amp;quot;&lt;br /&gt;
	args.aw = tonumber(args.aw)&lt;br /&gt;
	          -- if string is centering, use old width to not break it&lt;br /&gt;
	          or mw.ustring.find(args.text,&amp;quot;&amp;lt;center&amp;gt;&amp;quot;,1,true) and oldDefaultAW&lt;br /&gt;
	          or defaultAW&lt;br /&gt;
	args.textsize = args.textsize or &amp;quot;90%&amp;quot;&lt;br /&gt;
	-- Convert 4 nudge arguments to 2 numeric signed nudge dimensions (right, down)&lt;br /&gt;
	args.nudgeright = (tonumber(args.nudgeright) or 0)-(tonumber(args.nudgeleft) or 0)&lt;br /&gt;
	args.nudgedown = (tonumber(args.nudgedown) or 0)-(tonumber(args.nudgeup) or 0)&lt;br /&gt;
	-- Two cases: no arrow, and arrow&lt;br /&gt;
	--   For no arrow case, use previous CSS which works well to position text&lt;br /&gt;
	if args.noarr then&lt;br /&gt;
		-- First, place a bar that pushes annotation down to right spot&lt;br /&gt;
		local bar = container:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
		bar:addClass(&amp;quot;annot-bar&amp;quot;)&lt;br /&gt;
		bar:css(&amp;quot;width&amp;quot;,&amp;quot;auto&amp;quot;)&lt;br /&gt;
		bar:css(&amp;quot;font-size&amp;quot;,&amp;quot;100%&amp;quot;)&lt;br /&gt;
		bar:css(&amp;quot;position&amp;quot;,&amp;quot;absolute&amp;quot;)&lt;br /&gt;
		bar:css(&amp;quot;text-align&amp;quot;,&amp;quot;center&amp;quot;)&lt;br /&gt;
		bar:css(&amp;quot;margin-top&amp;quot;,checkDim(args.height*(args.to-args.at)/(args.to-args.from),args.unit,nil,&amp;quot;%.3f&amp;quot;))&lt;br /&gt;
		-- Now, nudge the text per nudge dimensions&lt;br /&gt;
		local nudge = bar:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
		nudge:addClass(&amp;quot;annot-nudge&amp;quot;)&lt;br /&gt;
		nudge:css(&amp;quot;float&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
		nudge:css(&amp;quot;position&amp;quot;,&amp;quot;relative&amp;quot;)&lt;br /&gt;
		nudge:css(&amp;quot;text-align&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
		nudge:css(&amp;quot;top&amp;quot;,checkDim(args.nudgedown-0.75,&amp;quot;em&amp;quot;,nil))&lt;br /&gt;
		nudge:css(&amp;quot;left&amp;quot;,checkDim(args.nudgeright,&amp;quot;em&amp;quot;,nil))&lt;br /&gt;
		nudge:css(&amp;quot;width&amp;quot;,checkDim(args.aw,&amp;quot;em&amp;quot;,true))&lt;br /&gt;
		-- Finally, place a dev for the text&lt;br /&gt;
		local text = nudge:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
		text:css(&amp;quot;position&amp;quot;,&amp;quot;relative&amp;quot;)&lt;br /&gt;
		text:css(&amp;quot;width&amp;quot;,&amp;quot;auto&amp;quot;)&lt;br /&gt;
		text:css(&amp;quot;z-index&amp;quot;,&amp;quot;10&amp;quot;)&lt;br /&gt;
		text:css(&amp;quot;font-size&amp;quot;,ignoreBlank(args.textsize))&lt;br /&gt;
		text:css(&amp;quot;color&amp;quot;,ignoreBlank(args.colour))&lt;br /&gt;
		text:css(&amp;quot;vertical-align&amp;quot;,&amp;quot;middle&amp;quot;)&lt;br /&gt;
		text:css(&amp;quot;line-height&amp;quot;,&amp;quot;105%&amp;quot;)&lt;br /&gt;
		text:css(&amp;quot;bottom&amp;quot;,&amp;quot;0&amp;quot;)&lt;br /&gt;
		text:wikitext(ignoreBlank(args.text))&lt;br /&gt;
	else&lt;br /&gt;
		-- In the arrow case, previous code didn&amp;#039;t correctly line up the text&lt;br /&gt;
		-- Now that we&amp;#039;re in Lua, it&amp;#039;s easy to use a table to hold the arrow against the text&lt;br /&gt;
		-- One row: first td is arrow, second td is text&lt;br /&gt;
		-- Table gets placed directly using top CSS and absolute position&lt;br /&gt;
		local tbl = container:tag(&amp;#039;table&amp;#039;)&lt;br /&gt;
		tbl:attr(&amp;quot;role&amp;quot;,&amp;quot;presentation&amp;quot;) -- warn screen readers this table is for layout only&lt;br /&gt;
		-- choose a reasonable height for table, then position middle of that height in the timeline&lt;br /&gt;
		local delta = (args.unit==&amp;quot;em&amp;quot; and 4) or (args.unit==&amp;quot;px&amp;quot; and 40) or 0&lt;br /&gt;
		tbl:css(&amp;quot;height&amp;quot;,checkDim(delta,args.unit,true))&lt;br /&gt;
		tbl:css(&amp;quot;position&amp;quot;,&amp;quot;absolute&amp;quot;)&lt;br /&gt;
		tbl:css(&amp;quot;top&amp;quot;,checkDim(args.height*(args.to-args.at)/(args.to-args.from)-0.5*delta,args.unit,nil,&amp;quot;%.3f&amp;quot;))&lt;br /&gt;
		tbl:css(&amp;quot;padding&amp;quot;,&amp;quot;0&amp;quot;)&lt;br /&gt;
		local row = tbl:tag(&amp;#039;tr&amp;#039;)&lt;br /&gt;
		row:css(&amp;quot;text-align&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
		row:css(&amp;quot;vertical-align&amp;quot;,&amp;quot;middle&amp;quot;)&lt;br /&gt;
		local arrowCell = row:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
		arrowCell:css(&amp;quot;padding&amp;quot;,&amp;quot;0&amp;quot;)&lt;br /&gt;
		local arrowSpan = arrowCell:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
		arrowSpan:css(&amp;quot;color&amp;quot;,args.colour)&lt;br /&gt;
		arrowSpan:wikitext(&amp;quot;&amp;amp;#8592;&amp;quot;) --- HTML for left-pointing arrow&lt;br /&gt;
		local textCell = row:tag(&amp;#039;td&amp;#039;)&lt;br /&gt;
		textCell:css(&amp;quot;padding&amp;quot;,&amp;quot;0&amp;quot;)&lt;br /&gt;
		local text = textCell:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
		text:css(&amp;quot;z-index&amp;quot;,&amp;quot;10&amp;quot;)&lt;br /&gt;
		text:css(&amp;quot;font-size&amp;quot;,ignoreBlank(args.textsize))&lt;br /&gt;
		text:css(&amp;quot;color&amp;quot;,ignoreBlank(args.colour))&lt;br /&gt;
		text:css(&amp;quot;display&amp;quot;,&amp;quot;block&amp;quot;)&lt;br /&gt;
		text:css(&amp;quot;line-height&amp;quot;,&amp;quot;105%&amp;quot;) --- don&amp;#039;t crunch multiple lines of text&lt;br /&gt;
		text:css(&amp;quot;bottom&amp;quot;,&amp;quot;0&amp;quot;)&lt;br /&gt;
		text:wikitext(ignoreBlank(args.text))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Function to render all annotations in timeline&lt;br /&gt;
-- Arguments:&lt;br /&gt;
--   container = parent HTML object&lt;br /&gt;
--   args = arguments to main function&lt;br /&gt;
--&lt;br /&gt;
--  Global (main) arguments are parsed, individual box arguments are picked out&lt;br /&gt;
--  and passed to p._singleNote() above&lt;br /&gt;
--&lt;br /&gt;
--  The function looks for note*, where * is a string of digits&lt;br /&gt;
--     That string of digits is then used to find corresponding parameters of the individual note.&lt;br /&gt;
--  For example, if note23 is found, then note23-colour turns into local colour,&lt;br /&gt;
--     note-at turns into local at, note-texdt turns into local text, etc.&lt;br /&gt;
--&lt;br /&gt;
--  args[&amp;quot;annotation-width&amp;quot;] overrides automatically determined width of annotation div&lt;br /&gt;
function p._annotations(container,args)&lt;br /&gt;
	local noteArgs = p._scanArgs(args,{&amp;quot;^note(%d+)$&amp;quot;},&lt;br /&gt;
								{{&amp;quot;text&amp;quot;,&amp;quot;note&amp;quot;},&lt;br /&gt;
								 {&amp;quot;noarr&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-remove-arrow&amp;quot;},&lt;br /&gt;
								 {&amp;quot;noarr&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-no-arrow&amp;quot;},&lt;br /&gt;
								 {&amp;quot;textsize&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-size&amp;quot;},&lt;br /&gt;
								 {&amp;quot;nudgedown&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-nudge-down&amp;quot;},&lt;br /&gt;
								 {&amp;quot;nudgeup&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-nudge-up&amp;quot;},&lt;br /&gt;
								 {&amp;quot;nudgeright&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-nudge-right&amp;quot;},&lt;br /&gt;
								 {&amp;quot;nudgeleft&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-nudge-left&amp;quot;},&lt;br /&gt;
								 {&amp;quot;colour&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-colour&amp;quot;},&lt;br /&gt;
								 {&amp;quot;at&amp;quot;,&amp;quot;note&amp;quot;,&amp;quot;-at&amp;quot;}})&lt;br /&gt;
	if #noteArgs == 0 then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	-- a div to hold all of the notes&lt;br /&gt;
	local notes = container:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	notes:attr(&amp;quot;id&amp;quot;,&amp;quot;Annotations&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	notes:css(&amp;quot;float&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
	notes:css(&amp;quot;position&amp;quot;,&amp;quot;relative&amp;quot;)&lt;br /&gt;
	-- Is there a &amp;quot;real&amp;quot; note? If so, leave room for it&lt;br /&gt;
	-- real is: is non-empty and (has arrow or isn&amp;#039;t nudged left)&lt;br /&gt;
	local realNote = false&lt;br /&gt;
	for _, narg in ipairs(noteArgs) do&lt;br /&gt;
		local left = (tonumber(narg.nudgeleft) or 0)-(tonumber(narg.nudgeright) or 0)&lt;br /&gt;
		if narg.text ~= &amp;quot;&amp;quot; and (not narg.noarr or left &amp;lt;= 0) then&lt;br /&gt;
			realNote = true&lt;br /&gt;
			args.hasRealNote = true -- record realNote boolean in args for further use&lt;br /&gt;
			break&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	-- width of notes holder depends on whethere there are any &amp;quot;real&amp;quot; notes&lt;br /&gt;
	-- width can be overriden&lt;br /&gt;
	local aw = tonumber(args[&amp;quot;annotations-width&amp;quot;]) or (realNote and defaultAW) or 0&lt;br /&gt;
	notes:css(&amp;quot;width&amp;quot;,checkDim(aw+2.25,&amp;quot;em&amp;quot;,true))&lt;br /&gt;
	for _, narg in ipairs(noteArgs) do&lt;br /&gt;
		--- copy required global parameters to local note args&lt;br /&gt;
		narg.from = args.from&lt;br /&gt;
		narg.to = args.to&lt;br /&gt;
		narg.height = args.height&lt;br /&gt;
		narg.unit = args[&amp;quot;height-unit&amp;quot;] or args[&amp;quot;width-unit&amp;quot;] or &amp;quot;em&amp;quot;&lt;br /&gt;
		narg.aw = args[&amp;quot;annotations-width&amp;quot;]&lt;br /&gt;
		p._singleNote(notes,narg)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--  ====================&lt;br /&gt;
--  LEGENDS AND CAPTIONS&lt;br /&gt;
--  ====================&lt;br /&gt;
&lt;br /&gt;
-- Function to render a single legend (below the timeline)&lt;br /&gt;
-- Arguments:&lt;br /&gt;
--   container = parent HTML object&lt;br /&gt;
--   args = argument table for this legend&lt;br /&gt;
--     args.colour = color to show in square&lt;br /&gt;
--     args.text = text that describes color&lt;br /&gt;
function p._singleLegend(container,args)&lt;br /&gt;
	if not args.text then  -- if no text, not a sensible legend&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	args.colour = args.colour or args.defaultColor or &amp;quot;transparent&amp;quot;&lt;br /&gt;
	local legend = container:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	local square = legend:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
	square:css(&amp;quot;background&amp;quot;,ignoreBlank(args.colour))&lt;br /&gt;
	square:css(&amp;quot;padding&amp;quot;,&amp;quot;0em .1em&amp;quot;)&lt;br /&gt;
	square:css(&amp;quot;border&amp;quot;,&amp;quot;solid 1px #242020&amp;quot;)&lt;br /&gt;
	square:css(&amp;quot;height&amp;quot;,&amp;quot;1.5em&amp;quot;)&lt;br /&gt;
	square:css(&amp;quot;margin&amp;quot;,&amp;quot;.25em .9em .25em .25em&amp;quot;)&lt;br /&gt;
	square:wikitext(&amp;quot;&amp;amp;emsp;&amp;quot;)&lt;br /&gt;
	local text = legend:tag(&amp;#039;span&amp;#039;)&lt;br /&gt;
	text:wikitext(args.text)&lt;br /&gt;
	local clear = legend:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	clear:css(&amp;quot;clear&amp;quot;,&amp;quot;both&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._legends(container,args)&lt;br /&gt;
	local legendArgs = p._scanArgs(args,{&amp;quot;^legend(%d+)$&amp;quot;},&lt;br /&gt;
		{{&amp;quot;text&amp;quot;,&amp;quot;legend&amp;quot;},&lt;br /&gt;
		 {&amp;quot;colour&amp;quot;,&amp;quot;bar&amp;quot;,&amp;quot;-colour&amp;quot;},&lt;br /&gt;
		 {&amp;quot;colour&amp;quot;,&amp;quot;legend&amp;quot;,&amp;quot;-colour&amp;quot;}&lt;br /&gt;
		 })&lt;br /&gt;
	if #legendArgs == 0 then&lt;br /&gt;
		return&lt;br /&gt;
	end&lt;br /&gt;
	local legend = container:tag(&amp;#039;div&amp;#039;)&lt;br /&gt;
	legend:attr(&amp;quot;id&amp;quot;,&amp;quot;Legend&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	legend:addClass(&amp;quot;toccolours&amp;quot;)&lt;br /&gt;
	legend:css(&amp;quot;margin-left&amp;quot;,&amp;quot;3.1em&amp;quot;)&lt;br /&gt;
	legend:css(&amp;quot;border-style&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	legend:css(&amp;quot;float&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
	legend:css(&amp;quot;clear&amp;quot;,&amp;quot;both&amp;quot;)&lt;br /&gt;
	for _,larg in ipairs(legendArgs) do&lt;br /&gt;
		p._singleLegend(legend,larg)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local helpString = [=[&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&amp;#039;&amp;#039;&amp;#039;Usage instructions&amp;#039;&amp;#039;&amp;#039;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Copy the text below, adding multiple bars, legends and notes as required.&lt;br /&gt;
&amp;lt;br&amp;gt;Comments, enclosed in &amp;lt;code&amp;gt;&amp;lt;!-&amp;lt;/code&amp;gt;&amp;lt;code&amp;gt;- -&amp;lt;/code&amp;gt;&amp;lt;code&amp;gt;-&amp;gt;&amp;lt;/code&amp;gt;, should be removed.&lt;br /&gt;
&lt;br /&gt;
Remember:&lt;br /&gt;
* You must use &amp;lt;code&amp;gt;{&amp;lt;/code&amp;gt;&amp;lt;code&amp;gt;{!}&amp;lt;/code&amp;gt;&amp;lt;code&amp;gt;}&amp;lt;/code&amp;gt; wherever you want a {{!}} to be&lt;br /&gt;
: rendered in the timeline&lt;br /&gt;
* Large borders will displace bars in many browsers&lt;br /&gt;
* Text should not be wider than its containing bar,&lt;br /&gt;
: as this may cause compatibility issues&lt;br /&gt;
* Units default to [[em (typography){{!}}em]], the height and width of an &amp;#039;M&amp;#039;.&lt;br /&gt;
&lt;br /&gt;
See {{tl|Graphical timeline}} for full documentation.&lt;br /&gt;
&lt;br /&gt;
{{Graphical timeline/blank}}}}]=]&lt;br /&gt;
&lt;br /&gt;
local function createCaption(container,args)&lt;br /&gt;
	local caption = container:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
	caption:attr(&amp;quot;id&amp;quot;,&amp;quot;Caption&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	caption:addClass(&amp;quot;toccolours&amp;quot;)&lt;br /&gt;
	if args.embedded then&lt;br /&gt;
		caption:css(&amp;quot;margin&amp;quot;,&amp;quot;0 auto&amp;quot;)&lt;br /&gt;
		caption:css(&amp;quot;float&amp;quot;,&amp;quot;left&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		caption:css(&amp;quot;margin&amp;quot;,&amp;quot;0 0.5em&amp;quot;)&lt;br /&gt;
	end&lt;br /&gt;
	caption:css(&amp;quot;border-style&amp;quot;,&amp;quot;none&amp;quot;)&lt;br /&gt;
	caption:css(&amp;quot;clear&amp;quot;,&amp;quot;both&amp;quot;)&lt;br /&gt;
	caption:css(&amp;quot;text-align&amp;quot;,&amp;quot;center&amp;quot;)&lt;br /&gt;
	local widthUnit = args[&amp;quot;width-unit&amp;quot;] or args.unit or &amp;quot;em&amp;quot;&lt;br /&gt;
	local aw = tonumber(args[&amp;quot;annotations-width&amp;quot;]) or (args.hasRealNote and defaultAW) or -0.25&lt;br /&gt;
	aw = aw+5+((widthUnit == &amp;quot;em&amp;quot; and tonumber(args.width)) or 10)&lt;br /&gt;
	caption:css(&amp;quot;width&amp;quot;,checkDim(aw,&amp;quot;em&amp;quot;,true))&lt;br /&gt;
	caption:wikitext((args.caption or &amp;quot;&amp;quot;)..((args.help and args.help ~= &amp;quot;off&amp;quot; and helpString) or &amp;quot;&amp;quot;))&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p._main(args)&lt;br /&gt;
	-- For backward compatibility with template, all empty arguments are accepted.&lt;br /&gt;
	-- But, for some parameters, empty will cause a Lua error, so for those, we convert&lt;br /&gt;
	-- empty to nil.&lt;br /&gt;
	for _, attr in pairs({&amp;quot;title&amp;quot;,&amp;quot;link-to&amp;quot;,&amp;quot;embedded&amp;quot;,&amp;quot;margin&amp;quot;,&amp;quot;height&amp;quot;,&amp;quot;width&amp;quot;,&amp;quot;unit&amp;quot;,&lt;br /&gt;
		&amp;quot;height-unit&amp;quot;,&amp;quot;width-unit&amp;quot;,&amp;quot;scale-increment&amp;quot;,&amp;quot;annotations-width&amp;quot;,&amp;quot;from&amp;quot;,&amp;quot;to&amp;quot;}) do&lt;br /&gt;
		args[attr] = ignoreBlank(args[attr])&lt;br /&gt;
	end&lt;br /&gt;
	-- Check that to &amp;gt; from, and that they&amp;#039;re both defined&lt;br /&gt;
	local from = tonumber(args.from) or 0&lt;br /&gt;
	local to = tonumber(args.to) or 0&lt;br /&gt;
	if from &amp;gt; to then&lt;br /&gt;
		args.from = to&lt;br /&gt;
		args.to = from&lt;br /&gt;
	else&lt;br /&gt;
		args.from = from&lt;br /&gt;
		args.to = to&lt;br /&gt;
	end&lt;br /&gt;
	-- Create container div&lt;br /&gt;
	local container = createContainer(args)&lt;br /&gt;
	-- TITLE&lt;br /&gt;
	if args.title then&lt;br /&gt;
		createTitle(container,args)&lt;br /&gt;
	end&lt;br /&gt;
	container = container:tag(&amp;quot;div&amp;quot;)&lt;br /&gt;
	container:attr(&amp;quot;id&amp;quot;,&amp;quot;Contains-Timeline-Scale-Note&amp;quot;..(args[&amp;quot;instance-id&amp;quot;] or &amp;quot;&amp;quot;))&lt;br /&gt;
	-- NAVBOX HEADER&lt;br /&gt;
	if args[&amp;quot;link-to&amp;quot;] then&lt;br /&gt;
		navboxHeader(container,args)&lt;br /&gt;
	end&lt;br /&gt;
	-- SCALEBAR&lt;br /&gt;
	p._scalemarkers(container,args)&lt;br /&gt;
	-- TIMELINE&lt;br /&gt;
	local timeline = createTimeline(container,args)&lt;br /&gt;
	-- PERIODS&lt;br /&gt;
	p._periods(timeline,args)&lt;br /&gt;
	-- BARS&lt;br /&gt;
	p._bars(timeline,args)&lt;br /&gt;
	-- ANNOTATIONS&lt;br /&gt;
	p._annotations(container,args)&lt;br /&gt;
	-- Pop to outer container for legend and captions&lt;br /&gt;
	container = container:allDone()&lt;br /&gt;
	-- LEGEND&lt;br /&gt;
	p._legends(container,args)&lt;br /&gt;
	-- CAPTION&lt;br /&gt;
	createCaption(container,args)&lt;br /&gt;
	return container&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function p.main(frame)&lt;br /&gt;
	local args = getArgs(frame,{frameOnly=false,parentOnly=false,parentFirst=true,removeBlanks=false})&lt;br /&gt;
	return tostring(p._main(args):allDone())&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
return p&lt;/div&gt;</summary>
		<author><name>imported&gt;Hike395</name></author>
	</entry>
</feed>