X

Track changes made to this page

If you find this page useful and would like to be notified of changes made to this page, start by inputting your email below.



Privacy policy
Close this window

powered by ChangeDetection

Location map

Usage

This module implements the {{Location map}}, {{Location map+}}, {{Location map~}}, and {{Location map many}} templates. Please see the template pages for usage instructions.



local p = {}

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

local function round(n, digits)
	local mult = math.pow(10, digits)
	return math.floor(n * mult + 0.5) / mult
end

local function getMapParams(map, frame)
	if mw.title.new('Module:Location map/data/' .. map).exists then
		local mapData = mw.loadData('Module:Location map/data/' .. map)
		return function(name, params)
			if mapData[name] == nil then
				return ''
			elseif params then
				return mw.message.newRawMessage(mapData[name], unpack(params)):plain()
			else
				return mapData[name]
			end
		end
	else
		local cache = {}
		return function(name, params)
			if params then
				return frame:expandTemplate{title = 'Location map ' .. map, args = { name, unpack(params) }}
			else
				if cache[name] == nil then
					cache[name] = frame:expandTemplate{title = 'Location map ' .. map, args = { name }}
				end
				return cache[name]
			end
		end
	end
end

local function decdeg(degrees, minutes, seconds, hemisphere, digits, decimal)
	if degrees == nil then
		return tonumber(decimal)
	end
	decimal = (degrees or 0) + (minutes or 0)/60 + (seconds or 0)/3600
	if hemisphere == 'W' or hemisphere == 'w' or hemisphere == 'S' or  hemisphere == 's' then
		decimal = -decimal
	end
	if digits == nil then
		digits = 7
	end
	return round(decimal, digits)
end

function p.top(frame, args, map)
	if not args then
		args = getArgs(frame)
	end
	if not map then
		map = getMapParams(args[1], frame)
	end
	local width
	if args.width then
		width = mw.ustring.gsub(args.width, 'px', '')
	else
		width = round((args.default_width or 240) * (tonumber(map('defaultscale')) or 1), 0)
	end
	local retval = ''
	if args.float == 'center' then
		retval = retval .. '<div class="center">'
	end
	if args.caption then
		retval = retval .. '<div class="thumb '
		if args.float == '"left"' or args.float == 'left' then
			retval = retval .. 'tleft'
		elseif args.float == '"center"' or args.float == 'center' or args.float == '"none"' or args.float == 'none' then
			retval = retval .. 'tnone'
		else
			retval = retval .. 'tright'
		end
		retval = retval .. '"><div class="thumbinner" style="width:' .. (width + 2) .. 'px; '
		if args.border == 'none' then
			retval = retval .. 'border: none;'
		elseif args.border then
			retval = retval .. 'border-color:' .. args.border .. ';'
		end
		retval = retval .. '"><div style="position: relative; '
		if args.border ~= 'none' then
			retval = retval .. 'border: 1px solid lightgray'
		end
		retval = retval .. '">'
	else
		retval = retval .. '<div style="width:' .. width .. 'px; '
		if args.float == '"left"' or args.float == 'left' then
			retval = retval .. 'float: left; clear: left'
		elseif args.float == '"center"' or args.float == 'center' then
			retval = retval .. 'float: none; clear: both; margin-left: auto; margin-right: auto'
		elseif args.float == '"none"' or args.float == 'none' then
			retval = retval .. 'float: none; clear: none'
		else
			retval = retval .. 'float: right; clear: right'
		end
		retval = retval .. '"><div style="width:' .. width .. 'px; padding:0"><div style="position: relative; ">'
	end
	local image
	if args.AlternativeMap then
		image = args.AlternativeMap
	elseif args.relief and map('image1') ~= '' then
		image = map('image1')
	else
		image = map('image')
	end
	retval = retval .. '[[File:' .. image .. '|' .. width .. 'px|' .. (args.alt or ((args.label or mw.title.getCurrentTitle().text) .. ' is located in ' .. map('name'))) .. ']]'
	if args.overlay_image then
		retval = retval .. '<div style="position:absolute; top: 0; left: 0">[[File:' .. args.overlay_image .. '|' .. width .. 'px|link=File:' .. image .. ']]</div>'
	end
	return retval
end

function p.bottom(frame, args, map)
	if not args then
		args = getArgs(frame)
	end
	if not map then
		map = getMapParams(args[1], frame)
	end
	local retval = ''
	retval = retval .. '</div><div ' .. (args.caption and 'class="thumbcaption"' or 'style="font-size: 90%; padding-top:3px"') .. '>'
	local caption = frame.args.caption or frame:getParent().args.caption
	if caption and not args.caption_undefined then
		retval = retval .. mw.text.trim(caption)
	else
		retval = retval .. (args.label or mw.title.getCurrentTitle().text) .. ' (' .. map('name') .. ')'
	end
	retval = retval .. '</div></div></div>'
	if args.float == 'center' then
		retval = retval .. '</div>'
	end
	return retval
