Modul:Location map

Aus Wikivoyage
Zur Navigation springen Zur Suche springen
Template-info.png Dokumentation für das Modul Location map[Ansicht] [Bearbeiten] [Versionsgeschichte] [Aktualisieren]

Das Modul Location map stellt Funktionen zur Erstellung von Positionskarten bereit.

Funktionen

Lagekarte von Ägypten
Golf von
Suez
Ägypten
Lagekarte der Welt
Kairo
Kairo
Orte in Ägypten
Karte Russlands

Kartenfunktionen

function locMap.locationMap(frame)

Stellt eine Karte mit einem Ort dar. Es können weitere Orte und Objekte eingefügt werden.

function locMap.addLocation(frame)

Ergänzt einen weiteren Ort auf der Karte.

function locMap.addObject(frame)

Fügt ein beliebiges Objekt in die Karte ein.

Dokumentation regionaler Kartendaten

function locMap.getMapValue(frame)

Gibt den Wert eines Parameters einer Kartendefinition aus.

function locMap.getMapValueSet(frame)

Erstellt eine Tabelle mit den Parametern einer Kartendefinition.

Benötigte weitere Module

Dieses Modul benötigt folgende weitere Module: Location map/i18n

Verwendung in anderen Modulen

Dieses Modul ist notwendig für die Ausführung folgender Module. Bei Anpassungen sollte die Funktionstüchtigkeit der folgenden Module geprüft werden. Benutze dazu auch diese Tracking-Kategorie um Fehler zu finden, die sich dann auf Artikel auswirken:

Hinweise
-- module import
local li = require( 'Module:Location map/i18n' )

-- module variable
local locMap = {}

-- Local functions, please do not call them directly

local function split( s )
	local tb = mw.text.split( s, ';' ), i
	for i = #tb, 1, -1 do
		tb[ i ] = mw.text.trim( tb[ i ] )
		if tb[ i ] == '' then
			table.remove( tb, i )
		end
	end
	return tb
end

local function analyzeStyle( style, list )
	local tb = split( style ), i, l
	for i = 1, #tb, 1 do
		l = list[ tb[ i ] ]
		if l then
			tb[ i ] = l
		end
	end
	return table.concat( tb, '; ' )
end

local function setLocation( args )
	local lmarksize = math.floor( args.marksize + 0.5 )
	local msize = math.floor( ( args.marksize - 1 ) / 2 + 0.5 )
	local msize3 = math.floor( ( args.marksize + 2 ) / 2 + 0.5 )
	local msize5 = math.floor( ( args.marksize + 4 ) / 2 + 0.5 )
	local centerPosition = -msize .. 'px'

	-- Creating marker box
	local sCode = '<div style="' .. li.styles.location
		.. 'top:' .. args.y * 100 .. '%; left:' .. args.x * 100 .. '%;">'

	-- Adding marker symbol
	if args.mark ~= 'none' then
		sCode = sCode .. '<div style="' .. li.styles.location
		.. 'top:' .. centerPosition .. ';left:' .. centerPosition
		.. ';min-width:' .. lmarksize .. 'px;min-height:' .. lmarksize .. 'px;">'
		.. '[[File:' .. args.mark .. '|' .. lmarksize .. 'x' .. lmarksize
		.. 'px|top|class=noviewer|link=' .. args.name .. '|' .. args.name .. ']]'
		.. '</div>'
	end

	-- Adding label
	if args.label ~= '' and args.label ~= 'none' then
		sCode = sCode .. '<div style="' .. li.styles.location
		if args.labelWrap and args.labelWrap == 'manual' then
			sCode = sCode .. li.styles.labelWidthNowrap
		else
			sCode = sCode .. li.styles.labelWidth -- prevent early wrapping
		end
		if li.labelPositions[ args.labelPosition ] then
			-- Fixed position
			sCode = sCode .. li.labelPositions[ args.labelPosition ]
				:gsub( 'msize_', msize )
				:gsub( 'msize3_', msize3 )
				:gsub( 'msize5_', msize5 )
		else
			-- Estimation of posititon
			if args.y <= 0.5 then
				sCode = sCode .. 'top:' .. msize3 .. 'px;'
			else
				sCode = sCode .. 'bottom:' .. msize3 .. 'px;'
			end
			if args.x < 0.25 then
				sCode = sCode .. 'text-align:left;left:' 
					.. math.floor( 3 - 60 * args.x ) / 10 .. 'em;'
			elseif args.x < 0.75 then
				sCode = sCode .. li.styles.centerX
			else
				sCode = sCode .. 'text-align:right;right:'
					.. math.floor( 10 * ( 0.3 - ( 1 - args.x ) * 6 ) ) / 10 .. 'em;'
			end
		end
		sCode = sCode .. analyzeStyle( args.labelStyle, li.labelStyles ) .. '">'
			.. args.label .. '</div>'
	end
	return sCode .. '</div>'
