我是fabric.js的新手,对浏览器canvas api的了解也不多,因此,我感谢别人会提供的所有帮助。
要达到的目标是用3种不同的模式用鼠标箭头绘制:
有一个很好的例子-但只有一个“提示”。
另一个更高级的主题可能是:选择一个已经 创建的箭头以进行更改(例如,单击按钮并将模式从一个带箭头的箭头更改为两个)。
_render: function(ctx) {
this.callSuper('_render', ctx);
// do not render if width/height are zeros or object is not visible
if (this.width === 0 || this.height === 0 || !this.visible) return;
ctx.save();
var xDiff = this.x2 - this.x1;
var yDiff = this.y2 - this.y1;
var angle = Math.atan2(yDiff, xDiff);
ctx.translate(xDiff / 2, yDiff / 2);
ctx.rotate(angle);
ctx.beginPath();
//move 10px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
ctx.moveTo(10, 0);
ctx.lineTo(-20, 15);
ctx.lineTo(-20, -15);
ctx.closePath();
ctx.fillStyle = this.stroke;
ctx.fill();
ctx.restore();
}
可以更改此特定部分,以代替添加另一个箭头:<--->
链接到正在工作的JFiddle:Fiddle
在此先感谢您的帮助。 祝一切顺利!
答案 0 :(得分:3)
将上下文转换为直线的两个端点,然后旋转以绘制箭头。
演示
// Extended fabric line class
fabric.LineArrow = fabric.util.createClass(fabric.Line, {
type: 'lineArrow',
initialize: function(element, options) {
options || (options = {});
this.callSuper('initialize', element, options);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'));
},
_render: function(ctx) {
this.ctx = ctx;
this.callSuper('_render', ctx);
let p = this.calcLinePoints();
let xDiff = this.x2 - this.x1;
let yDiff = this.y2 - this.y1;
let angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x2, p.y2);
ctx.save();
xDiff = -this.x2 + this.x1;
yDiff = -this.y2 + this.y1;
angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x1, p.y1);
},
drawArrow: function(angle, xPos, yPos) {
this.ctx.save();
this.ctx.translate(xPos, yPos);
this.ctx.rotate(angle);
this.ctx.beginPath();
// Move 5px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
this.ctx.moveTo(10, 0);
this.ctx.lineTo(-15, 15);
this.ctx.lineTo(-15, -15);
this.ctx.closePath();
this.ctx.fillStyle = this.stroke;
this.ctx.fill();
this.ctx.restore();
}
});
fabric.LineArrow.fromObject = function(object, callback) {
callback && callback(new fabric.LineArrow([object.x1, object.y1, object.x2, object.y2], object));
};
fabric.LineArrow.async = true;
var Arrow = (function() {
function Arrow(canvas) {
this.canvas = canvas;
this.className = 'Arrow';
this.isDrawing = false;
this.bindEvents();
}
Arrow.prototype.bindEvents = function() {
var inst = this;
inst.canvas.on('mouse:down', function(o) {
inst.onMouseDown(o);
});
inst.canvas.on('mouse:move', function(o) {
inst.onMouseMove(o);
});
inst.canvas.on('mouse:up', function(o) {
inst.onMouseUp(o);
});
inst.canvas.on('object:moving', function(o) {
inst.disable();
})
}
Arrow.prototype.onMouseUp = function(o) {
var inst = this;
this.line.set({
dirty: true,
objectCaching: true
});
inst.canvas.renderAll();
inst.disable();
};
Arrow.prototype.onMouseMove = function(o) {
var inst = this;
if (!inst.isEnable()) {
return;
}
var pointer = inst.canvas.getPointer(o.e);
var activeObj = inst.canvas.getActiveObject();
activeObj.set({
x2: pointer.x,
y2: pointer.y
});
activeObj.setCoords();
inst.canvas.renderAll();
};
Arrow.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
this.line = new fabric.LineArrow(points, {
strokeWidth: 5,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center',
hasBorders: false,
hasControls: false,
objectCaching: false,
perPixelTargetFind: true
});
inst.canvas.add(this.line).setActiveObject(this.line);
};
Arrow.prototype.isEnable = function() {
return this.isDrawing;
}
Arrow.prototype.enable = function() {
this.isDrawing = true;
}
Arrow.prototype.disable = function() {
this.isDrawing = false;
}
return Arrow;
}());
var canvas = new fabric.Canvas('canvas', {
selection: false
});
var arrow = new Arrow(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
Please draw arrow here
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>
答案 1 :(得分:0)
为了执行简单的线条,箭头需要一个或两个头,您需要设置自定义选项的路径。我使用自定义选项更新了@Durga代码。我已经使用和数组:heads: [1,1]
。磁头的可用选项可以是0或1。0-无磁头,1-有磁头。因此,在那种情况下,您可以控制要显示的头:向左,向右,既不显示又不显示:
// Extended fabric line class
fabric.LineArrow = fabric.util.createClass(fabric.Line, {
type: 'lineArrow',
initialize: function(element, options) {
options || (options = {});
this.callSuper('initialize', element, options);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'));
},
_render: function(ctx) {
this.ctx = ctx;
this.callSuper('_render', ctx);
let p = this.calcLinePoints();
let xDiff = this.x2 - this.x1;
let yDiff = this.y2 - this.y1;
let angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x2, p.y2, this.heads[0]);
ctx.save();
xDiff = -this.x2 + this.x1;
yDiff = -this.y2 + this.y1;
angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x1, p.y1,this.heads[1]);
},
drawArrow: function(angle, xPos, yPos, head) {
this.ctx.save();
if (head) {
this.ctx.translate(xPos, yPos);
this.ctx.rotate(angle);
this.ctx.beginPath();
// Move 5px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
this.ctx.moveTo(10, 0);
this.ctx.lineTo(-15, 15);
this.ctx.lineTo(-15, -15);
this.ctx.closePath();
}
this.ctx.fillStyle = this.stroke;
this.ctx.fill();
this.ctx.restore();
}
});
fabric.LineArrow.fromObject = function(object, callback) {
callback && callback(new fabric.LineArrow([object.x1, object.y1, object.x2, object.y2], object));
};
fabric.LineArrow.async = true;
var Arrow = (function() {
function Arrow(canvas) {
this.canvas = canvas;
this.className = 'Arrow';
this.isDrawing = false;
this.bindEvents();
}
Arrow.prototype.bindEvents = function() {
var inst = this;
inst.canvas.on('mouse:down', function(o) {
inst.onMouseDown(o);
});
inst.canvas.on('mouse:move', function(o) {
inst.onMouseMove(o);
});
inst.canvas.on('mouse:up', function(o) {
inst.onMouseUp(o);
});
inst.canvas.on('object:moving', function(o) {
inst.disable();
})
}
Arrow.prototype.onMouseUp = function(o) {
var inst = this;
this.line.set({
dirty: true,
objectCaching: true
});
inst.canvas.renderAll();
inst.disable();
};
Arrow.prototype.onMouseMove = function(o) {
var inst = this;
if (!inst.isEnable()) {
return;
}
var pointer = inst.canvas.getPointer(o.e);
var activeObj = inst.canvas.getActiveObject();
activeObj.set({
x2: pointer.x,
y2: pointer.y
});
activeObj.setCoords();
inst.canvas.renderAll();
};
Arrow.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
this.line = new fabric.LineArrow(points, {
strokeWidth: 5,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center',
hasBorders: false,
hasControls: false,
objectCaching: false,
perPixelTargetFind: true,
heads: [1, 0]
});
inst.canvas.add(this.line).setActiveObject(this.line);
};
Arrow.prototype.isEnable = function() {
return this.isDrawing;
}
Arrow.prototype.enable = function() {
this.isDrawing = true;
}
Arrow.prototype.disable = function() {
this.isDrawing = false;
}
return Arrow;
}());
var canvas = new fabric.Canvas('canvas', {
selection: false
});
var arrow = new Arrow(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
Please draw arrow here
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>https://stackoverflow.com/questions/53114152/draw-two-head-arrows-in-fabric-js#
P.S。 Durga 的所有学分。我只是对他的代码做了一些小的修改。