I am using FabricJS to draw circle in canvas:
var circle = new fabric.Circle({radius: 100,
fill: '',
stroke: 'red',
strokeWidth: 3,
originX: 'center',
originY: 'center'
});
var text = new fabric.Text('HELLO WORLD.',
{ fontSize: 30,
originX: 'center',
originY: 'center',
fill : 'red'
});
var group = new fabric.Group([ circle, text ], {
left: 150, top: 100
});
canvas.add(group);
This code draws a normal circle but I need to freely draw circle with mouse.
Any code help will be appreciated.
According to your previous code for drawing rectangle http://jsfiddle.net/Subhasish2015/8u1cqasa/2/ Here is the code for drawing circle:
$(document).ready(function(){
//Getting the canvas
var canvas1 = new fabric.Canvas("canvas2");
var freeDrawing = true;
var divPos = {};
var offset = $("#canvas2").offset();
$(document).mousemove(function(e){
divPos = {
left: e.pageX - offset.left,
top: e.pageY - offset.top
};
});
$('#2').click(function(){
//Declaring the variables
var isMouseDown=false;
var refCircle;
//Setting the mouse events
canvas1.on('mouse:down',function(event){
isMouseDown=true;
if(freeDrawing) {
var circle=new fabric.Circle({
left:divPos.left,
top:divPos.top,
radius:0,
stroke:'red',
strokeWidth:3,
fill:''
});
canvas1.add(circle);
refCircle=circle; //**Reference of rectangle object
}
});
canvas1.on('mouse:move', function(event){
if(!isMouseDown)
{
return;
}
//Getting yhe mouse Co-ordinates
if(freeDrawing) {
var posX=divPos.left;
var posY=divPos.top;
refCircle.set('radius',Math.abs((posX-refCircle.get('left'))));
canvas1.renderAll();
}
});
canvas1.on('mouse:up',function(){
canvas1.add(refCircle);
//alert("mouse up!");
isMouseDown=false;
//freeDrawing=false; // **Disables line drawing
});
});
});
var Circle = (function() {
function Circle(canvas) {
this.canvas = canvas;
this.className = 'Circle';
this.isDrawing = false;
this.bindEvents();
}
Circle.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();
})
}
Circle.prototype.onMouseUp = function(o) {
var inst = this;
inst.disable();
};
Circle.prototype.onMouseMove = function(o) {
var inst = this;
if (!inst.isEnable()) {
return;
}
var pointer = inst.canvas.getPointer(o.e);
var activeObj = inst.canvas.getActiveObject();
activeObj.stroke = 'red',
activeObj.strokeWidth = 5;
activeObj.fill = 'red';
if (origX > pointer.x) {
activeObj.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
activeObj.set({
top: Math.abs(pointer.y)
});
}
activeObj.set({
rx: Math.abs(origX - pointer.x) / 2
});
activeObj.set({
ry: Math.abs(origY - pointer.y) / 2
});
activeObj.setCoords();
inst.canvas.renderAll();
};
Circle.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var ellipse = new fabric.Ellipse({
top: origY,
left: origX,
rx: 0,
ry: 0,
transparentCorners: false,
hasBorders: false,
hasControls: false
});
inst.canvas.add(ellipse).setActiveObject(ellipse);
};
Circle.prototype.isEnable = function() {
return this.isDrawing;
}
Circle.prototype.enable = function() {
this.isDrawing = true;
}
Circle.prototype.disable = function() {
this.isDrawing = false;
}
return Circle;
}());
var canvas = new fabric.Canvas('canvas');
var circle = new Circle(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
Please draw circle here
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>
Here is the detail blog with jsfiddle - https://blog.thirdrocktechkno.com/sketching-circle-of-a-html5-canvas-using-the-fabricjs-f7dbfa20cf2d
Here is an example of drawing a rectangle which I carefully made and works for latest versions. Krunan example seems to work OK- just in case this is a rectangle free drawing implementation that doesn't use DOM apis like e.clientX, offsetLeft, etc to track the coords, but fabric.js APIs only which I think is safer. Also unregister event listeners - I'm still trying to refine it since I need free drawing support for my project - Since there is no official support for this I wanted to reference the example here for others.
https://cancerberosgx.github.io/demos/misc/fabricRectangleFreeDrawing.html
An easy way to add a Circle to a canvas:
canvas.add(new fabric.Circle({ radius: 30, fill: "green", top: 100, left: 100 }));
Related
So i'm using Konvajs, to draw segments, only vertical and horizontal. My problem is the following, when i start the debug, if the window is small and then i click to maximize, the layer will stay with same size as when small. Ex:
here it s the Javascript file for the Konva creation:
function setUpDesignMap(){
var width = $('#designContainer').width();
var height = $('#designContainer').height();
var blockSnapSize = gridSize;
var isDrawing = false;
var drawShape = null;
designStage = new Konva.Stage({
container: 'designContainer',
width: width,
height: height,
draggable: true,
name:'designStage'
// dragBoundFunc: function(pos) {
// var newY = pos.y < 0 ? 0 : pos.y;
// var newX = pos.x < 0 ? 0 : pos.x;
// return {
// x: newX,
// y: newY
// };
// }
});
/*Set up grid*/
var gridLayer = new Konva.Layer();
var tipLayer = new Konva.Layer();
drawLayer = new Konva.Layer();
segGrp = new Konva.Group({name:'segments'});
/* draw grid */
for (var i = 0; i < 240; i++) {
gridLayer.add(new Konva.Line({
points: [Math.round(i * blockSnapSize), 0, Math.round(i * blockSnapSize), 120*blockSnapSize],
stroke: '#888',
strokeWidth: 0.5,
}));
}
gridLayer.add(new Konva.Line({points: [0,0,10,10]}));
for (var j = 0; j < 120; j++) {
gridLayer.add(new Konva.Line({
points: [0, Math.round(j * blockSnapSize), 240*blockSnapSize, Math.round(j * blockSnapSize)],
stroke: '#888',
strokeWidth: 0.5,
}));
}
/* Stage initial position*/
zoomVars_design = {scale: 1, factor: 1.1, origin: {x:-100*gridSize,y:-50*gridSize}};
designStage.position(zoomVars_design.origin);
designStage.scale({ x: 1, y: 1 });
/*Set up mouse tip*/
var mouseTip = new Konva.Rect({
width: 6,
height: 6,
opacity:0,
fill: '#FFCC00',
stroke: '#FFCC00'
});
tipLayer.add(mouseTip);
/* Set up length indicator */
var lenShape = new Konva.Line({
points:[],
opacity: 1,
strokeWidth: 1,
stroke: '#000',
dash:[7,5]
});
gridLayer.add(lenShape);
/* Set up length text*/
var lenText = new Konva.Text({
align: 'center',
verticalAlign: 'middle',
fontSize: 12
});
gridLayer.add(lenText);
var lenSide = new Konva.Line({
points:[],
opacity: 1,
strokeWidth: 1,
stroke: '#000',
dash:[7,5]
});
gridLayer.add(lenSide);
/*Mouse handlers*/
//remove default behaviour for the container
$("#designContainer").on('mousedown', function(e){
e.preventDefault();
});
$("#designContainer").on('contextmenu', function(e){
e.preventDefault();
});
//mouse handlers on stage
designStage.on('contentMousedown', function (e) {
if(e.evt.button == 0){
designStage.draggable(false);
}
else{
designStage.draggable(true);
return;
}
if(mouseMode == 0){ //draw mode
var startPoint = {x:(mouseTip.attrs.x+3), y:(mouseTip.attrs.y+3)};
if(!isDrawing){
if(!isIntersection(startPoint)){ //cannot be intersection to avoid crosses
//check if there's an intersection on the begining
if(isCorner(startPoint)){
intersectingSeg = false;
intersectingCorner = true;
console.log('intersectingSeg = false')
}
else{
//check if its on an existing segment
var isonseg = isOnSegment(startPoint);
if(isonseg.b){
//validate resulting segments length
var intercected = getSegmentsArray(isonseg.d)[isonseg.i];
var res = breakSegAtIntersection(startPoint,intercected);
if(isValidLength(res[0].start,res[0].end) && isValidLength(res[1].start,res[1].end)){
intersectingSeg = true;
intersectingCorner = false;
console.log('>>>>>>>Intersecting Segment at start')
}
else{
consoleAdd('Resulting segments are too small to you');
return;
}
}
}
//start drawing
drawShape = new Konva.Line({
points: [startPoint.x, startPoint.y],
strokeWidth: 15,
stroke: 'black',
opacity: 0.5,
dir:'h'
});
drawShape.on('mouseover', function (e) {
if(mouseMode == 1){
this.stroke('#031C4D');
drawLayer.draw();
}
});
drawShape.on('mouseout', function (e) {
if(mouseMode == 1){
this.stroke('black');
drawLayer.draw();
}
});
drawShape.on('mouseup', function (e) {
if(mouseMode == 1){
this.stroke('#092C70');
drawLayer.draw();
}
});
segGrp.add(drawShape);
drawLayer.add(segGrp);
drawLayer.draw();
isDrawing = true;
}
else{
consoleAdd('Cannot start on an intersection');
}
gridLayer.draw();
}
}
});
So i want the layer not to be that small, always refitting. Thank you all for your attention!
You need to manually resize your stage when the size of container element is changed.
window.addEventListener('resize', () => {
var width = $('#designContainer').width();
var height = $('#designContainer').height();
designStage.width(width);
designStage.height(height);
})
You may also need to apply the scale to the stage.
Take a look into related demo: https://konvajs.org/docs/sandbox/Responsive_Canvas.html
I'm quite new to Fabric.js and I found some fiddle that is working correctly to 1.6.7 version including. So the tool allowed me to cut the selected area of the photo. However, since 1.7 this function draws a path in a different location than I select on the screen. Could I ask for a clue where the cause may lie?
http://jsfiddle.net/czechue/kNEaX/852/
var canvas = new fabric.Canvas('c1', {
isDrawingMode: true
});
var src = "http://fabricjs.com/lib/pug.jpg";
canvas.backgroundColor = "#333";
canvas.freeDrawingBrush.color = "purple"
canvas.freeDrawingBrush.width = 4
var el = new fabric.Rect({
fill: 'transparent',
originX: 'left',
originY: 'top',
stroke: '#ccc',
strokeDashArray: [2, 2],
opacity: 1,
width: 1,
height: 1
});
el.visible = false;
canvas.add(el);
var object;
fabric.util.loadImage(src, function (img) {
object = new fabric.Image(img);
object.set({
selectable: false
});
object.hasRotatingPoint = true;
canvas.add(object);
canvas.renderAll();
});
canvas.on('path:created', function(options) {
var path = options.path;
canvas.isDrawingMode = false;
object.clipTo = function(ctx) {
path.set({ objectCaching: false})
path.render(ctx);
};
object.selectable = true;
disabled = true;
el.visible = false;
canvas.renderAll();
});
So i suggest since the big differences between 1.6.7 and 1.7.x, to jump directly on 2.0, but apart this i think what you need to do is to use the object as dirty after you apply a clipPath.
canvas.on('path:created', function(options) {
var path = options.path;
canvas.isDrawingMode = false;
object.clipTo = function(ctx) {
path.set({ objectCaching: false })
path.render(ctx);
};
object.selectable = true;
object.dirty = true;
disabled = true;
el.visible = false;
canvas.renderAll();
});
Hi i have a fabricJs canvas and i load an image . after that i draw rectangle on it (Region of interest)
What i want is , when i drag the image to move on it (after a zoom for exemple) all the rectangle move with it .
That's my actual code .
var canvas = new fabric.Canvas('c');
fabric.Image.fromURL("/images/test.png", (oImg) => {
canvas.add(oImg);
canvas.sendToBack(oImg);
canvas.renderAll();
}, {evented: false, selectable: false, hasBorders: false, hasControls: false, hasRotatingPoint: false});
var text = new fabric.Textbox('1. Text inside canvas', {
left: 100,
top: 50,
width:300,
fill: 'white'
});
canvas.add(text);
$("#zoomIn").click(function(){
zoomIn();
});
$("#zoomOut").click(function(){
zoomOut();
});
$("#btnResetZoom").click(function(){
resetZoom();
});
function zoomIn() {
canvas.setZoom(canvas.getZoom() *1.1);
canvas.renderAll();
}
function zoomOut() {
canvas.setZoom(canvas.getZoom() * 0.9);
canvas.renderAll();
}
function resetZoom() {
canvas.setZoom(1);
canvas.renderAll();
}
var DrawingRectangle;
var rectangle, isDown, origX, origY;
$("#select").click(function(){
canvas.isDrawingMode = false;
canvas.forEachObject(function(object){
object.selectable = true;
object.evented =true;
})
});
$("#draw").click(function(){
DrawingRectangle = true;
canvas.forEachObject(function(object){
object.selectable = false;
object.evented =false;
})
draw();
});
$("#delete").click(function(){
canvas.isDrawingMode = false;
});
function draw(){
canvas.on('mouse:down', function(o){
var pointer = canvas.getPointer(o.e);
isDown = true;
origX = pointer.x;
origY = pointer.y;
rectangle = new fabric.Rect({
left: origX,
top: origY,
fill: 'transparent',
stroke: 'red',
strokeWidth: 3,
selectable: true,
});
rectangle.hasRotatingPoint=true;
canvas.add(rectangle);
});
canvas.on('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if(origX>pointer.x){
rectangle.set({ left: Math.abs(pointer.x) });
}
if(origY>pointer.y){
rectangle.set({ top: Math.abs(pointer.y) });
}
rectangle.set({ width: Math.abs(origX - pointer.x) });
rectangle.set({ height: Math.abs(origY - pointer.y) });
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
isDown = false;
canvas.off('mouse:down');
canvas.off('mouse:move');
canvas.off('mouse:up');
});
}
What i do actually is when i click on the "Draw" button all my object become unselectable so i can draw over the image.
Then when i click on the "select" button , all my object become selectable (that only work for my image but not for the rectangles that i draw)
and once i move my image , the image come in foreground and my rectangle diseappear in the background.
1) Why my rectangle can't be selectable
2) How can i move all object when the image object (i guess with ID 0 because it's the first loaded object) is moved .
EDIT : Solved No1 . still have issue with No 2 .
i Tried to fire event with my image object but doesn't work . like this :
oImg.on('mouse:down', function(o){ it says it's undefined
var canvas = new fabric.Canvas('paper',{preserveObjectStacking:true});
canvas.backgroundColor = 'grey';
var isDown = false;
fabric.Image.fromURL("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.svg?v=6e4af45f4d66", function (oImg) {
canvas.add(oImg);
canvas.sendToBack(oImg);
oImg.on('mousedown', function() {
oImg.centerPt = this.getCenterPoint();
canvas.forEachObject(function(obj) {
obj.origPose = new fabric.Point(obj.left, obj.top);
})
})
oImg.on('mouseup', function() {
delete this.centerPt;
canvas.forEachObject(function(obj) {
delete obj.origPose;
})
})
oImg.on('moving', function(evt) {
var self = this;
var diff = this.getCenterPoint().subtract(self.centerPt);
canvas.forEachObject(function(obj) {
if (obj == self) return;
obj.set({
left: obj.origPose.x + diff.x,
top: obj.origPose.y + diff.y
})
obj.setCoords();
})
})
canvas.renderAll();
}, {
selectable: false,
});
var text = new fabric.Textbox('1. Text inside canvas', {
left: 100,
top: 50,
width: 300,
fill: 'white',
selectable: false
});
canvas.add(text);
$("#zoomIn").click(function() {
zoomIn();
});
$("#zoomOut").click(function() {
zoomOut();
});
$("#btnResetZoom").click(function() {
resetZoom();
});
function zoomIn() {
canvas.setZoom(canvas.getZoom() * 1.1);
canvas.renderAll();
}
function zoomOut() {
canvas.setZoom(canvas.getZoom() * 0.9);
canvas.renderAll();
}
function resetZoom() {
canvas.setZoom(1);
canvas.renderAll();
}
$("#select").click(function() {
DrawingRectangle = false;
canvas.selection = true;
canvas.off('mouse:down');
canvas.off('mouse:move');
canvas.off('mouse:up');
changeSelectableStatus(true);
});
$("#draw").click(function() {
canvas.selection = false;
draw();
changeSelectableStatus(false);
});
function changeSelectableStatus(val) {
canvas.forEachObject(function(obj) {
obj.selectable = val;
})
canvas.renderAll();
}
function draw() {
canvas.on('mouse:down', onMouseDown);
canvas.on('mouse:move', onMouseMove);
canvas.on('mouse:up', onMouseUp);
}
function onMouseDown(o) {
var pointer = canvas.getPointer(o.e);
isDown = true;
origX = pointer.x;
origY = pointer.y;
rectangle = new fabric.Rect({
left: origX,
top: origY,
fill: 'transparent',
stroke: 'red',
strokeWidth: 3,
selectable: false
});
canvas.add(rectangle);
}
function onMouseMove(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rectangle.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
rectangle.set({
top: Math.abs(pointer.y)
});
}
rectangle.set({
width: Math.abs(origX - pointer.x)
});
rectangle.set({
height: Math.abs(origY - pointer.y)
});
canvas.renderAll();
};
function onMouseUp(o) {
rectangle.setCoords();
isDown = false;
DrawingRectangle = false;
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>
<canvas id="paper" width="800" height="300" style="border:1px solid #ccc;"></canvas>
<button id="draw">Draw ROI</button>
<button id="select">Select ROI(s)</button>
<button id="zoomIn">Zoom In</button>
<button id="zoomOut">Zoom Out</button>
<button id="btnResetZoom">Reset Zoom</button>
1) Draw ROI button> draw rectangle, where you draw rectangles.
2) Select ROI button > select objects(move,rotate).
3) zoom in/out button.
4) and in canvas one image there, if you drag that image what ever objects there they will drag with that much distance with which image covered.
use preserveObjectStacking:true then objects wont come on top while dragging.
I've got a question about fabric.js and the polygon-object.
I have an example of my problem in this fiddle:
Click me
First 4 fabric.Circle subobjects called linePoint are drawn.
The linePoint objects have an extra x(same as left) and y(same as top) coordinate and a reference to which polygon they belong to:
fabric.LinePoint = fabric.util.createClass(fabric.Circle,
{
initialize: function (options) {
options || (options = {});
this.callSuper('initialize', options);
options &&
this.set('type', 'line_point'),
this.set('x', this.left),
this.set('y', this.top),
this.set('polygon', options.polygon)
},
setPointCoordinates: function(new_left, new_top) {
this.set('x', new_left);
this.set('y', new_top);
this.set('left', new_left);
this.set('top', new_top);
}
With the now given x and y coordinates there is a Polygon drawn between the Points.
The problem is now, when you move the Circles, the Polygon is moved correctly, but its border (or I don't know how to exactly call it) will stay the same small rectangle as it was.
I want to update the polygon Coords too, I tried .setCoords(), but nothing happened.
Maybe you can help me. :) Thanks!
In reply also to:
https://groups.google.com/forum/#!topic/fabricjs/XN1u8E0EBiM
This is your modified fiddle:
https://jsfiddle.net/wum5zvwk/2/
fabric.LinePoint = fabric.util.createClass(fabric.Circle,
{
initialize: function (options) {
options || (options = {});
this.callSuper('initialize', options);
this.set('type', 'line_point'),
this.set('x', this.left),
this.set('y', this.top),
this.set('polygon', options.polygon)
},
setPointCoordinates: function(new_left, new_top) {
this.set('x', new_left);
this.set('y', new_top);
this.set('left', new_left);
this.set('top', new_top);
}
});
var canvas = new fabric.Canvas('canvas');
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
document.getElementById("canvas").tabIndex = 1000;
drawPolygonToCanvas();
canvas.on('object:moving', function(event) {
var object = event.target;
switch(object.type) {
case 'line_point':
//move polygon
object.setPointCoordinates(object.left, object.top);
object.polygon.setCoords();
object.polygon.initialize(object.polygon.points);
object.polygon.top += object.polygon.height / 2;
object.polygon.left += object.polygon.width / 2;
canvas.renderAll();
break;
}
});
function drawPolygonToCanvas()
{
//creting end_points and set them
old_position = canvas.getPointer(event.e);
var end_point_1 = createLinePoint(100, 100);
var end_point_2 = createLinePoint(100, 150);
var end_point_3 = createLinePoint(150, 150);
var end_point_4 = createLinePoint(150, 100);
end_points_in_use = [end_point_1, end_point_2, end_point_3, end_point_4];
canvas.add(end_point_1, end_point_2, end_point_3, end_point_4);
drawPoly(end_points_in_use);
canvas.deactivateAll();
canvas.renderAll();
}
function drawPoly(point_array)
{
var poly = new fabric.Polygon(point_array, {
left: (100 + ((150 - 100) /2)),
top: (100 + ((150 - 100) /2)),
fill: 'lightblue',
lockScalingX: true,
lockScalingY: true,
lockMovementX: true,
lockMovementY: true,
perPixelTargetFind: true,
opacity: 0.5,
type: 'polygon'
});
for (var i = 0; i < point_array.length; i++) {
point_array[i].polygon = poly;
}
canvas.add(poly);
poly.sendToBack();
}
function createLinePoint(left, top) {
return new fabric.LinePoint({
left: left,
top: top,
strokeWidth: 2,
radius: 15,
fill: '#fff',
stroke: '#666',
related_poly_point: 0,
lockScalingX: true,
lockScalingY: true
});
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<div id="canvas-wrapper" style="position:relative;width:704px;float:left;">
<canvas id="canvas" width="700" height="600" style="border:1px solid #000000;"></canvas>
</div>
Modifying the polygon points is not enough to have the bounding box adjusted. The easies thing i can think of is to re initialize the polygon with the new points coordinates.
I am inspired with KonvaJS tutorial Modify Curves with Anchor Points to make my own example which is to create multiple custom arrows.
on click on the selectionBox create an anchor.
on the creation of the third anchor create the curved arrow.
on the fourth click reset all variables in order to draw a new curved arrow.
var width = window.innerWidth;
var height = window.innerHeight;
// globals
var selectionBoxLayer, curveLayer, lineLayer, anchorLayer, quad, bezier;
function updateDottedLines() {
var q = quad;
var quadLine = lineLayer.get('#quadLine')[0];
quadLine.setPoints([q.start.attrs.x, q.start.attrs.y, q.control.attrs.x, q.control.attrs.y, q.end.attrs.x, q.end.attrs.y]);
lineLayer.draw();
}
function buildAnchor(x, y) {
var anchor = new Konva.Circle({
x: x,
y: y,
radius: 20,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
draggable: true
});
// add hover styling
anchor.on('mouseover', function() {
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
anchorLayer.draw();
});
anchor.on('mouseout', function() {
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
anchorLayer.draw();
});
anchor.on('dragend', function() {
drawCurves();
updateDottedLines();
});
anchorLayer.add(anchor);
anchorLayer.draw();
return anchor;
}
function drawCurves() {
var context = curveLayer.getContext();
var arrowLine = new Konva.Shape({
sceneFunc: function(context){
debugger;
// draw quad
context.beginPath();
context.moveTo(quad.start.attrs.x, quad.start.attrs.y);
context.quadraticCurveTo(quad.control.attrs.x, quad.control.attrs.y, quad.end.attrs.x, quad.end.attrs.y);
//Draw Arrow Head
var headlen = 10; // length of head in pixels
var angle = Math.atan2(quad.end.attrs.y - quad.control.attrs.y, quad.end.attrs.x - quad.control.attrs.x);
context.lineTo(quad.end.attrs.x-headlen*Math.cos(angle-Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle-Math.PI/6));
context.moveTo(quad.end.attrs.x, quad.end.attrs.y);
context.lineTo(quad.end.attrs.x- headlen*Math.cos(angle+Math.PI/6), quad.end.attrs.y-headlen*Math.sin(angle+Math.PI/6));
context.fillStrokeShape(this);
},
stroke: 'black',
strokeWidth: 4
});
curveLayer.add(arrowLine);
curveLayer.draw();
}
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
selectionBoxLayer = new Konva.Layer();
anchorLayer = new Konva.Layer();
lineLayer = new Konva.Layer();
// curveLayer just contains a canvas which is drawn
// onto with the existing canvas API
curveLayer = new Konva.Layer();
var quadLine = new Konva.Line({
dash: [10, 10, 0, 10],
strokeWidth: 3,
stroke: 'black',
lineCap: 'round',
id: 'quadLine',
opacity: 0.3,
points: [0, 0]
});
// add dotted line connectors
lineLayer.add(quadLine);
quad = {};
// keep curves insync with the lines
anchorLayer.on('beforeDraw', function() {
if(quad.start && quad.control && quad.end){
drawCurves();
updateDottedLines();
}
});
var selectionBoxBackground = new Konva.Rect({
x: 0,
y: 0,
height:stage.height(),
width: stage.width(),
fill: 'transparent',
draggable: false,
name: 'selectionBoxBackground'
});
selectionBoxLayer.add(selectionBoxBackground);
var clickCounter = 0;
selectionBoxBackground.on("click", function(){
clickCounter +=1;
var mousePos = {};
switch(clickCounter){
case 1:
mousePos = stage.getPointerPosition();
quad.start = buildAnchor(mousePos.x, mousePos.y);
break;
case 2:
mousePos = stage.getPointerPosition();
quad.control = buildAnchor(mousePos.x, mousePos.y);
break;
case 3:
mousePos = stage.getPointerPosition();
quad.end = buildAnchor(mousePos.x, mousePos.y);
drawCurves();
updateDottedLines();
break;
default:
clickCounter = 0;
quad = {};
anchorLayer.destroyChildren();
anchorLayer.draw();
}
});
stage.add(curveLayer);
stage.add(lineLayer);
stage.add(selectionBoxLayer);
stage.add(anchorLayer);
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #F0F0F0;
}
<script src="https://cdn.rawgit.com/konvajs/konva/0.11.1/konva.min.js"></script>
<body>
<div id="container"></div>
</body>
P.S Please note when I write in the browser console curveLayer.children, it will bring all created curved arrows.
Hint: I think on the creation of new Shape() the values of all created shapes will be changed to the new one.
I don't know what I am missing.