end

local function baseMap( args )
	-- Create outer box
	local sCode = '<table class="locationMap" style="' .. li.styles.mapBox
	if args.caption ~= '' then
		sCode = sCode .. 'border:' .. args.captionOuterBorder .. ';'
	end
	sCode = sCode .. ' ' .. analyzeStyle( args.mapStyle, li.mapStyles ) .. '">'
		.. '<tr><td class="thumb" style="' .. li.styles.mapCell
	if args.caption ~= '' then
		sCode = sCode .. '">'
	else
		sCode = sCode .. 'padding:0;">'
	end

	-- Create inner box
	sCode = sCode .. '<div style="' .. li.styles.mapDiv
	if args.caption ~= '' then
		sCode = sCode .. 'border:' .. args.captionInnerBorder .. ';">'
	else
		sCode = sCode .. 'border:none;">'
	end

	-- Add map and marker
	sCode = sCode .. '[[File:' .. args.mapImage .. '|' .. args.width
		.. 'px|center|class=noviewer|' .. args.description .. ']]'
	if args.x < 0 or args.x > 1 or args.y < 0 or args.y > 1 then
		sCode = sCode .. '<div style="' .. li.styles.mapError .. '">'
		   .. mw.ustring.format( li.errMsgs.coordError, args.name ) .. '</div>'
	else
		sCode = sCode .. setLocation( args )
	end

	-- Add places
	sCode = sCode .. args.places .. '</div></td></tr>'

	-- Add caption
	if args.caption ~= '' then
		sCode = sCode .. '<tr><td class="thumbcaption" style="' .. li.styles.mapCaption 
			.. args.captionStyle  .. '">' .. args.caption .. '</td></tr>'
	end
	return sCode .. '</table>'
end

-- Handling regional map data
-- This function is never to be called directly but with a pcall()
-- to handle exceptions in case of missing map modules
local function getMapObject( id )
	local region = require( 'Modul:Location map data ' .. id )
	if region and region.data then
		region.data.id = id
		return region
	end
	return nil
end

local function linearX( data, long )
	local left = data.left
	local right = data.right
	if not data or not left or not right or left == right then
		-- Error
		return -1
	elseif left < right then
		return ( long - left ) / ( right - left )
	elseif long < 0 then
		return ( 360 + long - left ) / ( 360 + right - left )
	else
		return ( long - left ) / ( 360 + right - left )
	end
end

local function linearY( data, lat )
	local top = data.top
	local bottom = data.bottom
	if not data or not top or not bottom or top == bottom then
		-- Error
		return -1
	end
	return ( lat - top ) / ( bottom - top )
end

local function getX( anObject, long, lat )
	if anObject.x then
		return anObject.x( lat, long )
	else
		return linearX( anObject.data, long )
	end
end

local function getY( anObject, long, lat )
	if anObject.y then
		return anObject.y( lat, long )
	else
		return linearY( anObject.data, lat )
	end
end

local function getMapImage( data, which )
	local image = data.default
	if which == 'quickbar' then
		which = li.defaults.quickbarMapType
		if data.quickbar and data.quickbar ~= '' then
			which = data.quickbar
		end
	end
	if which ~= '' and data[ which ] and data[ which ] ~= '' then
		image = data[ which ]
	end
	return image
end

-- Parameters and error handling
local function argCheck( param, altValue )
	if not param or param == '' then
		return altValue
	end
	local val = mw.text.trim( param )
	if val == '' then
		val = altValue
	end
	return val
end

local function errorStr( s )
	return mw.ustring.format( li.errMsgs.moduleError, s )
end

