「モジュール:Location map」の版間の差分

提供:関南・東山地方Wiki
ナビゲーションに移動 検索に移動
template>K-iczn
(モジュール:Location map/sandbox 2015年3月14日 (土) 16:40‎(UTC)より)
(13版 をインポートしました)
 
(3人の利用者による、間の6版が非表示)
12行目: 12行目:
function p.getMapParams(map, frame)
function p.getMapParams(map, frame)
if not map then
if not map then
error('The name of the location map definition to use must be specified', 2)
error('Location mapの名前は必ず指定しなければなりません。', 2)
end
end
local moduletitle = mw.title.new('Module:Location map/data/' .. map)
local moduletitle = mw.title.new('Module:Location map/data/' .. map)
if not moduletitle then
if not moduletitle then
error('"' .. map .. '" is not a valid name for a location map definition', 2)
error(string.format('%qはLocation mapの名前として無効です。', map), 2)
elseif moduletitle.exists then
elseif moduletitle.exists then
local mapData = mw.loadData('Module:Location map/data/' .. map)
local mapData = mw.loadData('Module:Location map/data/' .. map)
33行目: 33行目:
local cache = {}
local cache = {}
if type(frame) ~= 'table' or type(frame.expandTemplate) ~= 'function' then
if type(frame) ~= 'table' or type(frame.expandTemplate) ~= 'function' then
error('A frame must be provided when using a legacy location map')
error('古いLocation mapを使うときにフレームが存在しなければなりません。')
end
end
return function(name, params)
return function(name, params)
48行目: 48行目:
end
end
else
else
error('Unable to find the specified location map definition. Neither "Module:Location map/data/' .. map .. '" nor "Template:Location map ' .. map .. '" exists', 2)
error('Location mapのモジュール「"Module:Location map/data/' .. map .. '"」もしくはテンプレート「"Template:Location map ' .. map .. '"」が作成されていません。', 2)
end
end
end
end
76行目: 76行目:
if decimal then
if decimal then
if degrees then
if degrees then
error('Decimal and DMS degrees cannot both be provided for ' .. direction, 2)
error(direction .. 'において10進数形式と度分秒は両方指定できません。', 2)
elseif minutes then
elseif minutes then
error('Minutes can only be provided with DMS degrees for ' .. direction, 2)
error(direction .. 'において分は度分秒方式でのみ指定してください。', 2)
elseif seconds then
elseif seconds then
error('Seconds can only be provided with DMS degrees for ' .. direction, 2)
error(direction .. 'において秒は度分秒方式でのみ指定してください。', 2)
elseif hemisphere then
elseif hemisphere then
error('A hemisphere can only be provided with DMS degrees for ' .. direction, 2)
error(direction .. 'において半球は度分秒方式でのみ指定してください。', 2)
end
end
local retval = tonumber(decimal)
local retval = tonumber(decimal)
88行目: 88行目:
return retval
return retval
end
end
error('The value "' .. decimal .. '" provided for ' .. direction .. ' is not valid', 2)
error(direction .. 'の値"' .. decimal .. '"は無効です。', 2)
elseif seconds and not minutes then
elseif seconds and not minutes then
error('Seconds were provided for ' .. direction .. ' without minutes also being provided', 2)
error(direction .. 'の秒を指定する時は分も指定してください。', 2)
elseif not degrees then
elseif not degrees then
if minutes then
if minutes then
error('Minutes were provided for ' .. direction .. ' without degrees also being provided', 2)
error(direction .. 'の分を指定する時は度も指定してください。', 2)
elseif hemisphere then
elseif hemisphere then
error('A hemisphere was provided for ' .. direction .. ' without degrees also being provided', 2)
error(direction .. 'の半球を指定する時は度も指定してください。', 2)
end
end
return nil
return nil
101行目: 101行目:
decimal = tonumber(degrees)
decimal = tonumber(degrees)
if not decimal then
if not decimal then
error('The degree value "' .. degrees .. '" provided for ' .. direction .. ' is not valid', 2)
error(direction .. 'の度の値"' .. degrees .. '"は無効です。', 2)
elseif minutes and not tonumber(minutes) then
elseif minutes and not tonumber(minutes) then
error('The minute value "' .. minutes .. '" provided for ' .. direction .. ' is not valid', 2)
error(direction .. 'の分の値"' .. minutes .. '"は無効です。', 2)
elseif seconds and not tonumber(seconds) then
elseif seconds and not tonumber(seconds) then
error('The second value "' .. seconds .. '" provided for ' .. direction .. ' is not valid', 2)
error(direction .. 'の秒の値"' .. seconds .. '"は無効です。', 2)
end
end
decimal = decimal + (minutes or 0)/60 + (seconds or 0)/3600
decimal = decimal + (minutes or 0)/60 + (seconds or 0)/3600
111行目: 111行目:
local multiplier = hemisphereMultipliers[direction][hemisphere]
local multiplier = hemisphereMultipliers[direction][hemisphere]
if not multiplier then
if not multiplier then
error('The hemisphere "' .. hemisphere .. '" provided for ' .. direction .. ' is not valid', 2)
error(direction .. 'の半球である"' .. hemisphere .. '"は無効です。', 2)
end
end
decimal = decimal * multiplier
decimal = decimal * multiplier
end
end
return decimal
return decimal
end
-- Finds a parameter in a transclusion of {{Coord}}.
local function coord2text(para,coord) -- this should be changed for languages which do not use Arabic numerals or the degree sign
local result = mw.text.split(mw.ustring.match(coord,'%-?[%.%d]+°[NS] %-?[%.%d]+°[EW]') or '', '[ °]')
if para == 'longitude' then result = {result[3], result[4]} end
if not tonumber(result[1]) or not result[2] then return error('不正な座標指定です。', 2) end
return tonumber(result[1]) * hemisphereMultipliers[para][result[2]]
end
end


