Canvas统计图表(多边形,蜘蛛网,渐变色)

    let c = document.getElementById("myc");
    let ctx = c.getContext("2d");

    // 随机值记录
    let randomRes = [0, 0, 0, 0, 0, 0];
    //const randomRes = [3, 0, 0, 0, 0, 0];
    // 颜色值
    let COLOR_INIT = "#737373";
    // 单个梯形高度
    let onceHeight = 30;

    // 声明画布大小,及窗口文档的显示区的高度和宽度,以像素记
    c.width = 600;
    c.height = 600;
    // 将坐标原点移至画布中心
    ctx.translate(c.width/2,c.height/2);
    // r多边形半径,n多边形个数,deg:多边形与夹角的度数,layerCount:多边形层数
    let r=onceHeight, n=6, deg=360/n, layerCount=4;
    // 初始坐标点
    let prevPoint = {x: 0, y: r};
    // 初始渐变色层级点
    let prevLinearPoint = {x: 0, y: 0};
    // 渐变色坐标点记录
    let linearPointArray = [];
    // 指数结果坐标点记录
    let randomResPoint = [];
    // 上一个结果组
    let prevRandomRes = [];
    
    var mmm = ["CB2329", "1853B7", "C3253A", "7C0A20"];
    var mmmmm = 0;
    setInterval(() => {
        mmmmm === mmm.length && (mmmmm = 0);
        console.log(mmm[mmmmm++])
        setResult([getRandom(), getRandom(), getRandom(), getRandom(), getRandom(), getRandom()], ["粒子1", "粒子2", "粒子3", "粒子4", "粒子5", "粒子6"], mmm[mmmmm++]);
    }, 1500)
    

    /**
     * 设置结果
     * @param(randomResArr) array[int] 比例值 0-4
     * @param(textArr) array[string] 文字说明
     * @param(colorHex) string Hex基准颜色
     */
    function setResult(randomResArr, textArr, colorHex) {
        COLOR_INIT = colorHex;
        prevRandomRes = randomRes;
        randomRes = randomResArr;
        var timer = setInterval(() => {
            drawStatistics(textArr);
            console.log("run");
        }, 16);
        // 偷个懒
        setTimeout(() => {
            clearInterval(timer);
        }, 600);
    }

    function drawBg (textArr) {
        r = onceHeight;
        prevPoint = {x: 0, y: r};
        prevLinearPoint = {x: 0, y: 0};
        linearPointArray = [];
        randomResPoint = []; // 指数坐标点记录
        // 多边形线的颜色
        ctx.strokeStyle="#fff";
        // 多边形线的宽度
        ctx.lineWidth=1;
        ctx.globalAlpha = 1;
        ctx.globalCompositeOperation="destination-over";

        // 绘制多个线段
        for(let j=0;j<=layerCount;j++){
            // 恢复初始坐标点
            prevPoint = {x: 0, y: r};
            // 临时坐标变量
            let temporary = {};

            for(let i=1;i<=n;i++){
                let currentLinearPoint = {x: angleDistance(r)*Math.sin(getrad((i*2-1)*(deg/2))), y: angleDistance(r)*Math.cos((i*2-1)*getrad(deg/2))};
                let prevPointTemporary = {x: prevPoint.x, y: prevPoint.y};
                let grd = null;
                
                try {
                    grd = ctx.createLinearGradient(linearPointArray[j-1][i-1].x, linearPointArray[j-1][i-1].y, currentLinearPoint.x, currentLinearPoint.y);
                } catch (err) {
                    grd = ctx.createLinearGradient(0, 0, currentLinearPoint.x, currentLinearPoint.y);
                }

                linearPointArray[j] ? linearPointArray[j].push({x: currentLinearPoint.x, y: currentLinearPoint.y}) : linearPointArray[j] = [{x: currentLinearPoint.x, y: currentLinearPoint.y}];
                
                grd.addColorStop(0, getLightColor(COLOR_INIT, 0.6));
                grd.addColorStop(1, getLightColor(COLOR_INIT, 0.9));
                ctx.fillStyle = grd;
                // 开始路径
                ctx.beginPath();
                ctx.moveTo(0,0);
                ctx.lineTo(prevPoint.x, prevPoint.y);
                prevPoint = {x: r*Math.sin(getrad(i*deg)), y: r*Math.cos(i*getrad(deg))};
                ctx.lineTo(prevPoint.x, prevPoint.y);
                // 结束路径
                ctx.closePath();
                // 绘制线段
                ctx.stroke();
                // 填充
                ctx.fill();

                switch (i) {
                    case 1:
                        if (j === randomRes[0]) {
                            temporary = {index: 1, x: prevPoint.x, y: prevPoint.y};
                            randomResPoint.push(temporary);
                        }
                        if (j === 4) {
                            ctx.beginPath();
                            ctx.fillStyle = "#333";
                            ctx.textBaseline = "top";
                            ctx.textAlign = "center";
                            ctx.fillText(textArr[0], prevPointTemporary.x, prevPointTemporary.y);
                            ctx.closePath();
                        }
                    break;
                    case 2:
                        if (j === randomRes[1]) {
                            temporary = {index: 2, x: prevPoint.x, y: prevPoint.y};
                            randomResPoint.push(temporary);
                        }
                        if (j === 4) {
                            ctx.beginPath();
                            ctx.fillStyle = "#333";
                            ctx.textBaseline = "middle";
                            ctx.textAlign = "left";
                            ctx.fillText(textArr[1], prevPointTemporary.x, prevPointTemporary.y);
                            ctx.closePath();
                        }
                    break;
                    case 3:
                        if (j === randomRes[2]) {
                            temporary = {index: 3, x: prevPoint.x, y: prevPoint.y};
                            randomResPoint.push(temporary);
                        }
                        if (j === 4) {
                            ctx.beginPath();
                            ctx.fillStyle = "#333";
                            ctx.textBaseline = "middle";
                            ctx.textAlign = "left";
                            ctx.fillText(textArr[2], prevPointTemporary.x, prevPointTemporary.y);
                            ctx.closePath();
                        }
                    break;
                    case 4:
                        if (j === randomRes[3]) {
                            temporary = {index: 4, x: prevPoint.x, y: prevPoint.y};
                            randomResPoint.push(temporary);
                        }
                        if (j === 4) {
                            ctx.beginPath();
                            ctx.fillStyle = "#333";
                            ctx.textBaseline = "bottom";
                            ctx.textAlign = "center";
                            ctx.fillText(textArr[3], prevPointTemporary.x, prevPointTemporary.y);
                            ctx.closePath();
                        }
                    break;
                    case 5:
                        if (j === randomRes[4]) {
                            temporary = {index: 5, x: prevPoint.x, y: prevPoint.y};
                            randomResPoint.push(temporary);
                        }
                        if (j === 4) {
                            ctx.beginPath();
                            ctx.fillStyle = "#333";
                            ctx.textBaseline = "middle";
                            ctx.textAlign = "right";
                            ctx.fillText(textArr[4], prevPointTemporary.x, prevPointTemporary.y);
                            ctx.closePath();
                        }
                    break;
                    case 6:
                        if (j === randomRes[5]) {
                            temporary = {index: 6, x: prevPoint.x, y: prevPoint.y};
                            randomResPoint.push(temporary);
                        }
                        if (j === 4) {
                            ctx.beginPath();
                            ctx.fillStyle = "#333";
                            ctx.textBaseline = "middle";
                            ctx.textAlign = "right";
                            ctx.fillText(textArr[5], prevPointTemporary.x, prevPointTemporary.y);
                            ctx.closePath();
                        }
                    break;
                    default :
                }
            }
            // 递增层级半径
            r += onceHeight;
        }
    }

    function drawStatistics(textArr) {
        ctx.clearRect(-c.width / 2, -c.height / 2, c.width * 2, c.height * 2); // 清除画布

        // 画背景
        drawBg (textArr);
        // 画结果图
        let grdRadial=ctx.createRadialGradient(0,0,0,0,0,r);
        grdRadial.addColorStop(0,getLightColor(COLOR_INIT, 0.6));
        grdRadial.addColorStop(1,getDarkColor(COLOR_INIT, 0.3));
        // ctx.translate(c.width/2,c.height/2);
        ctx.globalCompositeOperation="source-over";
        ctx.lineWidth=2;
        ctx.strokeStyle=getLightColor(COLOR_INIT, 0.5);
        ctx.beginPath();
        ctx.fillStyle = grdRadial;
        ctx.globalAlpha = 0.8;
        let result = randomResPoint.sort((a, b) => (a.index - b.index));


        for(let randomIdx=0; randomIdx<result.length; randomIdx++) {
            let currentIncremnet = 0;
            if (prevRandomRes.length) {
                prevRandomRes[randomIdx] += (randomRes[randomIdx] - prevRandomRes[randomIdx]) / 10;
            }

            randomIdx === 0 ? ctx.moveTo(
                prevRandomRes.length ? 0 : result[randomIdx].x,
                prevRandomRes.length ? (prevRandomRes[randomIdx]+1)*onceHeight : result[0].y
            ) : ctx.lineTo(
                prevRandomRes.length ? ((prevRandomRes[randomIdx]+1)*onceHeight)*Math.sin(getrad(randomIdx*deg)) : result[randomIdx].x,
                prevRandomRes.length ? ((prevRandomRes[randomIdx]+1)*onceHeight)*Math.cos(randomIdx*getrad(deg)) : result[randomIdx].y
            );
            
        }
        ctx.closePath();
        ctx.stroke();
        ctx.fill();
    }

    console.log("randomRes", randomRes);
    console.log(randomResPoint);

    // 封装求弧度的方法 度->弧度
    function getrad(deg){
        return deg/180*Math.PI;
    }
    // 封装计算渐变色倾斜角度
    function angleDistance(rAngle) {
        return rAngle*Math.cos(getrad(deg/2));
    }
    // 获取随机指数
    function getRandom() {
        return Math.floor(Math.random() * 5)
    }

    // hex颜色转rgb颜色
    function HexToRgb (str) {
        var r = /^\#?[0-9A-F]{6}$/;
        // test方法检查在字符串中是否存在一个模式,如果存在则返回true,否则返回false
        if (!r.test(str)) return window.alert("输入错误的hex");
        // replace替换查找的到的字符串
        str = str.replace("#", "");
        // match得到查询数组
        var hxs = str.match(/../g);
        // alert('bf:'+hxs)
        for (var i = 0; i < 3; i++) hxs[i] = parseInt(hxs[i], 16);
        // alert(parseInt(80, 16))
        // console.log(hxs);
        return hxs;
    }
    // GRB颜色转Hex颜色
    function RgbToHex (a, b, c) {
        var r = /^\d{1,3}$/;
        if (!r.test(a) || !r.test(b) || !r.test(c)) return window.alert("输入错误的rgb颜色值");
        var hexs = [a.toString(16), b.toString(16), c.toString(16)];
        for (var i = 0; i < 3; i++) if (hexs[i].length == 1) hexs[i] = "0" + hexs[i];
        return "#" + hexs.join("");
    }

    // 得到hex颜色值为color的加深颜色值,level为加深的程度,限0-1之间
    function getDarkColor(color, level) {
        var r = /^\#?[0-9A-F]{6}$/;
        if (!r.test(color)) return window.alert("输入错误的hex颜色值");
        var rgbc = this.HexToRgb(color);
        // floor 向下取整
        for (var i = 0; i < 3; i++) rgbc[i] = Math.floor(rgbc[i] * (1 - level));
        return this.RgbToHex(rgbc[0], rgbc[1], rgbc[2]);
    }
    // 得到hex颜色值为color的减淡颜色值,level为加深的程度,限0-1之间
    function getLightColor(color, level) {
        var r = /^\#?[0-9A-F]{6}$/;
        if (!r.test(color)) return window.alert("输入错误的hex颜色值");
        var rgbc = this.HexToRgb(color);
        for (var i = 0; i < 3; i++) rgbc[i] = Math.floor((255 - rgbc[i]) * level + rgbc[i]);
        return this.RgbToHex(rgbc[0], rgbc[1], rgbc[2]);
    }

 

posted @ 2021-04-09 19:23  universe-cosmo  阅读(365)  评论(0编辑  收藏  举报