local function checkMarkerProperties( args, mData )
	local mark, marksize

	args.name = argCheck( args.name, '' )
	args.label = argCheck( args.label, '' )

	if mData.mark then
		mark = mData.mark
	else
		mark = li.defaults.marker
	end
	args.mark = argCheck( args.mark, mark )
	if mData.marksize then
		marksize = mData.marksize
	else
		marksize = li.defaults.marksize
	end
	args.marksize = argCheck( args.marksize, marksize )
	args.labelStyle = argCheck( args.labelStyle, '' )
	args.labelBackground = argCheck( args.labelBackground, '' )
	if args.labelBackground ~= '' then
		args.labelBackground = 'background: ' .. args.labelBackground
		if args.labelStyle ~= '' then
			args.labelStyle = args.labelStyle .. '; ' .. args.labelBackground
		else
			args.labelStyle = args.labelBackground
		end
	end
	args.labelWrap = argCheck( args.labelWrap, 'auto' )
	args.labelPosition = argCheck( args.labelPosition, 'auto' )
			
	return args
end

local function checkCoordinate( args, mObject, errorMsgs )
	local success = true, x, y
	args.lat = tonumber( argCheck( tostring( args.lat ), 0 ) )
	args.long = tonumber( argCheck( tostring( args.long ), 0 ) )

	x = getX( mObject, args.long, args.lat )
	if x < 0 or x > 1 then
		success = false
		if x == -1 then
			table.insert( errorMsgs, errorStr( li.errMsgs.wrongXBorders ) )
		else
			table.insert( errorMsgs, errorStr( mw.ustring.format( li.errMsgs.wrongLong, long ) ) )
		end
	end

	y = getY( mObject, args.long, args.lat )
	if y < 0 or y > 1 then
		success = false
		if y == -1 then
			table.insert( errorMsgs, errorStr( li.errMsgs.wrongYBorders ) )
		else
			table.insert( errorMsgs, errorStr( mw.ustring.format( li.errMsgs.wrongLat, lat ) ) )
		end
	end

	return x, y, success, errorMsgs
end

-- Map functions

local function apiLocationMap( args )
	local map = argCheck( args.map, 'missing' )
	local success, mObject = pcall( getMapObject, map )
	if not success then
		return errorStr( mw.ustring.format( li.errMsgs.unknownMap, map ) )
	end
	
	-- Error handling
	local errorMsgs = {}

	-- Parameters check
	local mData = mObject.data
	if not args.lat or not args.long then
		return li.errMsgs.notANumber
	end
	args.x, args.y, success, errorMsgs = checkCoordinate( args, mObject, errorMsgs )

	args.maptype = argCheck( args.maptype, 'default' )
	args.mapImage = argCheck( args.alternativeMap, getMapImage( mData, args.maptype ) )
	if not args.mapImage or args.mapImage == '' then
		success = false
		table.insert( errorMsgs, errorStr( li.errMsgs.noMapImage ) )
	end
	if not success then
		return table.concat(errorMsgs, '<br />')
	end

	args.caption = argCheck( args.caption, '' )
	args.captionStyle = argCheck( args.captionStyle, '' )
	args.captionInnerBorder = argCheck( args.captionInnerBorder, li.styles.innerBorder )
	args.captionOuterBorder = argCheck( args.captionOuterBorder, li.styles.outerBorder )
	args.places = argCheck( args.places, '' )
	args.mapStyle = argCheck( args.mapStyle, 'center' )

	-- Image size and description
	args.width = argCheck( tostring( args.width ), '' )
	if not args.width:match( '^%d+$' ) and not args.width:match( '^%d*x%d+$' ) then
		args.width = li.defaults.imgSize
	end
	args.description = ''
	if mData.description then
		args.description = mData.description
	end

	args = checkMarkerProperties( args, mData )
	return baseMap( args )
end

local function apiAddLocation( args )
	local map = argCheck( args.map, 'missing' )
	local success, mObject = pcall( getMapObject, map )
	if not success then
		return errorStr( mw.ustring.format( li.errMsgs.unknownMap, map ) )
	end

	-- Error handling
	local errorMsgs = {}
	local mData = mObject.data

	-- Parameters check
	if not args.lat or not args.long then
		return li.errMsgs.notANumber
	end
	args.x, args.y, success, errorMsgs = checkCoordinate( args, mObject, errorMsgs )
	if not success then
		return table.concat( errorMsgs, '<br />' )
	end

	args = checkMarkerProperties( args, mData )
	return setLocation( args )
