How to recreate radar charts?

Hey there developers!

So I was recently playing Loomian Legacy, and become interested in recreating something like this:

I really want to know how to recreate the radar chart in the centre of the image.
(btw, its also animated)

Here’s another image of a radar chart:

Do you use multiple frames? Connect points?

7 Likes
local sp=script.Parent
local HALF = Vector2.new(0.5, 0.5);

local IMG = Instance.new("ImageLabel");
IMG.BackgroundTransparency = 1;
IMG.AnchorPoint = HALF;
IMG.BorderSizePixel = 0;

local RIGHT = "rbxassetid://319692151";
local LEFT = "rbxassetid://319692171";

local function drawtriangle(a, b, c, w1, w2)
	local ab, ac, bc = b - a, c - a, c - b;
	local abd, acd, bcd = ab:Dot(ab), ac:Dot(ac), bc:Dot(bc);

	if (abd > acd and abd > bcd) then
		c, a = a, c;
	elseif (acd > bcd and acd > abd) then
		a, b = b, a;
	end

	ab, ac, bc = b - a, c - a, c - b;

	local unit = bc.unit;
	local height = unit:Cross(ab);
	local flip = (height >= 0);
	local theta = math.deg(math.atan2(unit.y, unit.x)) + (flip and 0 or 180);

	local m1 = (a + b)/2;
	local m2 = (a + c)/2;

	w1 = w1 or IMG:Clone();
	w1.Image = flip and RIGHT or LEFT;
	w1.AnchorPoint = HALF;
	w1.Size = UDim2.new(0, math.abs(unit:Dot(ab)), 0, height);
	w1.Position = UDim2.new(0, m1.x, 0, m1.y);
	w1.Rotation = theta;
	w1.Parent = sp.RadarChart;

	w2 = w2 or IMG:Clone();
	w2.Image = flip and LEFT or RIGHT;
	w2.AnchorPoint = HALF;
	w2.Size = UDim2.new(0, math.abs(unit:Dot(ac)), 0, height);
	w2.Position = UDim2.new(0, m2.x, 0, m2.y);
	w2.Rotation = theta;
	w2.Parent = sp.RadarChart;

	return w1, w2;
end

local center=Vector2.new(300,300)
local length=150
local function constructbackground()
	local color=Color3.new(.2,.2,.2)
	for i=1,5 do
		local degrees=math.rad(i*360/5+360/10)
		local prior=degrees-math.rad(360/5)
		local b=center+Vector2.new(1*math.sin(prior),1*math.cos(prior))*length
		local c=center+Vector2.new(1*math.sin(degrees),1*math.cos(degrees))*length
		local t1,t2=drawtriangle(center,b,c)
		t1.ImageColor3=color
		t2.ImageColor3=color
	end
end

constructbackground()

local order={
	"Power";
	"Speed";
	"Trick";
	"Recovery";
	"Defense";
}

local stats={
	5;
	2;
	7;
	5;
	1;
}

