Modulo:Mapframe

Dokumentado Dokumentado


Ŝablona programadoDiskutojLuaTestojSubpaĝoj
ModuloEsperantoEnglish

Modulo:Dokumentado


Se vi havas demandon pri ĉi tiu Lua-modulo, tiam vi povas demandi en la diskutejo pri Lua-moduloj. La Intervikiaj ligiloj estu metataj al Vikidatumoj. (Vidu Helpopaĝon pri tio.)
-- Note: Originally written on English Wikipedia at https://www.search.com.vn/wiki/en/Module:Mapframe-- ##### Localisation (L10n) settings #####-- Replace values in quotes ("") with localised values-- with adding from [[:ca:Mòdul:Map]] and [[:eo:Modulo:Mapkadro]]local L10n = {}-- Template parameter names (unnumbered versions only)--   Specify each as either a single string, or a table of strings (aliases)--   Aliases are checked left-to-right, i.e. `{ "one", "two" }` is equivalent to using `{{{one| {{{two|}}} }}}` in a templateL10n.para = {display= "display",type= "type",id              = { "id", "ids" },from= "from",raw= "raw",title= "title",description= "description",strokeColor     = { "stroke-color", "stroke-colour" },strokeWidth= "stroke-width",strokeOpacity = "stroke-opacity",fill        = "fill",fillOpacity     = "fill-opacity",coord= "coord",marker= "marker",markerColor= { "marker-color", "marker-colour" },markerSize = "marker-size",radius      = { "radius", "radius_m" },radiusKm    = "radius_km",radiusFt    = "radius_ft",radiusMi    = "radius_mi",edges       = "edges",turn        = "turn", -- from cawptext= "text",icon= "icon",zoom= "zoom",frame= "frame",plain= "plain",frameWidth= "frame-width",frameHeight= "frame-height",frameCoordinates = { "frame-coordinates", "frame-coord" }, frameLatitude= { "frame-lat", "frame-latitude" },frameLongitude= { "frame-long", "frame-longitude" },frameAlign= "frame-align"}-- Names of other templates this module depends onL10n.template = {Coord= "Coord"}-- Error messagesL10n.error = {badDisplayPara= "Invalid display parameter",noCoords= "Coordinates must be specified on Wikidata or in |" .. ( type(L10n.para.coord)== 'table' and L10n.para.coord[1] or L10n.para.coord ) .. "=",wikidataCoords= "Coordinates not found on Wikidata"}-- Other stringsL10n.str = {-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline)inline= "inline",title= "title",dsep= ",",-- separator between inline and title (comma in the example above)-- valid values for type paramterline= "line",-- geoline feature (e.g. a road)shape= "shape",-- geoshape feature (e.g. a state or province)shapeInverse= "shape-inverse",-- geomask feature (the inverse of a geoshape)data= "data",-- geoJSON data page on Commonspoint= "point",-- single point feature (coordinates)circle      = "circle",      -- circular area around a point-- valid values for icon, frame, and plain parametersaffirmedWords = ' '..table.concat({"add","added","affirm","affirmed","include","included","on","true","yes","y"}, ' ')..' ',declinedWords = ' '..table.concat({"decline","declined","exclude","excluded","false","none","not","no","n","off","omit","omitted","remove","removed"}, ' ')..' '}-- Default values for parametersL10n.defaults = {display= L10n.str.inline,text= "Map",frameWidth= "300",frameHeight= "200",markerColor= "5E74F3",markerSize= nil,strokeColor= "#ff0000",strokeWidth= 6,edges       = 32, -- number of edges used to approximate a circleturn        = 0 -- turn for the circle feature}-- #### End of L10n settings ####function getParameterValue(args, param_id, suffix)suffix = suffix or ''if type( L10n.para[param_id] ) ~= 'table' thenreturn args[L10n.para[param_id]..suffix]endfor _i, paramAlias in ipairs(L10n.para[param_id]) doif args[paramAlias..suffix] thenreturn args[paramAlias..suffix]endendreturn nilend-- Trim whitespace from args, and remove empty args. Also fix control characters.function trimArgs(argsTable)local cleanArgs = {}for key, val in pairs(argsTable) doif type(val) == 'string' thenval = val:match('^%s*(.-)%s*$')if val ~= '' then-- control characters inside json need to be escaped, but stripping them is simpler-- See also T214984cleanArgs[key] = val:gsub('%c',' ')endelsecleanArgs[key] = valendendreturn cleanArgsendfunction isAffirmed(val)if not(val) then return false endreturn string.find(L10n.str.affirmedWords, ' '..val..' ', 1, true ) and true or falseendfunction isDeclined(val)if not(val) then return false endreturn string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or falseendlocal coordsDerivedFromFeatures = false;function makeContent(args)if getParameterValue(args, 'raw') thencoordsDerivedFromFeatures = true -- Kartographer should be able to automatically calculate coords from raw geoJSONreturn getParameterValue(args, 'raw')endlocal content = {};local contentIndex = '';local nextTypeOrFromExists = getParameterValue(args, 'type') or getParameterValue(args, 'from')while nextTypeOrFromExists dolocal contentArgs = {}for k, v in pairs(args) doif string.match(k, '^[^0-9]+'..contentIndex..'$') thencontentArgs[string.gsub(k, contentIndex, '')] = vendend-- Kartographer automatically calculates coords if geolines/shapes are used (T227402)if not coordsDerivedFromFeatures thenlocal type = getParameterValue(args, 'type', contentIndex)coordsDerivedFromFeatures = ( type == L10n.str.line or type == L10n.str.shape ) and true or falseendif contentIndex == '' then contentIndex = 1 endcontent[contentIndex] = makeContentJson(contentArgs)contentIndex = contentIndex + 1nextTypeOrFromExists = getParameterValue(args, 'type', contentIndex) or getParameterValue(args, 'from', contentIndex)end--Single item, no array neededif #content==1 then return content[1] end--Multiple items get placed in a FeatureCollectionlocal contentArray = '[\n' .. table.concat( content, ',\n') .. '\n]'return contentArrayendfunction parseCoords(coords)local parts = mw.text.split((mw.ustring.match(coords,'[_%.%d]+[NS][_%.%d]+[EW]') or ''), '_')local lat_d = tonumber(parts[1])local lat_m = tonumber(parts[2]) -- nil if coords are in decimal formatlocal lat_s = lat_m and tonumber(parts[3]) -- nil if coords are either in decimal format or degrees and minutes onlylocal lat = lat_d + (lat_m or 0)/60 + (lat_s or 0)/3600if parts[#parts/2] == 'S' thenlat = lat * -1endlocal long_d = tonumber(parts[1+#parts/2])local long_m = tonumber(parts[2+#parts/2]) -- nil if coords are in decimal formatlocal long_s = long_m and tonumber(parts[3+#parts/2]) -- nil if coords are either in decimal format or degrees and minutes onlylocal long = long_d + (long_m or 0)/60 + (long_s or 0)/3600if parts[#parts] == 'W' thenlong = long * -1endreturn lat, longendfunction wikidataCoords(item_id)if not(mw.wikibase.isValidEntityId(item_id)) or not(mw.wikibase.entityExists(item_id)) thenerror(L10n.error.noCoords, 0)endlocal coordStatements = mw.wikibase.getBestStatements(item_id, 'P625')if not coordStatements or #coordStatements == 0 thenerror(L10n.error.wikidataCoords, 0)endlocal hasNoValue = ( coordStatements[1].mainsnak and coordStatements[1].mainsnak.snaktype == 'novalue' )if hasNoValue thenerror(L10n.error.wikidataCoords, 0)endlocal wdCoords = coordStatements[1]['mainsnak']['datavalue']['value']return tonumber(wdCoords['latitude']), tonumber(wdCoords['longitude'])endfunction makeCoords(args, plainOutput) local coords, lat, longlocal frame = mw.getCurrentFrame()if getParameterValue(args, 'coord') thencoords = frame:preprocess( getParameterValue(args, 'coord') )lat, long = parseCoords(coords)elselat, long = wikidataCoords(getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage())endif plainOutput thenreturn lat, longendreturn {[0] = long, [1] = lat}endfunction makeCircleCoords(args)local lat, long = makeCoords(args, true)local radius = getParameterValue(args, 'radius')if not radius thenradius = getParameterValue(args, 'radiusKm') and tonumber(getParameterValue(args, 'radiusKm'))*1000if not radius thenradius = getParameterValue(args, 'radiusMi') and tonumber(getParameterValue(args, 'radiusMi'))*1609.344if not radius thenradius = getParameterValue(args, 'radiusFt') and tonumber(getParameterValue(args, 'radiusFt'))*0.3048endendendlocal edges = getParameterValue(args, 'edges') or L10n.defaults.edgeslocal turn = getParameterValue(args, 'turn') or L10n.defaults.turnif not lat or not long thenerror("Circle centre coordinates must be specified, or available via Wikidata")elseif not radius thenerror("Circle radius must be specified")elseif tonumber(radius) <= 0 thenerror("Circle radius must be a positive number")elseif tonumber(edges) <= 0 thenerror("Circle edges must be a positive number")endreturn circleToPolygon(lat, long, radius, tonumber(edges), tonumber(turn))endfunction circleToPolygon(lat, long, radius, n, turn) -- n is number of edges-- Based on https://github.com/gabzim/circle-to-polygon, ISC licencefunction offset(cLat, cLon, distance, bearing)local lat1 = math.rad(cLat)local lon1 = math.rad(cLon)local dByR = distance / 6378137 -- distance divided by 6378137 (radius of the earth) wgs84local lat = math.asin(math.sin(lat1) * math.cos(dByR) +math.cos(lat1) * math.sin(dByR) * math.cos(bearing))local lon = lon1 + math.atan2(math.sin(bearing) * math.sin(dByR) * math.cos(lat1),math.cos(dByR) - math.sin(lat1) * math.sin(lat))return {math.deg(lon), math.deg(lat)}endlocal coordinates = {};local move = 2 * math.pi * (turn or 0)local i = 0;while i < n dotable.insert(coordinates, offset(lat, long, radius, ((2*math.pi*-i)/n) + move))i = i + 1endtable.insert(coordinates, offset(lat, long, radius, 0 + move))return coordinatesendfunction makeContentJson(contentArgs)local data = {}if getParameterValue(contentArgs, 'type') == L10n.str.point or getParameterValue(contentArgs, 'type') == L10n.str.circle thenlocal isCircle = getParameterValue(contentArgs, 'type') == L10n.str.circledata.type = "Feature"data.geometry = {type = isCircle and "LineString" or "Point",coordinates = isCircle and makeCircleCoords(contentArgs) or makeCoords(contentArgs)}data.properties = {title = getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():getParent():getTitle()}if isCircle then-- TODO: This is very similar to below, should be extracted into a functiondata.properties.stroke = getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColordata.properties["stroke-width"] = tonumber(getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidthlocal strokeOpacity = getParameterValue(contentArgs, 'strokeOpacity')if strokeOpacity thendata.properties['stroke-opacity'] = tonumber(strokeOpacity)endlocal fill = getParameterValue(contentArgs, 'fill')if fill thendata.properties.fill = filllocal fillOpacity = getParameterValue(contentArgs, 'fillOpacity')data.properties['fill-opacity'] = fillOpacity and tonumber(fillOpacity) or 0.6endelse -- is a pointdata.properties["marker-symbol"] = getParameterValue(contentArgs, 'marker') or  L10n.defaults.markerdata.properties["marker-color"] = getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColordata.properties["marker-size"] = getParameterValue(contentArgs, 'markerSize') or L10n.defaults.markerSizeendelsedata.type = "ExternalData"if getParameterValue(contentArgs, 'type') == L10n.str.data or getParameterValue(contentArgs, 'from') thendata.service = "page"elseif getParameterValue(contentArgs, 'type') == L10n.str.line thendata.service = "geoline"elseif getParameterValue(contentArgs, 'type') == L10n.str.shape thendata.service = "geoshape"elseif getParameterValue(contentArgs, 'type') == L10n.str.shapeInverse thendata.service = "geomask"endif getParameterValue(contentArgs, 'id') or (not (getParameterValue(contentArgs, 'from')) and mw.wikibase.getEntityIdForCurrentPage()) thendata.ids = getParameterValue(contentArgs, 'id') or mw.wikibase.getEntityIdForCurrentPage()else data.title = getParameterValue(contentArgs, 'from')enddata.properties = {stroke = getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor,["stroke-width"] = tonumber(getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth}local strokeOpacity = getParameterValue(contentArgs, 'strokeOpacity')if strokeOpacity thendata.properties['stroke-opacity'] = tonumber(strokeOpacity)endlocal fill = getParameterValue(contentArgs, 'fill')if fill and (data.service == "geoshape" or data.service == "geomask") thendata.properties.fill = filllocal fillOpacity = getParameterValue(contentArgs, 'fillOpacity')if fillOpacity thendata.properties['fill-opacity'] = tonumber(fillOpacity)endendenddata.properties.title = getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():preprocess('{{PAGENAME}}')if getParameterValue(contentArgs, 'description') thendata.properties.description = getParameterValue(contentArgs, 'description')endreturn mw.text.jsonEncode(data)endfunction makeTagAttribs(args, isTitle)local attribs = {}if getParameterValue(args, 'zoom') thenattribs.zoom = getParameterValue(args, 'zoom')endif isDeclined(getParameterValue(args, 'icon')) thenattribs.class = "no-icon"endif getParameterValue(args, 'type') == L10n.str.point and not coordsDerivedFromFeatures thenlocal lat, long = makeCoords(args, 'plainOutput')attribs.latitude = tostring(lat)attribs.longitude = tostring(long)endif isAffirmed(getParameterValue(args, 'frame')) and not(isTitle) thenattribs.width = getParameterValue(args, 'frameWidth') or L10n.defaults.frameWidthattribs.height = getParameterValue(args, 'frameHeight') or L10n.defaults.frameHeightif getParameterValue(args, 'frameCoordinates') thenlocal frameLat, frameLong = parseCoords(getParameterValue(args, 'frameCoordinates'))attribs.latitude = frameLatattribs.longitude = frameLongelseif getParameterValue(args, 'frameLatitude') thenattribs.latitude = getParameterValue(args, 'frameLatitude')endif getParameterValue(args, 'frameLongitude') thenattribs.longitude = getParameterValue(args, 'frameLongitude')endendif not attribs.latitude and not attribs.longitude and not coordsDerivedFromFeatures thenlocal success, lat, long = pcall(wikidataCoords, getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage())if success thenattribs.latitude = tostring(lat)attribs.longitude = tostring(long)endendif getParameterValue(args, 'frameAlign') thenattribs.align = getParameterValue(args, 'frameAlign')endif isAffirmed(getParameterValue(args, 'plain')) thenattribs.frameless = "1"elseattribs.text = getParameterValue(args, 'text') or L10n.defaults.textendelseattribs.text = getParameterValue(args, 'text') or L10n.defaults.textendreturn attribsendfunction makeTitleOutput(args, tagContent) local titleTag = mw.text.tag('maplink', makeTagAttribs(args, true), tagContent)local spanAttribs = {style = "font-size: small;",id = "coordinates"}return mw.text.tag('span', spanAttribs, titleTag)endfunction makeInlineOutput(args, tagContent)local tagName = 'maplink'if getParameterValue(args, 'frame') thentagName = 'mapframe'endreturn mw.text.tag(tagName, makeTagAttribs(args), tagContent)endlocal p = {}-- Entry point for templatesfunction p.main(frame)local parent = frame.getParent(frame)local output = p._main(parent.args)return frame:preprocess(output)end-- Entry point for modulesfunction p._main(_args)local args = trimArgs(_args) local tagContent = makeContent(args)local display = mw.text.split(getParameterValue(args, 'display') or L10n.defaults.display, '%s*' .. L10n.str.dsep .. '%s*')local displayInTitle = display[1] ==  L10n.str.title or display[2] ==  L10n.str.titlelocal displayInline = display[1] ==  L10n.str.inline or display[2] ==  L10n.str.inlinelocal outputif displayInTitle and displayInline thenoutput = makeTitleOutput(args, tagContent) .. makeInlineOutput(args, tagContent)elseif displayInTitle thenoutput = makeTitleOutput(args, tagContent)elseif displayInline thenoutput = makeInlineOutput(args, tagContent)elseerror(L10n.error.badDisplayPara)endreturn outputendreturn p