Created
March 5, 2021 08:40
-
-
Save fwindpeak/1ecafd1db6006d0d9ec09f274fcb369d to your computer and use it in GitHub Desktop.
vue pointline component with fabric.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<canvas id="canvas"></canvas> | |
</template> | |
<script> | |
import { fabric } from 'fabric' | |
export default { | |
props: { | |
value: { | |
type: Array, | |
required: true, | |
default: () => [], | |
}, | |
}, | |
watch: { | |
// value(val) { | |
// this.init(val) | |
// }, | |
}, | |
data() { | |
return { | |
fabricObj: {}, | |
circleList: [], | |
moving: false, | |
lineLeft: null, | |
} | |
}, | |
computed: { | |
canvasWidth() { | |
return window.innerWidth - 20 | |
}, | |
}, | |
mounted() { | |
//起始点居中 | |
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center' | |
//阻止group缩放 | |
fabric.Group.prototype.lockScalingX = true | |
fabric.Group.prototype.lockScalingY = true | |
this.fabricObj = new fabric.Canvas('canvas', { | |
isDrawingMode: false, | |
selectable: true, | |
selection: true, | |
devicePixelRatio: true, | |
}) | |
this.fabricObj.setWidth(this.canvasWidth) | |
this.fabricObj.setHeight(500) | |
//绑定事件 | |
this.fabricObjAddEvent() | |
this.init(this.value) | |
}, | |
methods: { | |
//绑定fabric事件 | |
fabricObjAddEvent() { | |
this.fabricObj.on({ | |
//鼠标双击事件 | |
'mouse:dblclick': o => { | |
this.addNode({ | |
x: o.pointer.x, | |
y: o.pointer.y, | |
}) | |
}, | |
//对象移动事件 | |
'object:moving': e => { | |
const p = e.target | |
if (p._objects) { | |
//多选 | |
for (let obj of p._objects) { | |
this.onNodeMoving(obj, p) | |
} | |
} else { | |
//单选 | |
this.onNodeMoving(p) | |
} | |
}, | |
}) | |
}, | |
makeCircle(left, top, lineLeft, lineRight) { | |
let c = new fabric.Circle({ | |
left: left, | |
top: top, | |
strokeWidth: 2, | |
radius: 12, | |
fill: 'red', | |
stroke: 'gray', | |
}) | |
c.hasControls = c.hasBorders = false | |
c.lineLeft = lineLeft | |
c.lineRigt = lineRight | |
return c | |
}, | |
makeLine(pa, pb) { | |
if (pa && pb) { | |
const c = new fabric.Line([pa.x, pa.y, pb.x, pb.y], { | |
fill: 'red', | |
stroke: 'red', | |
strokeWidth: 5, | |
selectable: false, | |
evented: false, | |
}) | |
c.hasControls = c.hasBorders = false | |
return c | |
} else { | |
return null | |
} | |
}, | |
/** | |
* 添加节点 | |
*/ | |
addNode(point) { | |
let lineLeft = null | |
let lineRight = null | |
if (this.circleList.length > 0) { | |
const lastCircle = this.circleList.slice(-1)[0] | |
const pointLast = { x: lastCircle.left, y: lastCircle.top } | |
lineLeft = this.makeLine(pointLast, point) | |
lastCircle.lineRight = lineLeft | |
this.fabricObj.add(lineLeft) | |
} | |
const circle = this.makeCircle(point.x, point.y, lineLeft, lineRight) | |
this.circleList.push(circle) | |
this.fabricObj.add(circle) | |
this.fabricObj.renderAll() | |
this.update() | |
}, | |
/** | |
* 节点移动 | |
*/ | |
onNodeMoving(p, group) { | |
let offsetX = p.left | |
let offsetY = p.top | |
if (group) { | |
offsetX += group.left | |
offsetY += group.top | |
} | |
p.lineLeft && p.lineLeft.set({ x2: offsetX, y2: offsetY }) | |
p.lineRight && p.lineRight.set({ x1: offsetX, y1: offsetY }) | |
this.fabricObj.renderAll() | |
this.update() | |
}, | |
/** | |
* 组件参数数据初始化 | |
*/ | |
init(pointList) { | |
this.circleList = [] | |
this.fabricObj.clear() | |
console.log('point init', pointList) | |
for (let p of pointList) { | |
const point = { x: p[0], y: p[1] } | |
this.addNode(point) | |
} | |
}, | |
/** | |
* 组件数据更新 | |
*/ | |
update() { | |
this.$emit( | |
'input', | |
this.circleList.map(p => [p.top, p.left]) | |
) | |
}, | |
}, | |
} | |
</script> | |
<style scoped> | |
#canvas { | |
margin: 5px; | |
border: 1px solid; | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment