vue 中canvas 根据点画出圆滑的曲线

文件BezierMaker.js

var BezierMaker = function(canvas, bezierCtrlNodesArr, color) {

    // this.canvas = canvas
    this.ctx = canvas
    this.bezierCtrlNodesArr = bezierCtrlNodesArr ? bezierCtrlNodesArr : []
    this.color = color ? color: '#ffffff'
    this.bezierArr = []
    
}
BezierMaker.prototype.bezier = function(t) { //贝塞尔公式调用
    var x = 0,
        y = 0,
        bezierCtrlNodesArr = this.bezierCtrlNodesArr,
        n = bezierCtrlNodesArr.length - 1,
        self = this
    bezierCtrlNodesArr.forEach(function(item, index) {
        if(!index) {
            x += item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
            y += item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
        } else {
            x += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.x * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
            y += self.factorial(n) / self.factorial(index) / self.factorial(n - index) * item.y * Math.pow(( 1 - t ), n - index) * Math.pow(t, index) 
        }
    })
    return {
        x: x,
        y: y
    }
}
BezierMaker.prototype.drawBezier = function() { //通过控制点算出实时xy值渲染到canvas
    var nodeArr = this.bezierCtrlNodesArr  
    if(nodeArr.length === 2) {
        console.warn('Control nodes should be more then two!')
        var startNode = nodeArr[0],
            endNode = nodeArr[1]

        this.ctx.moveTo(startNode.x, startNode.y)
        this.ctx.lineTo(endNode.x, endNode.y)
        this.ctx.strokeStyle = this.color
        this.ctx.stroke()
    } else if(nodeArr.length === 3) {
        var startNode = nodeArr[0],
            ctrlNode = nodeArr[1],
            endNode = nodeArr[2]
        this.ctx.beginPath()
        this.ctx.lineWidth = 6;
        this.ctx.lineJoin = 'round';
        this.ctx.lineCap = 'round';
        this.ctx.moveTo(startNode.x, startNode.y)
        this.ctx.quadraticCurveTo(ctrlNode.x, ctrlNode.y, endNode.x, endNode.y)
        this.ctx.strokeStyle = this.color
        this.ctx.stroke()
    } else if(nodeArr.length === 4) {
        var startNode = nodeArr[0],
            ctrlNodeA = nodeArr[1],
            ctrlNodeB = nodeArr[2],
            endNode = nodeArr[3]
        this.ctx.beginPath()
        this.ctx.lineWidth = 6;
        this.ctx.lineJoin = 'round';
        this.ctx.lineCap = 'round';
        this.ctx.moveTo(startNode.x, startNode.y)
        this.ctx.bezierCurveTo(ctrlNodeA.x, ctrlNodeA.y, ctrlNodeB.x, ctrlNodeB.y, endNode.x, endNode.y)
        this.ctx.strokeStyle = this.color
        this.ctx.stroke()
    } else {
        var self = this
        for(i = 0; i < 1; i+=0.01) {
            this.bezierArr.push(this.bezier(i))
        }
        this.bezierArr.forEach(function(obj, index) {
            if (index) {
                var startX = self.bezierArr[index - 1].x,
                    startY = self.bezierArr[index - 1].y,
                    x = obj.x,
                    y = obj.y
                self.ctx.beginPath()
                self.ctx.lineWidth = 6;
                self.ctx.lineJoin = 'round';
                self.ctx.lineCap = 'round';
                self.ctx.moveTo(startX, startY)
                self.ctx.lineTo(x, y)
                self.ctx.strokeStyle = self.color
                self.ctx.stroke()
            }
        })
    }
    
}
BezierMaker.prototype.factorial = function(num) { //递归阶乘
    if (num <= 1) {
        return 1;
    } else {
        return num * this.factorial(num - 1);
    }
}
export default BezierMaker
<canvas id="canvasBg" height="1026" width="1148"></canvas>
import BezierMaker from './BezierMaker.js'
data(){
	return{
		ctx:{},
	      canvas:{},
	      clickNodes:[],//点击的控制点对象数组
	      bezier:null,
	      num: 0, //控制点数
	      isPrinting :false, //正在绘制中
	      t:0,//贝塞尔函数涉及的占比比例,0<=t<=1
	      bezierNodes: [], //绘制内部控制点的数组
		}
	},
