Module:yo-dial-map

From Wiktionary, the free dictionary
Jump to navigation Jump to search


local export = {}

local m_links = require("Module:links")
local m_lang = require("Module:languages")
local yo = m_lang.getByCode("yo")
local dial_data = mw.loadData("Module:yo-dial-map/data")

local radius = 0.001

local colors = {
	"d2502e", "6941c7", "9fdd42", "e7ff79", "b66063",
	"30bcff", "c6ceff", "02f291", "2e1200", "a4ff46", 
	"ffcccf", "63001e", "c124de", "00ae2d", "ff4ce4", 
	"6fff8b", "b900b1", "bfff6b", "0035b6", "fffe8d", 
	"61008c", "adff9e", "d463ff", "3c8a00", "db0098", 
	"00c97f", "a20090", "01a145", "ff5ec8", "59ffc6", 
	"e50025", "01c0cc", "a60003", "02b9db", "d37200", 
	"0151c6", "949900", "00156f", "ffa938", "290062", 
	"b69700", "6d87ff", "c88100", "014592", "ff823e", 
	"000f36", "bdffc4", "1e003b", "ffce7a", "320029", 
	"d5ffea", "6a0050", "009267", "ff4c61", "019282", 
	"fd98ff", "094300", "ad96ff", "965a00", "8eb0ff", 
	"761f00", "9bd8ff", "490d00", "fbffe9", "1d000f", 
	"feecff", "00141e", "ffddad", "001b14", "ff93ce", 
	"004f23", "9d0050", "005e5e", "ffa291", "003e33", 
	"ff9cac", "00536c", "ffc594", "0079b1", "5a3600", 
}

local function delink(text)
	text = text:gsub("%[%[[^|%[%]]+|([^|%[%]]+)%]%]","%1")
		:gsub("%[%[([^|%[%]]+)%]%]","%1")
	return text
end

function export.make_list(data)
	return "<ul><li>" .. table.concat(data,"</li><li>") .. "</li></ul>"
end

function export.map_header(text)
	return tostring(
		mw.html.create("h2")
			:wikitext(text)
		:done()
	)
end

function export.get_coords(lat,long,i,n)
	if n > 1 then
		return {long+radius*math.cos(2*math.pi*i/n),lat+radius*math.sin(2*math.pi*i/n)}
	else
		return {long,lat}
	end
end

function export.make_point(lat,long,color,text,i,n)
	return {
		type = "Feature",
		properties = {
			title = text,
			["marker-color"] = color,
			["marker-size"] = "small",
		},
		geometry = {
			type = "Point",
			coordinates = export.get_coords(lat,long,i,n)
		}
	}
end

function export.make_polygon(text,color,points)
	local coords = {}
	for _,pt in ipairs(points) do
		table.insert(coords,{pt.long,pt.lat})
	end
	table.insert(coords,{points[1].long,points[1].lat})
	return {
		type = "Feature",
		properties = {
			title = text,
        	["stroke-width"] = 0,
	        ["fill"] = color,
	        ["fill-opacity"] = 0.2,
		},
		geometry = {
			type = "Polygon",
			coordinates = {coords},
		}
	}
end

function export.legend(colour, show, cat, hide)
	return tostring(
		mw.html.create("div")
			:addClass("yo-dial-map__legend-row")
			:addClass((colour == grey and "yo-dial-map__legend-row-other" or nil))
			
			:tag("div")
				:addClass("vsSwitcher")
				:attr("data-toggle-category", cat)
				:attr("data-vs-showtext", "lects ▼")
				:attr("data-vs-hidetext", "lects ▲")

				:tag("span")
					:addClass("yo-dial-map__legend-row-dot")
					:css("background-color", "#" .. colour)
					:wikitext("")
				:done()
				
				:tag("span")
					:addClass("vsToggleElement")
					:wikitext("")
				:done()
				
				:wikitext(show)
				
				:tag("div")
					:addClass("vsHide")
					:wikitext(hide)
		:allDone()
	)
end

