Module:Cyclone map
Appearance
From Wikipedia, the free encyclopedia
This is the current revision of this page, as edited by WOSlinker (talk | contribs) at 22:04, 21 October 2022 (use require('strict') instead of require('Module:No globals')). The present address (URL) is a permanent link to this version.Revision as of 22:04, 21 October 2022 by WOSlinker (talk | contribs) (use require('strict') instead of require('Module:No globals'))
Implements {{Cyclone map }}
The above documentation is transcluded from Module:Cyclone map/doc. (edit | history)
Editors can experiment in this module's sandbox (create | mirror) and testcases (create) pages.
Subpages of this module.
Editors can experiment in this module's sandbox (create | mirror) and testcases (create) pages.
Subpages of this module.
require('strict') localfn=require('Module:Formatnum') --local mm = require('Module:Math') localDate=require('Module:Date')._Date localp={} -- 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) localstr=p.getMapframeString() returnframe:preprocess(str)-- the mapframe needs to be preprocessed!!!!! end-- End the function. --[[ function to construct mapframe string sets up the <mapframe> tags <mapframe width= height= latitude= longitude= zoom= > MAPDATA in form of geojson constucted with function getGeoJSON() </mapframe> --]] p.getMapframeString=function(frame) --get mapframe arguments from calling templates localparent=mw.getCurrentFrame():getParent() -- get JSON data for features to display localmapData=p.getGeoJSON() localmapString="" --mapString = '<mapframe text="London football stadia" width=800 height=650 align=left zoom=11 latitude=51.530 longitude=-0.16 >' ifmapData~=""then mapString='<mapframe' ifparent.args['frameless']then-- don't and text as this overrides frameless parameter mapString=mapString..' frameless' else mapString=mapString..' text="'..(parent.args['text']or"")..'"' end -- set width and height using noth parameters, one parameter assuming 4:3 aspect ratio, or defaults localaspect=4/3 localwidth=parent.args['width']--or "220" localheight=parent.args['height']or(widthor220)/aspect--or "165" width=widthorheight*aspect-- if width null, use height localalign=parent.args['align']or"right" mapString=mapString..' width='..math.floor(width)..' height='..math.floor(height)..' align='..align localzoom=parent.args['zoom']--or "0" -- no longer set defaults (mapframe does automatically) locallatitude=parent.args['latitude']--or "0" locallongitude=parent.args['longitude']--or "0" --set if values, otherwise allow mapframe to set automatically (TODO check if longitude and latitude are independent) ifzoomthenmapString=mapString..' zoom='..zoomend iflatitudethenmapString=mapString..' latitude='..latitudeend iflongitudethenmapString=mapString..' longitude='..longitudeend mapString=mapString..' >'..mapData..'</mapframe>'-- add data and close tag else mapString="No data for map" end returnmapString end-- End the function. --[[ function getGeoJSON() - to construct JSON format data for markers on map. The information for each marker (coordinate, description and image for popup, etc) can be set in several ways (in order of priority): (1) using arguments in the template (|imageN=, |descriptionN=) (2) from values in the data module (i.e. Module:Football map/data) [not function for cyclone map] (3) from Wikidata ]] p.getGeoJSON=function(frame) -- now we need to iterate through the stadiumN parameters and get data for the feature markers localmaxNumber=200-- maximum number looked for localmapData="" localcycloneName=nil localcycloneID=nil --get mapframe arguments from calling templates localparent=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 --]] localuseWikidata=true localuseModule=false ifparent.args['wikidata']thenuseWikidata=true;useModule=falseend-- use wikidata or template data (no module data) ifparent.args['moduledata']thenuseModule=true;useWikidata=falseend-- use module of template data (no wikidata) ifparent.args['templatedata']thenuseModule=false;useWikidata=falseend-- only use template data -- default parameters for marker color, size and symbol, etc (i.e. those without index suffix) localstrokeColor=parent.args['stroke']or"#000000" ifstrokeColor=="auto"thenstrokeColor=nilend-- if using auto color -- the default properties are set by the unindexed parameters and affect all objects localdefaultProperties={ ['marker-color']=parent.args['marker-color'],-- default to nil --or "#0050d0", ['marker-size']=parent.args['marker-size']or"small", ['marker-symbol']=parent.args['marker-symbol']or"circle", ['stroke']=strokeColor,--parent.args['stroke'] or "#000000", -- nil default causes autocolor path; a value overrides autocolor ['stroke-width']=parent.args['stroke-width']or1, ['stroke-opacity']=parent.args['stroke-opacity']or1.0, -- these are for shapes drawn with polygon instead of the marker symbol ['symbol-stroke']=parent.args['symbol-stroke'],-- nil default causes autocolor path; a value overrides autocolor ['symbol-fill']=parent.args['symbol-fill'],-- nil default causes autocolor path; ['symbol-shape']=parent.args['symbol-shape']or"circle", ['symbol-size']=parent.args['symbol-size']or0.4, ['symbol-stroke-width']=parent.args['symbol-stroke-width']or0, ['symbol-stroke-opacity']=parent.args['symbol-stroke-opacity']or1.0, ['symbol-fill-opacity']=parent.args['symbol-fill-opacity']or1.0 } localindex=0 whileindex<maxNumberdo index=index+1 localcycloneID="" -- (1) get cyclone name cycloneID=parent.args['id'..tostring(index)] cycloneName=parent.args['name'..tostring(index)] ifcycloneNameandnotcycloneIDthen cycloneID=mw.wikibase.getEntityIdForTitle(cycloneName) end ifcycloneIDandnotcycloneNamethen 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) ifcycloneIDthen localfeature={name="",alias="",latitude=0,longitude=0,description="",image="",valid=false,path={}} localvalidFeatureData=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]] ifuseWikidataandcycloneIDthen--and feature['name'] == "" then -- get feature parameters from wikidata feature=p.getDataFromWikiData(cycloneName,cycloneID) ifnotfeature['valid']then-- no valid coordinates validFeatureData=false mw.addWarning("No valid coordinates found for "..cycloneName.." ("..cycloneID..")") end end ---------------------------------------------------- -- (3) data from template parameters will override those obtainied from a module table or wikidata localtemplateArgs={ latitude=parent.args['latitude'..tostring(index)], longitude=parent.args['longitude'..tostring(index)], description=parent.args['description'..tostring(index)], image=parent.args['image'..tostring(index)] } iftemplateArgs['latitude']andtemplateArgs['longitude']then-- if both explicitly set by template feature['latitude']=templateArgs['latitude'] feature['longitude']=templateArgs['longitude'] feature['name']=cycloneName-- as we have valid coordinates validFeatureData=true end -- use specified description and image if provided iftemplateArgs['description']then feature['description']=templateArgs['description'] end iftemplateArgs['image']then feature['image']=templateArgs['image']-- priority for image from template argument end iffeature['image']~=""thenfeature['image']='[['..feature['image']..']]'end -- wikilink - use redirect if alias iffeature['alias']~=''then feature['name']='[['..feature['name']..'|'..feature['alias']..']]' else feature['name']='[['..feature['name']..']]' end iffeature['image']~=""then feature['description']=feature['image']..feature['description'] end --check if current feature marker has specified color, size or symbol localstrokeColor=parent.args['stroke'..tostring(index)]ordefaultProperties['stroke'] ifstrokeColor=="auto"thenstrokeColor=nilend-- if using auto color -- the feature properties are set by the indexed parameters or defaults (see above) localfeatureProperties={ ['marker-color']=parent.args['marker-color'..tostring(index)]ordefaultProperties['marker-color'], ['marker-symbol']=parent.args['marker-symbol'..tostring(index)]ordefaultProperties['marker-symbol'], ['marker-size']=parent.args['marker-size'..tostring(index)]ordefaultProperties['marker-size'], ['stroke']=strokeColor,--parent.args['stroke'..tostring(index)] or defaultProperties['stroke'], ['stroke-width']=parent.args['stroke-width'..tostring(index)]ordefaultProperties['stroke-width'], ['stroke-opacity']=parent.args['stroke-opacity'..tostring(index)]ordefaultProperties['stroke-opacity'], -- these are for shapes drawn with polygon instead of the marker symbol ['symbol-stroke']=parent.args['symbol-stroke'..tostring(index)]ordefaultProperties['symbol-stroke'],-- nil default causes autocolor path; a value overrides autocolor ['symbol-fill']=parent.args['symbol-fill'..tostring(index)]ordefaultProperties['symbol-fill'], ['symbol-shape']=parent.args['symbol-shape'..tostring(index)]ordefaultProperties['symbol-shape'], ['symbol-size']=parent.args['symbol-size'..tostring(index)]ordefaultProperties['symbol-size'], ['symbol-stroke-width']=parent.args['symbol-stroke-width'..tostring(index)]ordefaultProperties['symbol-stroke-width'], ['symbol-stroke-opacity']=parent.args['symbol-stroke-opacity'..tostring(index)]ordefaultProperties['symbol-stroke-opacity'], ['symbol-fill-opacity']=parent.args['symbol-fill-opacity'..tostring(index)]ordefaultProperties['symbol-fill-opacity'] } --(4) construct the json for the features (if we have a storm with valid coordinates) ifvalidFeatureDatathen localfeatureData="" iffeature.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 localmarkerColor=featureProperties['marker-color']or"#0050d0" featureData='{ "type": "Feature", ' ..' "geometry": { "type": "Point", "coordinates": [' ..feature['longitude']..',' ..feature['latitude'] ..'] }, ' ..' "properties": { "title": "'..feature['name']..'", ' ..'"description": "'..feature['description']..'", ' ..'"marker-symbol": "'..featureProperties['marker-symbol']..'", ' ..'"marker-size": "'..featureProperties['marker-size']..'", ' ..'"marker-color": "'..markerColor..'" } ' ..' } ' end ifindex>1andmapData~=""then mapData=mapData..','..featureData else mapData=featureData end else --mapData = '{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [-0.066417, 51.60475] }, "properties": { "title": "White Hart Lane (default)", "description": "Stadium of Tottenham Hotspur F.C.", "marker-symbol": "soccer", "marker-size": "large", "marker-color": "0050d0" } } ' 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 --]] localgeoshape=parent.args['geoshape'..tostring(1)]or"" ifgeoshape~=""then mapData=mapData..','..geoshape-- assumes at least one stadium end -- add outer bracket to json if more than one element ifindex>1then mapData='['..mapData..']' --mapData = ' {"type": "FeatureCollection", "features": [' .. mapData .. ']}' -- is there an advantage using this? end returnmapData 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) ifnotfeature.path[1]thenreturn""end-- shouldn't be necessary now localmode=mw.getCurrentFrame():getParent().args['mode']or"default" localfeatureCollection="" localsep="" locali=1 table.sort(feature.path,function(a,b) if(a.timeStamp<b.timeStamp)then--- primary sort on timeStamp returntrue else returnfalse end end) fori,vinpairs(feature.path)do localautoColor=p.getCycloneColor(feature.path[i]['cycloneType'],featureProperties) localmarkerColor=featureProperties['marker-color']orautoColor localstrokeColor=featureProperties['stroke']orautoColor locallongitude=feature.path[i]['longitude'] locallatitude=feature.path[i]['latitude'] -- add a lines between the points (current point to the next point, if there is one) locallineFeature="" iffeature.path[i+1]then locallongitude2=feature.path[i+1]['longitude'] locallatitude2=feature.path[i+1]['latitude'] lineFeature='{ "type": "Feature", ' ..' "geometry": { "type": "LineString", "coordinates": [' ..'['..longitude..','..latitude..'],' ..'['..longitude2..','..latitude2..']' ..'] }, ' ..' "properties": { "stroke": "'..strokeColor..'" , ' ..' "stroke-width": '..featureProperties['stroke-width']..' , ' ..' "stroke-opacity": '..featureProperties['stroke-opacity'] ..' } ' ..' } ' featureCollection=featureCollection..sep..lineFeature sep="," end --[[ place mapframe markers and custom symbols on each object mode="marker": use mapframe markers for mark storm objects mode="test": use marker on first point of path and linePoint symbol default: use custom polygons to mark storm objects ]] ifmode=="marker"or(mode=="test"andi==1)then localpointFeature='{ "type": "Feature", ' ..' "geometry": { "type": "Point", "coordinates": ['..longitude..','..latitude..'] }, ' ..' "properties": { "title": "'..feature['name']..'", ' ..'"description": "'..feature['description']..'<br>Type: '..feature.path[i]['cycloneType']..'", ' ..'"marker-symbol": "'..featureProperties['marker-symbol']..'", ' ..'"marker-size": "'..featureProperties['marker-size']..'", ' ..'"marker-color": "'..markerColor..'" } ' ..' } ' featureCollection=featureCollection..sep..pointFeature sep="," elseifmode=="test"then-- short lines (test) to mark with objects localdateString=" 2020-06" iffeature.path[i]['timeStamp']then localformattedDate=Date(feature.path[i]['timeStamp']):text("dmy hm") dateString='<br/>date and time: '..formattedDate--tostring( feature.path[i]['timeStamp'] ) end localdescription='<div>latitude: '..tostring(latitude) ..'<br/>longitude: '..tostring(longitude) ..dateString ..'</div>' localcircleFeature='{ "type": "Feature", ' ..' "geometry": { "type": "LineString", "coordinates": [' ..'['..longitude..','..latitude..'],' ..'['..(longitude)..','..(latitude)..']' ..'] }, ' ..' "properties": { "stroke": "'..markerColor..'" , ' ..' "stroke-width": 10, '-- TODO change size based on marker size ..' "description": "'..description..'"' ..' } ' ..' } ' 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 ifmw.getCurrentFrame():getParent().args['mode']=="test3"then featureCollection= '{"type": "FeatureCollection", "features": [ {"type": "Feature","properties": {"marker-color": "#bbccff", "marker-symbol": "-number"}, "geometry": { "type": "Point", "coordinates": [80.298888888889,6.3316666666667]}}, {"type": "Feature","properties": {"marker-color": "#bbccff", "marker-symbol": "-number"}, "geometry": { "type": "Point", "coordinates": [80.263888888889,6.6644444444444]}}, {"type": "Feature","properties": {"marker-color": "#bbccff", "marker-symbol": "-number"}, "geometry": { "type": "Point", "coordinates": [80.434444444444,7.1883333333333]}}, {"type": "Feature","properties": {"marker-color": "#bbccff", "marker-symbol": "-number"}, "geometry": { "type": "Point", "coordinates": [80.656111111111,8.1086111111111]}}, {"type": "Feature","properties": {"marker-color": "#bbccff", "marker-symbol": "-number"}, "geometry": { "type": "Point", "coordinates": [80.9025,8.2961111111111]}}, {"type":"Feature", "properties": { "stroke":"#D3D3D3", "stroke-opacity":0.7, "stroke-width":50}, "geometry": {"type":"LineString", "coordinates": [[80.298888888889,6.3316666666667],[80.263888888889,6.6644444444444],[80.434444444444,7.1883333333333],[80.656111111111,8.1086111111111],[80.9025,8.2961111111111]]}} ]}' end --return sep .. featureCollection returnfeatureCollection end --[[ function p.addShapeFeature(i, feature, featureProperties) function adding shape features using polygon type: square, triangle, stars, etc ]] p.addShapeFeature=function(i,feature,featureProperties) localsize=featureProperties['symbol-size'] localshape=featureProperties['symbol-shape']-- symbol for tropical cyclone iffeature.path[i]['cycloneType2']=='extratropical cyclone'then shape='triangle'-- symbol for extratropical cyclone (Q1063457) elseiffeature.path[i]['cycloneType2']=='subtropical cyclone'then shape='square'-- symbol for subtropical cyclone (Q2331851) end localautoColor=p.getCycloneColor(feature.path[i]['cycloneType'],featureProperties) --local markerColor = featureProperties['symbol-color'] or autoColor localstrokeColor=featureProperties['symbol-stroke']orautoColor localfillColor=featureProperties['symbol-fill']orautoColor locallongitude=feature.path[i]['longitude'] locallatitude=feature.path[i]['latitude'] localdescription='<div style=\\"text-align:left;\\"> ' -- .. '<br/>date: ' .. mw.language.getContentLanguage():formatDate('d F Y', feature.path[i]['timeStamp']) ..'<br/>date: '..Date(feature.path[i]['timeStamp']):text("dmy")-- :text("dmy hm") ..'<br/>type: '..tostring(feature.path[i]['cycloneType']) ..'<br/>longitude: '..fn.formatNum(longitude,"en",6) ..'<br/>latitude: '..fn.formatNum(latitude,"en",6) ..'</div>' localshapeFeature="" --shape="circle" shapeFeature=' { "type": "Feature", ' ..' "geometry": { "type": "Polygon", ' ..' "coordinates": [ '..p.getPolygonCoordinates(shape,size,latitude,longitude)..' ] ' ..' }, ' ..' "properties": { "stroke": "'..strokeColor..'" , ' ..' "fill": "'..fillColor..'" ,' ..' "fill-opacity": 1, ' ..' "stroke-width": '..featureProperties['symbol-stroke-width']..',' ..' "description": "'..description..'"' ..' } ' ..' } ' -- if shape==cyclone, a circle shape will have been drawn; now add the tails ifshape=="cyclone"then-- superimpose a second shape localshape2="cyclone_tails" shapeFeature=shapeFeature..', ' ..'{ "type": "Feature", ' ..' "geometry": { "type": "Polygon", ' ..' "coordinates": [ '..p.getPolygonCoordinates(shape2,size,latitude,longitude)..' ] ' ..' }, ' ..' "properties": { "stroke": "'..strokeColor..'" , ' ..' "fill": "'..fillColor..'" ,' ..' "fill-opacity": 1, ' ..' "stroke-width": '..0..',' ..' "description": "'..description..'"' ..' } ' ..' } ' end returnshapeFeature end p.getPolygonCoordinates=function(shape,size,latitude,longitude) -- shape = "circle" -- shape ="spiral" localcoordinates="" ifshape=="square"then coordinates=' [ ' ..'['..(longitude+size)..','..(latitude+size)..'],' ..'['..(longitude+size)..','..(latitude-size)..'],' ..'['..(longitude-size)..','..(latitude-size)..'],' ..'['..(longitude-size)..','..(latitude+size)..'],' ..'['..(longitude+size)..','..(latitude+size)..']' ..'] ' elseifshape=="triangle2"then coordinates=' [ ' ..'['..(longitude)..','..(latitude+size)..'],' ..'['..(longitude+size)..','..(latitude-size)..'],' ..'['..(longitude-size)..','..(latitude-size)..'],' ..'['..(longitude)..','..(latitude+size)..']' ..'] ' elseifshape=="inverse-triangle"then coordinates=' [ ' ..'['..(longitude)..','..(latitude-size)..'],' ..'['..(longitude+size)..','..(latitude+size)..'],' ..'['..(longitude-size)..','..(latitude+size)..'],' ..'['..(longitude)..','..(latitude-size)..']' ..'] ' elseifshape=="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) ..'] ' elseifshape=="circle2"then localradius=size coordinates=coordinates..' [ ' forangle=0,360,3do ifangle>0thencoordinates=coordinates..','end coordinates=coordinates..'['..longitude+(radius*math.cos(math.rad(angle)))..',' ..latitude+(radius*math.sin(math.rad(angle))) ..']' end coordinates=coordinates..'] ' elseifshape=="cyclone_tails"then localradius=size*2 -- add tail at 3 o'clock coordinates=coordinates..' [ ' forangle=0,60,3do ifangle>0thencoordinates=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..', [ ' forangle=180,240,3do ifangle>180thencoordinates=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..', [ ' forangle=270,330,3do ifangle>270thencoordinates=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..', [ ' forangle=90,150,3do ifangle>90thencoordinates=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 .. '] ' --]] elseifshape=="spiral"then coordinates=' [ ' localradius=size*0.01 forangle=0,360*4,4do radius=radius+size*0.01 ifangle>0thencoordinates=coordinates..','end coordinates=coordinates..'['..longitude+(radius*math.cos(math.rad(angle)))..',' ..latitude+(radius*math.sin(math.rad(angle))) ..']' end coordinates=coordinates..'] ' elseifshape=="circle"orshape=="cyclone"then-- circle as 120 sided polygon returnp.calculatePolygonCoordinates(120,1,size,latitude,longitude) elseifshape=="triangle"then returnp.calculatePolygonCoordinates(3,1,size,latitude,longitude) elseifshape=="diamond"then returnp.calculatePolygonCoordinates(4,1,size,latitude,longitude) elseifshape=="hexagon"then returnp.calculatePolygonCoordinates(6,1,size,latitude,longitude) elseifshape=="octagon"then returnp.calculatePolygonCoordinates(8,1,size,latitude,longitude) elseifshape=="star4"then returnp.calculatePolygonCoordinates(8,3,size,latitude,longitude) elseifshape=="star5"then returnp.calculatePolygonCoordinates(10,3,size,latitude,longitude) elseifshape=="star8"then returnp.calculatePolygonCoordinates(16,3,size,latitude,longitude) elseifshape=="star12"then returnp.calculatePolygonCoordinates(24,3,size,latitude,longitude) elseifshape=="star"then returnp.calculatePolygonCoordinates(10,2,size,latitude,longitude) end returncoordinates end --[[ p.calculatePolygonCoordinates(sides, ratio, size, latitude, longitude) calculates coordinates for polygons or stars a star is a polygon with alternate points with different radii (determined by ratio) sides: number of sides on polygon for a star this is twice the number of points of the star ratio: ratio of inner and outer radii for a star (a higher number makes a more pointy star) use 1 for a simple polygon size: the outer radius of the a circle surrounding the polygon latitude and longitude: self explanatory ]] p.calculatePolygonCoordinates=function(sides,ratio,size,latitude,longitude) localcoordinates=' [ ' localouter=true localradius=size forangle=0,360,360/sidesdo ifangle>0thencoordinates=coordinates..','end-- important for geojson structure (unlike Lua) ifradius~=1then-- if a star ifouterthenradius=sizeelseradius=size/ratioend-- alternate inner and outer radius outer=notouter end coordinates=coordinates..'['..longitude+(radius*math.sin(math.rad(angle)))..',' ..latitude+(radius*math.cos(math.rad(angle))) ..']' end returncoordinates..'] ' end --[[ p.getCycloneColor=function(cycloneType, featureProperties) sets color of symbols/lines based on storm type (from wikidata) ]] p.getCycloneColor=function(cycloneType,featureProperties) --[[ codors from "Tropical cyclone scales" article #80ccff Depression, Zone of Disturbed Weather, Tropical Disturbance (?) #5ebaff Tropical Depression, Deep Depression Tropical Disturbance (?), Tropical Depression, Tropical Low #00faf4 tropical storm, moderate tropical storm, cyclonic storm, Category 1 Tropical Cyclone #ccffff severe cyclonic storm, severe tropical storm, Category 1 Hurricane #ffffcc Very Severe Cyclonic Storm Tropical Cyclone #fdaf9a Typhoon #ffc140 Very Strong Typhoon, Extremely Severe Cyclonic Storm, Intense Tropical Cyclone Category 4 #ff6060 Violent Typhoon, Category 5 Severe Tropical Cyclone, Super Typhoon, Super Cyclonic Storm, Very Intense Tropical Cyclone, Category 5 Major Hurricane ]] localcolor="#000000" cycloneType=string.lower(cycloneType) ifcycloneType=="depression"orcycloneType=="zone of disturbed weather"orcycloneType=="Tropical disturbance" thencolor="#80ccff" elseifcycloneType=="tropical depression"orcycloneType=="deep depression"orcycloneType=="tropical Depression" orcycloneType=="tropical low" thencolor="#5ebaff" elseifcycloneType=="cyclonic storm"orcycloneType=="tropical storm"orcycloneType=="moderate tropical storm" orcycloneType=="category 1 tropical cyclone" thencolor="#00faf4" elseifcycloneType=="severe cyclonic storm"orcycloneType=="severe tropical storm"orcycloneType=="category 1 hurricane" thencolor="#ccffff" elseifcycloneType=="very severe cyclonic storm"orcycloneType=="tropical cyclone" thencolor="#ffffcc" elseifcycloneType=="typhoon" thencolor="#fdaf9a" elseifcycloneType=="very strong typhoon"orcycloneType=="extremely severe cyclonic storm"orcycloneType=="intense tropical cyclone" orcycloneType=="category 4 severe tropical storm" thencolor="#ffc140" elseifcycloneType=="violent typhoon"orcycloneType=="category 5 severe tropical cyclone"orcycloneType=="super typhoon" orcycloneType=="super cyclonic storm"orcycloneType=="very intense tropical cyclone" orcycloneType=="category 5 major hurricane" thencolor="#ff6060" end returncolor end --[[-------------------------------Retrieve information from wikidata------------------------- statements of interest (datavalue element) item = mw.wikibase.getEntity(WikidataId), statements = item:getBestStatements('P625')[1] "claims": P625 coordinate location (value.longitude/latitude) "P625":[{ "mainsnake": { ... "datavalue": { "value": {"latitude": 51.4, "longitude": -0.19] ... statements.mainsnak.datavalue.value.latitude P18 image on commons (value, "File:value") "P18":[{ "mainsnake": { ... "datavalue": { "value": "Stamford Bridge Clear Skies.JPG" P1566 GeoNames ID (value, "geonames.org/value") P31 (instance of) Q483110 (stadium) "P18":[{ "mainsnake": { ... "datavalue": { "value": { "id": "Q483110" however also sports venue, olympic stadium, association football stadium P159 headquarters location (for football club) e..g. London qualifier property: coordinates(P625) page title on enwiki mw.wikibase.getSitelink( itemId ) - gets local version "sitelink": { "enwiki": { "title": "Hurricane Katrina" } other properties of possible interest: P276 location P17 country P580 start time P582 end time P1120 number of deaths P2630 cost of damage P2532 lowest atmospheric pressure P2895 maximum sustained winds --]] p.getDataFromWikiData=function(cycloneName,cycloneID) localwd={name="",latitude="",longitude="",description="",image="",alias="",type="",valid=false,path={}} -- get wikidata id corresponding to wikipedia stadium page --local WikidataId = mw.wikibase.getEntityIdForTitle(cycloneName) localWikidataId=cycloneID ifnotcycloneNamethencycloneName="unnamed"end--TODO get the name ifWikidataIdandmw.wikibase.isValidEntityId(WikidataId)then-- valid id localitem=mw.wikibase.getEntity(WikidataId) ifnotitemthenreturnwdend-- will test for wiki localenwikiTitle=mw.wikibase.getSitelink(WikidataId)-- name of local Wikipedia page localwikidataTitle=mw.wikibase.getLabel(WikidataId)-- name of Wikidata page ifenwikiTitleandwikidataTitleandenwikiTitle~=wikidataTitlethen wd['alias']=wikidataTitle wd['name']=cycloneName else wd['name']=cycloneName end -- get storm type P31 instance of localstatements=item:getBestStatements('P31')--coordinate location ifstatementsandstatements[2]then-- check cordinates available localtype=statements[2].mainsnak.datavalue.value.idor"" wd['type']=mw.wikibase.getLabel(type) end -- get coordinates localstatements=item:getBestStatements('P625')[1]--coordinate location ifstatements~=nilthen-- check cordinates available localcoord=statements.mainsnak.datavalue.value iftype(coord.latitude)=='number'andtype(coord.longitude)=='number'then -- add coordinate data from wikidata for unindexed stadium wd['latitude']=coord.latitude wd['longitude']=coord.longitude wd['valid']=true -- if we have a path of coordinates ifitem:getBestStatements('P625')[2]then-- TODO make sure ordinal number locali=1 whileitem:getBestStatements('P625')[i]do -- get coordinates localstatements=item:getBestStatements('P625')[i]--coordinate location ifstatements~=nilthen-- check cordinates available localcoord=statements.mainsnak.datavalue.value iftype(coord.latitude)=='number'andtype(coord.longitude)=='number'then -- add coordinate data from wikidata for path wd.path[i]={} wd.path[i].latitude=coord.latitude wd.path[i].longitude=coord.longitude -- get series ordinal as index (now removed so set to i) -- TODO sort based on point in time, i.e. wd.path(i).timeStamp wd.path[i].index=i-- statements.qualifiers['P1545'][1]['datavalue']['value'] -- P1545 = series ordinal {a number] -- get storm type using instance of (P31) localcycloneType=statements.qualifiers['P31'][1]['datavalue']['value']['id']-- P31 = instance of [cyclone type] ifcycloneTypethenwd.path[i].cycloneType=mw.wikibase.getLabel(cycloneType)end -- get storm type using instance of (P31) ifstatements.qualifiers['P31'][2]then cycloneType=statements.qualifiers['P31'][2]['datavalue']['value']['id']-- P31 = instance of [cyclone type] ifcycloneTypethenwd.path[i].cycloneType2=mw.wikibase.getLabel(cycloneType)end end --get point in time (P585) qualifier localtimeStamp=statements.qualifiers['P585'][1]['datavalue']['value']['time'] iftimeStampthenwd.path[i].timeStamp=timeStampend end end i=i+1 end-- end while loop end end end-- end if coordinate statements --get image statements=item:getBestStatements('P18')[1]--image ifstatements~=nilthen wd['image']='File:'..statements.mainsnak.datavalue.value end end returnwd end --[[------------------------------------------------------------------------------ This function gets data from a module subpage (not implemented) --------------------------------------------------------------------------------]] p.getModuleData=function(frame,stormName) localfeature={} feature['name']="" --feature['data'] = "" feature['alias']="" feature['description']="" feature['image']="" -- check the module storm list for name match -- set feature parameters from the module data for_,paramsinpairs(stormDatabase.storm)do ifstormName==params[1]then-- if we have a match from the list feature['name']=params[1] feature['latitude']=params[2] feature['longitude']=params[3] feature['alias']=params[4] feature['description']=params[5] feature['image']=params[6] break end end returnfeature end -- All modules end by returning the variable containing its functions to Wikipedia. returnp