canvas 绘制雷达图

116 阅读3分钟

image.png

<script lang="ts" setup>

bus.on('sendReportData', (res: any) => {
    // 他评均分列表数据;
    const otherScoreList = (res.reportTeamIndexScoreBoList || []).map((item: any) => item.otherScore);
    // 自评均分列表数据;
    const selfScoreList = (res.reportTeamIndexScoreBoList || []).map((item: any) => item.selfScore);
    const maxScore = Math.max(...otherScoreList, ...selfScoreList);
    const multiple = maxScore;
    
    let mW = 700;
    let mH = 500;
    let otherScoreData = <any>[];
    let selfScoreData = <any>[];
    res.reportTeamIndexScoreBoList.forEach((item: any) => {
        otherScoreData.push([item.indicatorName, item.otherScore]);
        selfScoreData.push([item.indicatorName, item.selfScore]);
    });
    
    console.log('otherScoreData:', otherScoreData); // [["有问题先自省", 3.78], ["务实求真", 3.33], ["永远可以更好", 3.56], ["快速反馈", 3.22], ["坚决执行", 3.67], ["说到做到", 3.78], ["公开透明", 4.22], ["简单直接", 4], ["凡事向前一步", 3.89]]
    console.log('selfScoreData:', selfScoreData); // [["有问题先自省", 3], ["务实求真", 2], ["永远可以更好", 1], ["快速反馈", 1], ["坚决执行", 2], ["说到做到", 3], ["公开透明", 4], ["简单直接", 5], ["凡事向前一步", 4]]
    
    let mCount = otherScoreData.length; // 边数;
    let xCenter = mW / 2; // x中心点;
    let yCenter = mH / 2; // y中心点;
    let mRadius = xCenter - 180; // 半径(减去的值用于给绘制的文本留空间);
    let mAngle = (Math.PI * 2) / mCount; // 角度;
    let mCtx = <any>null;
    let mColorPolygon = 'rgba(184, 184, 184, 0.7)'; // 多边形颜色;
    let mColorLines = '#B8B8B8'; // 顶点连线颜色;
    let mColorText = '#000000'; // 初始化;
    
    (function () {
        var canvas = <any>document.getElementById('canvasDom');
        canvas.height = mH;
        canvas.width = mW;
        mCtx = canvas.getContext('2d');
        drawPolygon(mCtx);
        drawPolygon2(mCtx);
        drawLines(mCtx);
        drawText(mCtx);
        drawCircle(mCtx);
        drawCircleLines(mCtx);
        drawCircleData(mCtx);
        drawCircle2(mCtx);
        drawCircleLines2(mCtx);
        drawCircleData2(mCtx);
    })();
    
    // 绘制多边形边
    function drawPolygon(ctx: CanvasRenderingContext2D) {
        ctx.save();
        ctx.strokeStyle = mColorPolygon;
        var r = mRadius / mCount + 23; //单位半径
        for (var i = 0; i < 3; i++) {
            ctx.beginPath();
            var currR = r * (i + 1); //当前半径
            for (var j = 0; j < mCount; j++) {
                var x = xCenter + currR * Math.cos(mAngle * j);
                var y = yCenter + currR * Math.sin(mAngle * j);
                ctx.setLineDash([3]);
                ctx.lineTo(x, y);
            }
            ctx.closePath();
            ctx.stroke();
        }
        ctx.restore();
    }
    
    // 绘制实线多边形
    function drawPolygon2(ctx: CanvasRenderingContext2D) {
        ctx.save();
        ctx.beginPath();
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + mRadius * Math.cos(mAngle * i);
            var y = yCenter + mRadius * Math.sin(mAngle * i);
            ctx.lineTo(x, y);
        }
        ctx.closePath();
        ctx.strokeStyle = mColorPolygon;
        ctx.stroke();
        ctx.restore();
    }
    
    //顶点连线
    function drawLines(ctx: CanvasRenderingContext2D) {
        ctx.save();
        ctx.beginPath();
        ctx.strokeStyle = mColorLines;
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + mRadius * Math.cos(mAngle * i);
            var y = yCenter + mRadius * Math.sin(mAngle * i);
            ctx.moveTo(xCenter, yCenter);
            ctx.lineTo(x, y);
        }
        ctx.strokeStyle = 'rgba(184, 184, 184, 0.5)';
        ctx.stroke();
        ctx.restore();
    }
    
    //绘制文本
    function drawText(ctx: CanvasRenderingContext2D) {
        ctx.save();
        var fontSize = 18;
        ctx.font = fontSize + 'px Microsoft Yahei';
        ctx.fillStyle = mColorText;
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + mRadius * Math.cos(mAngle * i);
            var y = yCenter + mRadius * Math.sin(mAngle * i);
            if (mAngle * i >= 0 && mAngle * i <= Math.PI / 2) {
                ctx.fillText(otherScoreData[i][0], x + 10, y + 20);
            } else if (mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI) {
                ctx.fillText(otherScoreData[i][0], x - ctx.measureText(otherScoreData[i][0]).width, y + 25);
            } else if (mAngle * i > Math.PI && mAngle * i <= (Math.PI * 3) / 2) {
                ctx.fillText(otherScoreData[i][0], x - ctx.measureText(otherScoreData[i][0]).width, y - 10);
            } else {
                ctx.fillText(otherScoreData[i][0], x + 10, y - 10);
            }
        }
        ctx.restore();
    }
    
    //画点
    function drawCircle(ctx: CanvasRenderingContext2D) {
        ctx.save();
        var r = 3;
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + (mRadius * Math.cos(mAngle * i) * otherScoreData[i][1]) / multiple;
            var y = yCenter + (mRadius * Math.sin(mAngle * i) * otherScoreData[i][1]) / multiple;
            console.log('x:', x, 'y:', y);

            ctx.beginPath();
            ctx.arc(x, y, r, 0, Math.PI * 2);
            ctx.fillStyle = 'rgba(37, 170, 173, 0.8)';
            ctx.fill();
        }
        ctx.restore();
    }
    
    //画点连线;
    function drawCircleLines(ctx: CanvasRenderingContext2D) {
        ctx.save();
        ctx.beginPath();
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + (mRadius * Math.cos(mAngle * i) * otherScoreData[i][1]) / multiple;
            var y = yCenter + (mRadius * Math.sin(mAngle * i) * otherScoreData[i][1]) / multiple;
            ctx.lineTo(x, y);
        }
        ctx.closePath();
        ctx.strokeStyle = 'rgba(37, 170, 173, 0.8)';
        ctx.stroke();
        ctx.restore();
    }
    
    //画点数据;
    function drawCircleData(ctx: CanvasRenderingContext2D) {
        ctx.save();
        var fontSize = 16;
        ctx.font = fontSize + 'px Microsoft Yahei';
        ctx.fillStyle = 'rgba(37, 170, 173, 0.8)';
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + (mRadius * Math.cos(mAngle * i) * otherScoreData[i][1]) / multiple;
            var y = yCenter + (mRadius * Math.sin(mAngle * i) * otherScoreData[i][1]) / multiple;
            if (mAngle * i >= 0 && mAngle * i <= Math.PI / 2) {
                ctx.fillText(otherScoreData[i][1], x + 5, y + fontSize);
            } else if (mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI) {
                ctx.fillText(otherScoreData[i][1], x - ctx.measureText(otherScoreData[i][1]).width - 5, y + fontSize - 5);
            } else if (mAngle * i > Math.PI && mAngle * i <= (Math.PI * 3) / 2) {
                ctx.fillText(otherScoreData[i][1], x - ctx.measureText(otherScoreData[i][1]).width - 5, y - 5);
            } else {
                ctx.fillText(otherScoreData[i][1], x + 5, y - 5);
            }
        }
        ctx.restore();
    }
    
    //画点2
    function drawCircle2(ctx: CanvasRenderingContext2D) {
        ctx.save();
        var r = xCenter / 50;
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + (mRadius * Math.cos(mAngle * i) * selfScoreData[i][1]) / multiple;
            var y = yCenter + (mRadius * Math.sin(mAngle * i) * selfScoreData[i][1]) / multiple;
            ctx.beginPath();
            ctx.fillStyle = 'rgba(244, 112, 112, 0.8)';
            ctx.fillRect(x - 3, y - 3, 6, 6);
            ctx.fill();
            ctx.stroke();
        }
        ctx.restore();
    }
    
    //画点连线2;
    function drawCircleLines2(ctx: CanvasRenderingContext2D) {
        ctx.save();
        ctx.beginPath();
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + (mRadius * Math.cos(mAngle * i) * selfScoreData[i][1]) / multiple;
            var y = yCenter + (mRadius * Math.sin(mAngle * i) * selfScoreData[i][1]) / multiple;
            ctx.lineTo(x, y);
        }
        ctx.closePath();
        ctx.strokeStyle = 'rgba(244, 112, 112, 0.8)';
        ctx.stroke();
        ctx.restore();
    }
    
    //画点数据;
    function drawCircleData2(ctx: CanvasRenderingContext2D) {
        ctx.save();
        var fontSize = 16;
        ctx.font = fontSize + 'px Microsoft Yahei';
        ctx.fillStyle = 'rgba(244, 112, 112, 0.8)';
        for (var i = 0; i < mCount; i++) {
            var x = xCenter + (mRadius * Math.cos(mAngle * i) * selfScoreData[i][1]) / multiple;
            var y = yCenter + (mRadius * Math.sin(mAngle * i) * selfScoreData[i][1]) / multiple;
            if (mAngle * i >= 0 && mAngle * i <= Math.PI / 2) {
                ctx.fillText(selfScoreData[i][1], x - 25, y + fontSize - 10);
            } else if (mAngle * i > Math.PI / 2 && mAngle * i <= Math.PI) {
                ctx.fillText(selfScoreData[i][1], x - ctx.measureText(selfScoreData[i][1]).width + 25, y + fontSize - 10);
            } else if (mAngle * i > Math.PI && mAngle * i <= (Math.PI * 3) / 2) {
                ctx.fillText(selfScoreData[i][1], x - ctx.measureText(selfScoreData[i][1]).width + 25, y + 10);
            } else {
                ctx.fillText(selfScoreData[i][1], x - 25, y + 10);
            }
        }
        ctx.restore();
    }
})
</script>