This wiki is still in active development, many areas of the site are unstable or broken.

In the meantime, consider adding content to pages you like!

Module:RadarGraph

From NBITTRPG Wiki

Documentation for this module may be created at Module:RadarGraph/doc

local a = require('Module:ACandy').a
local getArgs = require('Module:Arguments').getArgs

local p = {}

local function deg2rad(d) return d * math.pi / 180 end

local function makeRings(max)
	local step = 50 / max
	local parts = {}
	for i = 1, max do
		local pct = i * step
		local style = "radial-gradient(circle at center, rgba(127,127,127,0.1) %.2f%%, rgba(0,0,0,0) %.2f%%)"
		table.insert(parts, string.format(style, pct-0.3, pct+0.3))
	end
	return table.concat(parts, ",")
end

function p.main(frame)
	local args = getArgs(frame, {removeBlanks = true})
	local maxValue = tonumber(args.max) or 5
	local width = args.width or "500px"

	local names, values = {}, {}
	for _, arg in ipairs(args) do
		local i, _ = string.find(arg, "::");
		local key, value;
		if i then
		    key = string.sub(arg, 1, i - 1);
		    value = string.sub(arg, i + 2);
			local num = tonumber(value)
			if num then
				table.insert(names, key)
				table.insert(values, num)
			end
		end
	end

	local n = #names
	if n < 3 then
		return 'Error: Need at least 3 axes.'
	end

	local maxR, center = 35, 50 -- percentages
	local points, markers, labels, spokes = {}, {}, {}, {}

	for i=1,n do
		-- Ensure there is always one angled to point to the top
		local angle = - 90 - (i-1) * (360/n)
		local r = (values[i] / maxValue) * maxR
		local x = center + r * math.cos(deg2rad(angle))
		local y = center + r * math.sin(deg2rad(angle))
		table.insert(points, string.format('%.3f%% %.3f%%', x, y))

		-- marker
		table.insert(markers, a.div {
			style = string.format(
				'position:absolute;left:%.3f%%;top:%.3f%%;' ..
				'width:2%%;height:2%%;margin:-1%% 0 0 -1%%;' ..
				'border-radius:50%%;background:#377dff;border:0.6%% solid #fff',
				x, y
			)
		})

		-- label (slightly beyond maxR)
		-- X-axis needs to be further away since text spans horizontally
		local lx = center + maxR * 1.3 * math.cos(deg2rad(angle))
		local ly = center + maxR * 1.2 * math.sin(deg2rad(angle))
		table.insert(labels, a.div {
			style = string.format(
				'position:absolute;left:%.3f%%;top:%.3f%%;' ..
				'transform:translate(-50%%,-50%%);' ..
				'font-size: larger;' ..
				'z-index: 1',
				lx, ly
			),
			names[i]
		})

		-- spoke
		table.insert(spokes, a.div {
			style = string.format(
				'position:absolute;left:50%%;top:50%%;' ..
				'width:0.6%%;height:%d%%;background:#7777774d;' ..
				'transform-origin:50%% 0%%;transform:translateX(-50%%) rotate(%.1fdeg);',
				maxR, - angle + 90
			)
		})
	end

	-- polygon fill
	local poly = a.div {
		style = string.format(
			'position:absolute;left:0;top:0;width:100%%;height:100%%;' ..
			'clip-path:polygon(%s);' ..
			'background:linear-gradient(135deg,rgba(55,125,255,0.28),rgba(55,125,255,0.18));' ..
			'border:0.6%% solid rgba(55,125,255,0.5);border-radius:2%%;',
			table.concat(points, ',')
		)
	}
	
	local rings = makeRings(maxValue);

	return a.div {
		style = string.format(
			'width:%s;max-width:100%%;position:relative;' ..
			'aspect-ratio : 1 / 1;' ..
			'background: %s; ' ..
			'border-radius:2%%;box-shadow:0 0.3%% 0.6%% rgba(0,0,0,0.06);',
			width, rings
		),
		-- center dot
		a.div { style = 'position:absolute;left:50%;top:50%;width:1.8%;height:1.8%;margin:-0.9% 0 0 -0.9%;border-radius:50%;background:#666;opacity:0.8' },
		-- spokes, labels, polygon, markers
		spokes,
		labels,
		poly,
		markers
	};
end

return p