end

local function apiAddObject( args )
	args.object = argCheck( args.object, '' )
	if args.object == '' then
		return errorStr( li.errMsgs.noObject )
	end
	
	local success = true
	local errorMsgs = {}
		
	args.right = argCheck( args.right, '' )
	args.left = argCheck( args.left, '' )
	if args.right == '' and args.left == '' then
		success = false
		table.insert( errorMsgs, errorStr( li.errMsgs.noXPos ) )
	end
	args.top = argCheck( args.top, '' )
	args.bottom = argCheck( args.bottom, '' )
	if args.top == '' and args.bottom == '' then
		success = false
		table.insert( errorMsgs, errorStr( li.errMsgs.noYPos ) )
	end
	if not success then
		return table.concat( errorMsgs, '<br />' )
	end
		
	args.objectStyle = argCheck( args.objectStyle, '' )
	args.objectBackground = argCheck( args.objectBackground, '' )
	if args.objectBackground ~='' then
		args.objectBackground = 'background: ' .. args.objectBackground
		if args.objectStyle ~='' then
			args.objectStyle = args.objectStyle .. '; ' .. args.objectBackground
		else
			args.objectStyle = args.objectBackground
		end
	end

	local sCode = '<div class="locationMapObject" style="' .. li.styles.objectBox
	if args.left ~= '' then
		sCode = sCode .. 'left:' .. args.left .. ';'
	else
		sCode = sCode .. 'right:' .. args.right .. ';'
	end
	if args.top ~= '' then
		sCode = sCode .. 'top: ' .. args.top .. ';'
	else
		sCode = sCode .. 'bottom: ' .. args.bottom .. ';'
	end
	return sCode .. analyzeStyle( args.objectStyle, li.labelStyles ) .. '">'
		.. args.object .. '</div>'
end

-- Documentation of map data

local function apiGetMapValue( args )
	local map = argCheck( args.map, 'missing' ), p
	local success, mData = pcall( getMapObject, map )
	if not success then
		return errorStr( mw.ustring.format( li.errMsgs.unknownMap, map ) )
	end
	
	args.param = argCheck( args.param, '' )
	if args.param == '' then
		return errorStr( li.errMsgs.noParam )
	else
		p = mData.data[ args.param ]
		if p then
			return p
		else
			return li.errMsgs.anError
		end
	end
end

local function apiGetMapValueSet( args )
	local map = argCheck( args.map, 'missing' ), i, j, sCode, v
	local success, mData = pcall( getMapObject, map )
	if not success then
		return errorStr( mw.ustring.format( li.errMsgs.unknownMap, map ) )
	end
	
	sCode = '<table class="' .. li.mapDocs.tableClass .. '">'
	for i = 1, #li.paramList, 1 do
		j = li.paramList[ i ]
		sCode = sCode .. '<tr><th style="text-align: left">'
			.. li.mapDocs[ j ] .. '</th><td>'
		v = mData.data[ j ]
		if not v then
			sCode = sCode .. li.errMsgs.notDefined .. '</td></tr>'
		else
			if li.mapDocs[ v ] then
				v = li.mapDocs[ v ]
			end
			sCode = sCode .. v .. '</td></tr>'
		end
	end
	return sCode .. '</table>'
end

-- API function calls

locMap[ li.api.apiLocationMap ] = function( frame )
	return apiLocationMap( frame.args )
end

locMap[ li.api.apiAddLocation ] = function( frame )
	return apiAddLocation( frame.args )
end

locMap[ li.api.apiAddObject ] = function( frame )
	return apiAddObject( frame.args )
end

locMap[ li.api.apiGetMapValue ] = function( frame )
	return apiGetMapValue( frame.args )
end

locMap[ li.api.apiGetMapValueSet ] = function( frame )
	return apiGetMapValueSet(frame.args)
end

-- Example for usage in a Lua script

function locMap.exampleLuaCall()
	local frame = {}
	frame.args = {
		map   = 'de',
		lat   = 52.51789,
		long  = 13.38873,
		name  = 'Berlin',
		label = '[[Berlin]]',
	}
	return locMap.locationMap( frame )
end

return locMap