zoukankan      html  css  js  c++  java
  • 使用canvas 根据角度画圆弧

    最近收到一个需求,根据角度在平面上画出对应的区域,实际就是 以固定的原点,根据起始角度和结束角度和半径,画出他的区域。

    写了一小段,试试

    
    
    export class Draw {
      constructor(domId) {
        let canvas = document.getElementById(domId);
        this.initLoad = false
        this.storeName = ""
        this.canvas = canvas;
        this.context = canvas.getContext('2d'); //创建在画布上绘图的环境
      }
      init(x,y,offset=0) {
        // 圆心坐标 x, y .  起始角度的偏差值 offset
        this.initLoad = true
        this.cx = x;
        this.cy = y;
        this.offset = offset
      }
      mousemoveInit(callback) {
        let _this = this
        this.canvas.addEventListener("mousemove", function __handler__(evt) {
          if (!_this.initLoad) return
            var x = evt.clientX;
            var y = evt.clientY;
            var rect = _this.canvas.getBoundingClientRect();  //返回元素的大小及其相对于视口的位置
            x -= rect.left;
            y -= rect.top;
            let xl = Math.abs(x-_this.cx) //取绝对值
            let yl = Math.abs(y-_this.cy)
            let hl = _this.findHypotenuse(xl,yl)  //根据直角边,求斜边的长度
            if (hl<200){
              let ang = _this.getAngle(xl,yl,x,y) // 获取点相对圆心的角度, 0 度在横轴x 上
              let offsetAng = _this.getOffsetAngle(ang)
              callback(x, y,offsetAng)
              // console.log(x, y,offsetAng); // (x, y) 就是鼠标在 canvas 单击时的坐标 ang 是角度
            }else{
              callback(0, 0,500)
            }
            
        });
      }
      
      getOffsetAngle(ang) {
        // 根据计算的标准角度 返回用户需要的偏差角度
        return ang>90?ang-this.offset:ang+270
      }
      getAngle(x, y,ox,oy) {
          // 根据直角边 求角度
          var radian = Math.atan(y / x);//弧度    (y / x)为直线的斜率
          var angle = Math.floor(180 / (Math.PI / radian));//弧度转角度
          if (x < 0) {//x小于0的时候加上180°,即实际角度
              angle = angle + 180;
          }
          if (ox>=this.cx && oy>= this.cy) {
            return angle;
          } else if (ox  <= this.cx && oy>= this.cy) {
            return 180-angle
          }else if (ox  <= this.cx && oy<= this.cy) {
            return 180+angle
          }else if (ox>=this.cx && oy<= this.cy) {
            return 360-angle
          }
      }
      findHypotenuse (base,perpendicular) {
        // 根据直角边 求斜边的长度
        const bSquare = base ** 2;
        const pSquare = perpendicular ** 2;
        const sum = bSquare + pSquare;
        const hypotenuse = Math.sqrt(sum);  //返回一个数的平方根
        return Math.floor(hypotenuse);
      }
      mathAngle(angle,r) {
        // 根据角度求 坐标
        let angObj = {
          x: '',
          y: ''
        }
        var angles = 0;
        var radian = 0;
        if (angle<=90) {
          angles = 90-angle
        }else if (angle>90 && angle <=180) {
          angles = angle-90
        }else if (angle>180 && angle <=270) {
          angles = 270- angle
        }else if (angle>270 && angle <=360) {
          angles = angle-270
        }
        radian = angles * Math.PI / 180
        let xlen = Math.floor(Math.sin(radian)*r)
        let ylen = Math.floor(Math.cos(radian)*r)
        
        if (angle<=90) {
          angObj.x = this.cx+xlen
          angObj.y = this.cy+ylen
        }else if (angle>90 && angle <=180) {
          angObj.x = this.cx-xlen
          angObj.y = this.cy+ylen
        }else if (angle>180 && angle <=270) {
          angObj.x = this.cx-xlen
          angObj.y = this.cy-ylen
        }else if (angle>270 && angle <=360) {
          angObj.x = this.cx+xlen
          angObj.y = this.cy-ylen
        }
        return angObj
      }
      clearRect () {
        // 清除画布
        this.context.clearRect(0,0,this.cx*2,this.cy*2);
      }
      lines (x1,y1,x2,y2,color,width=5) {
        // 画直线
        this.context.beginPath();
        this.context.lineWidth = width;
        this.context.moveTo(x1,y1);
        
        this.context.lineTo(x2,y2); 
        this.context.strokeStyle = color; 
        this.context.stroke();
      }

      pieChart(r,sAngle,eAngle,color,flag=true) {
        // 画扇形
        let startAngle = 2*sAngle/360
        let endAngle = 2*eAngle/360
        this.context.beginPath();
        this.context.lineWidth = 1;
        this.context.moveTo(this.cx,this.cy);
        this.context.strokeStyle = "white";
        this.context.fillStyle = color;
        this.context.arc(this.cx,this.cy,r,startAngle*Math.PI,endAngle*Math.PI);
        this.context.fill();
        this.context.closePath();
        this.context.stroke();
      }
      pieName(x,y,color,name) {
        //文字绘制到扇形旁边
        this.context.fillText(name,x,y);
      }
    }

    export class Angle extends Draw {
      correct (ang) {
        // 将传入的角度按照偏差值 进行纠正
        return ang+this.offset<=360?ang+this.offset:ang+this.offset-360
      }
      correctM (sAngle,eAngle) {
        // 取俩角度中间值
        if (sAngle > eAngle) {
          let ang = sAngle + 1/2*(360-sAngle+eAngle);
          return ang>360?ang-360:ang
        }
        return sAngle + 1/2*(eAngle-sAngle);
      }
      drawAir (r,sAngle,eAngle,color,name) {
        // 画分区的扇形
        sAngle = this.correct(sAngle)
        eAngle = this.correct(eAngle)
        this.pieChart(r,sAngle,eAngle,color,name)
        
      }
      drawName (r,sAngle,eAngle,color,name) {
        // 画分区的名字
        sAngle = this.correct(sAngle)
        eAngle = this.correct(eAngle)
        //计算文字要放的角度
        var txtAngle = this.correctM(sAngle,eAngle)
        this.context.textAlign = 'center';
        if(txtAngle>95 && txtAngle<260){
          this.context.textAlign = 'end';
        }
        if(txtAngle<85 && txtAngle>5){
          this.context.textAlign = 'left';
        }
        if(txtAngle<350 && txtAngle>275){
          this.context.textAlign = 'left';
        }
        
        var x,y;
        x=this.cx+Math.cos(txtAngle*Math.PI/180)*(r+20);
        y=this.cy+Math.sin(txtAngle*Math.PI/180)*(r+20);
        this.pieName(x,y,color,name)
        
      }
      drawMachine(r,angle,color) {
        // 画机器的位置
        this.lines(this.cx,this.cy,40,140,"#ff0")
      }
    }



     
    <template>
        <canvas id="can" width="600" height="600"></canvas>
    </template>
    <script>
    import {onMounted} from 'vue'
    import {Draw} from './draw.js'
    export default {
      setup(){
        function pageLoad(){
          let draw = new Draw('can')
          draw.init(300,300)
          draw.airAngle(200,20,90,'#ff0',false)
          draw.airAngle(200,150,290,'#ff8',false)
          draw.mousemoveInit((x, y,ang)=>{
            console.log(x, y,ang)
          })
        }
        onMounted(() =>{
          pageLoad()
        })
      }
      
    }
    </script>

    得到了这样的效果

     鼠标滑到 对应的区域,将返回该点的坐标 和角度

  • 相关阅读:
    luogu 2962 [USACO09NOV]灯Lights
    bzoj 1923
    bzoj 1013
    bzoj 3513
    bzoj 4259
    bzoj 4503
    CF 632E
    bzoj 3527
    bzoj 3160
    bzoj 2179
  • 原文地址:https://www.cnblogs.com/buxiugangzi/p/15748156.html
Copyright © 2011-2022 走看看