1. 程式人生 > 其它 >Web 前端實戰(三):雷達圖

Web 前端實戰(三):雷達圖

前言

《Canvas 線性圖形(五):多邊形》實現了繪製多邊形的函式。本篇文章將記錄如何繪製雷達圖。

最終實現的效果是這樣的:

繪製雷達圖

繪製雷達圖裡外層

如動圖中所示,雷達圖從裡到外一共有 6 層,所以,我們需要改造繪製多邊形的函式:

點選檢視程式碼
function calcPolygonX(x, radius, increaseAngle) {
	return x + radius * Math.cos(increaseAngle);
}

function calcPolygonY(y, radius, increaseAngle) {
	return y - radius * Math.sin(increaseAngle);
}

function drawPolygon(sides, radius, x, y, ctx) {
	let averageAngle = Math.PI * 2 / sides;
	let increaseAngle = 0;
	let targetX, targetY;

	ctx.beginPath();
	for ( let i = 0; i < sides; i++ ) {
		targetX = calcPolygonX(x, radius, increaseAngle);
		targetY = calcPolygonY(y, radius, increaseAngle);
		ctx.lineTo(targetX, targetY);
		increaseAngle += averageAngle;
	}

	ctx.closePath();
	ctx.stroke();
}

function drawRadarMap(options, x, y, ctx) {
	let radius = options.radius;

	for ( let j = 0; j < options.layer; j++ ) {
		drawPolygon(options.sides, radius, x, y, ctx);
		radius = radius + options.radius;
	}
}
let canvas = document.getElementById("radar-map");
let ctx = canvas.getContext("2d");
drawRadarMap({ radius: 20, sides: 6, layer: 6 }, 100, 100, ctx);

最終實現效果:

連線雷達圖裡外層

儲存點座標

連線雷達圖裡外層繪製六條直線,已知圓心座標,需要知道最外層多邊形每一個點的座標。在drawPolygon中我們需要儲存每一個點的座標。

drawRadarMap函式裡面宣告一個數組用於儲存每一個多邊形的每一個點座標:

function drawRadarMap(layer, step, sides, x, y, data, options, ctx) {
	let coordinates = []; // 宣告一個數組,用於儲存每一個多邊形的每一個點座標
	let radius = options.radius;

	for ( let j = 0; j < layer; j++ ) {
		drawPolygon(sides, radius, x, y, coordinates, j, ctx);
		radius = radius + step;
	}
}

drawPolygon函式中每一個點都要儲存到陣列中:

function drawPolygon(sides, radius, x, y, coordinates, ctx) {
	let averageAngle = Math.PI * 2 / sides;
	let increaseAngle = 0;
	let targetX, targetY;

	ctx.beginPath();
	coordinates.push({ layer: j, coords: [] });
	for ( let i = 0; i < sides; i++ ) {
		targetX = calcPolygonX(x, radius, increaseAngle);
		targetY = calcPolygonY(y, radius, increaseAngle);
		ctx.lineTo(targetX, targetY);
		increaseAngle += averageAngle;
		coordinates[j].coords.push({ x: targetX, y: targetY });
	}

	ctx.closePath();
	ctx.stroke();
}

列印陣列結果:

繪製直線函式

function drawStria(surface, coordinates, originX, originY, options, ctx) {
	let length = coordinates.length;
	let coords = coordinates[length - 1].coords;
	for ( let i = 0; i < surface; i++ ) {
		ctx.beginPath();
		ctx.moveTo(originX, originY);
		ctx.lineTo(coords[i].x, coords[i].y);
		ctx.closePath();
		ctx.stroke();
		drawPointText(options, coords, i, originX, ctx); // 這個函式在後面講解
	}
}

coordinates[length - 1].coords代表雷達圖中最外層的多邊形的所有點座標。順時針遍歷其中元素,ctx.lineTo(coords[i].x, coords[i].y)從圓點開始依次連線最外層的多邊形的點,從而構成一條條直線。

繪製雷達圖外層節點文字

在雷達圖最外層的多邊形的每一個點新增文字,表示直線代表的是什麼資料。

function drawPointText(coords, i, originX, ctx) {
	ctx.font = `16px Georgia`;
	if ( coords[i].x <= originX ) {
		ctx.textAlign = "right";
	} else {
		ctx.textAlign = "left";
	}
	ctx.fillText(data[i].title, coords[i].x, coords[i].y);
}

繪製資料區域

function drawDataArea(surface, radius, coordinates, originX, originY, data, options, ctx) {
	let decidedCoords = [];
	let lastLayer = coordinates[coordinates.length - 1].coords;
	ctx.beginPath();
	for ( let i = 0; i < surface; i++ ) {
		let { x, y } = drawDataAreaTop(coordinates, i, originX, originY);
		if ( i === 0 ) {
			ctx.moveTo(x, y);
		} else {
			ctx.lineTo(x, y);
		}
		decidedCoords.push({ x: x, y: y });
	}
	ctx.closePath();
	ctx.strokeStyle = options.dataArea.lineColor;
	ctx.stroke();
	ctx.fillStyle = options.dataArea.fillColor;
	ctx.fill();
	drawDataAreaPoint(decidedCoords, ctx);
}

繪製資料區域頂點

function drawDataAreaTop(coordinates, i, originX, originY) {
	let layer = data[i].star - 1;
	let x, y;
	if ( layer < 0 ) {
		x = originX;
		y = originY;
	} else {
		x = coordinates[layer].coords[i].x;
		y = coordinates[layer].coords[i].y;
	}
	return { x: x, y: y };
}

繪製資料區域頂點圓點

function drawDataAreaPoint(coordinates, ctx) {
	ctx.strokeStyle = "white";
	for ( let i = 0; i < coordinates.length; i++ ) {
		ctx.beginPath();
		ctx.arc(coordinates[i].x, coordinates[i].y, 1, 0, Math.PI * 2);
		ctx.closePath();
		ctx.stroke();
		ctx.fillStyle = "white";
		ctx.fill();
	}
}

呼叫雷達圖函式

在繪製雷達圖的函式下面新增drawStriadrawDataArea兩個函式,完整一個完整的雷達圖繪製

點選檢視雷達圖資料
let data = [
	{
	title: "js",
	star: 4
	},
	{
	title: "ts",
	star: 2
	},
	{
	title: "html",
	star: 4
	},
	{
	title: "css",
	star: 4
	},
	{
	title: "vue",
	star: 4
	},
	{
	title: "uniapp",
	star: 4
	},
	{
	title: "java",
	star: 2
	},
	{
	title: "flutter",
	star: 3
	},
	{
	title: "dart",
	star: 4
	},
	{
	title: "python",
	star: 0
	}
];
function drawRadarMap(layer, step, sides, x, y, data, options, ctx) {
	// ...
	// ...

	drawStria(sides, coordinates, x, y, options, ctx);
	drawDataArea(sides, radius, coordinates, x, y, data, options, ctx);
}

drawRadarMap(5, 40, 10, 300, 300, data, options, ctx);

Gitee 倉庫-雷達圖完整程式碼