(html)canvas制作画板

<html>
<head>
    <title></title>
<style>
    button.active{
        color: #fff;
        background-color: blue;
    }

    #canv{
     width: 800px; 
     height: 600px;
     border: 1px solid black;
    }
</style>
<script>

</script>
</head>
<body>

<div style="text-align:center;">
    <canvas id="canv" width="800px" height="600px"></canvas>
</div>

<!-- 显示画布上鼠标所在坐标 -->
<div class="canvasShowPosition">

</div>

<hr>

<input type="file" id="fileInput" name="file" />
<hr>



<button id="rectBtn" class="btn rectBtn" type="button">矩形</button>
<button id="circleBtn" class="btn circleBtn" type="button"></button>

<button id="saveBtn" class="btn saveBtn" type="button">保存</button>
<input id="color" type="color"></input>
<button id="clearCanvasBtn" class="btn clearCanvasBtn" >清空画布</button>
<button id="AlgoProcessBtn" class="btn AlgoProcessBtn" >前处理</button>

<hr>


</body>

<script>
    /*
    1.图像按原图比例在画布上显示
    
    2.获取画布对应画出的区域的坐标
    
    3.能将坐标上的图像抠出来
    ctx.getImageData(0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);
    4.画笔改成多边形
    
    5.保存txt标签数据到本地
    
    6.元素拖拽
    */
    
    // 1.获取canvas画布和绘制对象
    const mycanvas = document.querySelector('#canv')
    const ctx = mycanvas.getContext('2d');
    

    // 矩形框按钮
    let rectBtn = document.querySelector('#rectBtn')
    // 圆按钮
    let circleBtn = document.querySelector('#circleBtn')
    // 颜色
    let inputColor = document.querySelector('#color')
    // 保存
    let saveBtn = document.querySelector('#saveBtn')
    // 清空画布
    let clearCanvasBtn = document.querySelector('#clearCanvasBtn')
    // 上传图像
    let inputElement = document.getElementById('fileInput');
    // 显示图像
    let img = new Image();

    const canvasShowPosition = document.querySelector(".canvasShowPosition")
    
    // 所有绘制对象列表
    const allDrawedObjs = []

    const statusConfig = {
        IDLE:0,
        DRAG_START:1,
        DRAGGING:2,
    }
    
    // 所有网页上的按钮document.getElementsByTagName("input")
    let btn = document.querySelectorAll('.btn');
    // 画板字典变量
    let draw_board = {
          // 拖拽属性
          status:statusConfig.IDLE,
          dragTarget :null, // 拖拽对象
          lastEvtPos:{x:null,y:null}, // 最后移动坐标
          drawedPosData:{}, // 绘制对象坐标


          // 绘制对象
          type: "null",   // 绘制类型,是矩形,圆,还是线
          isDraw: false,  // 是否绘制标志符
          beginX: 0,     // 鼠标在canvas画布上按下的x坐标
          beginY: 0,     // 鼠标在canvas画布上按下的y坐标
          dataPx: 0,     // 画板上一次绘画结束后的图像数据
          lineWidth: 2,   // 初始化线条的长度
          color: null,   // 默认颜色黑色
          

    
          // 画矩形
          rectFn: function(e) {
                let x = e.pageX - mycanvas.offsetLeft;
                let y = e.pageY - mycanvas.offsetTop;
                ctx.beginPath();
                ctx.strokeStyle = draw_board.color;
                ctx.clearRect(0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);  //由于画笔是用一个个小圆构成的,所以每次都要清除画板数据,不然会导致线条的成型
                // 绘制图像
                drawImg()
                if(draw_board.dataPx != 0) {
                ctx.putImageData(draw_board.dataPx,0,0,0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);  //保留画板数据
                }
                ctx.lineWidth = draw_board.lineWidth;
                ctx.strokeRect(draw_board.beginX,draw_board.beginY,x-draw_board.beginX,y-draw_board.beginY);
                ctx.closePath(); 
                
                // 获取当前绘制矩形对象坐标
                draw_board.drawedPosData['centerX'] = draw_board.beginX + ( x - draw_board.beginX)/2
                draw_board.drawedPosData['centerY'] = draw_board.beginY + ( y - draw_board.beginY)/2
                draw_board.drawedPosData['w'] = x - draw_board.beginX
                draw_board.drawedPosData['h'] = y - draw_board.beginY

            },
    
          // 画圆(鼠标移动中)
          circleFn: function(e) {
                // 获取当前点坐标
                let x = e.pageX - mycanvas.offsetLeft;
                let y = e.pageY - mycanvas.offsetTop;
                // 开始绘制
                ctx.beginPath();
                // 线宽
                ctx.lineWidth = draw_board.lineWidth;
                // 绘制颜色
                ctx.strokeStyle = draw_board.color;
                // 清除
                ctx.clearRect(0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);
                // 绘制图像
                drawImg()
                //  x y r 圆(0-2pi)
                ctx.arc(draw_board.beginX,draw_board.beginY,Math.abs(y-draw_board.beginY),0,2*Math.PI);
                // 如果画板当前数据不为0,则放置当前画板数据(就是把上一次绘制完的画布再画一遍)
                if(draw_board.dataPx != 0) {
                    ctx.putImageData(draw_board.dataPx,0,0,0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);
                }
                // 绘制
                ctx.stroke();
                // 结束绘制
                ctx.closePath();

                // 获取当前绘制圆对象坐标
                draw_board.drawedPosData['x'] = draw_board.beginX
                draw_board.drawedPosData['y'] = draw_board.beginY
                draw_board.drawedPosData['r'] = Math.abs(y-draw_board.beginY)

    
          },
    
    };
    
    

    // 计算点与点之间的距离
    const getDistance=(p1,p2) =>{
            return Math.sqrt((p1.x-p2.x)**2+(p1.y-p2.y)**2)
    }
    // 判断当前位置是否在绘画对象内,如果在,则返回该绘制对象;否则返回 false
    const ifInDrawedObj=(pos)=>{
        // 如果不存在绘制对象,则直接返回false
        if(allDrawedObjs.length ==0){
            return false
        }
        // 遍历所有绘制对象
        for(let i =0;i<allDrawedObjs.length;i++){
                // 如果当前绘制对象是圆,进行是否在圆内判断
                if(allDrawedObjs[i].type=='circle')
                {
                    
                    circle_r = allDrawedObjs[i].drawedPosData['r']
                    if(getDistance(allDrawedObjs[i].drawedPosData,pos)<circle_r)
                    {
                        console.log('在园内')
                        return allDrawedObjs[i]
                    }
                }
                // 如果当前绘制对象是矩形,进行是否在矩形框内进行判断
                else if(allDrawedObjs[i].type=='rect')
                {
                    
                    let x1 = allDrawedObjs[i].drawedPosData['centerX'] -allDrawedObjs[i].drawedPosData['w']/2
                    let y1 = allDrawedObjs[i].drawedPosData['centerY'] -allDrawedObjs[i].drawedPosData['h']/2
                    let x2 = allDrawedObjs[i].drawedPosData['centerX'] +allDrawedObjs[i].drawedPosData['w']/2
                    let y2 = allDrawedObjs[i].drawedPosData['centerY'] +allDrawedObjs[i].drawedPosData['h']/2


                    if(x1<pos.x && pos.x<x2 && pos.y>y1 && pos.y<y2)
                    {
                        console.log('在矩形框内')
                        return allDrawedObjs[i]
                    }
                }
        }
        return false
    }
    
    
    // 获取画布位置
    const getCanvasPosition=e=>{
        return {
            x:e.offsetX,
            y:e.offsetY,
        }
    }
    

    
    // 监听获取上传文件路径
    inputElement.addEventListener('change', (e) => {
     img.src = URL.createObjectURL(e.target.files[0]);
    }, false);
    // 图像加载时,在画布上显示图像
    img.onload = function(){
        // 获取图像最长边
        max_length = (img.width>img.height)?img.width:img.height
        // 画布高
        canvH = mycanvas.height;
        // 画布宽
        canvW = mycanvas.width;
        // 图像高宽和画布高宽比
        rh = img.height / canvH;
        rw = img.width / canvW;
        // 最大高宽比
        max_radio = (rw>rh)?rw:rh
    
       /*
       最大比例值大于1,就同比缩小到1
       最大比例值小于1,就同比放大到1
       */
    
        if(max_radio > 1){
            // console.log(img.width);
            // console.log(img.height);
            // console.log(img.width/max_radio);
            // console.log(img.height/max_radio);
            ctx.drawImage(img, 0, 0, img.width/max_radio, img.height/max_radio);
    
        }else{
            // console.log(img.width);
            // console.log(img.height);
            // console.log(img.width/max_radio);
            // console.log(img.height/max_radio);
            ctx.drawImage(img, 0, 0, img.width/max_radio, img.height/max_radio);
    
        }
    
      
    }

    function drawImg(){
         // 获取图像最长边
         max_length = (img.width>img.height)?img.width:img.height
        // 画布高
        canvH = mycanvas.height;
        // 画布宽
        canvW = mycanvas.width;
        // 图像高宽和画布高宽比
        rh = img.height / canvH;
        rw = img.width / canvW;
        // 最大高宽比
        max_radio = (rw>rh)?rw:rh
    
       /*
       最大比例值大于1,就同比缩小到1
       最大比例值小于1,就同比放大到1
       */
    
        if(max_radio > 1){
            // console.log(img.width);
            // console.log(img.height);
            // console.log(img.width/max_radio);
            // console.log(img.height/max_radio);
            ctx.drawImage(img, 0, 0, img.width/max_radio, img.height/max_radio);
    
        }else{
            // console.log(img.width);
            // console.log(img.height);
            // console.log(img.width/max_radio);
            // console.log(img.height/max_radio);
            ctx.drawImage(img, 0, 0, img.width/max_radio, img.height/max_radio);
    
        }
    }
    
    
    
    
    // 绘制 绘画对象
    const drawDrawedObj = (drawedObj)=>{

      if(drawedObj.type=='circle'){
            ctx.beginPath();
            ctx.arc(drawedObj.drawedPosData.x,drawedObj.drawedPosData.y,drawedObj.drawedPosData.r,0,Math.PI*2)
            ctx.stroke()
            ctx.closePath();

      }else if(drawedObj.type == 'rect'){
            ctx.beginPath();
            let x = drawedObj.drawedPosData.centerX - drawedObj.drawedPosData.w/2
            let y = drawedObj.drawedPosData.centerY - drawedObj.drawedPosData.h/2
            let w = drawedObj.drawedPosData.w
            let h = drawedObj.drawedPosData.h
            ctx.strokeRect(x,y,w,h);
            ctx.closePath(); 
      }

    }


    // 显示按钮激活状态
    function click_boxshowdow(selectedBtn) {
          
          btn.forEach((item)=> {
           // console.log(item);
            item.classList.remove('active');
          });
          selectedBtn.classList.add('active');
         // console.log(selectedBtn);
    };
    
    
    // 2  选中矩形
    rectBtn.onclick = function() {
        draw_board.type = "rect";
        click_boxshowdow(this);
    }
    
    // 3 选中圆形
    circleBtn.onclick = function() {
        draw_board.type = "circle";
        click_boxshowdow(this);
    }
    
    // 在画布中鼠标按下事件
    mycanvas.onmousedown = function(e) {

        // 获取当前点击下,的画布坐标
        const canvasPostion = getCanvasPosition(e)
                
        // 判断当前点击位置是否在绘画对象内
        const DrawedObjRef = ifInDrawedObj(canvasPostion)
        console.log('DrawedObjRef')
        console.log(DrawedObjRef)
        // 1.是,则返回绘画对象
        if(DrawedObjRef){
            // 停止绘画
            draw_board.isDraw = false;
            // 赋值拖拽对象
            draw_board.dragTarget = DrawedObjRef
            draw_board.status = statusConfig.DRAG_START
            draw_board.lastEvtPos = canvasPostion
        }
        // 2.不是,则进行绘画
        else{
        // 开始绘画
        draw_board.isDraw = true;
        // 获取起点
        draw_board.beginX = e.pageX - mycanvas.offsetLeft;
        draw_board.beginY=  e.pageY - mycanvas.offsetTop;
    
        }
    
    }
    
    
    // 在画布中鼠标移动事件(核心)
    mycanvas.onmousemove = function(e) {
        // 确定在绘画状态
        if(draw_board.isDraw) {
            // 确定是哪种绘制,并进行绘制
            if(draw_board.type != 'null') {
                // 确定调用哪个绘画函数
                let str = draw_board.type + "Fn";
                // 绘画
                draw_board[str](e);
            }
        }
        // 拖拽状态
        else{

            // 获取当前画布位置
            const canvasPostion = getCanvasPosition(e)
            // 如果当前状态为开始拖拽状态并且移动距离大于5,则将拖拽状态设置为拖拽中
            if(draw_board.status == statusConfig.DRAG_START && getDistance(canvasPostion,draw_board.lastEvtPos) >5 ){
                console.log('try to drag')
                draw_board.status = statusConfig.DRAGGING
            }else if(draw_board.status === statusConfig.DRAGGING){
                // 拖拽状态为拖拽中,则开始拖拽
                console.log('dragging')
       
                // 赋值拖拽对象位置,移动到当前鼠标移动位置
                if(draw_board.dragTarget.type=='circle'){
                    draw_board.dragTarget.drawedPosData.x = canvasPostion.x
                    draw_board.dragTarget.drawedPosData.y = canvasPostion.y

                }else if(draw_board.dragTarget.type=='rect'){
                    draw_board.dragTarget.drawedPosData.centerX = canvasPostion.x
                    draw_board.dragTarget.drawedPosData.centerY = canvasPostion.y
                }
                

                // 清空画布
                ctx.clearRect(0, 0, mycanvas.width, mycanvas.height);

                // 绘制图像
                drawImg()

                // 绘制所有 绘制对象
                allDrawedObjs.forEach(drawedObj=>drawDrawedObj(drawedObj))
            }

        }
    

      

        // 显示鼠标所在坐标
        canvasShowPosition.innerHTML=`x:${e.offsetX}  y:${e.offsetY} `
    
    }

    // 获取对象属性个数
    const attributeCount = function(obj) {
            let count = 0;
            for(let i in obj) {
                if(obj.hasOwnProperty(i)) {  // 建议加上判断,如果没有扩展对象属性可以不加
                    count++;
                }
            }
            return count;
    }
    // 在画布中鼠标抬起时间
    mycanvas.onmouseup = function(e) {
        // 停止绘画
        draw_board.isDraw = false; 
        // 记录当前绘画对象
        // 绘制完矩形后,添加到绘画对象列表中
        
        if(draw_board.type != "null" && attributeCount(draw_board.drawedPosData)>0) {
           
            allDrawedObjs.push({
                    type:draw_board.type,
                    drawedPosData:draw_board.drawedPosData,

            })
            // 获取绘制对象后,清空绘制对象坐标,为下一个绘制对象做准备
            draw_board.drawedPosData = {}
        }
        console.log(allDrawedObjs)



        // 获取当前所有画布内容
        draw_board.dataPx = ctx.getImageData(0,0,mycanvas.offsetWidth,mycanvas.offsetHeight);
    
        //如果鼠标抬起,同时当前画布的状态是拖拽中,则将拖拽中状态置为闲置状态
        if(draw_board.status === statusConfig.DRAGGING){
            draw_board.status = statusConfig.IDLE
        }
    
    
    }


    //getImageData() 方法返回 ImageData 对象,该对象拷贝了画布指定矩形的像素数据。
    // x	开始复制的左上角位置的 x 坐标(以像素计)。
    // y	开始复制的左上角位置的 y 坐标(以像素计)。
    // width	要复制的矩形区域的宽度。
    // height	要复制的矩形区域的高度。
    clearCanvasBtn.onclick = function(e){
       ctx.clearRect(0,0,mycanvas.width,mycanvas.height)
    }
    
</script>


</html>


在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值