mounted(){
	this.canvas=document.querySelector('#canvasBg')
    this.ctx = this.canvas.getContext('2d');
    // this.canvas.style.transform= `scale(.5)`;
    this.canvas.addEventListener('mousedown', down, false);
    this.canvas.addEventListener('mousemove', move, false);
    this.canvas.addEventListener('mouseup', up, false);
    // this.canvas.addEventListener('mouseout', up, false);
    let that = this
    
    // this.clickNodes = [] //点击的控制点对象数组
    var bezierNodes = [] //绘制内部控制点的数组
    var isPrinted = false //当前存在绘制的曲线
    
    var isDrag = false //是否进入拖拽行为
    var isDragNode = false //是否点击到了控制点
    var dragIndex = 0 //被拖拽的点的索引
    var clickon = 0 //鼠标按下时间戳
    var clickoff = 0 //鼠标抬起
    function down(evt) {

          isDrag = true
          clickon = new Date().getTime()
          var 
              x = evt.offsetX,
              y = evt.offsetY
              // x = clientX - diffLeft,
              // y = clientY - diffTop
              
              that.clickNodes.forEach(function(item, index) {
                  var absX = Math.abs(item.x - x),
                      absY = Math.abs(item.y - y)
                  if(absX < 10 && absY < 10) {
                      isDragNode = true
                      dragIndex = index
                  }
              })
              
      }
      function move(e){
        if(isDrag && isDragNode) {
          var 
          x = e.offsetX,
          y = e.offsetY
          // x = clientX - diffLeft,
          // y = clientY - diffTop
          that.clickNodes[dragIndex] = {
              x: x,
              y: y
          }
          that.ctx.clearRect(0, 0, that.canvas.width, that.canvas.height)
          if( that.setDate.length>0){
            that.setDate.forEach(item=>{
              that.bezier= new BezierMaker(that.ctx,item,'red')
              that.bezier.drawBezier()
            })
          }
          that.clickNodes.forEach(function(item, index) {
              var x = item.x,
                  y = item.y,
                  i = parseInt(index, 10) + 1
              that.ctx.fillText("p" + i, x, y + 20)
              that.ctx.beginPath()
              that.ctx.arc(x, y, 10, 0, Math.PI * 2, false)
              that.ctx.fill()
              that.ctx.beginPath()
              that.ctx.moveTo(startX, startY)
             
              that.ctx.lineTo(x, y)
              that.ctx.strokeStyle = '#696969'
              that.ctx.stroke()
              if (index) {
                  var startX = that.clickNodes[index - 1].x,
                      startY = that.clickNodes[index - 1].y
                  that.ctx.beginPath()
                  that.ctx.moveTo(startX, startY)
                  that.ctx.lineTo(x, y)
                  that.ctx.stroke()
                  
              }
          })
          if(isPrinted) {
              var bezierArr = []
              for(i = 0; i < 1; i+=0.01) {
                  bezierArr.push(that.bezierFun(that.clickNodes, i))
              }
              bezierArr.forEach(function(obj, index) {
                  if (index) {
                      var startX = bezierArr[index - 1].x,
                          startY = bezierArr[index - 1].y,
                          x = obj.x,
                          y = obj.y
                      that.ctx.beginPath()
                      that.ctx.moveTo(startX, startY)
                      that.ctx.lineTo(x, y)
                      that.ctx.strokeStyle = 'red'
                      that.ctx.stroke()
                  }
              })
          }
      }
      }
      function up(e){
        isDrag = false
        isDragNode = false
        clickoff = new Date().getTime()
        if(clickoff - clickon < 200) {
            var 
             x = e.offsetX,
          y = e.offsetY
            if(!isPrinted && !isDragNode) {
                that.num++
                that.ctx.fillStyle = '#696969'
                that.ctx.font = "30pt Calibri";
                that.ctx.fillText("p" + that.num, x, y + 20);
                // that.ctx.fillText("p" + that.num + ': ('+ x +', '+ y +')', 10, that.num * 30)
                that.ctx.beginPath()
                that.ctx.arc(x, y, 10, 0, Math.PI * 2, false)
                that.ctx.fill()
                if(that.clickNodes.length) {
                    var startX = that.clickNodes[that.clickNodes.length - 1].x,
                        startY = that.clickNodes[that.clickNodes.length - 1].y
                    that.ctx.beginPath() 
                    that.ctx.moveTo(startX, startY)
                    that.ctx.lineTo(x, y)
                    that.ctx.strokeStyle = '#696969'
                    that.ctx.stroke()
                } 
                that.clickNodes.push({
                    x: x,
                    y: y
                })
            }
        }
      }
},
methods:{
	//绘画
	ligature(){
		this.bezier= new BezierMaker(this.ctx,this.clickNodes,'red')
      	this.bezier.drawBezier()
	}
	//清除
	removeBtn(){
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
      this.clickNodes = []
      this.setDate=[]
      this.num=0
      this.t=0
    },
     // 确定
    sureBtn(){
    //确定是 请画板上的点去掉 要清空画板 所以线要重新绘画
      this.clickNodes=[]
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)
      this.bezier= new BezierMaker(this.ctx,this.clickNodes,'red')
      this.bezier.drawBezier()
    },
}

上面的点是可以点击滑动的 改变线的走向 这里用到的是贝塞尔曲线
在这里插入图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值