绘制弧线

603 阅读2分钟

绘制弧线

1.arc(x,y,r,sAngle,eAngle,counterclockwise)

创建弧/曲线(用于创建圆形或部分圆)

image.png

弧度换算为度:1°= Math.PI / 180;

454586607B3A4F6EEB607C698092AC7A.png

2.arcTo(x1,y1,x2,y2,r)

创建两切线之间的弧/曲线

x1:弧的起点的 x 坐标

y1:弧的起点的 y 坐标

x2:弧的终点的 x 坐标

y2:弧的终点的 y 坐标

r:弧的半径

arcTo()方法将利用当前端点、端点1(x1,y1)和端点2(x2,y2)这三个点所形成的夹角,然后绘制一段与夹角的两边相切并且半径为radius的圆上的弧线。弧线的起点就是当前端点所在边与圆的切点,弧线的终点就是端点2(x2,y2)所在边与圆的切点,并且绘制的弧线是两个切点之间长度最短的那个圆弧

起始点(50,50)就是当前端点,所以arcTo()将会利用起始点(50,50)、端点1(200,50)、端点2(200,100)所形成的夹角,然后绘制一段与夹角两边相切的圆弧。


<script>
    let canvas = document.getElementById("myCanvas");
    let ctx = canvas.getContext("2d");   
    //指定绘制路径的起始点
    ctx.moveTo(50, 50); 
    //此时,坐标点(50,50)就是绘制弧线时的当前端点
    
    //端点1
    let p1 = {
        x : 200,
        y : 50
    };
    
    //端点2
    let p2 = {
        x : 200,
        y : 100         
    };
    
    //绘制与当前端点、端点1、端点2三个点所形成的夹角的两边相切并且半径为50px的圆的一段弧线
    ctx.arcTo(p1.x, p1.y, p2.x, p2.y, 50);
    
    //设置线条颜色为蓝色
    ctx.strokeStyle = "blue";
    
    //按照上述绘制路径绘制弧线
    ctx.stroke();
}
</script>

E2173DDCC43EE7E33115A66A7F855EE1.png

绘制时钟

表盘的秒针刻度线原理,绘制时针和分针时同理,但是分针会随着秒针动而动分针走过的角度应该是几分钟后基于这几分钟内秒针走过的总角度和(1秒时秒针走6度,1秒时分针走1/10度,1分钟分针走1乘以60乘以1/10度,依次类推),时针同理(1分时分针走6度,1分时时针走1/2度,1小时时针走1乘以60乘以1/2度,依次类推),时针随着分针动而动:

FFCB9760D347D16FAEFDF7FFCF751E0D.png