local function showstats()
	local color=Color3.new(1,.6,0)
	for i,v in pairs(order) do
		local stat=stats[i]
		local laststat=stats[i-1] or stats[#stats]
		local degrees=math.rad(i*360/5+360/10)
		local prior=degrees-math.rad(360/5)
		local b=center+Vector2.new(1*math.sin(prior),1*math.cos(prior))*length*laststat/10
		local c=center+Vector2.new(1*math.sin(degrees),1*math.cos(degrees))*length*stat/10
		local t1,t2=drawtriangle(center,b,c)
		t1.ImageColor3=color
		t2.ImageColor3=color
	end
end

constructbackground()
showstats()

I used EgoMoose’s triangle function and cos/sin to get the rotation direction. This script generates a very fragmentary hexagonal radar chart. Still working on how I can make it look more complete.

19 Likes

The result:

From what I can tell, the loomian radar chart was made similarly

2 Likes

I thank you, my good man, as I do not have the brainpower to process this.

1 Like

I made it into a module that i can use but what kind of left right images are you using in that script
i used the your ids but i think they are deleted

local RadarChart = {}

local HALF = Vector2.new(0.5, 0.5)
local IMG_RIGHT = "rbxassetid://100029582962422"
local IMG_LEFT = "rbxassetid://100029582962422"

local function drawTriangle(center, a, b, c, container, color, transparency)
	local ab, ac, bc = b - a, c - a, c - b
	local abd, acd, bcd = ab:Dot(ab), ac:Dot(ac), bc:Dot(bc)

	if abd > acd and abd > bcd then
		c, a = a, c
	elseif acd > bcd and acd > abd then
		a, b = b, a
	end

	ab, ac, bc = b - a, c - a, c - b
	local unit = bc.unit
	local height = unit:Cross(ab)
	local flip = (height >= 0)
	local theta = math.deg(math.atan2(unit.y, unit.x)) + (flip and 0 or 180)

	local m1 = (a + b) / 2
	local m2 = (a + c) / 2

	local w1 = Instance.new("ImageLabel")
	w1.Image = flip and IMG_RIGHT or IMG_LEFT
	w1.AnchorPoint = HALF
	w1.BorderSizePixel = 0
	w1.BackgroundTransparency = 1
	w1.Size = UDim2.new(0, math.abs(unit:Dot(ab)), 0, height)
	w1.Position = UDim2.new(0, m1.x, 0, m1.y)
	w1.Rotation = theta
	w1.ImageColor3 = color
	w1.ImageTransparency = transparency
	w1.Parent = container

	local w2 = Instance.new("ImageLabel")
	w2.Image = flip and IMG_LEFT or IMG_RIGHT
	w2.AnchorPoint = HALF
	w2.BorderSizePixel = 0
	w2.BackgroundTransparency = 1
	w2.Size = UDim2.new(0, math.abs(unit:Dot(ac)), 0, height)
	w2.Position = UDim2.new(0, m2.x, 0, m2.y)
	w2.Rotation = theta
	w2.ImageColor3 = color
	w2.ImageTransparency = transparency
	w2.Parent = container
end

function RadarChart.new(parent, stats, options)
	options = options or {}

	local maxValue = options.maxValue or 10
	local fillColor = options.fillColor or Color3.new(1, 0.6, 0)
	local fillTransparency = options.fillTransparency or 0
	local gridColor = options.gridColor or Color3.new(0.2, 0.2, 0.2)
	local gridTransparency = options.gridTransparency or 0

	local statCount = #stats
	local centerPos = Vector2.new(150, 150)
	local radius = 100

	local container = Instance.new("Frame")
	container.Name = "RadarChart"
	container.Size = UDim2.new(0, 300, 0, 300)
	container.BackgroundTransparency = 1
	container.BorderSizePixel = 0
	container.Parent = parent

	--// Draw grid background
	for i = 1, statCount do
		local angle = math.rad((i - 1) * 360 / statCount + 360 / (statCount * 2))
		local prevAngle = angle - math.rad(360 / statCount)

		local b = centerPos + Vector2.new(math.sin(prevAngle), math.cos(prevAngle)) * radius
		local c = centerPos + Vector2.new(math.sin(angle), math.cos(angle)) * radius

		drawTriangle(centerPos, centerPos, b, c, container, gridColor, gridTransparency)
	end

	--// Draw stat overlay
	for i = 1, statCount do
		local stat = stats[i]
		local lastStat = stats[i - 1] or stats[statCount]

		local angle = math.rad((i - 1) * 360 / statCount + 360 / (statCount * 2))
		local prevAngle = angle - math.rad(360 / statCount)

		local b = centerPos + Vector2.new(math.sin(prevAngle), math.cos(prevAngle)) * radius * (lastStat / maxValue)
		local c = centerPos + Vector2.new(math.sin(angle), math.cos(angle)) * radius * (stat / maxValue)

		drawTriangle(centerPos, centerPos, b, c, container, fillColor, fillTransparency)
	end

	return container
end

return RadarChart
1 Like