Web 前端實戰(三):雷達圖
阿新 • • 發佈:2022-05-23
前言
在《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();
}
}
呼叫雷達圖函式
在繪製雷達圖的函式下面新增drawStria
和drawDataArea
兩個函式,完整一個完整的雷達圖繪製
點選檢視雷達圖資料
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);