文件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()
},
}