end

function p.container(frame, args, map)
	if not args then
		args = getArgs(frame)
	end
	if not map then
		map = getMapParams(args[1], frame)
	end
	return p.top(frame, args, map) .. (args.places or '') .. p.bottom(frame, args, map)
end

local function markOuterDiv(x, y, content)
	return '<div style="position:absolute;top:' .. y .. '%;left:' .. x .. '%;height:0;width:0;margin:0;padding:0">' .. content .. '</div>'
end

local function markImageDiv(mark, marksize, label, link, alt, title)
	local retval = '<div style="position:relative;text-align:center;left:-' .. round(marksize / 2, 0) .. 'px;top:-' .. round(marksize / 2, 0) .. 'px;width:' .. marksize .. 'px;font-size:' .. marksize .. 'px;line-height:0"'
	if title then
		retval = retval .. ' title="' .. title .. '"'
	end
	retval = retval .. '>'
	if marksize ~= 0 then
		retval = retval .. '[[File:' .. mark .. '|' .. marksize .. 'x' .. marksize .. 'px|' .. label .. '|link=' .. link
		if alt then
			retval = retval .. '|alt=' .. alt
		end
		retval = retval .. ']]'
	end
	return retval .. '</div>'
end

local function markLabelDiv(label, label_size, label_width, position, background, x)
	local retval = '<div style="font-size:' .. label_size .. '%;line-height:110%;position:relative;top:-1.5em;width:' .. label_width .. 'em;'
	if position == 'top' then -- specified top
		retval = retval .. 'top:-2.65em;left:-3em;text-align:center'
	elseif position == 'bottom' then -- specified bottom
		retval = retval .. 'top:-0.15em;left:-3em;text-align:center'
	elseif position == 'left' or (tonumber(x) > 70 and position ~= 'right') then -- specified left or autodetected to left
		retval = retval .. 'left:-6.5em;text-align:right'
	else -- specified right or autodetected to right
		retval = retval .. 'left:0.5em;text-align:left'
	end
	retval = retval .. '"><span style="padding:1px'
	if background then
		retval = retval .. ';background-color:' .. background
	end
	return retval .. '">' .. label .. '</span></div>'
end

local function getX(longitude, latitude, lon_dir, left, right, top, bottom, crosses180, skew, lon_shift)
	local crosses180_correction = crosses180 and lon_dir == 'W' and (-36000/(left - right)) or 0
	if skew then
		local lat_ratio = (top - latitude)/(top - bottom)
		local skew_factor = (1 - skew) * lat_ratio + skew
		longitude = (longitude - 0.5 * (right + left) + lon_shift) * skew_factor + 0.5 * (right + left) - lon_shift
	end
	return round(crosses180_correction + 100 * (longitude - left) / (right - left), 1)
end

local function getY(latitude, top, bottom)
	return round(100 * (top - latitude) / (top - bottom), 1)
end

function p.mark(frame, args, map)
	if not args then
		args = getArgs(frame)
	end
	if not map then
		map = getMapParams(args[1], frame)
	end
	local x, y, longitude, latitide
	longitude = decdeg(args.lon_deg, args.lon_min, args.lon_sec, args.lon_dir, nil, args.long)
	latitude = decdeg(args.lat_deg, args.lat_min, args.lat_sec, args.lat_dir, nil, args.lat)
	if map('x') ~= '' then
		x = frame:callParserFunction('#expr', map('x', { latitude, longitude }))
	else
		x = getX(longitude, latitude, args.lon_dir, map('left'), map('right'), map('top'), map('bottom'), map('crosses180') ~= '', tonumber(args.skew or map('skew')), args.lon_shift or 0)
	end
	if map('y') ~= '' then
		y = frame:callParserFunction('#expr', map('y', { latitude, longitude }))
	else
		y = getY(latitude, map('top'), map('bottom'))
	end
	local mark = args.mark or map('mark')
	if mark == '' then
		mark = 'Red pog.svg'
	end
	local divContent = markImageDiv(mark, tonumber(args.marksize) or tonumber(map('marksize')) or 8, args.label or mw.title.getCurrentTitle().text, args.link or '', args.alt, args[2])
	if args.label and args.position ~= 'none' then
		divContent = divContent .. markLabelDiv(args.label, args.label_size or 90, args.label_width or 6, args.position, args.background, x)
	end
	return markOuterDiv(x, y, divContent)
end

function p.main(frame, args, map)
	if not args then
		args = getArgs(frame)
	end
	if not args[1] then
		args[1] = 'World'
	end
	if not map then
		map = getMapParams(args[1], frame)
	end
	return p.top(frame, args, map) .. p.mark(frame, args, map) .. p.bottom(frame, args, map)
end

return p