Module:Sandbox/Yurik/Mapmask

From Wikivoyage
Jump to navigation Jump to search

Documentation for this module may be created at Module:Sandbox/Yurik/Mapmask/doc

local p = {}

-- If <name> is not in <params> table, set it to <default>
-- If <name> exists but is set to an empty string, delete it
-- Otherwise keep it as is
-- If <target> table is given, copy the value and remove original
function parseParam(params, target, name, default, isNumber)
  if params[name] == nil then
    params[name] = default
  elseif params[name] == '' then
    -- special case - empty string value removes the default value
    params[name] = nil
  elseif isNumber then
    params[name] = tonumber(params[name])
  end
  if target ~= nil and params[name] ~= nil then
    target[name] = params[name]
    params[name] = nil
  end
end

function parseGeoPairs(tbl, params)
  local coordinates = {}
  -- Parse an array of strings of number pairs "latitude, longitude" into the real number pairs
  -- If key is not a number, treat it as a named parameter and save it in params (if given)
  for k, v in pairs( tbl ) do
    if type(k) == "number" then
      local v2 = mw.text.split( v, ',', true )
      if #v2 == 2 then
        local lat = tonumber(v2[1])
        local lon = tonumber(v2[2])
        if lat ~= nil and lon ~= nil then
            table.insert(coordinates, { lon, lat } )
        end
      end
    elseif params then
      params[k] = v
    end
  end
  return coordinates
end

function toGeoJsonImpl(frameArguments, params)
  local coordinates = parseGeoPairs(frameArguments, params)
  local properties = {}
  parseParam(params, properties, 'stroke-width', 0.5, true)
  parseParam(params, properties, 'fill-opacity', 0.3, true)
  parseParam(params, properties, 'stroke-opacity', nil, true)
  parseParam(params, properties, 'title')
  parseParam(params, properties, 'description')
  parseParam(params, properties, 'fill')
  parseParam(params, properties, 'stroke')

  -- by default, mask the whole world, but if mask='', only highlight, without inverting
  parseParam(params, nil, 'mask', true)
  if params.mask then
    coordinates = {
      {{36000,-180}, {36000,180}, {-36000,180}, {-36000,-180}, {36000,-180}},
      coordinates
    }
  else
    coordinates = { coordinates }
  end

  -- Negate the above data by creating a Polygon geojson with a giant gray block minus the above data
  local result = {
    type = "FeatureCollection",
    features = { {
      type = "Feature",
      properties = properties,
      geometry = {
        type = "Polygon",
        coordinates = coordinates
      }
  } } }

  if params.pretty ~= nil then
    params.pretty = nil
   return mw.text.jsonEncode(result, mw.text.JSON_PRETTY)
  else
    return mw.text.jsonEncode(result)
  end
end

function p.toGeoJson( frame )
  local f = frame:getParent()
  local params = {}
  local geojson = toGeoJsonImpl(f.args, params)
  -- Create a hidden maplink with the needed geojson
  -- Named parameters are passed as maplink parameters
  parseParam(params, nil, 'text', '')
  parseParam(params, nil, 'zoom', 0, true)
  parseParam(params, nil, 'latitude', 0, true)
  parseParam(params, nil, 'longitude', 0, true)
  parseParam(params, nil, 'group', 'mask')
  return frame:extensionTag( params.tag or 'maplink', params.geojson or geojson, params)
end

return p