需要绘制一条可控制的贝塞尔曲线,发现fabic官网中一个demo有点类似。感兴趣的可以移步官网查看demo。
官网的demo是对于html 而言的,放在vue中需要变换一下,具体代码如下:
<template>
<div class="dashboard-container" @contextmenu.prevent>
<canvas id="editorCanvas" ref="canvas" style="margin-top: 10px;" />
</div>
</template>
<script>
import { mapGetters } from 'vuex'
// import fabric from 'fabric'
let canvas = ''
export default {
name: 'Dashboard',
computed: {
...mapGetters([
'name'
])
},
data () {
return {
width: window.innerWidth,
height: window.innerHeight,
activeEl: {}// 获取当前点击元素
}
},
mounted () {
const self = this
// canvas = new fabric.StaticCanvas('editorCanvas', {//静态画布,不可以修改
canvas = new fabric.Canvas('editorCanvas', {
width: self.width,
height: self.height,
backgroundColor: '#ffffff'
})
var line = new fabric.Path('M 65 0 Q 100, 100, 200, 0', { fill: '', stroke: 'black', objectCaching: false })
line.path[0][1] = 100
line.path[0][2] = 100
line.path[1][1] = 200
line.path[1][2] = 200
line.path[1][3] = 300
line.path[1][4] = 100
line.selectable = false
canvas.add(line)
var p1 = self.makeCurvePoint(200, 200, null, line, null)
p1.name = 'p1'
canvas.add(p1)
var p0 = self.makeCurveCircle(100, 100, line, p1, null)
p0.name = 'p0'
canvas.add(p0)
var p2 = self.makeCurveCircle(300, 100, null, p1, line)
p2.name = 'p2'
canvas.add(p2)
canvas.on('object:selected', function (opt) {
self.onObjectSelected(opt)
})
canvas.on('object:moving', function (opt) {
self.onObjectMoving(opt)
})
canvas.on('selection:cleared', function (opt) {
self.onSelectionCleared(opt)
// canvas.on({
// 'object:selected': this.onObjectSelected(e),
// 'object:moving': this.onObjectMoving(e),
// 'selection:cleared': this.onSelectionCleared(e)
})
},
methods: {
makeCurveCircle (left, top, line1, line2, line3) {
var c = new fabric.Circle({
left: left,
top: top,
strokeWidth: 5,
radius: 12,
fill: '#fff',
stroke: '#666',
originX: 'center',
originY: 'center'
})
c.hasBorders = c.hasControls = false
c.line1 = line1
c.line2 = line2
c.line3 = line3
return c
},
makeCurvePoint (left, top, line1, line2, line3) {
var c = new fabric.Circle({
left: left,
top: top,
strokeWidth: 8,
originX: 'center',
originY: 'center',
radius: 14,
fill: '#fff',
stroke: '#666'
})
c.hasBorders = c.hasControls = false
c.line1 = line1
c.line2 = line2
c.line3 = line3
return c
},
onObjectSelected (e) {
// console.log(e.target)
var activeObject = e.target
if (activeObject.name == 'p0' || activeObject.name == 'p2') {
activeObject.line2.animate('opacity', '1', {
duration: 200,
onChange: canvas.renderAll.bind(canvas)
})
activeObject.line2.selectable = true
}
},
onSelectionCleared (e) {
var activeObject = e.target
if (activeObject.name == 'p0' || activeObject.name == 'p2') {
activeObject.line2.animate('opacity', '0', {
duration: 200,
onChange: canvas.renderAll.bind(canvas)
})
activeObject.line2.selectable = false
} else if (activeObject.name == 'p1') {
activeObject.animate('opacity', '0', {
duration: 200,
onChange: canvas.renderAll.bind(canvas)
})
activeObject.selectable = false
}
},
onObjectMoving (e) {
if (e.target.name == 'p0' || e.target.name == 'p2') {
var p = e.target
if (p.line1) {
p.line1.path[0][1] = p.left
p.line1.path[0][2] = p.top
} else if (p.line3) {
p.line3.path[1][3] = p.left
p.line3.path[1][4] = p.top
}
} else if (e.target.name == 'p1') {
var p = e.target
if (p.line2) {
p.line2.path[1][1] = p.left
p.line2.path[1][2] = p.top
}
} else if (e.target.name == 'p0' || e.target.name == 'p2') {
var p = e.target
p.line1 && p.line1.set({ 'x2': p.left, 'y2': p.top })
p.line2 && p.line2.set({ 'x1': p.left, 'y1': p.top })
p.line3 && p.line3.set({ 'x1': p.left, 'y1': p.top })
p.line4 && p.line4.set({ 'x1': p.left, 'y1': p.top })
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
效果如图:
核心:定义 line时,设置path数组值。变换时修改path数组中的值。直接=
但是我需要绘制三阶贝塞尔曲线,即要两个控制点。这时候就需要变形一下。
const line = new fabric.Path(`M ${item1.left} ${item1.top} C ${item1.left} ${item2.top}, ${item2.left} ${item1.top}, ${item2.left}, ${item2.top}`, {
......
/* 起点 */
line.path[0][1] = item1.left
line.path[0][2] = item1.top
/* 控制点1 */
line.path[1][1] = item1.left
line.path[1][2] = item2.top
/* 控制点2 */
line.path[1][3] = item2.left
line.path[1][4] = item1.top
/* 结束点 */
line.path[1][5] = item2.left
line.path[1][6] = item2.top
修改直接进行重新赋值。