Module:Map
Jump to navigation
Jump to search
| This module is rated as pre-alpha. It is incomplete and may or may not be in active development. Do not use it in article namespace pages. A module remains in pre-alpha until its developer, or another editor who adopts it if it is abandoned for some time, considers the basic structure complete. |
Module invoked by Template:Map in order to generate a choropleth map of countries.
local Map = {}
function Map.main()
-- Get the arguments
local map = Map.getArg( 'map', 'world' )
local region = Map.getArg( 'region' )
local color = Map.getArg( 'color', 'red' )
local width = Map.getArg( 'width', '100%' )
local height = Map.getArg( 'height', 'auto' )
local countries = Map.getArg( 'countries', '' )
-- Get the map data
local data = mw.loadData( 'Module:Map/' .. map )
local paths = data.paths
-- If any color directive is an absolute value
-- we need to figure out what the top value is
-- before we can color any of them
local topValue
for directive in mw.text.gsplit( countries, ',' ) do
directive = mw.text.trim( directive )
local value = directive:match( '[A-Za-z ]- *%(([0-9]-)%)' )
if value then
value = tonumber( value )
if not topValue or value > topValue then
topValue = value
end
end
end
-- Color the map
for directive in mw.text.gsplit( countries, ',' ) do
directive = mw.text.trim( directive )
local countryDirective, colorDirective = directive:match( '([A-Za-z ]-) *%(([#0-9A-Za-z .%%]-)%)' )
local country, opacity
if countryDirective and colorDirective then
country = countryDirective
local percentage = colorDirective:match( '^([0-9.]+)%%$' )
local value = colorDirective:match( '^[0-9.]+$' )
if percentage then
opacity = tonumber( percentage ) / 100
elseif value then
opacity = tonumber( value ) / topValue
else
color = colorDirective
end
else
country = directive
end
if data.aliases then
for id, aliases in pairs( data.aliases ) do
for _, alias in pairs( aliases ) do
if alias == country then
country = id
end
end
end
end
local id = 'id="' .. country .. '"'
local fill = 'fill="' .. color .. '"'
if opacity then
fill = fill .. ' fill-opacity="' .. tostring( opacity ) .. '"'
end
paths = paths:gsub( id, id .. ' ' .. fill )
end
-- Set the SVG properties
local svgWidth = tostring( data.width )
local svgHeight = tostring( data.height )
local svgViewBox = ''
if region then
local regionData = data.regions[ region ]
local minX = tostring( regionData.minX )
local minY = tostring( regionData.minY )
svgWidth = tostring( regionData.width )
svgHeight = tostring( regionData.height )
svgViewBox = minX .. ',' .. minY .. ',' .. svgWidth .. ',' .. svgHeight
if regionData.paths then
local ids
for _, id in pairs( regionData.paths ) do
ids = ( ids and ( ids .. ', ' ) or '' ) .. '#' .. id
end
if ids then
local style = '<style>g:not(' .. ids .. ') { display: none }</style>'
paths = style .. paths
end
end
end
-- Build and return the map
return mw.svg.new()
:setContent( paths )
:setAttribute( 'width', svgWidth )
:setAttribute( 'height', svgHeight )
:setAttribute( 'viewBox', svgViewBox )
:setAttribute( 'stroke', 'black' )
:setAttribute( 'stroke-width', '.2' )
:setAttribute( 'fill', '#ececec' )
:setImgAttribute( 'width', width )
:setImgAttribute( 'height', height )
:toImage()
end
-- Helper function to get arguments
-- Arguments from Lua calls have priority over parent arguments from templates
function Map.getArg( key, default )
local frame = mw.getCurrentFrame()
local parent = frame:getParent()
for k, value in pairs( parent.args ) do
if k == key and mw.text.trim( value ) ~= '' then
return value
end
end
for k, value in pairs( frame.args ) do
if k == key and mw.text.trim( value ) ~= '' then
return value
end
end
return default
end
return Map