canvas

544 阅读1分钟

最近和canvas 杠上了,写一个总结。

需求: 1、画圆:单纯 点击画固定大小的圆, 鼠标按下a 并且 滑动 鼠标松开b 画 半径 不固定的圆(半径 根据 a b 间距确定 , a 为圆心)。

canvas 属性

通过 attr 设置 width, height, 不推荐style/css 设置 width, height 标签中间可以添写 当浏览器不支持 canvas 时显示的内容; 不能写成

<canvas id="can" width="800px" height="1000px" ></<canvas>

要在画布上操作需要先获取画布的 上下文 ,可通过 getContext 获取;

画圆

image.png

定义圈的结构

{
    x:1, // x轴坐标
    y:1, // y轴坐标
    r:20, // 半径
    fontPos: { // 下标的坐标
        x: 1,
        y:2
    }
}

通过 监听鼠标事件 来判断是否是点击,完整代码如下

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="./jquery-1.9.0.min.js" ></script>
</head>
<body>
    <div id="box" style="width: 500px;height: 500px;margin: 0 auto;">
        <canvas id="can" width="800px" height="1000px" style="border: 1px solid black;">
    
        </canvas>
    </div>
    <div>
    <input id="num" />
    <button id="btn" οnclick="del()">删除</button>

    </div>
</body>
<script type="text/javascript" >
    

    var canvas_w = 800;
    var canvas_h = 1000;
    var list = [];
    var index = 1;
    var can = document.getElementById('can');
    var ctx = can.getContext("2d");
    //鼠标点击生成圆
    var radius = 40;
    
    
    function mouseCoords(ev){
        var e = event || window.event;
        var x = e.offsetX || e.layerX;
        var y = e.offsetY || e.layerY;
        return {x,y};
    }
    //生成圆
    function makearc(x,y,r,color){
        ctx.beginPath();
        ctx.lineWidth = "2"
        ctx.strokeStyle='red';
        ctx.arc(x,y,r,0,180); // 圆心位置: x,y ; 圆半径:r;  起始角:s;  结束角:e; 
        ctx.stroke();
    }

    function getFontPos(x, y, r) {
        return {x: x + r, y: y + r}
    }

    function drawFont(x, y, num, color) {
        ctx.font = "16px serif";
        ctx.fillStyle = color;
        ctx.fillText(num, x, y);
    }
    function isPointInRetc(x,y){
        let len=layers.length;
        for(let i=0;i<len;i++){
            if(layers[i].x1<x&&x<layers[i].x2&&layers[i].y1<y&&y<layers[i].y2){
                return layers[i];
            }
        }
    }

    $('#btn').click(function(){
        del();
    })
    function del() {
        var num = document.getElementById('num').value;
        if(!+num) {
            return;
        }
       
        var index  = list.findIndex(val=> val.idx === +num);
        if(index === -1) {
            return;
        }
        list.splice(index, 1);
        
        reDraw();
        
    }

    function reDraw () {
        ctx.clearRect( 0, 0, 800, 1000 );  //清除画布
        list.forEach((item)=>{
         makearc(item.x,item.y, item.radius,'red');
         drawFont(item.fontPos.x, item.fontPos.y, item.idx, 'red')
        })
    }
    var isMove = false;
    can.onmousedown = function(oEvent) {
        origin = mouseCoords(oEvent);
        isClick = true;
        isMove = false;
    };
    var movePoint = {x: 0, y : 0, r: 0}, isClick = false, origin;

    offset = getOffset(can);
    function getOffset(obj) {
        var x = 0,
          y = 0;
        do {
          x += obj.offsetLeft;
          y += obj.offsetTop;
          obj = obj.offsetParent;
        } while (obj);
        return  Point(x, y);
      }
    function Point(x, y) {
        return  {x:  x || 0, y: y|| 0}
      }
    document.onmousemove = function(oEvent) {
        if (!isClick) {
            return;
        }
        oEvent = oEvent || event;
        pt = Point(oEvent.clientX - offset.x, oEvent.clientY - offset.y);
        r = Math.sqrt(
            (pt.x - origin.x) * (pt.x - origin.x) +
            (pt.y - origin.y) * (pt.y - origin.y)
        );
        if (!posIslegal({ x: origin.x,
            y: origin.y,}, r)) {
                console.log('超出边界了');
            return;
        }
        movePoint = {
            x: origin.x,
            y: origin.y,
            r
        }
        reDraw();
        makearc(origin.x, origin.y, r, "green");
        isMove = true;
    };
       


    document.onmouseup = function(oEvent) {
        isClick = false;
        var mousePos = mouseCoords(oEvent);
        if (mousePos.x === origin.x && mousePos.y === origin.y && !isMove) {
            handleClick(mousePos)
            return;
        }
        
       if(movePoint && isMove) {
        var fontPos = getFontPos(movePoint.x, movePoint.y, movePoint.r);
        var idx = index ++;
        list.push({
            x: movePoint.x,
            y: movePoint.y,
            radius: movePoint.r,
            idx,
            fontPos
        })
        reDraw();
        isMove = false;
       }
    };
    
    function handleClick (mousePos) {
        if(!posIslegal(mousePos, radius)) {
            console.log('圆的位置超出边界!');
            return;
        }
        mousePosX = mousePos.x;
        mousePosY = mousePos.y;
        var fontPos = getFontPos(mousePosX, mousePosY, radius);
        var idx = index ++;
        list.push({
            x: mousePosX,
            y: mousePosY,
            radius,
            idx,
            fontPos
        })
        makearc(mousePosX,mousePosY, radius,'red');
        drawFont(fontPos.x, fontPos.y, idx, 'red')
    }

    function  posIslegal(pos, r) {
        const x = pos.x + r;
        const y = pos.y + r;
        const left_x = pos.x - r;
        const left_y = pos.y - r;
        console.log('-----', left_x, left_y); // || left_x < canvas_w || left_y < canvas_h
        if(x > canvas_w || y > canvas_h || left_x < 0 || left_y < 0 ) {
            return false;
        }
        return true;
    }

    </script>
