Module:zh-dial-map/sandbox


local export = {}
local m_links = require("Module:links")
local lang = require("Module:languages").getByCode("zh")
local variety_data = require("Module:zh/data/dial")

local dots = {
	"e72c27", "2589e7", "96e725", "8328e7", "ece65a",
	"28dde7", "e727dc", "e78322", "20e680", "3b49d1", 
	"9b5b5a", "59869c", "809c59", "79599c", "9d9a5a", 
	"52a1a3", "9c5995", "9c7a59", "5a9b7a", "59619c", 
	"da716c", "6ca5da", "8fda6c", "a16dda", "e1d08a", 
	"6dd3da", "da6dd4", "dca875", "84d9ad", "726dda", 
	"783017", "164f73", "4d7313", "411777", "766312", 
	"167364", "7e187d", "744116", "16742b", "161f7a", 
	"e1a4a3", "a2c3e1", "bedc93", "bb9ade", "dcd993", 
	"93d8dc", "dc93d8", "dcb793", "93dcb6", "9395dc", 
	"b74945", "538bbd", "87b644", "844fbd", "cdc741", 
	"4db6bc", "b644af", "b67c44", "44b67a", "4448b6", 
	"a06d6d", "6f88a0", "8ba16d", "876ea0", "b0ae84", 
	"6d9ea1", "a16d9e", "a1866d", "6da186", "6d6da1", 
	"f18383", "83bbf1", "c3f183", "bb83f1", "f1eb82", 
	"83ebf1", "f282e9", "f1b883", "83f1b8", "8286f2", 
}

local grey = "ccccbf"

local elements = {}

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

elements.map = function(points, legend)
	return tostring(
		mw.html.create( "div" )
			:addClass( "thumb" )
			:addClass( "zh-dial-map__container" )

			:tag( "div" )
				:addClass( "thumbinner" )
				:addClass( "zh-dial-map__frame" )
				-- these styles can't be moved to the .css file because .thumbinner has its own definitions
				:css( "overflow", "auto" )
				:css( "font-size", "1px" ) -- related to the positioning of the dots

				:tag( "div" )
					:addClass( "zh-dial-map__map" )
					:wikitext( '[[File:Chinese dialectal variation location map.svg|1200px|link=]]' )
					:wikitext( points )
				:done()
			:done()

			:tag( "div" )
				:addClass( "zh-dial-map__legend" )
				:wikitext( legend )
			:done()
		:done()
	)
end

elements.dot = function(loc_name, loc, top, left, terms, colors)
	if #terms == 0 then return nil end
	local term = table.concat(terms,"/"):gsub("[%[%]]+", "")
	local n = #colors
	for i=1,n do
		colors[i] = "#"..colors[i].." "..((i-1)/n).."turn "..(i/n).."turn"
	end
	local pie = "conic-gradient("..table.concat(colors,",")..")"
	
	return tostring(
		mw.html.create( "span" )
			:attr( "data-location-en", loc_name )
			:attr( "data-location-zh", loc.chinese )
			:attr( "data-group", loc.group )
			:attr( "data-word", terms[1] )
			:addClass( "zh-dial-map__dot" )

			:css( "top", top .. "em" ) -- The size of 1 em is tied to the font-size of .zh-dial-map__frame
			:css( "left", left .. "em" )
			:css( "background", pie )
			:attr( "title", loc_name .. " (" .. loc.chinese .. ") " .. loc.group .. ": " .. term )

			-- without text in the <span> it seems like the wikitext render discards the whole <span>???
			-- and makes a link with no text at all??????
			:wikitext( "&nbsp;" )
		:done()
	)
end

elements.legend = function(d, colour, appendedText)
	return tostring(
		mw.html.create( "div" )
			:attr( "data-word", (d and d.term or "other") )
			:addClass( "zh-dial-map__legend-row" )
			:addClass( (colour == grey and "zh-dial-map__legend-row-other" or nil) )

			:tag( "span" )
				:addClass( "zh-dial-map__legend-row-dot" )
				:css( "background-color", "#" .. colour )

				:wikitext( "&nbsp;" ) -- please let me make empty spans
			:done()

			:wikitext( appendedText )
		:done()
	)
end

function export.make_map(frame)
	local syn_data = require("Module:zh/data/dial-syn/" .. frame.args[1]).list
	local prelim_data, data, points, legend = {}, {}, {}, {}
	local loc, cur = {}, {}
	local syn_data_show = {}
	for i = 1,#variety_data,1 do
		loc = variety_data[i]
		cur = syn_data[loc.key] or {""}
		if cur[1] ~= "" and loc.lat then
			syn_data_show[loc] = {}
			for _, term in ipairs(cur) do
				term = mw.text.split(term, ":")
				if term[2] ~= "mT" and term[2] ~= "GT" then
					term = term[1]
					table.insert(syn_data_show[loc], term)
					if prelim_data[term] then
						prelim_data[term].count = prelim_data[term].count + 1
						table.insert(prelim_data[term].locations, loc)
					else
						prelim_data[term] = { count = 1, locations = { loc } }
					end
				end
			end
		end
	end
	for term, term_data in pairs(prelim_data) do
		table.insert(data, { term = term, count = term_data.count, locations = term_data.locations })
	end
	table.sort(data, function(first, second) return first.count > second.count end)
	
	local colors = {}
	-- assign color to each existing form
	-- grey out anything below or equal to the 81st count
	local grey_count = #data > 80 and data[81].count or 0
	local greyed_count = 0
	for i, d in ipairs(data) do
		local greyed = d.count <= grey_count
		local colour = greyed and grey or dots[i]
		colors[d.term] = colour
		if greyed then
			greyed_count = greyed_count + d.count
		else
			local link = m_links.full_link({
				lang = lang,
				term = mw.ustring.gsub(d.term, "(.+)_[1-9]", "%1"),
				alt = mw.ustring.gsub(d.term, "(.+)_([1-9])", "%1<sub>%2</sub>"),
				tr = "-",
			})
			table.insert(legend, elements.legend(d, colour, link .. " (" .. d.count .. ")"))
		end
	end
	
	-- make the points; one point for each given locality
	for loc, terms in pairs(syn_data_show) do
		local dot_colors = {}
		for i,term in ipairs(terms) do
			dot_colors[i] = colors[term]
		end
		local top = (55 - loc.lat) * 89520 / 5593 -- (55 - loc.lat) * 1200 * 746 / 799 / 70
		local left = (loc.long - 70) * 16 -- (loc.long - 70) * 1200 / 75
		local loc_name = mw.ustring.gsub(loc.english or loc.key, "%((.*)%)$", "- %1")
		table.insert(points, elements.dot(loc_name, loc, top, left, terms, dot_colors))
	end
	
	if greyed_count > 0 then
		table.insert(legend, elements.legend(false, grey, "other terms (" .. greyed_count .. ")"))
	end

	local map_header = elements.map_header(
		"Map of Chinese dialectal equivalents for " .. m_links.full_link(
			{
				lang = lang,
				term = mw.ustring.gsub(frame.args[1], "%-.*", ""),
				gloss = syn_data["meaning"],
				tr = '-'
			}
		)
	)

	local note = "\n''Note: This map may not be well-supported on mobile devices. Please view this page on a computer.''"
	local map = elements.map(table.concat(points), table.concat(legend))

	return map_header .. note .. map
end

return export