<body>
    <canvas class="can" width="1000px" height="1000px">
        浏览器版本太低无法识别,请升级浏览器或更换浏览器。
    </canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        let can = document.querySelector(".can");
        let ctx = can.getContext("2d");
        //挂钟
        function biaopan() {
            //画圆
            //1°的单位
            let deg = Math.PI / 180;
            let r = 200;
            let x = 300;
            let y = 300;
            ctx.arc(x, y, r, 0, 360 * deg);
            //360°/60秒=1秒钟占用6°:60秒占用1圈就是360°
            //表盘的秒针刻度线:将上下两点连接
            let startdeg = 6;//1秒钟就是6°,初始角度
            //表盘的刻度线在每5秒钟后会变长一些
            for (let i = 0; i < 60; i++) {
                let kedu = 10;
                //余数为0时,就让刻度线边长,kedu变量就增大2倍,余数不为0,kedu变量就为10
                if (i % 5) {
                    kedu = kedu;
                } else {
                    kedu *= 2;
                }
                //下面的点
                let y1 = y + r * Math.sin(i * startdeg * deg);
                let x1 = x + r * Math.cos(i * startdeg * deg);
                // 上面的点
                let y2 = y + (r - kedu) * Math.sin(i * startdeg * deg);
                let x2 = x + (r - kedu) * Math.cos(i * startdeg * deg);
                ctx.moveTo(x1, y1);
                ctx.lineTo(x2, y2);
                let arr = [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2];
                let sdeg = 30;
                for (let j = 0; j < arr.length; j++) {
                    ctx.textAlign="center";
                    ctx.fillRect = "rgb(44,34,85)";
                    ctx.fillText(arr[j], x + (r + 20) * Math.cos(j * sdeg * deg), y + (r + 20) * Math.sin(j * sdeg * deg));
                };
                ctx.stroke();
                //分钟时针秒针交叉点
                ctx.beginPath();
                ctx.arc(x, y, 7, 0, 360 * deg);
                ctx.fillStyle = "gray";
                ctx.fill();
                ctx.stroke();
            };

        };
        function biaozhen() {
            let deg = Math.PI / 180;
            let r = 200;
            let x = 300;
            let y = 300;
            //表盘秒针
            let dt = new Date();
            let sec = dt.getSeconds();//得到当前时间的秒数返回0-59秒
            let min = dt.getMinutes();//得到当前时间的分钟数返回0-59分
            let hour = dt.getHours();//得到当前时间的小时数返回0-23时
            //秒针的长度,比表盘的半径小
            //表针1秒走6°,sec秒走sec*6度,0秒绘制是从3点钟方向开始绘制,需要减去90°
            let sh = 170;
            let start=6*deg;
            ctx.beginPath();
            ctx.lineWidth=3;
            ctx.strokeStyle = "blue";
            ctx.moveTo(x, y);
            let x1=x+sh*Math.cos(sec*start-90*deg);
            let y1=x+sh*Math.sin(sec*start-90*deg);
            ctx.lineTo(x1, y1);
            ctx.stroke();
            //分针60秒走6°,1秒走1/10度,min分后就是min*60秒,min分后走min*60*1/10度
            start=6/60*deg;
            let mh=150;
            ctx.beginPath();
            ctx.lineWidth=4;
            ctx.strokeStyle = "green";
            ctx.moveTo(x, y);
            let x2=x+mh*Math.cos(min*60*start-90*deg);
            let y2=y+mh*Math.sin(min*60*start-90*deg);
            ctx.lineTo(x2,y2);
            ctx.stroke();
            //时针1小时走30°,1分走1/2度,hour时后就是hour*60分,走的度数是hour*60*1/2
            start=1/2*deg;
            let hh=130;
            ctx.beginPath();
            ctx.lineWidth=5;
            ctx.strokeStyle = "yellow";
            ctx.moveTo(x, y);
            let x3=x+hh*Math.cos(hour*60*start-90*deg);
            let y3=y+hh*Math.sin(hour*60*start-90*deg);
            ctx.lineTo(x3,y3);
            ctx.stroke();
        };
        // //每隔1秒调用1次,就可以实现秒针1秒走1格刻度线
        setInterval(() => {
            //需要清除画布,避免之前画布上的线与后来绘制的线重叠
            can.width = can.width;
            biaopan();
            biaozhen();
        }, 1000);
    </script>
</body>

绘制饼状图

<body>
    <style>
        #canvas {
            border: 1px goldenrod solid;
        }
    </style>
    <canvas id="canvas" width="1000px" height="700px">
        浏览器版本太低无法访问,请更换浏览器
    </canvas>
    <script>
        /** @type {HTMLCanvasElement} */
        let data=[{
				name: "衣服",
				money: 8000
			}, {
				name: "car",
				money: 2000
			}, {
				name: "food",
				money: 7000
			}, {
				name: "cash",
				money: 1000
			},{
				name: "cash2",
				money: 5000
			},{
				name: "cash3",
				money: 5400
			}];
        let canvas=document.querySelector("#canvas");
        let ctx=canvas.getContext("2d");
        // 算总价
        let total=data.reduce((n1,n2)=>{
            return n1+n2.money;
        },0);
        //饼状图平分总价,根据单项的价格在饼状图中有不同的占比
        let deg=Math.PI/180;
        let startdeg=0;//起始角度
        //循环数组,有几个商品就画几条线
        data.forEach(el => {
            ctx.beginPath();
            let r=parseInt(Math.random()*255);
			let g=parseInt(Math.random()*255);
			let b=parseInt(Math.random()*255);
            //画圆,第1个商品起始角度为0,结束角度是商品单价除以总价的比例在乘以360°
            //此后商品的起始角度是上一个商品绘制的结束角度
            ctx.arc(300,300,200,startdeg*deg,((startdeg+el.money/total*360)*deg));
            ctx.lineTo(300,300);
            ctx.fillStyle=`rgb(${r},${g},${b})`;
            ctx.fill();
            ctx.strokeStyle="red";
            ctx.textAlign="center";
            ctx.strokeText(el.name,300+230*Math.cos((((startdeg+el.money/total*360)*deg)-startdeg*deg)/2+startdeg*deg),300+230*Math.sin((((startdeg+el.money/total*360)*deg)-startdeg*deg)/2+startdeg*deg));
            ctx.stroke();
            ctx.beginPath();
            ctx.fillStyle="brown";
            ctx.textAlign="center";
            ctx.fillText(el.money,300+180*Math.cos((((startdeg+el.money/total*360)*deg)-startdeg*deg)/2+startdeg*deg),300+180*Math.sin((((startdeg+el.money/total*360)*deg)-startdeg*deg)/2+startdeg*deg));
            ctx.stroke();
            startdeg=startdeg+el.money/total*360;
        });

    </script>
</body>

image.png

6893FCAF786AAF580568FC7F84961AA8.png