canvas学习--曲线图形

439 阅读2分钟

圆形

在canvas中,我们使用arc()方法来画一个圆

语法:

  1. cxt.beginPath();
  2. cxt.arc(x,y,r,开始角度,结束角度,anticlockwise);
  3. cxt.closePath();

image.png

其中x和y代表圆心坐标,r为半径;开始角度和结束角度都以“弧度”为单位,例如180°应该写成Math.PI;anticlockwise是一个布尔值,当为true时,逆时针方向绘制,默认值为false,顺时针方向绘制。

学习完绘制完圆之后,可以尝试canvas中最常见的图形操作:描边(stroke)和填充(fill)

语法:

  1. cxt.strokeStyle = "属性值";

  2. cxt.stroke();

  3. cxt.fillStyle = "属性值";

  4. cxt.fill();

预备代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id = "canvas" width = "300" height = "300" style = "border: 1px dashed gray;"></canvas>
</body>

<script>
    window.onload = function() {
        //写逻辑
    }
</script>
</html>

效果图为:

image.png

let canvas = document.getElementById('canvas');
let cxt = canvas.getContext('2d');

cxt.beginPath();
cxt.arc(100,100,100,0,90 * Math.PI / 180);
cxt.closePath();

cxt.lineWidth = 5;
cxt.strokeStyle = "yellow";
cxt.stroke();

cxt.fillStyle = "black";
cxt.fill();

效果图为:

image.png

弧线

在canvas中,如果想画弧线,常见的方法有两种:arc()、arcTo()

语法:

  1. cxt.beginPath();
  2. cxt.arc(x,y,r,开始角度,结束角度,anticlockwise);
  3. cxt.strokeStyle = "属性值";
  4. cxt.stroke();

必须要注意的是,“使用arc()方法绘制圆”,需要closePath()来关闭路径,而“使用arc()方法画弧线”不需要,原因是弧线不是闭合图形

同时,stroke()和fill()这两个方法只能用来绘制当前路径,不能同时绘制多个路径

let canvas = document.getElementById('canvas');
let cxt = canvas.getContext('2d');

cxt.moveTo(0,100);
cxt.lineTo(100,100);
cxt.stroke();

cxt.beginPath();
cxt.moveTo(100,100);
cxt.arc(100,100,100,0,90 * Math.PI / 180);
cxt.closePath();

cxt.strokeStyle = "yellow";
cxt.stroke();

效果图为:

image.png

如果删除了第一个cxt.stroke(),预览效果如下所示:

image.png

语法:

  1. cxt.arcTo(x1,y1,x2,y2,r);

(x1,y1)表示控制点的坐标,(x2,y2)表示结束点的坐标,r表示圆弧的半径,借用一张网上的图片

image.png

练习:绘制扇形

昨天晚上准备更这一期学习内容的时候,准备做一下扇形,当时想到了之前校企实训用的echarts的饼状图,就想着自己也尝试输入数据,然后就可以生成一个扇形统计图,花了几个小时,最终也是简单实现了一些功能。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <canvas id = "canvas" width = "300" height = "300" style = "border: 1px dashed gray;"></canvas>
</body>

<script>
    window.onload = function() {
        //写逻辑
        let canvas = document.getElementById('canvas');
        let cxt = canvas.getContext('2d');

        let arr = [
            {name:'苹果',amount:2},
            {name:'柿子',amount:2},
            {name:'橘子',amount:2},
            // {name:'柚子',amount:4},
        ];
        let colorArr = createColor(arr.length);  // 随机颜色合集
        let array = [0 * Math.PI / 180];   // 角度合集
        let angle;  // 鼠标点的位置的夹角
        let line1; 

        function createPie(x,y,r,arr){   
            let sum = 0;
            let h = 20;
            let hrect = 12;
            for(let i = 0;i < arr.length;i++){
                let obj = arr[i];
                sum += obj.amount;
            }

            for(let i = 0;i < arr.length;i++){  // 判断弧度
                let obj = arr[i];
                let number = (obj.amount / sum) * Math.PI * 2 + array[i];
                array.push(number);
            }

            console.log(array);

            for(let i = 0;i < array.length - 1;i++){   // 绘制扇形

                cxt.beginPath();
                cxt.moveTo(x,y);
                cxt.arc(x,y,r,array[i],array[i+1] );
                cxt.closePath();
                
                cxt.fillStyle = colorArr[i];
                cxt.fill(); 

            }

            for(let i = 0;i < arr.length;i++){    // 数据列表
                let obj = arr[i];

                cxt.fillStyle = colorArr[i];
                cxt.fillRect(canvas.width / 1.5, hrect , 40 , 10);

                let text = `${obj.name}${obj.amount}`;
                cxt.font = "bold 10px 楷体";
                cxt.fillStyle = colorArr[i];
                cxt.fillText(text,canvas.width / 1.5 + 50, h);

                h += 20;
                hrect += 20;
            }

        }

        createPie(canvas.width / 3 , canvas.height / 2 , 80 , arr);

        canvas.onclick = function(e){    // 点击饼状图局部放大(没有实现再次点击变回原来的样式)
            //console.log(e.offsetX,e.offsetY);
            let clickX = e.offsetX;
            let clickY = e.offsetY;

            let x = canvas.width / 3;
            let y = canvas.height / 2;
            let r = 80;

            let calx = clickX;
            let caly = y;

            line1 = getDistance(clickX,clickY,x,y);   // 斜边
            let line2 = getDistance(clickX,clickY,calx,caly);
            let line3 = getDistance(x,y,calx,caly); 

            angle = Math.acos((Math.pow(line1,2) + Math.pow(line3,2) - Math.pow(line2,2)) / (2 * line1 * line3));

            console.log(angle);

            if(clickX > x && clickY > y){
                // 在第一象限
                
            }
            else if(clickX < x && clickY > y){
                // 在第二象限
                angle = Math.PI - angle ;
            }
            else if(clickX < x && clickY < y){
                // 在第三象限
                angle += Math.PI;
            }
            else {
                // 在第四象限
                angle = Math.PI * 2 - angle;
            }

            for(let i = 0;i < array.length;i++){
                if(angle > array[i] && angle < array[i+1] && line1 <= r){
                    console.log(colorArr[i]);
                    cxt.beginPath();
                    cxt.moveTo(x,y);
                    cxt.arc(x,y,r+20,array[i],array[i+1] );
                    cxt.closePath();
                    
                    cxt.fillStyle = colorArr[i];
                    cxt.fill();
                }
            }
            
        }


        function getDistance(x1,y1,x2,y2){
            return Math.sqrt(Math.pow(x1-x2,2) + Math.pow(y1-y2,2));
        }

        function createColor(len){    // 随机生成颜色列表
            let arr = [];

            while(arr.length < len){
                let r = Math.floor(Math.random() * 255);
                let g = Math.floor(Math.random() * 255);
                let b = Math.floor(Math.random() * 255);
                arr.push(`rgb(${r}, ${g}, ${b})`);
            }

            return [...new Set(arr)];
        }

    }

    
</script>
</html>

效果图为:

pie2.gif

封面制作网站 ColorFu
gif制作软件ScreenToGif - Record your screen, edit and save as a gif, video or other formats

文章内容参考莫振杰 著《HTML5 CANVAS开发详解》,感兴趣的同学可以阅读一下这本书,如有错误,欢迎指正!!