150行目: 158行目:
end
end
local width
local width
local default_as_number = tonumber(mw.ustring.match(tostring(args.default_width),"%d*"))
if not args.width then
if not args.width then
width = round((args.default_width or 240) * (tonumber(map('defaultscale')) or 1))
width = round((default_as_number or 240) * (tonumber(map('defaultscale')) or 1))
elseif mw.ustring.sub(args.width, -2) == 'px' then
elseif mw.ustring.sub(args.width, -2) == 'px' then
width = mw.ustring.sub(args.width, 1, -3)
width = mw.ustring.sub(args.width, 1, -3)
157行目: 166行目:
width = args.width
width = args.width
end
end
local width_as_number = tonumber(mw.ustring.match(tostring(width),"%d*")) or 0;
    if width_as_number == 0 then
    -- check to see if width is junk. If it is, then use default calculation
    width = round((default_as_number or 240) * (tonumber(map('defaultscale')) or 1))
    width_as_number = tonumber(mw.ustring.match(tostring(width),"%d*")) or 0;
    end
    if args.max_width ~= "" and args.max_width ~= nil then
        -- check to see if width bigger than max_width
        local max_as_number = tonumber(mw.ustring.match(args.max_width,"%d*")) or 0;
        if width_as_number>max_as_number and max_as_number>0 then
            width = args.max_width;
        end
    end
