需求:在canvas画布上绘制多个圆形,并添加连接线,图形移动,线自动跟随移动。类似于拓扑关系。
查看fabic文档,Stickman火柴人demo完美适应。官网具体代码如下:
- (function() {
- var canvas = this.__canvas = new fabric.Canvas('c', { selection: false });
- fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
-
- function makeCircle(left, top, line1, line2, line3, line4) {
- var c = new fabric.Circle({
- left: left,
- top: top,
- strokeWidth: 5,
- radius: 12,
- fill: '#fff',
- stroke: '#666'
- });
- c.hasControls = c.hasBorders = false;
-
- c.line1 = line1;
- c.line2 = line2;
- c.line3 = line3;
- c.line4 = line4;
-
- return c;
- }
-
- function makeLine(coords) {
- return new fabric.Line(coords, {
- fill: 'red',
- stroke: 'red',
- strokeWidth: 5,
- selectable: false,
- evented: false,
- });
- }
-
- var line = makeLine([ 250, 125, 250, 175 ]),
- line2 = makeLine([ 250, 175, 250, 250 ]),
- line3 = makeLine([ 250, 250, 300, 350]),
- line4 = makeLine([ 250, 250, 200, 350]),
- line5 = makeLine([ 250, 175, 175, 225 ]),
- line6 = makeLine([ 250, 175, 325, 225 ]);
-
- canvas.add(line, line2, line3, line4, line5, line6);
-
- canvas.add(
- makeCircle(line.get('x1'), line.get('y1'), null, line),
- makeCircle(line.get('x2'), line.get('y2'), line, line2, line5, line6),
- makeCircle(line2.get('x2'), line2.get('y2'), line2, line3, line4),
- makeCircle(line3.get('x2'), line3.get('y2'), line3),
- makeCircle(line4.get('x2'), line4.get('y2'), line4),
- makeCircle(line5.get('x2'), line5.get('y2'), line5),
- makeCircle(line6.get('x2'), line6.get('y2'), line6)
- );
-
- canvas.on('object:moving', function(e) {
- 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 });
- canvas.renderAll();
- });
- })();
我在vue项目中使用,变形如下:
- <div class="dashboard-container" @contextmenu.prevent>
- <canvas id="editorCanvas" ref="canvas" style="margin-top: 10px;" />
- div>
-
- <script>
- import { mapGetters } from 'vuex'
- import { getMapList } from '@/api/table'
- // import fabric from 'fabric'
- let canvas = ''
- export default {
- name: 'Dashboard',
- computed: {
- ...mapGetters([
- 'name'
- ])
- },
- data () {
- return {
- width: window.innerWidth,
- height: window.innerHeight,
- activeEl: {}// 获取当前点击元素
- }
- },
- mounted () {
- canvas = new fabric.Canvas('editorCanvas', {
- width: this.width,
- height: this.height,
- selection: false,
- backgroundColor: '#ffffff',
- transparentCorners: false,
- fireRightClick: true, // 启用右键,button的数字为3
- stopContextMenu: true // 禁止默认右键菜单
- })
-
- var line = this.makeLine([250, 125, 250, 175])
- var line2 = this.makeLine([250, 175, 250, 250])
- var line3 = this.makeLine([250, 250, 300, 350])
- var line4 = this.makeLine([250, 250, 200, 350])
- var line5 = this.makeLine([250, 175, 175, 225])
- var line6 = this.makeLine([250, 175, 325, 225])
-
- canvas.add(line, line2, line3, line4, line5, line6)
-
- canvas.add(
- this.makeCircle(line.get('x1'), line.get('y1'), null, line),
- this.makeCircle(line.get('x2'), line.get('y2'), line, line2, line5, line6),
- this.makeCircle(line2.get('x2'), line2.get('y2'), line2, line3, line4),
- this.makeCircle(line3.get('x2'), line3.get('y2'), line3),
- this.makeCircle(line4.get('x2'), line4.get('y2'), line4),
- this.makeCircle(line5.get('x2'), line5.get('y2'), line5),
- this.makeCircle(line6.get('x2'), line6.get('y2'), line6)
- )
-
- canvas.on('object:moving', function (e) {
- 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 })
- canvas.renderAll()
- })
- },
- methods: {
- makeCircle (left, top, line1, line2, line3, line4) {
- var c = new fabric.Circle({
- left: left,
- top: top,
- strokeWidth: 5,
- radius: 12,
- fill: '#fff',
- stroke: '#666',
- originX: 'center',
- originY: 'center'
- })
- c.hasControls = c.hasBorders = false
-
- c.line1 = line1
- c.line2 = line2
- c.line3 = line3
- c.line4 = line4
-
- return c
- },
- makeLine (coords) {
- return new fabric.Line(coords, {
- fill: 'red',
- stroke: 'red',
- strokeWidth: 5,
- selectable: false,
- evented: false, originX: 'center',
- originY: 'center'
- })
- }
-
- }
- }
- script>
-
- <style lang="scss" scoped>
-
- style>
效果如图(随便拖动一点移动,关联线自动跟随):


分析:最核心代码为set({ 'x2': p.left, 'y2': p.top }),通过为canvas添加元素移动判定canvas.on('object:moving',根据移动重新设定线段的绘制坐标。
变形使用:(仅为逻辑,请自行编写判定逻辑)
- canvas.on('object:moving', function (e) {
- var p = e.target
- if (....) { /* 判定我移动的元素是点 ,即是移动会改变关联的元素*/
- canvas.forEachObject(function (object) {
- if(....){ /* 定位到关联的线 */
- object.set({ 'x1': p.left, 'y1': p.top })
- }
- })
- }
- })