If you find this page useful and would like to be notified of changes made to this page, start by inputting your email below.
powered by ChangeDetection
m (1 revision) |
Jackmcbarn (talk | contribs) (handle marks placed to the left of the map more nicely) |
||
Line 1: | Line 1: | ||
+ | require('Module:No globals') | ||
+ | |||
local p = {} | local p = {} | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
− | |||
− | |||
− | |||
− | |||
− | |||
local function getMapParams(map, frame) | local function getMapParams(map, frame) | ||
− | if mw.title.new('Module:Location map/data/' .. map).exists then | + | if not map then |
+ | error('The name of the location map definition to use must be specified', 2) | ||
+ | end | ||
+ | local moduletitle = mw.title.new('Module:Location map/data/' .. map) | ||
+ | if not moduletitle then | ||
+ | error('"' .. map .. '" is not a valid name for a location map definition', 2) | ||
+ | elseif moduletitle.exists then | ||
local mapData = mw.loadData('Module:Location map/data/' .. map) | local mapData = mw.loadData('Module:Location map/data/' .. map) | ||
return function(name, params) | return function(name, params) | ||
Line 15: | Line 18: | ||
return '' | return '' | ||
elseif params then | elseif params then | ||
− | return mw.message.newRawMessage(mapData[name], unpack(params)):plain() | + | return mw.message.newRawMessage(tostring(mapData[name]), unpack(params)):plain() |
else | else | ||
return mapData[name] | return mapData[name] | ||
end | end | ||
end | end | ||
− | + | elseif mw.title.new('Template:Location map ' .. map).exists then | |
local cache = {} | local cache = {} | ||
return function(name, params) | return function(name, params) | ||
Line 32: | Line 35: | ||
end | end | ||
end | end | ||
+ | else | ||
+ | error('Unable to find the specified location map definition. Neither "Module:Location map/data/' .. map .. '" nor "Template:Location map ' .. map .. '" exists', 2) | ||
end | end | ||
end | end | ||
− | + | function p.data(frame, args, map) | |
− | if | + | if not args then |
− | + | args = getArgs(frame) | |
end | end | ||
− | + | if not map then | |
− | if | + | map = getMapParams(args[1], frame) |
− | |||
end | end | ||
− | if | + | local params = {} |
− | + | for k,v in ipairs(args) do | |
+ | if k > 2 then | ||
+ | params[k-2] = v | ||
+ | end | ||
end | end | ||
− | return | + | return map(args[2], #params and params) |
+ | end | ||
+ | |||
+ | local hemisphereMultipliers = { | ||
+ | longitude = { W = -1, w = -1, E = 1, e = 1 }, | ||
+ | latitude = { S = -1, s = -1, N = 1, n = 1 } | ||
+ | } | ||
+ | |||
+ | local function decdeg(degrees, minutes, seconds, hemisphere, decimal, direction) | ||
+ | if not degrees then | ||
+ | if not decimal then | ||
+ | error('No value was provided for ' .. direction, 2) | ||
+ | end | ||
+ | local retval = tonumber(decimal) | ||
+ | if retval then | ||
+ | return retval | ||
+ | end | ||
+ | error('The value "' .. decimal .. '" provided for ' .. direction .. ' is not valid', 2) | ||
+ | end | ||
+ | decimal = tonumber(degrees) | ||
+ | if not decimal then | ||
+ | error('The degree value "' .. degrees .. '" provided for ' .. direction .. ' is not valid', 2) | ||
+ | end | ||
+ | if minutes and not tonumber(minutes) then | ||
+ | error('The minute value "' .. minutes .. '" provided for ' .. direction .. ' is not valid', 2) | ||
+ | end | ||
+ | if seconds and not tonumber(seconds) then | ||
+ | error('The second value "' .. seconds .. '" provided for ' .. direction .. ' is not valid', 2) | ||
+ | end | ||
+ | decimal = decimal + (minutes or 0)/60 + (seconds or 0)/3600 | ||
+ | if hemisphere then | ||
+ | local multiplier = hemisphereMultipliers[direction][hemisphere] | ||
+ | if not multiplier then | ||
+ | error('The hemisphere "' .. hemisphere .. '" provided for ' .. direction .. ' is not valid', 2) | ||
+ | end | ||
+ | decimal = decimal * multiplier | ||
+ | end | ||
+ | return decimal | ||
end | end | ||
Line 57: | Line 101: | ||
end | end | ||
local width | local width | ||
− | if args.width then | + | if not args.width then |
− | width = mw.ustring. | + | width = math.floor((args.default_width or 240) * (tonumber(map('defaultscale')) or 1) + 0.5) |
+ | elseif mw.ustring.sub(args.width, -2) == 'px' then | ||
+ | width = mw.ustring.sub(args.width, 1, -3) | ||
else | else | ||
− | width = | + | width = args.width |
− | |||
− | |||
− | |||
− | |||
end | end | ||
+ | local retval = args.float == 'center' and '<div class="center">' or '' | ||
if args.caption then | if args.caption then | ||
retval = retval .. '<div class="thumb ' | retval = retval .. '<div class="thumb ' | ||
Line 75: | Line 118: | ||
retval = retval .. 'tright' | retval = retval .. 'tright' | ||
end | end | ||
− | retval = retval .. '"><div class="thumbinner" style="width:' .. (width + 2) .. 'px | + | retval = retval .. '"><div class="thumbinner" style="width:' .. (width + 2) .. 'px' |
if args.border == 'none' then | if args.border == 'none' then | ||
− | retval = retval .. 'border: none | + | retval = retval .. ';border:none' |
elseif args.border then | elseif args.border then | ||
− | retval = retval .. 'border-color:' .. args.border | + | retval = retval .. ';border-color:' .. args.border |
end | end | ||
− | retval = retval .. '"><div style="position: relative; ' | + | retval = retval .. '"><div style="position:relative;width:' .. width .. 'px' .. (args.border ~= 'none' and ';border:1px solid lightgray">' or '">') |
− | |||
− | |||
− | |||
− | |||
else | else | ||
− | retval = retval .. '<div style="width:' .. width .. 'px; ' | + | retval = retval .. '<div style="width:' .. width .. 'px;' |
if args.float == '"left"' or args.float == 'left' then | if args.float == '"left"' or args.float == 'left' then | ||
− | retval = retval .. 'float: left; clear: left' | + | retval = retval .. 'float:left;clear:left' |
elseif args.float == '"center"' or args.float == 'center' then | elseif args.float == '"center"' or args.float == 'center' then | ||
− | retval = retval .. 'float: none; clear: both; margin-left: auto; margin-right: auto' | + | retval = retval .. 'float:none;clear:both;margin-left:auto;margin-right:auto' |
elseif args.float == '"none"' or args.float == 'none' then | elseif args.float == '"none"' or args.float == 'none' then | ||
− | retval = retval .. 'float: none; clear: none' | + | retval = retval .. 'float:none;clear:none' |
else | else | ||
− | retval = retval .. 'float: right; clear: right' | + | retval = retval .. 'float:right;clear:right' |
end | end | ||
− | retval = retval .. '"><div style="width:' .. width .. 'px; padding:0"><div style="position: relative; ">' | + | retval = retval .. '"><div style="width:' .. width .. 'px;padding:0"><div style="position:relative;width:' .. width .. 'px">' |
end | end | ||
local image | local image | ||
Line 109: | Line 148: | ||
retval = retval .. '[[File:' .. image .. '|' .. width .. 'px|' .. (args.alt or ((args.label or mw.title.getCurrentTitle().text) .. ' is located in ' .. map('name'))) .. ']]' | 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 | if args.overlay_image then | ||
− | + | return retval .. '<div style="position:absolute;top:0;left:0">[[File:' .. args.overlay_image .. '|' .. width .. 'px|link=File:' .. image .. ']]</div>' | |
+ | else | ||
+ | return retval | ||
end | end | ||
− | |||
end | end | ||
Line 121: | Line 161: | ||
map = getMapParams(args[1], frame) | map = getMapParams(args[1], frame) | ||
end | end | ||
− | local retval = | + | local 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 | local caption = frame.args.caption or frame:getParent().args.caption | ||
if caption and not args.caption_undefined then | if caption and not args.caption_undefined then | ||
Line 132: | Line 171: | ||
if args.float == 'center' then | if args.float == 'center' then | ||
retval = retval .. '</div>' | retval = retval .. '</div>' | ||
+ | end | ||
+ | if args.caption_undefined then | ||
+ | retval = retval .. '[[Category:Location maps using skew|!]]' | ||
end | end | ||
return retval | return retval | ||
Line 151: | Line 193: | ||
local function markImageDiv(mark, marksize, label, link, alt, title) | local function markImageDiv(mark, marksize, label, link, alt, title) | ||
− | local retval = '<div style="position:relative;text-align:center;left:-' .. | + | local retval = '<div style="position:relative;text-align:center;left:-' .. math.floor(marksize / 2 + 0.5) .. 'px;top:-' .. math.floor(marksize / 2 + 0.5) .. 'px;width:' .. marksize .. 'px;font-size:' .. marksize .. 'px;line-height:0"' .. (title and (' title="' .. title .. '">') or '>') |
− | |||
− | |||
− | |||
− | |||
if marksize ~= 0 then | if marksize ~= 0 then | ||
retval = retval .. '[[File:' .. mark .. '|' .. marksize .. 'x' .. marksize .. 'px|' .. label .. '|link=' .. link | retval = retval .. '[[File:' .. mark .. '|' .. marksize .. 'x' .. marksize .. 'px|' .. label .. '|link=' .. link | ||
Line 184: | Line 222: | ||
end | end | ||
− | local function getX(longitude | + | local function getX(longitude, left, right) |
− | local | + | local width = (right - left) % 360 |
− | if | + | if width == 0 then |
− | + | width = 360 | |
− | + | end | |
− | + | local distanceFromLeft = (longitude - left) % 360 | |
+ | -- the distance needed past the map to the right equals distanceFromLeft - width. the distance needed past the map to the left equals 360 - distanceFromLeft. to minimize page stretching, go whichever way is shorter | ||
+ | if distanceFromLeft - width / 2 >= 180 then | ||
+ | distanceFromLeft = distanceFromLeft - 360 | ||
end | end | ||
− | return | + | return 100 * distanceFromLeft / width |
end | end | ||
local function getY(latitude, top, bottom) | local function getY(latitude, top, bottom) | ||
− | return | + | return 100 * (top - latitude) / (top - bottom) |
end | end | ||
Line 205: | Line 246: | ||
map = getMapParams(args[1], frame) | map = getMapParams(args[1], frame) | ||
end | end | ||
− | local x, y, longitude, | + | local x, y, longitude, latitude |
− | longitude = decdeg(args.lon_deg, args.lon_min, args.lon_sec, args.lon_dir | + | longitude = decdeg(args.lon_deg, args.lon_min, args.lon_sec, args.lon_dir, args.long, 'longitude') |
− | latitude = decdeg(args.lat_deg, args.lat_min, args.lat_sec, args.lat_dir, | + | latitude = decdeg(args.lat_deg, args.lat_min, args.lat_sec, args.lat_dir, args.lat, 'latitude') |
+ | local retval = '' | ||
+ | if args.skew or args.lon_shift or (map('skew') ~= '') or (map('lat_skew') ~= '') or (map('crosses180') ~= '') then | ||
+ | retval = retval .. '[[Category:Location maps using skew|' .. args[1] .. ']]' | ||
+ | end | ||
if map('x') ~= '' then | if map('x') ~= '' then | ||
x = frame:callParserFunction('#expr', map('x', { latitude, longitude })) | x = frame:callParserFunction('#expr', map('x', { latitude, longitude })) | ||
else | else | ||
− | x = getX(longitude | + | x = getX(longitude, map('left'), map('right')) |
end | end | ||
if map('y') ~= '' then | if map('y') ~= '' then | ||
Line 226: | Line 271: | ||
divContent = divContent .. markLabelDiv(args.label, args.label_size or 90, args.label_width or 6, args.position, args.background, x) | divContent = divContent .. markLabelDiv(args.label, args.label_size or 90, args.label_width or 6, args.position, args.background, x) | ||
end | end | ||
− | return markOuterDiv(x, y, divContent) | + | return retval .. markOuterDiv(x, y, divContent) |
end | end | ||
Line 240: | Line 285: | ||
end | end | ||
return p.top(frame, args, map) .. p.mark(frame, args, map) .. p.bottom(frame, args, map) | return p.top(frame, args, map) .. p.mark(frame, args, map) .. p.bottom(frame, args, map) | ||
+ | end | ||
+ | |||
+ | local function manyMakeArgs(fullArgs, n) | ||
+ | if n == 1 then | ||
+ | return { | ||
+ | fullArgs[1], | ||
+ | lat = fullArgs.lat1 or fullArgs.lat, | ||
+ | long = fullArgs.long1 or fullArgs.long, | ||
+ | lat_deg = fullArgs.lat1_deg or fullArgs.lat_deg, | ||
+ | lat_min = fullArgs.lat1_min or fullArgs.lat_min, | ||
+ | lat_sec = fullArgs.lat1_sec or fullArgs.lat_sec, | ||
+ | lat_dir = fullArgs.lat1_dir or fullArgs.lat_dir, | ||
+ | lon_deg = fullArgs.lon1_deg or fullArgs.lon_deg, | ||
+ | lon_min = fullArgs.lon1_min or fullArgs.lon_min, | ||
+ | lon_sec = fullArgs.lon1_sec or fullArgs.lon_sec, | ||
+ | lon_dir = fullArgs.lon1_dir or fullArgs.lon_dir, | ||
+ | mark = fullArgs.mark1 or fullArgs.mark, | ||
+ | marksize = fullArgs.mark1size or fullArgs.marksize, | ||
+ | link = fullArgs.link1 or fullArgs.link, | ||
+ | label = fullArgs.label1 or fullArgs.label, | ||
+ | label_size = fullArgs.label1_size or fullArgs.label_size, | ||
+ | position = fullArgs.position1 or fullArgs.pos1 or fullArgs.position or fullArgs.pos, | ||
+ | background = fullArgs.background1 or fullArgs.bg1 or fullArgs.background or fullArgs.bg | ||
+ | } | ||
+ | else | ||
+ | return { | ||
+ | fullArgs[1], | ||
+ | lat = fullArgs['lat' .. n], | ||
+ | long = fullArgs['long' .. n], | ||
+ | lat_deg = fullArgs['lat' .. n .. '_deg'], | ||
+ | lat_min = fullArgs['lat' .. n .. '_min'], | ||
+ | lat_sec = fullArgs['lat' .. n .. '_sec'], | ||
+ | lat_dir = fullArgs['lat' .. n .. '_dir'], | ||
+ | lon_deg = fullArgs['lon' .. n .. '_deg'], | ||
+ | lon_min = fullArgs['lon' .. n .. '_min'], | ||
+ | lon_sec = fullArgs['lon' .. n .. '_sec'], | ||
+ | lon_dir = fullArgs['lon' .. n .. '_dir'], | ||
+ | mark = fullArgs['mark' .. n], | ||
+ | marksize = fullArgs['mark' .. n .. 'size'], | ||
+ | link = fullArgs['link' .. n], | ||
+ | label = fullArgs['label' .. n], | ||
+ | label_size = fullArgs['label' .. n .. '_size'], | ||
+ | position = fullArgs['position' .. n] or fullArgs['pos' .. n], | ||
+ | background = fullArgs['background' .. n] or fullArgs['bg' .. n] | ||
+ | } | ||
+ | end | ||
+ | end | ||
+ | |||
+ | function p.many(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 | ||
+ | local marks = {} | ||
+ | local markhigh = args.markhigh | ||
+ | for k, v in pairs(args) do -- @todo change to uargs once we have that | ||
+ | if v then | ||
+ | if string.sub(k, -4) == '_deg' then | ||
+ | k = string.sub(k, 1, -5) | ||
+ | end | ||
+ | if string.sub(k, 1, 3) == 'lat' then | ||
+ | k = tonumber(string.sub(k, 4)) | ||
+ | if k then | ||
+ | table.insert(marks, k) | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | table.sort(marks) | ||
+ | if marks[1] ~= 1 and (args.lat or args.lat_deg) then | ||
+ | table.insert(marks, 1, 1) | ||
+ | end | ||
+ | local body = '' | ||
+ | for _, v in ipairs(marks) do | ||
+ | -- don't try to consolidate this into the above loop. ordering of elements from pairs() is unspecified | ||
+ | body = body .. p.mark(frame, manyMakeArgs(args, v), map) | ||
+ | if args['mark' .. v .. 'high'] then | ||
+ | markhigh = true | ||
+ | end | ||
+ | end | ||
+ | args.label = nil -- there is no global label | ||
+ | return p.top(frame, args, map) .. body .. p.bottom(frame, args, map) .. (markhigh and '[[Category:Location map many using markhigh parameter]]' or '') | ||
end | end | ||
return p | return p |
40x40px | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
This module implements the {{Location map}}, {{Location map+}}, {{Location map~}}, and {{Location map many}} templates. Please see the template pages for usage instructions.
require('Module:No globals') local p = {} local getArgs = require('Module:Arguments').getArgs local function getMapParams(map, frame) if not map then error('The name of the location map definition to use must be specified', 2) end local moduletitle = mw.title.new('Module:Location map/data/' .. map) if not moduletitle then error('"' .. map .. '" is not a valid name for a location map definition', 2) elseif moduletitle.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(tostring(mapData[name]), unpack(params)):plain() else return mapData[name] end end elseif mw.title.new('Template:Location map ' .. map).exists then 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 else error('Unable to find the specified location map definition. Neither "Module:Location map/data/' .. map .. '" nor "Template:Location map ' .. map .. '" exists', 2) end end function p.data(frame, args, map) if not args then args = getArgs(frame) end if not map then map = getMapParams(args[1], frame) end local params = {} for k,v in ipairs(args) do if k > 2 then params[k-2] = v end end return map(args[2], #params and params) end local hemisphereMultipliers = { longitude = { W = -1, w = -1, E = 1, e = 1 }, latitude = { S = -1, s = -1, N = 1, n = 1 } } local function decdeg(degrees, minutes, seconds, hemisphere, decimal, direction) if not degrees then if not decimal then error('No value was provided for ' .. direction, 2) end local retval = tonumber(decimal) if retval then return retval end error('The value "' .. decimal .. '" provided for ' .. direction .. ' is not valid', 2) end decimal = tonumber(degrees) if not decimal then error('The degree value "' .. degrees .. '" provided for ' .. direction .. ' is not valid', 2) end if minutes and not tonumber(minutes) then error('The minute value "' .. minutes .. '" provided for ' .. direction .. ' is not valid', 2) end if seconds and not tonumber(seconds) then error('The second value "' .. seconds .. '" provided for ' .. direction .. ' is not valid', 2) end decimal = decimal + (minutes or 0)/60 + (seconds or 0)/3600 if hemisphere then local multiplier = hemisphereMultipliers[direction][hemisphere] if not multiplier then error('The hemisphere "' .. hemisphere .. '" provided for ' .. direction .. ' is not valid', 2) end decimal = decimal * multiplier end return decimal 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 not args.width then width = math.floor((args.default_width or 240) * (tonumber(map('defaultscale')) or 1) + 0.5) elseif mw.ustring.sub(args.width, -2) == 'px' then width = mw.ustring.sub(args.width, 1, -3) else width = args.width end local retval = args.float == 'center' and '<div class="center">' or '' 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;width:' .. width .. 'px' .. (args.border ~= 'none' and ';border:1px solid lightgray">' or '">') 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;width:' .. width .. 'px">' 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 return retval .. '<div style="position:absolute;top:0;left:0">[[File:' .. args.overlay_image .. '|' .. width .. 'px|link=File:' .. image .. ']]</div>' else return retval end 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 = '</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 if args.caption_undefined then retval = retval .. '[[Category:Location maps using skew|!]]' 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:-' .. math.floor(marksize / 2 + 0.5) .. 'px;top:-' .. math.floor(marksize / 2 + 0.5) .. 'px;width:' .. marksize .. 'px;font-size:' .. marksize .. 'px;line-height:0"' .. (title and (' title="' .. title .. '">') or '>') 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, left, right) local width = (right - left) % 360 if width == 0 then width = 360 end local distanceFromLeft = (longitude - left) % 360 -- the distance needed past the map to the right equals distanceFromLeft - width. the distance needed past the map to the left equals 360 - distanceFromLeft. to minimize page stretching, go whichever way is shorter if distanceFromLeft - width / 2 >= 180 then distanceFromLeft = distanceFromLeft - 360 end return 100 * distanceFromLeft / width end local function getY(latitude, top, bottom) return 100 * (top - latitude) / (top - bottom) 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, latitude longitude = decdeg(args.lon_deg, args.lon_min, args.lon_sec, args.lon_dir, args.long, 'longitude') latitude = decdeg(args.lat_deg, args.lat_min, args.lat_sec, args.lat_dir, args.lat, 'latitude') local retval = '' if args.skew or args.lon_shift or (map('skew') ~= '') or (map('lat_skew') ~= '') or (map('crosses180') ~= '') then retval = retval .. '[[Category:Location maps using skew|' .. args[1] .. ']]' end if map('x') ~= '' then x = frame:callParserFunction('#expr', map('x', { latitude, longitude })) else x = getX(longitude, map('left'), map('right')) 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 retval .. 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 local function manyMakeArgs(fullArgs, n) if n == 1 then return { fullArgs[1], lat = fullArgs.lat1 or fullArgs.lat, long = fullArgs.long1 or fullArgs.long, lat_deg = fullArgs.lat1_deg or fullArgs.lat_deg, lat_min = fullArgs.lat1_min or fullArgs.lat_min, lat_sec = fullArgs.lat1_sec or fullArgs.lat_sec, lat_dir = fullArgs.lat1_dir or fullArgs.lat_dir, lon_deg = fullArgs.lon1_deg or fullArgs.lon_deg, lon_min = fullArgs.lon1_min or fullArgs.lon_min, lon_sec = fullArgs.lon1_sec or fullArgs.lon_sec, lon_dir = fullArgs.lon1_dir or fullArgs.lon_dir, mark = fullArgs.mark1 or fullArgs.mark, marksize = fullArgs.mark1size or fullArgs.marksize, link = fullArgs.link1 or fullArgs.link, label = fullArgs.label1 or fullArgs.label, label_size = fullArgs.label1_size or fullArgs.label_size, position = fullArgs.position1 or fullArgs.pos1 or fullArgs.position or fullArgs.pos, background = fullArgs.background1 or fullArgs.bg1 or fullArgs.background or fullArgs.bg } else return { fullArgs[1], lat = fullArgs['lat' .. n], long = fullArgs['long' .. n], lat_deg = fullArgs['lat' .. n .. '_deg'], lat_min = fullArgs['lat' .. n .. '_min'], lat_sec = fullArgs['lat' .. n .. '_sec'], lat_dir = fullArgs['lat' .. n .. '_dir'], lon_deg = fullArgs['lon' .. n .. '_deg'], lon_min = fullArgs['lon' .. n .. '_min'], lon_sec = fullArgs['lon' .. n .. '_sec'], lon_dir = fullArgs['lon' .. n .. '_dir'], mark = fullArgs['mark' .. n], marksize = fullArgs['mark' .. n .. 'size'], link = fullArgs['link' .. n], label = fullArgs['label' .. n], label_size = fullArgs['label' .. n .. '_size'], position = fullArgs['position' .. n] or fullArgs['pos' .. n], background = fullArgs['background' .. n] or fullArgs['bg' .. n] } end end function p.many(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 local marks = {} local markhigh = args.markhigh for k, v in pairs(args) do -- @todo change to uargs once we have that if v then if string.sub(k, -4) == '_deg' then k = string.sub(k, 1, -5) end if string.sub(k, 1, 3) == 'lat' then k = tonumber(string.sub(k, 4)) if k then table.insert(marks, k) end end end end table.sort(marks) if marks[1] ~= 1 and (args.lat or args.lat_deg) then table.insert(marks, 1, 1) end local body = '' for _, v in ipairs(marks) do -- don't try to consolidate this into the above loop. ordering of elements from pairs() is unspecified body = body .. p.mark(frame, manyMakeArgs(args, v), map) if args['mark' .. v .. 'high'] then markhigh = true end end args.label = nil -- there is no global label return p.top(frame, args, map) .. body .. p.bottom(frame, args, map) .. (markhigh and '[[Category:Location map many using markhigh parameter]]' or '') end return p