local retval = args.float == 'center' and '<div class="center">' or ''
local retval = args.float == 'center' and '<div class="center">' or ''
if args.caption and args.caption ~= '' then
if args.caption and args.caption ~= '' and args.border ~= 'infobox' then
retval = retval .. '<div class="noviewer thumb '
retval = retval .. '<div class="noviewer thumb '
if args.float == '"left"' or args.float == 'left' then
if args.float == '"left"' or args.float == 'left' then
212行目: 234行目:
local retval = '</div>'
local retval = '</div>'
if not args.caption then
if not args.caption or args.border == 'infobox' then
retval = retval .. '<div style="font-size:90%;padding-top:3px">'
if args.border then
.. ((args.label or mw.title.getCurrentTitle().text) .. ' (' .. map('name') .. ')')
retval = retval .. '<div>'
else
retval = retval .. '<div style="font-size:90%;padding-top:3px">'
end
retval = retval
.. (args.caption or (args.label or mw.title.getCurrentTitle().text) .. ' (' .. map('name') .. ')')
.. '</div>'
.. '</div>'
elseif args.caption == ''  then
elseif args.caption ~= ''  then
retval = retval .. '<div style="font-size:90%;padding-top:3px"></div>'
else
-- This is not the pipe trick. We're creating a link with no text on purpose, so that CSS can give us a nice image
-- This is not the pipe trick. We're creating a link with no text on purpose, so that CSS can give us a nice image
retval = retval .. '<div class="thumbcaption"><div class="magnify">[[:File:' .. getContainerImage(args, map) .. '| ]]</div>' .. args.caption .. '</div>'
retval = retval .. '<div class="thumbcaption"><div class="magnify">[[:File:' .. getContainerImage(args, map) .. '| ]]</div>' .. args.caption .. '</div>'
226行目: 251行目:
retval = retval .. '<span class="switcher-label" style="display:none">' .. args.switcherLabel .. '</span>'
retval = retval .. '<span class="switcher-label" style="display:none">' .. args.switcherLabel .. '</span>'
elseif args.autoSwitcherLabel then
elseif args.autoSwitcherLabel then
retval = retval .. '<span class="switcher-label" style="display:none">Show map of ' .. map('name') .. '</span>'
retval = retval .. '<span class="switcher-label" style="display:none">' .. map('name') .. 'の地図を表示</span>'
end
end
retval = retval .. '</div></div>'
retval = retval .. '</div></div>'
if args.caption_undefined then
if args.caption_undefined then
mw.log('Removed parameter caption_undefined used.')
mw.log('caption_undefinedは廃止されたパラメータです。')
local parent = frame:getParent()
local parent = frame:getParent()
if parent then
if parent then
237行目: 262行目:
end
end
mw.logObject(args, 'args')
mw.logObject(args, 'args')
retval = retval .. ''
end
if map('skew') ~= '' or map('lat_skew') ~= '' or map('crosses180') ~= '' or map('type') ~= '' then
mw.log(map() .. 'において廃止されたパラメータです。')
retval = retval .. ''
end
if string.find(map('name'), '|', 1, true) then
mw.log(map() .. 'のLocation map名でパイプを使用しています。')
retval = retval .. ''
retval = retval .. ''
end
end
247行目: 280行目:
local function markOuterDiv(x, y, imageDiv, labelDiv)
local function markOuterDiv(x, y, imageDiv, labelDiv)
return mw.html.create('div')
return mw.html.create('div')
:cssText('position:absolute;z-index:1;top:' .. round(y, 3) .. '%;left:' .. round(x, 3) .. '%;height:0;width:0;margin:0;padding:0')
:cssText('position:absolute;z-index:1;top:' .. round(y, 3) .. '%;left:' .. round(x, 3) .. '%')
:node(imageDiv)
:node(imageDiv)
:node(labelDiv)
:node(labelDiv)
254行目: 287行目:
local function markImageDiv(mark, marksize, label, link, alt, title)
local function markImageDiv(mark, marksize, label, link, alt, title)
local builder = mw.html.create('div')
local builder = mw.html.create('div')
:cssText('position:absolute;text-align:center;left:-' .. round(marksize / 2) .. 'px;top:-' .. round(marksize / 2) .. 'px;width:' .. marksize .. 'px;font-size:' .. marksize .. 'px;line-height:0')
:cssText('position:absolute;left:-' .. round(marksize / 2) .. 'px;top:-' .. round(marksize / 2) .. 'px;line-height:0')
:attr('title', title)
:attr('title', title)
if marksize ~= 0 then
if marksize ~= 0 then
271行目: 304行目:


local function markLabelDiv(label, label_size, label_width, position, background, x, marksize)
local function markLabelDiv(label, label_size, label_width, position, background, x, marksize)
if tonumber(label_size) == 0 then
return mw.html.create('div'):cssText('font-size:0%;position:absolute'):wikitext(label)
end
local builder = mw.html.create('div')
local builder = mw.html.create('div')
:cssText('font-size:' .. label_size .. '%;line-height:110%;position:absolute;width:' .. label_width .. 'em')
:cssText('font-size:' .. label_size .. '%;line-height:110%;position:absolute;width:' .. label_width .. 'em')
323行目: 359行目:
longitude = decdeg(args.lon_deg, args.lon_min, args.lon_sec, args.lon_dir, args.long, 'longitude')
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')
latitude = decdeg(args.lat_deg, args.lat_min, args.lat_sec, args.lat_dir, args.lat, 'latitude')
if not longitude and not latitude and args.useWikidata then
if args.coordinates then
-- Temporarily removed to facilitate infobox conversion.
 
