Module:Period fossil range

Documentation for this module may be created at Module:Period fossil range/doc

local p = {} --p stands for package

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

function p.zoomController ( frame )
	period, _ = string.gsub(mw.ustring.lower(frame.args[1]), '%s', '')
	breakpoint = string.find( period, "%W" )
	if breakpoint then
		return p.multiZoom( frame, period, {string.sub(period, 1, breakpoint-1), string.sub(period, breakpoint+1)} )
	elseif period == 'cenozoic' then
		return p.multiZoom( frame, 'cenozoic', {'paleogene', 'neogene', 'quaternary'} )
	elseif period == 'proterozoic' then
		return p.multiZoom( frame, 'proterozoic', {'paleoproterozoic', 'mesoproterozoic', 'neoproterozoic'} )
	else
		return p.zoom(frame)
	end
end

function p.zoom( frame )
	period = mw.ustring.lower(frame.args[1])
	periodStart = tonumber(frame:expandTemplate{ title = 'period start', args = { period } })
	periodEnd = tonumber(frame:expandTemplate{ title = 'period end', args = { period } })
	
	if periodStart > 650 then
		frameStart = frame:expandTemplate{ title = 'period start', args = { 'hadean' } }
		frameEnd = 0
	else
		frameStart = 650 -- Main timescale goes mid Cryogenian – Recent
		frameEnd = 0
	end
	
	left = tostring(250 * (frameStart - periodStart) / (frameStart - frameEnd))
	right = tostring(250 * (frameStart - periodEnd) / (frameStart - frameEnd))
	
	if period == 'silurian' or period == 'neogene' or period == 'quaternary' then
		opacity = '85'
	else
		opacity = '50'
	end
	color = frame:expandTemplate{ title = 'period color', args = { period } }
	
	style = 'height:12px; width: 250px; margin: 0 auto; clear:both; opacity:' .. opacity .. '%; color:inherit; background-color: ' .. color .. '; clip-path: polygon('
	if period == 'quaternary' then
		style = style .. left .. 'px 1px, ' .. left .. 'px 0, ' .. right .. 'px 0, 250px 12px, 0 12px);'
	else
		style = style .. left .. 'px 0, ' .. right .. 'px 0, 250px 12px, 0 12px);'
	end
	
	return '<div style="' .. style .. '"></div>'
end

