require('strict')local fn = require('Module:Formatnum')--local mm = require('Module:Math')local Date = require('Module:Date')._Datelocal p =
-- N/A but possible option: keep cyclone data in subpage data files--local stormDatabase = require("Module:Cyclone map/data") -- configuration module -- main function callable in Wikipedia via the #invoke command.p.main = function(frame) local str = p.getMapframeString return frame:preprocess(str) -- the mapframe needs to be preprocessed!!!!!end -- End the function.
--function to construct mapframe string sets up the
--get mapframe arguments from calling templates local parent = mw.getCurrentFrame:getParent -- get JSON data for features to display local mapData = p.getGeoJSON local mapString = ""
--mapString = '
mapString = ' mapString = mapString .. ' width=' .. math.floor(width) .. ' height=' .. math.floor(height) .. ' align=' .. align local zoom = parent.args['zoom'] --or "0" -- no longer set defaults (mapframe does automatically) local latitude = parent.args['latitude'] --or "0" local longitude = parent.args['longitude'] --or "0" --set if values, otherwise allow mapframe to set automatically (TODO check if longitude and latitude are independent) if zoom then mapString = mapString .. ' zoom=' .. zoom end if latitude then mapString = mapString .. ' latitude=' .. latitude end if longitude then mapString = mapString .. ' longitude=' .. longitude end mapString = mapString .. ' >' .. mapData .. '
end -- End the function.
--imageN=, |descriptionN=) (2) from values in the data module (i.e. Module:Football map/data) [not function for cyclone map] (3) from Wikidatap.getGeoJSON = function(frame)
-- now we need to iterate through the stadiumN parameters and get data for the feature markers local maxNumber = 200 -- maximum number looked for local mapData = "" local cycloneName = nil local cycloneID = nil --get mapframe arguments from calling templates local parent = mw.getCurrentFrame:getParent --There are three ways of getting data about the stadium features (1) from a list in the module subpages (n/a but possible alternative) (2) from wikidata (3) from the parameters in the template (these always override other) The parameters useWikiData, useModule restrict use of source -- local useWikidata = true local useModule = false if parent.args['wikidata'] then useWikidata = true; useModule = false end -- use wikidata or template data (no module data) if parent.args['moduledata'] then useModule = true; useWikidata = false end -- use module of template data (no wikidata) if parent.args['templatedata'] then useModule = false; useWikidata = false end -- only use template data -- default parameters for marker color, size and symbol, etc (i.e. those without index suffix) local strokeColor = parent.args['stroke'] or "#000000" if strokeColor
local index=0 while index < maxNumber do index = index + 1 local cycloneID = "" -- (1) get cyclone name cycloneID = parent.args['id'..tostring(index)] cycloneName = parent.args['name'..tostring(index)] if cycloneName and not cycloneID then cycloneID = mw.wikibase.getEntityIdForTitle(cycloneName) end if cycloneID and not cycloneName then cycloneName = mw.wikibase.getLabel(cycloneID) --TODO get associated Wikipedia page for linking end -- if we have a valid cyclone id (note:Lua has no continue statement) if cycloneID then local feature = local validFeatureData = true -- assume now -- (2) get feature parameters from module (n/a) or wikidata or both --if useModule then -- get feature parameters from module data stadium list feature = p.getModuleData(frame, stadiumName) end if useWikidata and cycloneID then --and feature['name']
if feature['image'] ~= "" then feature['description'] = feature['image'] .. feature['description'] end
--check if current feature marker has specified color, size or symbol local strokeColor = parent.args['stroke'..tostring(index)] or defaultProperties['stroke'] if strokeColor
-- the feature properties are set by the indexed parameters or defaults (see above) local featureProperties = --(4) construct the json for the features (if we have a storm with valid coordinates) if validFeatureData then local featureData = ""
if feature.path[1] then -- add path if multiple coordinates featureData = p.addPathFeatureCollection(feature,featureProperties) else -- else show single marker -- make sure a marker color is set (if not set by template or not autocoloring storm path) -- note the default colour is left as nil for the auto coloring of paths by storm type -- and that this can be overriden with a value, but might be nil here local markerColor = featureProperties['marker-color'] or "#0050d0" featureData = ' ' end if index > 1 and mapData ~= "" then mapData = mapData .. ',' .. featureData else mapData = featureData end else --mapData = ' ' mw.addWarning("No valid information found for " .. cycloneName .. " (" .. cycloneID .. ")") end -- if valid parameters end -- end if if cycloneID end -- end while loop --(5) check for external data (geoshape) TODO add more than index=1 and generalise for any json feature -- local geoshape = parent.args['geoshape'..tostring(1)] or "" if geoshape ~= "" then mapData = mapData .. ',' .. geoshape -- assumes at least one stadium end -- add outer bracket to json if more than one element if index > 1 then mapData = '[' .. mapData .. ']' --mapData = ' ' -- is there an advantage using this? end return mapData end -- End the function.
--functions adding path to cyclone item p.addPathFeatureCollection -- adds markers/symbols and lines for path of storm (cordinates from wikidata) p.addShapeFeature -- returns geoJson for the custom symbol p.getPolygonCoordinates -- returns coordinate set for the custom symbol (loop for diffent shapes) p.calculatePolygonCoordinates -- calculates the coordinates for the specified shape p.getCycloneColor -- sets color of symbols/lines based on storm type (from wikidata)
--
p.addPathFeatureCollection=function(feature, featureProperties) if not feature.path[1] then return "" end -- shouldn't be necessary now local mode = mw.getCurrentFrame:getParent.args['mode'] or "default"local featureCollection = "" local sep = "" local i = 1 table.sort (feature.path, function(a,b) if (a.timeStamp < b.timeStamp) then --- primary sort on timeStamp return true else return false end end) for i, v in pairs(feature.path) do local autoColor = p.getCycloneColor(feature.path[i]['cycloneType'], featureProperties) local markerColor = featureProperties['marker-color'] or autoColor local strokeColor = featureProperties['stroke'] or autoColor local longitude = feature.path[i]['longitude'] local latitude = feature.path[i]['latitude']
-- add a lines between the points (current point to the next point, if there is one) local lineFeature = "" if feature.path[i+1] then local longitude2 = feature.path[i+1]['longitude'] local latitude2 = feature.path[i+1]['latitude']
lineFeature = ' ' featureCollection = featureCollection .. sep .. lineFeature sep = "," end
-- if mode
"test" and i
local pointFeature = ' ' featureCollection = featureCollection .. sep .. pointFeature sep = ","
elseif mode
latitude: ' .. tostring(latitude) .. '
longitude: ' .. tostring(longitude) .. dateString .. '
' local circleFeature = ' ' featureCollection = featureCollection .. sep .. circleFeature sep = "," else -- use polygons (default if not marker) to mark with objects
featureCollection = featureCollection .. sep .. p.addShapeFeature(i, feature, featureProperties) sep = "," end i=i+1 -- increment for next point in storm path end -- while/for in pairs if mw.getCurrentFrame:getParent.args['mode']
'extratropical cyclone' then shape = 'triangle' -- symbol for extratropical cyclone (Q1063457) elseif feature.path[i]['cycloneType2']
local description = '
' -- .. '
date: ' .. mw.language.getContentLanguage:formatDate('d F Y', feature.path[i]['timeStamp']) .. '
date: ' .. Date(feature.path[i]['timeStamp']):text("dmy") -- :text("dmy hm") .. '
type: ' .. tostring(feature.path[i]['cycloneType']) .. '
longitude: ' .. fn.formatNum(longitude,"en",6) .. '
latitude: ' .. fn.formatNum(latitude,"en",6) .. '
' local shapeFeature ="" --shape="circle" shapeFeature = ' ' -- if shape
"cyclone" then -- superimpose a second shape local shape2="cyclone_tails" shapeFeature = shapeFeature .. ', ' .. ' ' end return shapeFeatureendp.getPolygonCoordinates = function(shape, size, latitude, longitude) -- shape = "circle" -- shape ="spiral" local coordinates = "" if shape
"triangle2" then coordinates = ' [' .. '[' .. (longitude) .. ',' .. (latitude+size) .. '],' .. '[' .. (longitude+size) .. ',' .. (latitude-size) .. '],' .. '[' .. (longitude-size) .. ',' .. (latitude-size) .. '],' .. '[' .. (longitude) .. ',' .. (latitude+size) .. ']' .. '] ' elseif shape
"star2" then --size = size * 5 coordinates = ' [' .. '[' .. longitude .. ',' .. latitude+(size*1.2) .. '],' -- top point .. '[' .. longitude+(size*0.2) .. ',' .. latitude+(size*0.2) .. '],' .. '[' .. longitude+(size*1.2) .. ',' .. latitude+(size*0.4) .. '],' -- 2pm point .. '[' .. longitude+(size*0.3) .. ',' .. latitude-(size*0.1) .. '],' .. '[' .. longitude+(size) .. ',' .. latitude-(size) .. '],' -- 5pm point .. '[' .. longitude .. ',' .. latitude-(size*0.3) .. '],' -- 6pm (innner) .. '[' .. longitude-(size) .. ',' .. latitude-(size) .. '],' -- 7pm point .. '[' .. longitude-(size*0.3) .. ',' .. latitude-(size*0.1) .. '],' .. '[' .. longitude-(size*1.2) .. ',' .. latitude+(size*0.4) .. '],' -- 10pm point .. '[' .. longitude-(size*0.2) .. ',' .. latitude+(size*0.2) .. '],' .. '[' .. longitude .. ',' .. latitude+(size*1.2) .. ']' -- top point (close) .. '] '
elseif shape
"cyclone_tails" then
local radius = size*2 -- add tail at 3 o'clock coordinates = coordinates .. ' [' for angle = 0, 60, 3 do if angle > 0 then coordinates = coordinates .. ',' end coordinates = coordinates .. '[' .. longitude-size+(radius*math.cos(math.rad(angle))) .. ',' .. latitude +(radius*math.sin(math.rad(angle))) .. ']' end coordinates = coordinates .. '] '
-- add tail at 9 o'clock coordinates = coordinates .. ', [' for angle = 180, 240, 3 do if angle > 180 then coordinates = coordinates .. ',' end coordinates = coordinates .. '[' .. longitude+size+(radius*math.cos(math.rad(angle))) .. ',' .. latitude +(radius*math.sin(math.rad(angle))) .. ']' end coordinates = coordinates .. '] ' -- add tail at 6 o'clock coordinates = coordinates .. ', [' for angle = 270, 330, 3 do if angle > 270 then coordinates = coordinates .. ',' end coordinates = coordinates .. '[' .. longitude+(radius*math.cos(math.rad(angle))) .. ',' .. latitude+size +(radius*math.sin(math.rad(angle))) .. ']' end coordinates = coordinates .. '] '
-- add tail at 6 o'clock coordinates = coordinates .. ', [' for angle = 90, 150, 3 do if angle > 90 then coordinates = coordinates .. ',' end coordinates = coordinates .. '[' .. longitude+(radius*math.cos(math.rad(angle))) .. ',' .. latitude-size +(radius*math.sin(math.rad(angle))) .. ']' end coordinates = coordinates .. '] ' --for adding circle local radius = size coordinates = coordinates .. ', [' for angle = 0, 360, 3 do if angle > 0 then coordinates = coordinates .. ',' end coordinates = coordinates .. '[' .. longitude+(radius*math.cos(math.rad(angle))) .. ',' .. latitude +(radius*math.sin(math.rad(angle))) .. ']' end coordinates = coordinates .. '] ' -- elseif shape
coordinates = ' [' local radius = size*0.01 for angle = 0, 360*4, 4 do radius = radius + size*0.01 if angle > 0 then coordinates = coordinates .. ',' end coordinates = coordinates .. '[' .. longitude+(radius*math.cos(math.rad(angle))) .. ',' .. latitude +(radius*math.sin(math.rad(angle))) .. ']' end coordinates = coordinates .. '] ' elseif shape
"cyclone" then -- circle as 120 sided polygon return p.calculatePolygonCoordinates(120, 1, size, latitude, longitude) elseif shape
"diamond" then return p.calculatePolygonCoordinates(4, 1, size, latitude, longitude) elseif shape
"octagon" then return p.calculatePolygonCoordinates(8, 1, size, latitude, longitude) elseif shape
"star5" then return p.calculatePolygonCoordinates(10, 3, size, latitude, longitude) elseif shape
"star12" then return p.calculatePolygonCoordinates(24, 3, size, latitude, longitude) elseif shape
"depression" or cycloneType
"Tropical disturbance" then color = "#80ccff" elseif cycloneType
"deep depression" or cycloneType
"tropical low" then color = "#5ebaff" elseif cycloneType
"tropical storm" or cycloneType
"category 1 tropical cyclone" then color = "#00faf4" elseif cycloneType
"severe tropical storm" or cycloneType
"very severe cyclonic storm" or cycloneType
"typhoon" then color = "#fdaf9a" elseif cycloneType
"extremely severe cyclonic storm" or cycloneType
"category 4 severe tropical storm" then color = "#ffc140" elseif cycloneType
"category 5 severe tropical cyclone" or cycloneType
"super cyclonic storm" or cycloneType
"category 5 major hurricane" then color = "#ff6060" end return colorend
--