function export.make_legends(legend)
	-- divide into five columns manually
	-- DO NOT replace with css column-count
	local r = #legend%5
	local q = math.floor(#legend/5)
	local d1 = q+(r>0 and 1 or 0)
	local d2 = d1+q+(r>1 and 1 or 0)
	local d3 = d2+q+(r>2 and 1 or 0)
	local d4 = d3+q+(r>3 and 1 or 0)
	local l1 = table.concat(legend,"",1,d1)
	local l2 = table.concat(legend,"",d1+1,d2)
	local l3 = table.concat(legend,"",d2+1,d3)
	local l4 = table.concat(legend,"",d3+1,d4)
	local l5 = table.concat(legend,"",d4+1,#legend)
	local cell = {width="20%",["vertical-align"]="top"}
	return tostring(
		mw.html.create("table"):css("width","100%"):tag("tr")
			:tag("td"):css(cell):wikitext(l1):done()
			:tag("td"):css(cell):wikitext(l2):done()
			:tag("td"):css(cell):wikitext(l3):done()
			:tag("td"):css(cell):wikitext(l4):done()
			:tag("td"):css(cell):wikitext(l5):done()
		:allDone()
	)
end

function export.make_map(frame,geojson,legend)
	return tostring(
		mw.html.create("div")
			:addClass("thumb")
			:addClass("yo-dial-map__container")
			:wikitext(frame:extensionTag("mapframe",mw.text.jsonEncode(geojson),{
				class = "yo-dial-map__map",
				mapstyle = "osm-intl",
				width = 1200,
				height = 600,
				latitude = 7.38298,
				longitude = 3.94703,
				zoom = 7
			}))
			:done()

			:tag("div")
				:wikitext(legend)
			:done()
		:done()
	)
end

function export.show(frame)
	local geojson = {}
	local legend = {}
	local dial = mw.loadData("Module:dialect synonyms/yo").varieties
	local syn = mw.loadData("Module:dialect synonyms/yo/"..frame.args[1])
	
	-- recurse through dial to find all the lects
	local lects = {}
	local layer = {dial}
	while layer[1] do
		local children = {}
		for _,node in ipairs(layer) do
			if node[1] then -- node is a subfamily
				for _,child in ipairs(node) do
					table.insert(children,child)
				end
			elseif node.long and syn.syns[node.name] and syn.syns[node.name][1] ~= "" then
				table.insert(lects,node)
			end
		end
		layer = children
	end
	
	local locs = {} -- loc[form] = {lect1, lect2, ...}
	local n = {}
	for _,lect in ipairs(lects) do
		local syn_lect = syn.syns[lect.name]
		n[lect.name] = 0 -- `#` doesn't work with mw.loadData
		local i = 0
		for _,form in ipairs(syn_lect) do
			i = i + 1
			n[lect.name] = n[lect.name] + 1
			locs[form] = locs[form] or {}
			table.insert(locs[form],{lect,i})
		end
	end
	
	local forms = {}
	for form,lects in pairs(locs) do
		table.insert(forms,form)
	end
	table.sort(forms, function(a,b) return #locs[a] > #locs[b]
		or (#locs[a] == #locs[b] and a > b) end)
	
	for idx,form in ipairs(forms) do
		local color = colors[idx]
		local legend_lects = {}
		local link = m_links.full_link({
			lang = yo,
			term = form,
		})
		for _,lect_i in ipairs(locs[form]) do
			local lect,i = lect_i[1],lect_i[2]
			local link_ = link
			if lect.code then
				link_ =  m_links.full_link({
					lang = m_lang.getByCode(lect.code),
					term = form,
				})
			end
			local display = lect.text_display .. ": <br>" .. link_
			table.insert(geojson,export.make_point(lect.lat,lect.long,color,display,i,n[lect.name]))
			table.insert(legend_lects, lect.text_display)
		end
		table.insert(legend, export.legend(color, link .. " (" .. #locs[form] .. ")", form, export.make_list(legend_lects)))
	end
	
	local title = syn.title and syn.title ~= "" and syn.title or frame.args[1]
	title = title:gsub("[0-9%-]", "")
	local map_header = export.map_header(
		"Map of Yoruba varieties and languages for " .. m_links.full_link(
			{
				lang = yo,
				term = title,
				gloss = syn.meaning,
			}
		)
	)
	
	-- draw the families
	for _,fam in ipairs(dial_data.groups) do
		table.insert(geojson,export.make_polygon(fam.name,fam.color,fam.points))
	end
	
	local legends = export.make_legends(legend)
	local map = export.make_map(frame, geojson, legends)
	
	return map_header .. map
end

return export