编辑“︁
Module:沙盒/Hello903hello/map
”︁
跳转到导航
跳转到搜索
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
-- copied from Wikivoyage (English) [[wikivoyage:Module:Map]] CC BY-SA 3.0 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
摘要:
请注意,所有对Local Chinese Wikipedia的贡献均可能会被其他贡献者编辑、修改或删除。如果您不希望您的文字作品被随意编辑,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源(详情请见
Project:著作权
)。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)
导航菜单
个人工具
未登录
讨论
贡献
创建账号
登录
命名空间
模块
讨论
English
查看
阅读
编辑
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息