Dokumentation für das Modul Map[Ansicht] [Bearbeiten] [Versionsgeschichte] [Aktualisieren]

Funktion

Dieses Modul ermittelt Aufrufparameter für die Tags #mapframe und #maplink, die von der Erweiterung Kartographer bereitgestellt werden.

Verwendung

{{#invoke:map|tag|type=maplink|geotype=Point|title=Example|latitude=59.0|longitude=29.0}} 
Parameter Bedeutung
type maplink oder mapframe, abhängig davon, welches Tag verwendet werden soll.
geotype Point für einzelne Punkte, Polygon für Polygonzüge
title Objektbezeichnung
latitude und longitude Länge und Breite
zoom Zoom-Level der Karte
marker-symbol Symbol, Buchstabe oder Zahl für die Anzeige auf einem Kartenmarker
marker-color Farbe des Kartenmarkers
group Gruppe des Kartenmarkers (see, eat, drink, usw.)
data data=values befüllt einen Polygonzug mit den spezifizierten Daten data
data=world;;values befüllt die Fläche außerhalb des Polygonzugs.
image Dateiname des Bilds, das im Thumbnail-Fenster angezeigt wird.
width und height Kartenhöhe und -breite in Pixeln (px) oder Prozent (%) der Bildschirmbreite, nur für mapframe

Verwendung in Vorlagen

  • keine
Hinweise
local getArgs = require('Module:Arguments').getArgs local p = {}  function dbg(v, msg)     mw.log((msg or '') .. mw.text.jsonEncode(v)) end  -- Parse all unnamed string parameters in a form of "latitude, longitude" into the real number pairs function getSequence(args)     local coords = {}     for ind, val in pairs( args ) do         if type(ind) == "number" then             local valid = false             local val2 = mw.text.split( val, ',', true )             -- allow for elevation             if #val2 >= 2 and #val2 <= 3 then                 local lat = tonumber(val2[1])                 local lon = tonumber(val2[2])                 if lat ~= nil and lon ~= nil then                     table.insert(coords, { lon, lat } )                     valid = true                 end             end             if not valid then error('Unnamed parameter #' .. ind .. ' "' .. val .. '" is not recognized as a valid "latitude,longitude" value') end         end     end     return coords end  --   See http://geojson.org/geojson-spec.html -- Convert a comma and semicolon separated numbers into geojson coordinate arrays -- Each geotype expects a certain array depth: --   Point           - [ lon, lat ]  All other types use point as the basic type --   MultiPoint      - array of points: [ point, ... ] --   LineString      - array of 2 or more points: [ point, point, ... ] --   MultiLineString - array of LineStrings: [ [ point, point, ... ], ... ] --   Polygon         - [ [ point, point, point, point, ... ], ... ] --                     each LinearRing is an array of 4 or more points, where first and last must be the same --                     first LinearRing is the exterior ring, subsequent rings are holes in it --   MultiPolygon    - array of Polygons: [ [ [ point, point, point, point, ... ], ... ], ... ] -- -- For example, for the LineString, data "p1;p2;p3" would be converted to [p1,p2,p3] (each "p" is a [lon,lat] value) -- LineString has the depth of "1" -- array of points (each point being a two value array) -- For Polygon, the same sequence "p1;p2;p3" would be converted to [[p1,p2,p3]] -- Which is an array of array of points. But sometimes we need to specify two subarrays of points: -- [[p1,p2],[p3]] (last point is in a separate array), and we do it with "p1;p2;;p3" -- Similarly, for MultiPolygon, "p1;p2;;;p3" would generate [[[p1,p2]],[[p3]]] -- function p.parseGeoSequence(args)     local result = p._parseGeoSequence(args)     if type(result) == 'string' then error(result) end     return result end  function p._parseGeoSequence(args)     local allTypes = {         -- how many nested array levels until we get to the Point,         -- second is the minimum number of values each Points array must have         Point           = { 1, 1 },         MultiPoint      = { 1, 0 },         LineString      = { 1, 2 },         MultiLineString = { 2, 2 },         Polygon         = { 2, 4 },         MultiPolygon    = { 3, 4 },     }      if not allTypes[args.geotype] then return ('Unknown geotype ' .. args.geotype) end     local levels, min = unpack(allTypes[args.geotype])      local result     result = {}     for i = 1, levels do result[i] = {} end     local gap = 0      -- Example for levels==3, converting "p1 ; p2 ; ; ; p3 ; ; p4" => [[[p1, p2]], [[p3],[p4]]]     -- This function will be called after each gap, and all values are done, so the above will call:     -- before p3:  gap=2, [],[],[p1,p2]            => [[[p1,p2]]],[],[]     -- before p4:  gap=1, [[[p1,p2]]],[],[p3]      => [[[p1,p2]]],[[p3]]],[]     -- the end,    gap=2, [[[p1,p2]]],[[p3]]],[p4] => [[[p1,p2]],[[p3],[p4]]],[],[]     -- Here, convert at "p1 ; ; " from [[],[p1]]     local closeArrays = function (gap)         if #result[levels] < min then             error('Each points array must be at least ' .. min .. ' values')         elseif min == 1 and #result[levels] ~= 1 then             -- Point             error('Point must have exactly one data point')         end         -- attach arrays in reverse order to the higher order ones         for i = levels, levels-gap+1, -1 do             table.insert(result[i-1], result[i])             result[i] = {}         end         return 0     end      local usedSequence = false     for val in mw.text.gsplit(args.data, ';', true) do         local val2 = mw.text.split(val, ',', true)         -- allow for elevation         if #val2 >= 2 and #val2 <= 3 and not usedSequence then             if gap > 0 then gap = closeArrays(gap) end             local lat = tonumber(val2[1])             local lon = tonumber(val2[2])             if lat == nil or lon == nil then return ('Bad data value "' .. val .. '"') end             table.insert(result[levels], { lon, lat } )         else             val = mw.text.trim(val)             if val == '' then                 usedSequence = false                 gap = gap + 1                 if (gap >= levels) then return ('Data must not skip more than ' .. levels-1 .. ' values') end             elseif usedSequence then                 return ('Coordinates may not be added right after the named sequence')             else                 if gap > 0 then                     gap = closeArrays(gap)                 elseif #result[levels] > 0 then                     return ('Named sequence "' .. val .. '" cannot be used in the middle of the sequence')                 end                  -- Parse value as a sequence name. Eventually we can load data from external data sources                 if val == 'values' then                     val = getSequence(args)                 elseif min == 4 and val == 'world' then                     val = {{36000,-180}, {36000,180}, {-36000,180}, {-36000,-180}, {36000,-180}}                 elseif tonumber(val) ~= nil then                     return ('Not a valid coordinate or a sequence name: ' .. val)                 else                     return ('Sequence "' .. val .. '" is not known. Try "values" or "world" (for Polygons), or specify values as lat,lon;lat,lon;... pairs')                 end                 result[levels] = val                 usedSequence = true             end         end     end     -- allow one empty last value (some might close the list with an extra semicolon)     if (gap > 1) then return ('Data values must not have blanks at the end') end     closeArrays(levels-1)     return args.geotype == 'Point' and result[1][1] or result[1] end  -- Run this function to check that the above works ok function p.parseGeoSequenceTest()     local testSeq = function(data, expected)         local result = getSequence(data)         if type(result) == 'table' then             local actual = mw.text.jsonEncode(result)             result = actual ~= expected and 'data="' .. mw.text.jsonEncode(data) .. '", actual="' .. actual .. '", expected="' .. expected .. '"<br>\n' or ''         else             result = result .. '<br>\n'         end         return result     end     local test = function(geotype, data, expected, values)         values = values or {}         values.geotype = geotype;         values.data = data;         local result = p._parseGeoSequence(values)         if type(result) == 'table' then             local actual = mw.text.jsonEncode(result)             result = actual ~= expected and 'geotype="' .. geotype .. '", data="' .. data .. '", actual="' .. actual .. '", expected="' .. expected .. '"<br>\n' or ''         else             result = 'geotype="' .. geotype .. '", data="' .. data .. '", error="' .. result .. '<br>\n'         end         return result     end     local values = {' 9 , 8 ','7,6'}     local result = '' ..             testSeq({}, '[]') ..             testSeq({'\t\n 1 \r,-10'}, '[[-10,1]]') ..             testSeq(values, '[[8,9],[6,7]]') ..             test('Point', '1,2', '[2,1]') ..             test('MultiPoint', '1,2;3,4;5,6', '[[2,1],[4,3],[6,5]]') ..             test('LineString', '1,2;3,4', '[[2,1],[4,3]]') ..             test('MultiLineString', '1,2;3,4', '[[[2,1],[4,3]]]') ..             test('MultiLineString', '1,2;3,4;;5,6;7,8', '[[[2,1],[4,3]],[[6,5],[8,7]]]') ..             test('Polygon', '1,2;3,4;5,6;1,2', '[[[2,1],[4,3],[6,5],[2,1]]]') ..             test('MultiPolygon', '1,2;3,4;5,6;1,2', '[[[[2,1],[4,3],[6,5],[2,1]]]]') ..             test('MultiPolygon', '1,2;3,4;5,6;1,2;;11,12;13,14;15,16;11,12', '[[[[2,1],[4,3],[6,5],[2,1]],[[12,11],[14,13],[16,15],[12,11]]]]') ..             test('MultiPolygon', '1,2;3,4;5,6;1,2;;;11,12;13,14;15,16;11,12', '[[[[2,1],[4,3],[6,5],[2,1]]],[[[12,11],[14,13],[16,15],[12,11]]]]') ..             test('MultiPolygon', '1,2;3,4;5,6;1,2;;;11,12;13,14;15,16;11,12;;21,22;23,24;25,26;21,22', '[[[[2,1],[4,3],[6,5],[2,1]]],[[[12,11],[14,13],[16,15],[12,11]],[[22,21],[24,23],[26,25],[22,21]]]]') ..             test('MultiLineString', 'values;;1,2;3,4', '[[[8,9],[6,7]],[[2,1],[4,3]]]', values) ..             test('Polygon', 'world;;world', '[[[36000,-180],[36000,180],[-36000,180],[-36000,-180],[36000,-180]],[[36000,-180],[36000,180],[-36000,180],[-36000,-180],[36000,-180]]]') ..             ''     return result ~= '' and result or 'Tests passed' end   function p._tag(args)     local tagname = args.type or 'maplink'     if tagname ~= 'maplink' and tagname ~= 'mapframe' then error('unknown type "' .. tagname .. '"') end      local geojson     local tagArgs = {         text = args.text,         zoom = tonumber(args.zoom),         latitude = tonumber(args.latitude),         longitude = tonumber(args.longitude),         group = args.group,         show = args.show,         class = args.class,     }     if tagname == 'mapframe' then         tagArgs.width = args.width == nil and 420 or args.width         tagArgs.height = args.height == nil and 420 or args.height         tagArgs.align = args.align == nil and 'right' or args.align     elseif not args.class and (args.text == '' or args.text == '""') then 		-- Hide pushpin icon in front of an empty text link 		tagArgs.class = 'no-icon'     end      if args.data == '' then args.data = nil end     if (not args.geotype) ~= (not args.data) then         -- one is given, but not the other         if args.data then             error('Parameter "data" is given, but "geotype" is not set. Use one of these: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon')         elseif args.geotype == "Point" and tagArgs.latitude ~= nil and tagArgs.longitude ~= nil then             -- For Point geotype, it is enough to set latitude and logitude, and data will be set up automatically             args.data = tagArgs.latitude .. ',' .. tagArgs.longitude         else             error('Parameter data must be set. Use "values" to use all unnamed parameters as coordinates (lat,lon|lat,lon|...), "world" for the whole world, a combination to make a mask, e.g. "world;;values", or direct values "lat,lon;lat,lon..." with ";" as value separator')         end     end      -- Kartographer can now automatically calculate needed zoom & lat/long based on the data provided     -- Current version ignores mapmasks, but that will also be fixed soon.  Leaving this for now, but can be removed if all is good.     -- tagArgs.zoom = tagArgs.zoom == nil and 14 or tagArgs.zoom     -- tagArgs.latitude = tagArgs.latitude == nil and 51.47766 or tagArgs.latitude     -- tagArgs.longitude = tagArgs.longitude == nil and -0.00115 or tagArgs.longitude  	if args.image then 		args.description = (args.description or '') .. '[[file:' .. args.image .. '|300px]]' 	end      if args.geotype then         geojson = {             type = "Feature",             properties = {                 title = args.title,                 description = args.description,                 ['marker-size'] = args['marker-size'],                 ['marker-symbol'] = args['marker-symbol'],                 ['marker-color'] = args['marker-color'],                 stroke = args.stroke,                 ['stroke-opacity'] = tonumber(args['stroke-opacity']),                 ['stroke-width'] = tonumber(args['stroke-width']),                 fill = args.fill,                 ['fill-opacity'] = tonumber(args['fill-opacity']),             },             geometry = {                 type = args.geotype,                 coordinates = p.parseGeoSequence(args)             }         }     end      if args.debug ~= nil then         local html = mw.html.create(tagname, not geojson and {selfClosing=true} or nil)         :attr(tagArgs)         if geojson then             html:wikitext( mw.text.jsonEncode(geojson, mw.text.JSON_PRETTY) )         end         return 'syntaxhighlight', tostring(html) .. mw.text.jsonEncode(args, mw.text.JSON_PRETTY), { lang = 'json' }     end      return tagname, geojson and mw.text.jsonEncode(geojson) or '', tagArgs end  function p.tag(frame)     local args = getArgs(frame)     local tag, geojson, tagArgs = p._tag(args)     return frame:extensionTag(tag, geojson, tagArgs) end  return p