</html>

阅览

画每个圆的时间控制在1s, 可使用 setInterval来控制 采取画圆弧的策略; 记录当前的圆的下标 和 当前 圆弧的长度/百分数;

完整代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="./jquery-1.9.0.min.js" ></script>
</head>
<style>
    #yuan {
        border: 1px solid;
    }
   
    .show {
        display: inline-block;
    }
    .hide {
        display: none;
    }
    
    .zebra {
        width: 700px;
        height: 700px;
        border: 1px solid red;
        position: relative;
    }

    
      
</style>

<body>
    <p>input:<input onclick="circleProgress()" value="画圆" type="button"></p>
    <div>
    <canvas id="yuan" width="500" height="800"></canvas>
    </div>

   
</body>
<script type="text/javascript" >
    var timer=null, n = 0;
    var canvas = document.getElementById("yuan");
    var context = canvas.getContext('2d');
    var _this = $(canvas),
    maxpercent = 100,//最大百分比,可设置
    c_width = _this.width(),// canvas,宽度
    c_height =_this.height();// canvas,高度


    list = [{
        x: 100,
        y: 50,
        r: 20,
    }, {
        x: 76,
        y: 177,
        r: 20,
    },
    {
        x: 400,
        y: 280,
        r: 30,
    }, {
        x: 200,
        y: 397,
        r: 40,
    },{
        x: 388,
        y: 140,
        r: 23,
    }, {
        x: 426,
        y: 547,
        r: 45,
    },
    ]
    
    function circleProgress(){
        
        if(timer) {
            clearInterval(timer);
        }
        n = 0;
        index = 0;
        loadCanvas(0);
       
        // 调用定时器实现动态效果
        
    }; 

    var index = 0, len = list.length; 
    function loadCanvas(nowT){
        timer = setInterval(function(){
            console.log('----', n, index);
            if(index === (len - 1) && n > 100) {
                clearInterval(timer);
                return;
            }
            if(n > 100){
                // clearInterval(timer);
                // return;
                index++;
                n = 0;
            }
            draw(n / 100);
            n += 1;
            
        },10); // 1000 一秒  
    }
    function draw(cur){
        context.strokeStyle = "#27b5ff";
        context.lineWidth = 2.0;
        context.clearRect(0, 0, c_width, c_height);
    
        for(let i = 0; i < index; i++) {
            context.beginPath();
            const c = list[i];
            context.arc(c.x, c.y, c.r, 0, 180, false);
            context.stroke()
        }
        context.beginPath();
        const curC = list[index];
        // 绘制一个中心点为(c_width/2, c_height/2),半径为c_height/2-5不与外圆重叠,
        // 起始点-(Math.PI/2),终止点为((Math.PI*2)*cur)-Math.PI/2的 整圆cur为每一次绘制的距离
        context.arc(curC.x, curC.y, curC.r, -(Math.PI / 2), ((Math.PI * 2) * cur ) - Math.PI / 2, false);
        context.stroke();
    }
    

    </script>
</html>

image.png

点击画圆,会在画布上顺序画圆;