function p.multiZoom( frame, period, subdivisions )
	content = '<div style="width:250px; height:12px; margin: 0 auto; clear:both; position:relative">'
	periodStart = tonumber(frame:expandTemplate{ title = 'period start', args = { subdivisions[1] } })
	periodEnd = tonumber(frame:expandTemplate{ title = 'period end', args = { subdivisions[#subdivisions] } })
	
	for i, s in ipairs(subdivisions) do
		content = content .. p.multizoomCore( frame, s, periodStart, periodEnd )
	end
	
	content = content .. '</div>'
	return content
end

function p.multizoomCore( frame, subperiod, periodStart, periodEnd )
	subperiodStart = tonumber(frame:expandTemplate{ title = 'period start', args = { subperiod } })
	subperiodEnd = tonumber(frame:expandTemplate{ title = 'period end', args = { subperiod } })
	
	if periodStart > 650 then
		frameStart = frame:expandTemplate{ title = 'period start', args = { 'hadean' } }
		frameEnd = 0
	else
		frameStart = 650 -- Main timescale goes mid Cryogenian – Recent
		frameEnd = 0
	end
	
	leftTop = 250 * (frameStart - subperiodStart) / (frameStart - frameEnd)
	leftBottom = 250 * (periodStart - subperiodStart) / (periodStart - periodEnd)
	rightTop = 250 * (frameStart - subperiodEnd) / (frameStart - frameEnd)
	rightBottom = 250 * (periodStart - subperiodEnd) / (periodStart - periodEnd)
	
	if subperiod == 'silurian' or subperiod == 'neogene' or subperiod == 'quaternary' then
		opacity = '85'
	elseif subperiod == 'neoproterozoic' then
		opacity = '60'
	else
		opacity = '50'
	end
	color = frame:expandTemplate{ title = 'period color', args = { subperiod } }
	
	style = 'position: absolute; height:12px; width: 250px; margin: 0 auto; clear:both; opacity:' .. opacity .. '%; color:inherit; background-color: ' .. color .. '; clip-path: polygon('
	style = style .. leftTop .. 'px 0, ' .. rightTop .. 'px 0, ' .. rightBottom .. 'px 12px, ' .. leftBottom .. 'px 12px);'
	
	return '<div style="' .. style .. '"></div>'
end

function p.periodToStart( frame, period )
	if tonumber(period) ~= nil then
		return tonumber(period)
	else
		return tonumber(frame:expandTemplate{ title = 'period start', args = { mw.ustring.lower(period) } })
	end
end

function p.periodToEnd( frame, period )
	if tonumber(period) ~= nil then
		return tonumber(period)
	else
		return tonumber(frame:expandTemplate{ title = 'period end', args = { mw.ustring.lower(period) } })
	end
end

function p.markerController ( frame )
	period, _ = string.gsub(mw.ustring.lower(frame.args[1]), '%s', '')
	breakpoint = string.find( period, "%W" )
	if breakpoint then
		periodStart = tonumber(frame:expandTemplate{ title = 'period start', args = { string.sub(period, 1, breakpoint-1) } })
		periodEnd = tonumber(frame:expandTemplate{ title = 'period end', args = { string.sub(period, breakpoint+1) } })
	else
		periodStart = tonumber(frame:expandTemplate{ title = 'period start', args = { period } })
		periodEnd = tonumber(frame:expandTemplate{ title = 'period end', args = { period } })
	end
	
	rangeStart = p.periodToStart(frame, frame.args[2])
	
	if frame.args[3] ~= 'nil' then
		rangeEnd = p.periodToEnd(frame, frame.args[3])
	else
		rangeEnd = p.periodToEnd(frame, frame.args[2])
	end
	
	if frame.args['earliest'] ~= 'nil' then
		rangeEarliest = p.periodToStart(frame, frame.args['earliest'])
	else
		rangeEarliest = p.periodToStart(frame, frame.args[2])
	end
	
	if frame.args['latest'] ~= 'nil' then
		rangeLatest = p.periodToEnd(frame, frame.args['latest'])
	elseif frame.args[3] ~= 'nil' then
		rangeLatest = p.periodToEnd(frame, frame.args[3])
	else
		rangeLatest = p.periodToEnd(frame, frame.args[2])
	end
	
	firstMarker = p.markerWide( frame, periodStart, periodEnd, rangeEarliest, rangeLatest )
	secondMarker = p.marker( frame, periodStart, periodEnd, rangeStart, rangeEnd )
	
	divStyle = 'margin:0 auto; line-height:0; clear:both; width:250px; padding:0px; height:8px; overflow:visible; color:inherit; background-color:transparent; position:relative; top:14px; z-index:100;'
	return '<div name=Range style="' .. divStyle .. '">' .. firstMarker .. secondMarker .. '</div>'
end

function p.marker( frame, periodStart, periodEnd, rangeStart, rangeEnd )
	left = math.max( -1, (periodStart - rangeStart) / (periodStart - periodEnd) * 250 )
	right = math.min( 251, (periodStart - rangeEnd) / (periodStart - periodEnd) * 250 )
	outerWidth = math.min(250, right) - math.max(0, left)
	innerWidth = right - left - 2
	if rangeStart - rangeEnd > (periodStart - periodEnd) * 2/250 then
		outerDiv = '<div style="position:absolute; height:8px; left:' .. math.max(0, left) .. 'px; width:' .. outerWidth .. 'px; color:inherit; background-color:#360; "><!--range-border--></div>'
		innerDiv = '<div style="position:absolute; height:6px; top: 1px; left:' .. (left + 1) .. 'px; width:' .. innerWidth .. 'px; color:inherit; background-color:#6c3; "><!--range-marker--></div>'
		return outerDiv .. innerDiv
	else
		return '<div style="position:absolute; left:' .. (left - 4) .. 'px; top:4px; width:0px; border-bottom:8px solid #360; border-left:4px solid transparent; border-right:4px solid transparent;";><div style="position:absolute; top:1px; left:-3px; width:0px; border-bottom: 6px solid #6c3; border-left: 3px solid transparent; border-right: 3px solid transparent;";></div></div>'
	end
end

function p.markerWide( frame, periodStart, periodEnd, rangeEarliest, rangeLatest )
	left = math.max( 0, (periodStart - rangeEarliest) / (periodStart - periodEnd) * 250 )
	right = math.min( 250, (periodStart - rangeLatest) / (periodStart - periodEnd) * 250 )
	width = right - left
	if rangeEarliest - rangeLatest > (periodStart - periodEnd) * 2/250 then
		return '<div style="position:absolute; height:8px; left:' .. left .. 'px; width:' .. width .. 'px; color:inherit; background-color:#360; opacity: 0.42; "><!--range-border--></div>'
	else
		return ''
	end
end

return p