-- if longitude or latitude then
-- error('[[Module:Coordinates]]からの座標とローカル指定座標の両方を提供できません。')
-- end
longitude = coord2text('longitude', args.coordinates)
latitude = coord2text('latitude', args.coordinates)
elseif not longitude and not latitude and args.useWikidata then
-- If they didn't provide either coordinate, try Wikidata. If they provided one but not the other, don't.
-- If they didn't provide either coordinate, try Wikidata. If they provided one but not the other, don't.
local entity = mw.wikibase.getEntity()
local entity = mw.wikibase.getEntity()
if entity and entity.claims and entity.claims.p625 and entity.claims.p625[0].mainsnak.snaktype == 'value' then
if entity and entity.claims and entity.claims.P625 and entity.claims.P625[1].mainsnak.snaktype == 'value' then
local value = entity.claims.p625[0].mainsnak.datavalue.value
local value = entity.claims.P625[1].mainsnak.datavalue.value
longitude, latitude = value.longitude, value.latitude
longitude, latitude = value.longitude, value.latitude
end
end
end
end
if not longitude then
if not longitude then
error('No value was provided for longitude')
error('緯度の値が指定されていません。')
end
elseif not latitude then
if not latitude then
error('経度の値が指定されていません。')
error('No value was provided for latitude')
end
end
local builder = mw.html.create()
local builder = mw.html.create()
350行目: 393行目:
end
end
if args.skew or args.lon_shift or args.markhigh then
if args.skew or args.lon_shift or args.markhigh then
mw.log('Removed parameter used in invocation.')
mw.log('呼び出しにおいて廃止されたパラメータです。')
local parent = frame:getParent()
local parent = frame:getParent()
if parent then
if parent then
mw.log('Parent is ' .. parent:getTitle())
mw.log(parent:getTitle() .. 'の親です。')
end
end
mw.logObject(args, 'args')
mw.logObject(args, 'args')
builder:wikitext('')
end
if map('skew') ~= '' or map('lat_skew') ~= '' or map('crosses180') ~= '' or map('type') ~= '' then
mw.log('Removed parameter used in map definition ' .. map())
builder:wikitext('')
builder:wikitext('')
end
end
373行目: 412行目:
end
end
if (x < 0 or x > 100 or y < 0 or y > 100) and not args.outside then
if (x < 0 or x > 100 or y < 0 or y > 100) and not args.outside then
mw.log('Mark placed outside map boundaries without outside flag set. x = ' .. x .. ', y = ' .. y)
mw.log('外部フラグ設定無しに地図外にマークが置かれました。 x = ' .. x .. ', y = ' .. y)
local parent = frame:getParent()
local parent = frame:getParent()
if parent then
if parent then
mw.log('Parent is ' .. parent:getTitle())
mw.log(parent:getTitle() .. 'の親です。')
end
end
mw.logObject(args, 'args')
mw.logObject(args, 'args')
392行目: 431行目:
end
end
return builder:node(markOuterDiv(x, y, imageDiv, labelDiv))
return builder:node(markOuterDiv(x, y, imageDiv, labelDiv))
end
local function switcherSeparate(s)
if s == nil then return {} end
local retval = {}
for i in string.gmatch(s .. '#', '([^#]*)#') do
i = mw.text.trim(i)
retval[#retval + 1] = (i ~= '' and i)
end
return retval
end
end


413行目: 462行目:
end
end
if type(map) == 'table' then
if type(map) == 'table' then
local altmaps = switcherSeparate(args.AlternativeMap)
if #altmaps > #map then
error(string.format('%dのAlternativeMapsが提供されていますが、%dの地図のみの提供になります。', #altmaps, #map))
end
local overlays = switcherSeparate(args.overlay_image)
if #overlays > #map then
error(string.format('%dのoverlay_imagesが提供されていますが、%dの地図のみの提供になります。', #overlays, #map))
end
local outputs = {}
local outputs = {}
args.autoSwitcherLabel = true
args.autoSwitcherLabel = true
for k,v in ipairs(map) do
for k,v in ipairs(map) do
args.AlternativeMap = altmaps[k]
args.overlay_image = overlays[k]
outputs[k] = p.main(frame, args, v)
outputs[k] = p.main(frame, args, v)
end
end

2021年3月3日 (水) 23:57時点における最新版

このモジュールについての説明文ページを モジュール:Location map/doc に作成できます

require('Module:No globals')

local p = {}

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

local function round(n, decimals)
	local pow = 10^(decimals or 0)
	return math.floor(n * pow + 0.5) / pow
end

function p.getMapParams(map, frame)
	if not map then
		error('Location mapの名前は必ず指定しなければなりません。', 2)
	end
	local moduletitle = mw.title.new('Module:Location map/data/' .. map)
	if not moduletitle then
		error(string.format('%qはLocation mapの名前として無効です。', map), 2)
	elseif moduletitle.exists then
		local mapData = mw.loadData('Module:Location map/data/' .. map)
		return function(name, params)
			if name == nil then
				return 'Module:Location map/data/' .. map
			elseif 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 = {}
		if type(frame) ~= 'table' or type(frame.expandTemplate) ~= 'function' then
			error('古いLocation mapを使うときにフレームが存在しなければなりません。')
		end
		return function(name, params)
			if params then
				return frame:expandTemplate{title = 'Location map ' .. map, args = { name, unpack(params) }}
			else
				if name == nil then
					return 'Template:Location map ' .. map
				elseif cache[name] == nil then
					cache[name] = frame:expandTemplate{title = 'Location map ' .. map, args = { name }}
				end
				return cache[name]
			end
		end
	else
		error('Location mapのモジュール「"Module:Location map/data/' .. map .. '"」もしくはテンプレート「"Template:Location map ' .. map .. '"」が作成されていません。', 2)
	end
end

function p.data(frame, args, map)
	if not args then
		args = getArgs(frame, {frameOnly = true})
	end
	if not map then
		map = p.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 ~= 0 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 decimal then
		if degrees then
			error(direction .. 'において10進数形式と度分秒は両方指定できません。', 2)
		elseif minutes then
			error(direction .. 'において分は度分秒方式でのみ指定してください。', 2)
		elseif seconds then
			error(direction .. 'において秒は度分秒方式でのみ指定してください。', 2)
		elseif hemisphere then
			error(direction .. 'において半球は度分秒方式でのみ指定してください。', 2)
		end
		local retval = tonumber(decimal)
		if retval then
			return retval
		end
		error(direction .. 'の値"' .. decimal .. '"は無効です。', 2)
	elseif seconds and not minutes then
		error(direction .. 'の秒を指定する時は分も指定してください。', 2)
	elseif not degrees then
		if minutes then
			error(direction .. 'の分を指定する時は度も指定してください。', 2)
		elseif hemisphere then
			error(direction .. 'の半球を指定する時は度も指定してください。', 2)
		end
		return nil
	end
	decimal = tonumber(degrees)
	if not decimal then
		error(direction .. 'の度の値"' .. degrees .. '"は無効です。', 2)
	elseif minutes and not tonumber(minutes) then
		error(direction .. 'の分の値"' .. minutes .. '"は無効です。', 2)
	elseif seconds and not tonumber(seconds) then
		error(direction .. 'の秒の値"' .. seconds .. '"は無効です。', 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(direction .. 'の半球である"' .. hemisphere .. '"は無効です。', 2)
		end
		decimal = decimal * multiplier
	end
	return decimal
end

-- Finds a parameter in a transclusion of {{Coord}}.
local function coord2text(para,coord) -- this should be changed for languages which do not use Arabic numerals or the degree sign
	local result = mw.text.split(mw.ustring.match(coord,'%-?[%.%d]+°[NS] %-?[%.%d]+°[EW]') or '', '[ °]')
	if para == 'longitude' then result = {result[3], result[4]} end
	if not tonumber(result[1]) or not result[2] then return error('不正な座標指定です。', 2) end
	return tonumber(result[1]) * hemisphereMultipliers[para][result[2]]
end

-- effectively make removeBlanks false for caption and maplink, and true for everything else
-- if useWikidata is present but blank, convert it to false instead of nil
-- p.top, p.bottom, and their callers need to use this
function p.valueFunc(key, value)
	if value then
		value = mw.text.trim(value)
	end
	if value ~= '' or key == 'caption' or key == 'maplink' then
		return value
	elseif key == 'useWikidata' then
		return false
	end
end

local function getContainerImage(args, map)
	if args.AlternativeMap then
		return args.AlternativeMap
	elseif args.relief and map('image1') ~= '' then
		return map('image1')
	else
		return map('image')
	end
end

function p.top(frame, args, map)
	if not args then
		args = getArgs(frame, {frameOnly = true, valueFunc = p.valueFunc})
	end
	if not map then
		map = p.getMapParams(args[1], frame)
	end
	local width
	local default_as_number = tonumber(mw.ustring.match(tostring(args.default_width),"%d*"))
	if not args.width then
		width = round((default_as_number or 240) * (tonumber(map('defaultscale')) or 1))
	elseif mw.ustring.sub(args.width, -2) == 'px' then
		width = mw.ustring.sub(args.width, 1, -3)
	else
		width = args.width
	end
	local width_as_number = tonumber(mw.ustring.match(tostring(width),"%d*")) or 0;
    if width_as_number == 0 then
    	-- check to see if width is junk. If it is, then use default calculation
    	width = round((default_as_number or 240) * (tonumber(map('defaultscale')) or 1))
    	width_as_number = tonumber(mw.ustring.match(tostring(width),"%d*")) or 0;
    end	
    if args.max_width ~= "" and args.max_width ~= nil then
        -- check to see if width bigger than max_width
        local max_as_number = tonumber(mw.ustring.match(args.max_width,"%d*")) or 0;
        if width_as_number>max_as_number and max_as_number>0 then
            width = args.max_width;
        end
    end
	local retval = args.float == 'center' and '<div class="center">' or ''
	if args.caption and args.caption ~= '' and args.border ~= 'infobox' then
		retval = retval .. '<div class="noviewer 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 = getContainerImage(args, map)
	retval = string.format(
		'%s[[File:%s|%spx|%s%s]]',
		retval,
		image,
		width,
		args.alt or ((args.label or mw.title.getCurrentTitle().text) .. 'の位置(' .. map('name')) .. '内)',
		args.maplink and ('|link=' .. args.maplink) or ''
	)
	if args.overlay_image then
		return retval .. '<div style="position:absolute;top:0;left:0">[[File:' .. args.overlay_image .. '|' .. width .. 'px]]</div>'
	else
		return retval
	end
end

function p.bottom(frame, args, map)
	if not args then
		args = getArgs(frame, {frameOnly = true, valueFunc = p.valueFunc})
	end
	if not map then
		map = p.getMapParams(args[1], frame)
	end
	local retval = '</div>'
	
	if not args.caption or args.border == 'infobox' then
		if args.border then
			retval = retval .. '<div>'
		else
			retval = retval .. '<div style="font-size:90%;padding-top:3px">'
		end
		retval = retval
		.. (args.caption or (args.label or mw.title.getCurrentTitle().text) .. ' (' .. map('name') .. ')')
		.. '</div>'
	elseif args.caption ~= ''  then
		-- This is not the pipe trick. We're creating a link with no text on purpose, so that CSS can give us a nice image
		retval = retval .. '<div class="thumbcaption"><div class="magnify">[[:File:' .. getContainerImage(args, map) .. '| ]]</div>' .. args.caption .. '</div>'
	end

	if args.switcherLabel then
		retval = retval .. '<span class="switcher-label" style="display:none">' .. args.switcherLabel .. '</span>'
	elseif args.autoSwitcherLabel then
		retval = retval .. '<span class="switcher-label" style="display:none">' .. map('name') .. 'の地図を表示</span>'
	end
	
	retval = retval .. '</div></div>'
	if args.caption_undefined then
		mw.log('caption_undefinedは廃止されたパラメータです。')
		local parent = frame:getParent()
		if parent then
			mw.log('Parent is ' .. parent:getTitle())
		end
		mw.logObject(args, 'args')
		retval = retval .. ''
	end
	if map('skew') ~= '' or map('lat_skew') ~= '' or map('crosses180') ~= '' or map('type') ~= '' then
		mw.log(map() .. 'において廃止されたパラメータです。')
		retval = retval .. ''
	end
	if string.find(map('name'), '|', 1, true) then
		mw.log(map() .. 'のLocation map名でパイプを使用しています。')
		retval = retval .. ''
	end
	if args.float == 'center' then
		retval = retval .. '</div>'
	end
	return retval
end

local function markOuterDiv(x, y, imageDiv, labelDiv)
	return mw.html.create('div')
		:cssText('position:absolute;z-index:1;top:' .. round(y, 3) .. '%;left:' .. round(x, 3) .. '%')
		:node(imageDiv)
		:node(labelDiv)
end

local function markImageDiv(mark, marksize, label, link, alt, title)
	local builder = mw.html.create('div')
		:cssText('position:absolute;left:-' .. round(marksize / 2) .. 'px;top:-' .. round(marksize / 2) .. 'px;line-height:0')
		:attr('title', title)
	if marksize ~= 0 then
		builder:wikitext(string.format(
			'[[File:%s|%dx%dpx|%s|link=%s%s]]',
			mark,
			marksize,
			marksize,
			label,
			link,
			alt and ('|alt=' .. alt) or ''
		))
	end
	return builder
end

local function markLabelDiv(label, label_size, label_width, position, background, x, marksize)
	if tonumber(label_size) == 0 then
		return mw.html.create('div'):cssText('font-size:0%;position:absolute'):wikitext(label)
	end
	local builder = mw.html.create('div')
		:cssText('font-size:' .. label_size .. '%;line-height:110%;position:absolute;width:' .. label_width .. 'em')
	local distance = round(marksize / 2 + 1)
	local spanCss
	if position == 'top' then -- specified top
		builder:cssText('bottom:' .. distance .. 'px;left:' .. (-label_width / 2) .. 'em;text-align:center')
	elseif position == 'bottom' then -- specified bottom
		builder:cssText('top:' .. distance .. 'px;left:' .. (-label_width / 2) .. 'em;text-align:center')
	elseif position == 'left' or (tonumber(x) > 70 and position ~= 'right') then -- specified left or autodetected to left
		builder:cssText('top:-0.75em;right:' .. distance .. 'px;text-align:right')
		spanCss = 'float:right'
	else -- specified right or autodetected to right
		builder:cssText('top:-0.75em;left:' .. distance .. 'px;text-align:left')
		spanCss = 'float:left'
	end
	builder = builder:tag('span')
		:cssText('padding:1px')
		:cssText(spanCss)
		:wikitext(label)
	if background then
		builder:cssText('background-color:' .. background)
	end
	return builder:done()
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, {wrappers = 'Template:Location map~'})
	end
	if not map then
		map = p.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')
	if args.coordinates then
--		Temporarily removed to facilitate infobox conversion.

--		if longitude or latitude then
--			error('[[Module:Coordinates]]からの座標とローカル指定座標の両方を提供できません。')
--		end
		longitude = coord2text('longitude', args.coordinates)
		latitude = coord2text('latitude', args.coordinates)
	elseif not longitude and not latitude and args.useWikidata then
		-- If they didn't provide either coordinate, try Wikidata. If they provided one but not the other, don't.
		local entity = mw.wikibase.getEntity()
		if entity and entity.claims and entity.claims.P625 and entity.claims.P625[1].mainsnak.snaktype == 'value' then
			local value = entity.claims.P625[1].mainsnak.datavalue.value
			longitude, latitude = value.longitude, value.latitude
		end
	end
	if not longitude then
		error('緯度の値が指定されていません。')
	elseif not latitude then
		error('経度の値が指定されていません。')
	end
	local builder = mw.html.create()
	if (not args.lon_deg) ~= (not args.lat_deg) then
		builder:wikitext('')
	elseif (not args.lon_min) ~= (not args.lat_min) then
		builder:wikitext('')
	elseif (not args.lon_sec) ~= (not args.lat_sec) then
		builder:wikitext('')
	elseif (not args.lon_dir) ~= (not args.lat_dir) then
		builder:wikitext('')
	elseif (not args.long) ~= (not args.lat) then
		builder:wikitext('')
	end
	if args.skew or args.lon_shift or args.markhigh then
		mw.log('呼び出しにおいて廃止されたパラメータです。')
		local parent = frame:getParent()
		if parent then
			mw.log(parent:getTitle() .. 'の親です。')
		end
		mw.logObject(args, 'args')
		builder:wikitext('')
	end
	if map('x') ~= '' then
		x = tonumber(mw.ext.ParserFunctions.expr(map('x', { latitude, longitude })))
	else
		x = tonumber(getX(longitude, map('left'), map('right')))
	end
	if map('y') ~= '' then
		y = tonumber(mw.ext.ParserFunctions.expr(map('y', { latitude, longitude })))
	else
		y = tonumber(getY(latitude, map('top'), map('bottom')))
	end
	if (x < 0 or x > 100 or y < 0 or y > 100) and not args.outside then
		mw.log('外部フラグ設定無しに地図外にマークが置かれました。 x = ' .. x .. ', y = ' .. y)
		local parent = frame:getParent()
		if parent then
			mw.log(parent:getTitle() .. 'の親です。')
		end
		mw.logObject(args, 'args')
		builder:wikitext('')
	end
	local mark = args.mark or map('mark')
	if mark == '' then
		mark = 'Red pog.svg'
	end
	local marksize = tonumber(args.marksize) or tonumber(map('marksize')) or 8
	local imageDiv = markImageDiv(mark, marksize, args.label or mw.title.getCurrentTitle().text, args.link or '', args.alt, args[2])
	local labelDiv
	if args.label and args.position ~= 'none' then
		labelDiv = markLabelDiv(args.label, args.label_size or 90, args.label_width or 6, args.position, args.background, x, marksize)
	end
	return builder:node(markOuterDiv(x, y, imageDiv, labelDiv))
end

local function switcherSeparate(s)
	if s == nil then return {} end
	local retval = {}
	for i in string.gmatch(s .. '#', '([^#]*)#') do
		i = mw.text.trim(i)
		retval[#retval + 1] = (i ~= '' and i)
	end
	return retval
end

function p.main(frame, args, map)
	if not args then
		args = getArgs(frame, {wrappers = 'Template:Location map', valueFunc = p.valueFunc})
	end
	if args.useWikidata == nil then
		args.useWikidata = true
	end
	if not map then
		if args[1] then
			map = {}
			for mapname in string.gmatch(args[1], '[^#]+') do
				map[#map + 1] = p.getMapParams(mapname, frame)
			end
			if #map == 1 then map = map[1] end
		else
			map = p.getMapParams('World', frame)
		end
	end
	if type(map) == 'table' then
		local altmaps = switcherSeparate(args.AlternativeMap)
		if #altmaps > #map then
			error(string.format('%dのAlternativeMapsが提供されていますが、%dの地図のみの提供になります。', #altmaps, #map))
		end
		local overlays = switcherSeparate(args.overlay_image)
		if #overlays > #map then
			error(string.format('%dのoverlay_imagesが提供されていますが、%dの地図のみの提供になります。', #overlays, #map))
		end
		local outputs = {}
		args.autoSwitcherLabel = true
		for k,v in ipairs(map) do
			args.AlternativeMap = altmaps[k]
			args.overlay_image = overlays[k]
			outputs[k] = p.main(frame, args, v)
		end
		return '<div class="switcher-container">' .. table.concat(outputs) .. '</div>'
	else
		return p.top(frame, args, map) .. tostring( p.mark(frame, args, map) ) .. p.bottom(frame, args, map)
	end
end

return p